Index: programs/mythfrontend/globalsettings.h
===================================================================
--- programs/mythfrontend/globalsettings.h	(revision 15495)
+++ programs/mythfrontend/globalsettings.h	(working copy)
@@ -149,6 +149,53 @@
     HostComboBox *grouptrigger;
 };
 
+class PlaybackSpeedsConfigWizard : public QObject, public ConfigurationWizard
+{
+    Q_OBJECT
+
+  public:
+    PlaybackSpeedsConfigWizard(vector<int> &_ff_rew, vector<int> &_repos,
+                               vector<int> &_slowmo);
+    virtual void save(void);
+
+  private:
+    TransComboBoxSetting* slowmoCombo(uint value);
+
+    vector<int> &ff_rew;
+    vector<int> &repos;
+    vector<int> &slowmo;
+
+    vector<TransSpinBoxSetting*> ff_rew_spins;
+    vector<TransSpinBoxSetting*> repos_spins;
+    vector<TransComboBoxSetting*> slowmo_combos;
+};
+
+class PlaybackSpeedsConfig : public VerticalConfigurationGroup
+{
+    Q_OBJECT
+
+  public:
+    PlaybackSpeedsConfig();
+    virtual void save(void);
+
+  private slots:
+    void pressed(QString);
+
+  private:
+    void InitLabels();
+    void InitUI(void);
+
+  private:
+    bool        needs_save;
+    vector<int> ff_rew_speeds;
+    vector<int> ff_rew_repos;
+    vector<int> slowmo_speeds;
+
+    TransLabelSetting*          ff_rew_label;
+    TransLabelSetting*          slowmo_label;
+    TransButtonSetting*         edit;
+};
+
 #ifdef USING_IVTV
 class PVR350VideoDevice : public PathSetting, public HostDBStorage
 {
Index: programs/mythfrontend/globalsettings.cpp
===================================================================
--- programs/mythfrontend/globalsettings.cpp	(revision 15495)
+++ programs/mythfrontend/globalsettings.cpp	(working copy)
@@ -1375,6 +1375,222 @@
     TriggeredConfigurationGroup::triggerChanged(trig);
 }
 
+TransLabelSetting* makeLabel(const QString &value)
+{
+    TransLabelSetting* l = new TransLabelSetting();
+    l->setValue(value);
+    return l;
+}
+
+PlaybackSpeedsConfigWizard::PlaybackSpeedsConfigWizard(vector<int> &_ff_rew, 
+                    vector<int> &_repos, vector<int> &_slowmo) :
+                    ff_rew(_ff_rew), repos(_repos), slowmo(_slowmo)
+{
+    for (uint i = 0; i < ff_rew.size(); i++)
+    {
+        TransSpinBoxSetting* spin = new TransSpinBoxSetting(0, 360, 5, true, 
+                                                "(" + tr("disabled") + ")");
+        spin->setValue(ff_rew[i]);
+        ff_rew_spins.push_back(spin);
+
+        spin = new TransSpinBoxSetting(-5, 200, 5, false,
+                                        "(" + tr("default") + ")");
+        spin->setValue(repos[i]);
+        spin->setHelpText(tr(
+                    "When exiting sticky keys fast forward/rewind "
+                    "mode, reposition this many 1/100th seconds before "
+                    "resuming normal playback. This "
+                    "compensates for the reaction time between seeing "
+                    "where to resume playback and actually exiting seeking."));
+        repos_spins.push_back(spin);
+    };
+    for (uint i = 0; i < slowmo.size(); i++)
+    {
+        slowmo_combos.push_back(slowmoCombo(slowmo[i]));
+    };
+
+    VerticalConfigurationGroup *ff_rew_rows =
+        new VerticalConfigurationGroup(true, true, false, true);
+    ff_rew_rows->setLabel(tr("Fast forward/rewind"));
+
+    HorizontalConfigurationGroup *row =
+        new HorizontalConfigurationGroup(false, false, true, true);
+    row->addChild(makeLabel(""));
+    row->addChild(makeLabel(tr("Speed")));
+    row->addChild(makeLabel(tr("Reposition")));
+    ff_rew_rows->addChild(row);
+
+    for (uint i = 0; i < ff_rew_spins.size(); i++)
+    {
+        QString str = (i == ff_rew_spins.size()-1) ? tr("Fastest") :
+                      (i == 0) ? tr("Slowest") : "" ;
+        row = new HorizontalConfigurationGroup(false, false, true, true);
+        row->addChild(makeLabel(str));
+        row->addChild(ff_rew_spins[i]);
+        row->addChild(repos_spins[i]);
+        ff_rew_rows->addChild(row);
+    };
+   
+    HorizontalConfigurationGroup *slowmo_rows =
+        new HorizontalConfigurationGroup(true, true, false, true);
+    VerticalConfigurationGroup *column1 = 
+        new VerticalConfigurationGroup(false, false, true, true);
+    VerticalConfigurationGroup *column2 = 
+        new VerticalConfigurationGroup(false, false, true, true);
+
+    slowmo_rows->setLabel(tr("Slow motion"));
+
+    column1->addChild(makeLabel(""));
+    column2->addChild(makeLabel(tr("Speed")));
+
+    for (uint i = 0; i < slowmo_combos.size(); i++)
+    {
+        QString str = (i == slowmo_combos.size()-1) ? tr("Slowest") :
+                      (i == 0) ? tr("Fastest") : "" ;
+        column1->addChild(makeLabel(str));
+        column2->addChild(slowmo_combos[i]);
+    };
+
+    for (uint i = slowmo_combos.size(); i < ff_rew_spins.size(); i++)
+    {
+        column1->addChild(makeLabel(""));
+        column2->addChild(makeLabel(""));
+    };
+
+    slowmo_rows->addChild(column1);
+    slowmo_rows->addChild(column2);
+
+    HorizontalConfigurationGroup *main =
+        new HorizontalConfigurationGroup(false, false, true, true);
+    main->setLabel(tr("Playback Speed Configuration"));
+    main->addChild(ff_rew_rows);
+    main->addChild(slowmo_rows);
+    
+    addChild(main);
+}
+
+void PlaybackSpeedsConfigWizard::save(void)
+{
+    for (uint i = 0; i < ff_rew.size(); i++)
+    {
+        ff_rew[i] = ff_rew_spins[i]->getValue().toInt();
+        repos[i] = repos_spins[i]->getValue().toInt();
+    };
+
+    for (uint i = 0; i < slowmo.size(); i++)
+    {
+        slowmo[i] = slowmo_combos[i]->getValue().toInt();
+    };
+}
+
+TransComboBoxSetting* PlaybackSpeedsConfigWizard::slowmoCombo(uint value)
+{
+    TransComboBoxSetting* combo = new TransComboBoxSetting();
+    combo->addSelection("(" + tr("disabled") + ")", "0", (value == 0));
+    for (uint i = 2; i <= 64; i++)
+    {
+        combo->addSelection(QString("1/%1").arg(i), QString::number(i), 
+                            (i == value));
+    };
+    return combo;
+};
+
+PlaybackSpeedsConfig::PlaybackSpeedsConfig() :
+    VerticalConfigurationGroup(false, false, true, true),
+    needs_save(false)
+{
+    int def1[8] = {3, 5, 10, 20, 30, 60, 120, 180};
+    for (uint i = 0; i < sizeof(def1)/sizeof(def1[0]); i++)
+    {
+        int speed = gContext->GetNumSetting(QString("FFRewSpeed%1").arg(i),
+                                            def1[i]);
+        ff_rew_speeds.push_back(speed);
+        
+        int repos = gContext->GetNumSetting(QString("FFRewReposTime%1").
+                                                arg(i), -5);
+        ff_rew_repos.push_back(repos);
+    };
+
+    int def2[4] = {3, 8, 16, 0};
+    for (uint i = 0; i < sizeof(def2)/sizeof(def2[0]); i++)
+    {
+        int speed = gContext->GetNumSetting(QString("SlowMotionSpeed%1").
+                                            arg(i), def2[i]);
+        slowmo_speeds.push_back(speed);
+    };
+
+    InitUI();
+}
+
+void PlaybackSpeedsConfig::InitLabels()
+{
+    QString str = tr("Fast forward/rewind") + ":";
+    for (uint i = 0; i < ff_rew_speeds.size(); i++)
+        if (ff_rew_speeds[i] > 0 )
+            str += QString("   %1x").arg(ff_rew_speeds[i]);
+           
+    ff_rew_label->setValue(str);
+
+    str = tr("Slow motion") + ":";
+    for (uint i = 0; i < slowmo_speeds.size(); i++)
+        if (slowmo_speeds[i] > 0 )
+            str += QString("   1/%1x").arg(slowmo_speeds[i]);
+           
+    slowmo_label->setValue(str);
+}
+
+void PlaybackSpeedsConfig::InitUI(void)
+{
+    VerticalConfigurationGroup *rows =
+        new VerticalConfigurationGroup(true, true, false, true);
+    rows->setLabel(tr("Playback Speeds"));
+
+    ff_rew_label = new TransLabelSetting();
+    slowmo_label = new TransLabelSetting();
+    InitLabels();
+    rows->addChild(ff_rew_label);
+    rows->addChild(slowmo_label);
+
+    edit = new TransButtonSetting("edit");
+    edit->setLabel(QObject::tr("Edit Playback Speeds"));
+    rows->addChild(edit);
+    connect(edit, SIGNAL(pressed(QString)),
+            this, SLOT  (pressed(QString)));
+
+    addChild(rows);
+}
+
+void PlaybackSpeedsConfig::save(void)
+{
+    if (!needs_save)
+        return; // nothing to do..
+
+    for (uint i = 0; i < ff_rew_speeds.size(); i++)
+    {
+        gContext->SaveSetting(QString("FFRewSpeed%1").arg(i),
+                              QString::number(ff_rew_speeds[i]));
+        gContext->SaveSetting(QString("FFRewReposTime%1").arg(i),
+                              QString::number(ff_rew_repos[i]));
+    };
+    for (uint i = 0; i < slowmo_speeds.size(); i++)
+    {
+        gContext->SaveSetting(QString("SlowMotionSpeed%1").arg(i),
+                              QString::number(slowmo_speeds[i]));
+    };
+}
+
+void PlaybackSpeedsConfig::pressed(QString cmd)
+{
+    PlaybackSpeedsConfigWizard cfg(ff_rew_speeds, ff_rew_repos, slowmo_speeds);
+    if (cfg.exec() != QDialog::Accepted)
+        VERBOSE(VB_IMPORTANT, "playback speeds rejected");
+
+    InitLabels();
+    needs_save = true;
+
+    repaint();
+}
+
 static HostComboBox *PlayBoxOrdering()
 {
     QString str[4] =
@@ -4494,6 +4710,7 @@
     seek->addChild(SmartForward());
     seek->addChild(StickyKeys());
     seek->addChild(FFRewReposTime());
+    seek->addChild(new PlaybackSpeedsConfig());
     seek->addChild(FFRewReverse());
     seek->addChild(ExactSeeking());
     addChild(seek);

