From 2eef004b8b70861fd377ad50393a9a0ccbbbc152 Mon Sep 17 00:00:00 2001
From: Andrei Karas <akaras@inbox.ru>
Date: Tue, 21 Feb 2012 00:10:57 +0300
Subject: Move some settings from video to visual page.

---
 src/gui/setup_video.cpp       | 172 +++++-------------------------------------
 src/gui/setup_video.h         |  21 ------
 src/gui/setup_visual.cpp      |  48 +++++++++++-
 src/gui/setup_visual.h        |  10 +++
 src/gui/widgets/setupitem.cpp | 161 ++++++++++++++++++++++++++++++++++++++-
 src/gui/widgets/setupitem.h   |  51 ++++++++++++-
 src/utils/mathutils.h         |   5 ++
 7 files changed, 286 insertions(+), 182 deletions(-)

diff --git a/src/gui/setup_video.cpp b/src/gui/setup_video.cpp
index 65fb460e5..ae7e7a9cc 100644
--- a/src/gui/setup_video.cpp
+++ b/src/gui/setup_video.cpp
@@ -28,7 +28,6 @@
 #include "localplayer.h"
 #include "logger.h"
 #include "main.h"
-#include "particle.h"
 
 #include "gui/gui.h"
 #include "gui/okdialog.h"
@@ -214,95 +213,26 @@ public:
     }
 };
 
-static const char *speechModeToString(Being::Speech mode)
-{
-    switch (mode)
-    {
-        case Being::NO_SPEECH:
-        default:
-            return _("No text");
-        case Being::TEXT_OVERHEAD:
-            return _("Text");
-        case Being::NO_NAME_IN_BUBBLE:
-            return _("Bubbles, no names");
-        case Being::NAME_IN_BUBBLE:
-            return _("Bubbles with names");
-    }
-}
-
-const char *Setup_Video::overlayDetailToString(int detail)
-{
-    if (detail == -1)
-        detail = config.getIntValue("OverlayDetail");
-
-    switch (detail)
-    {
-        case 0:
-            return _("off");
-        case 1:
-            return _("low");
-        case 2:
-            return _("high");
-        default:
-            return "";
-    }
-    return "";
-}
-
-const char *Setup_Video::particleDetailToString(int detail)
-{
-    if (detail == -1)
-        detail = 3 - config.getIntValue("particleEmitterSkip");
-
-    switch (detail)
-    {
-        case 0:
-            return _("low");
-        case 1:
-            return _("medium");
-        case 2:
-            return _("high");
-        case 3:
-            return _("max");
-        default:
-            return "";
-    }
-    return "";
-}
-
 Setup_Video::Setup_Video():
     mFullScreenEnabled(config.getBoolValue("screen")),
     mOpenGLEnabled(config.getIntValue("opengl")),
     mCustomCursorEnabled(config.getBoolValue("customcursor")),
-    mParticleEffectsEnabled(config.getBoolValue("particleeffects")),
     mFps(config.getIntValue("fpslimit")),
     mAltFps(config.getIntValue("altfpslimit")),
     mEnableResize(config.getBoolValue("enableresize")),
     mNoFrame(config.getBoolValue("noframe")),
-    mSpeechMode(static_cast<Being::Speech>(
-        config.getIntValue("speech"))),
     mModeListModel(new ModeListModel),
     mModeList(new ListBox(mModeListModel)),
     mFsCheckBox(new CheckBox(_("Full screen"), mFullScreenEnabled)),
     mCustomCursorCheckBox(new CheckBox(_("Custom cursor"),
                           mCustomCursorEnabled)),
-    mParticleEffectsCheckBox(new CheckBox(_("Particle effects"),
-                             mParticleEffectsEnabled)),
     mEnableResizeCheckBox(new CheckBox(_("Enable resize"), mEnableResize)),
     mNoFrameCheckBox(new CheckBox(_("No frame"), mNoFrame)),
-    mSpeechSlider(new Slider(0, 3)),
-    mSpeechLabel(new Label("")),
     mFpsCheckBox(new CheckBox(_("FPS limit:"))),
     mFpsSlider(new Slider(2, 160)),
     mFpsLabel(new Label),
     mAltFpsSlider(new Slider(2, 160)),
     mAltFpsLabel(new Label(_("Alt FPS limit: "))),
-    mOverlayDetail(config.getIntValue("OverlayDetail")),
-    mOverlayDetailSlider(new Slider(0, 2)),
-    mOverlayDetailField(new Label),
-    mParticleDetail(3 - config.getIntValue("particleEmitterSkip")),
-    mParticleDetailSlider(new Slider(0, 3)),
-    mParticleDetailField(new Label),
     mDialog(nullptr)
 {
     setName(_("Video"));
@@ -311,10 +241,6 @@ Setup_Video::Setup_Video():
     scrollArea->setWidth(150);
     scrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
 
-    speechLabel = new Label(_("Overhead text"));
-    overlayDetailLabel = new Label(_("Ambient FX"));
-    particleDetailLabel = new Label(_("Particle detail"));
-
     mOpenGLListModel = new OpenGLListModel;
     mOpenGLDropDown = new DropDown(mOpenGLListModel),
     mOpenGLDropDown->setSelected(mOpenGLEnabled);
@@ -343,49 +269,28 @@ Setup_Video::Setup_Video():
 
     mModeList->setActionEventId("videomode");
     mCustomCursorCheckBox->setActionEventId("customcursor");
-    mParticleEffectsCheckBox->setActionEventId("particleeffects");
     mFpsCheckBox->setActionEventId("fpslimitcheckbox");
-    mSpeechSlider->setActionEventId("speech");
     mFpsSlider->setActionEventId("fpslimitslider");
     mAltFpsSlider->setActionEventId("altfpslimitslider");
-    mOverlayDetailSlider->setActionEventId("overlaydetailslider");
-    mOverlayDetailField->setActionEventId("overlaydetailfield");
-    mParticleDetailSlider->setActionEventId("particledetailslider");
-    mParticleDetailField->setActionEventId("particledetailfield");
     mOpenGLDropDown->setActionEventId("opengl");
     mEnableResizeCheckBox->setActionEventId("enableresize");
     mNoFrameCheckBox->setActionEventId("noframe");
 
     mModeList->addActionListener(this);
     mCustomCursorCheckBox->addActionListener(this);
-    mParticleEffectsCheckBox->addActionListener(this);
     mFpsCheckBox->addActionListener(this);
-    mSpeechSlider->addActionListener(this);
     mFpsSlider->addActionListener(this);
     mAltFpsSlider->addActionListener(this);
-    mOverlayDetailSlider->addActionListener(this);
-    mOverlayDetailField->addKeyListener(this);
-    mParticleDetailSlider->addActionListener(this);
-    mParticleDetailField->addKeyListener(this);
     mOpenGLDropDown->addActionListener(this);
     mEnableResizeCheckBox->addActionListener(this);
     mNoFrameCheckBox->addActionListener(this);
 
-    mSpeechLabel->setCaption(speechModeToString(mSpeechMode));
-    mSpeechSlider->setValue(mSpeechMode);
-
-    mOverlayDetailField->setCaption(overlayDetailToString(mOverlayDetail));
-    mOverlayDetailSlider->setValue(mOverlayDetail);
-
-    mParticleDetailField->setCaption(particleDetailToString(mParticleDetail));
-    mParticleDetailSlider->setValue(mParticleDetail);
-
     // Do the layout
     LayoutHelper h(this);
     ContainerPlacer place = h.getPlacer(0, 0);
 
-    place(0, 0, scrollArea, 1, 6).setPadding(2);
-    place(0, 6, mOpenGLDropDown, 1);
+    place(0, 0, scrollArea, 1, 5).setPadding(2);
+    place(0, 5, mOpenGLDropDown, 1);
 
     place(1, 0, mFsCheckBox, 2);
 
@@ -401,26 +306,26 @@ Setup_Video::Setup_Video():
 //    place(0, 7, mAlphaSlider);
 //    place(1, 7, alphaLabel, 3);
 
-    place(0, 9, mFpsSlider);
-    place(1, 9, mFpsCheckBox).setPadding(3);
-    place(2, 9, mFpsLabel).setPadding(1);
+    place(0, 6, mFpsSlider);
+    place(1, 6, mFpsCheckBox).setPadding(3);
+    place(2, 6, mFpsLabel).setPadding(1);
 
-    place(0, 10, mAltFpsSlider);
-    place(1, 10, mAltFpsLabel).setPadding(3);
+    place(0, 7, mAltFpsSlider);
+    place(1, 7, mAltFpsLabel).setPadding(3);
 
-    place(0, 11, mSpeechSlider);
-    place(1, 11, speechLabel);
-    place(2, 11, mSpeechLabel, 3).setPadding(2);
+//    place(0, 11, mSpeechSlider);
+//    place(1, 11, speechLabel);
+//    place(2, 11, mSpeechLabel, 3).setPadding(2);
 
-    place(0, 12, mOverlayDetailSlider);
-    place(1, 12, overlayDetailLabel);
-    place(2, 12, mOverlayDetailField, 3).setPadding(2);
+//    place(0, 12, mOverlayDetailSlider);
+//    place(1, 12, overlayDetailLabel);
+//    place(2, 12, mOverlayDetailField, 3).setPadding(2);
 
-    place(0, 13, mParticleEffectsCheckBox, 5);
+//    place(0, 13, mParticleEffectsCheckBox, 5);
 
-    place(0, 14, mParticleDetailSlider);
-    place(1, 14, particleDetailLabel);
-    place(2, 14, mParticleDetailField, 3).setPadding(2);
+//    place(0, 14, mParticleDetailSlider);
+//    place(1, 14, particleDetailLabel);
+//    place(2, 14, mParticleDetailField, 3).setPadding(2);
 
     int width = 600;
 
@@ -518,11 +423,7 @@ void Setup_Video::apply()
     // We sync old and new values at apply time
     mFullScreenEnabled = config.getBoolValue("screen");
     mCustomCursorEnabled = config.getBoolValue("customcursor");
-    mParticleEffectsEnabled = config.getBoolValue("particleeffects");
 
-    mSpeechMode = static_cast<Being::Speech>(
-        config.getIntValue("speech"));
-    mOverlayDetail = config.getIntValue("OverlayDetail");
     mOpenGLEnabled = config.getIntValue("opengl");
     mEnableResize = config.getBoolValue("enableresize");
     mNoFrame = config.getBoolValue("noframe");
@@ -534,14 +435,10 @@ void Setup_Video::cancel()
     mFsCheckBox->setSelected(mFullScreenEnabled);
     mOpenGLDropDown->setSelected(mOpenGLEnabled);
     mCustomCursorCheckBox->setSelected(mCustomCursorEnabled);
-    mParticleEffectsCheckBox->setSelected(mParticleEffectsEnabled);
     mFpsSlider->setValue(mFps);
     mFpsSlider->setEnabled(mFps > 0);
     mAltFpsSlider->setValue(mAltFps);
     mAltFpsSlider->setEnabled(mAltFps > 0);
-    mSpeechSlider->setValue(mSpeechMode);
-    mOverlayDetailSlider->setValue(mOverlayDetail);
-    mParticleDetailSlider->setValue(mParticleDetail);
     mFpsLabel->setCaption(mFpsCheckBox->isSelected()
                           ? toString(mFps) : _("None"));
     mAltFpsLabel->setCaption(_("Alt FPS limit: ") + toString(mAltFps));
@@ -558,8 +455,6 @@ void Setup_Video::cancel()
     config.setValue("screenheight", mainGraphics->mHeight);
 
     config.setValue("customcursor", mCustomCursorEnabled);
-    config.setValue("particleeffects", mParticleEffectsEnabled);
-    config.setValue("speech", static_cast<int>(mSpeechMode));
     config.setValue("opengl", mOpenGLEnabled);
     config.setValue("enableresize", mEnableResize);
     config.setValue("noframe", mNoFrame);
@@ -627,39 +522,6 @@ void Setup_Video::action(const gcn::ActionEvent &event)
     {
         config.setValue("customcursor", mCustomCursorCheckBox->isSelected());
     }
-    else if (id == "particleeffects")
-    {
-        config.setValue("particleeffects",
-                        mParticleEffectsCheckBox->isSelected());
-        Particle::enabled = mParticleEffectsCheckBox->isSelected();
-
-        if (Game::instance())
-        {
-            new OkDialog(_("Particle Effect Settings Changed."),
-                         _("Changes will take effect on map change."));
-        }
-    }
-    else if (id == "speech")
-    {
-        Being::Speech val = static_cast<Being::Speech>(
-            mSpeechSlider->getValue());
-        mSpeechLabel->setCaption(speechModeToString(val));
-        mSpeechSlider->setValue(val);
-        config.setValue("speech", static_cast<int>(val));
-    }
-    else if (id == "overlaydetailslider")
-    {
-        int val = static_cast<int>(mOverlayDetailSlider->getValue());
-        mOverlayDetailField->setCaption(overlayDetailToString(val));
-        config.setValue("OverlayDetail", val);
-    }
-    else if (id == "particledetailslider")
-    {
-        int val = static_cast<int>(mParticleDetailSlider->getValue());
-        mParticleDetailField->setCaption(particleDetailToString(val));
-        config.setValue("particleEmitterSkip", 3 - val);
-        Particle::emitterSkip = 4 - val;
-    }
     else if (id == "fpslimitcheckbox" || id == "fpslimitslider")
     {
         int tempFps = static_cast<int>(mFpsSlider->getValue());
diff --git a/src/gui/setup_video.h b/src/gui/setup_video.h
index 32a5d444c..0e7bc0f21 100644
--- a/src/gui/setup_video.h
+++ b/src/gui/setup_video.h
@@ -46,59 +46,38 @@ class Setup_Video : public SetupTab, public gcn::KeyListener
 
         void action(const gcn::ActionEvent &event);
 
-        static const char *overlayDetailToString(int detail = -1);
-
-        static const char *particleDetailToString(int detail = -1);
-
         virtual void externalUpdated();
 
     private:
         bool mFullScreenEnabled;
         int mOpenGLEnabled;
         bool mCustomCursorEnabled;
-        bool mParticleEffectsEnabled;
         int mFps;
         int mAltFps;
         bool mEnableResize;
         bool mNoFrame;
-        Being::Speech mSpeechMode;
 
         ModeListModel *mModeListModel;
 
         OpenGLListModel *mOpenGLListModel;
 
-        gcn::Label *speechLabel;
         gcn::Label *scrollRadiusLabel;
         gcn::Label *scrollLazinessLabel;
-        gcn::Label *overlayDetailLabel;
-        gcn::Label *particleDetailLabel;
 
         gcn::ListBox *mModeList;
         gcn::CheckBox *mFsCheckBox;
         gcn::DropDown *mOpenGLDropDown;
         gcn::CheckBox *mCustomCursorCheckBox;
-        gcn::CheckBox *mParticleEffectsCheckBox;
 
         gcn::CheckBox *mEnableResizeCheckBox;
         gcn::CheckBox *mNoFrameCheckBox;
 
-        gcn::Slider *mSpeechSlider;
-        gcn::Label *mSpeechLabel;
         gcn::CheckBox *mFpsCheckBox;
         gcn::Slider *mFpsSlider;
         gcn::Label *mFpsLabel;
-//        gcn::CheckBox *mAltFpsCheckBox;
         gcn::Slider *mAltFpsSlider;
         gcn::Label *mAltFpsLabel;
 
-        int mOverlayDetail;
-        gcn::Slider *mOverlayDetailSlider;
-        gcn::Label *mOverlayDetailField;
-
-        int mParticleDetail;
-        gcn::Slider *mParticleDetailSlider;
-        gcn::Label *mParticleDetailField;
-
         TextDialog *mDialog;
 };
 
diff --git a/src/gui/setup_visual.cpp b/src/gui/setup_visual.cpp
index 1cf35e4f2..9c172da04 100644
--- a/src/gui/setup_visual.cpp
+++ b/src/gui/setup_visual.cpp
@@ -30,7 +30,6 @@
 #include "gui/widgets/label.h"
 #include "gui/widgets/layouthelper.h"
 #include "gui/widgets/scrollarea.h"
-#include "gui/widgets/setupitem.h"
 #include "gui/widgets/slider.h"
 
 #include "resources/image.h"
@@ -38,6 +37,7 @@
 #include "configuration.h"
 #include "localplayer.h"
 #include "logger.h"
+#include "particle.h"
 
 #include "utils/gettext.h"
 
@@ -64,9 +64,46 @@ Setup_Visual::Setup_Visual()
     new SetupItemSlider(_("Gui opacity"), "", "guialpha",
         this, "guialphaEvent", 0.1, 1.0);
 
+    mSpeachList = new SetupItemNames();
+    mSpeachList->push_back(_("No text"));
+    mSpeachList->push_back(_("Text"));
+    mSpeachList->push_back(_("Bubbles, no names"));
+    mSpeachList->push_back(_("Bubbles with names"));
+    new SetupItemSlider2(_("Overhead text"),"", "speech", this,
+        "speechEvent", 0, 3, mSpeachList);
+
+    mAmbientFxList = new SetupItemNames();
+    mAmbientFxList->push_back(_("off"));
+    mAmbientFxList->push_back(_("low"));
+    mAmbientFxList->push_back(_("high"));
+    new SetupItemSlider2(_("Ambient FX"), "", "OverlayDetail", this,
+        "OverlayDetailEvent", 0, 2, mAmbientFxList);
+
+    new SetupItemCheckBox(_("Particle effects"), "",
+        "particleeffects", this, "particleeffectsEvent");
+
+    mParticleList = new SetupItemNames();
+    mParticleList->push_back(_("low"));
+    mParticleList->push_back(_("medium"));
+    mParticleList->push_back(_("high"));
+    mParticleList->push_back(_("max"));
+    (new SetupItemSlider2(_("Particle detail"), "", "particleEmitterSkip",
+        this, "particleEmitterSkipEvent", 0, 3,
+        mParticleList))->setInvertValue(3);
+
     setDimension(gcn::Rectangle(0, 0, 550, 350));
 }
 
+Setup_Visual::~Setup_Visual()
+{
+    delete mSpeachList;
+    mSpeachList = nullptr;
+    delete mAmbientFxList;
+    mAmbientFxList = nullptr;
+    delete mParticleList;
+    mParticleList = nullptr;
+}
+
 void Setup_Visual::apply()
 {
     SetupTabScroll::apply();
@@ -85,4 +122,13 @@ void Setup_Visual::action(const gcn::ActionEvent &event)
             Image::setEnableAlpha(config.getFloatValue("guialpha") != 1.0f);
         }
     }
+    else if (event.getId() == "particleEmitterSkipEvent")
+    {
+        Slider *slider = static_cast<Slider*>(event.getSource());
+        if (slider)
+        {
+            int val = static_cast<int>(slider->getValue());
+            Particle::emitterSkip = 4 - val;
+        }
+    }
 }
diff --git a/src/gui/setup_visual.h b/src/gui/setup_visual.h
index c76002c06..60d8ac787 100644
--- a/src/gui/setup_visual.h
+++ b/src/gui/setup_visual.h
@@ -25,6 +25,7 @@
 
 #include "guichanfwd.h"
 
+#include "gui/widgets/setupitem.h"
 #include "gui/widgets/setuptabscroll.h"
 
 #include <guichan/actionlistener.hpp>
@@ -34,9 +35,18 @@ class Setup_Visual : public SetupTabScroll
     public:
         Setup_Visual();
 
+        ~Setup_Visual();
+
         void apply();
 
         void action(const gcn::ActionEvent &event A_UNUSED);
+
+    private:
+        SetupItemNames *mSpeachList;
+
+        SetupItemNames *mAmbientFxList;
+
+        SetupItemNames *mParticleList;
 };
 
 #endif
diff --git a/src/gui/widgets/setupitem.cpp b/src/gui/widgets/setupitem.cpp
index 1d6bf5916..581d9f239 100644
--- a/src/gui/widgets/setupitem.cpp
+++ b/src/gui/widgets/setupitem.cpp
@@ -25,6 +25,7 @@
 #include "logger.h"
 
 #include "gui/editdialog.h"
+#include "gui/gui.h"
 
 #include "gui/widgets/button.h"
 #include "gui/widgets/checkbox.h"
@@ -40,7 +41,9 @@
 
 #include "utils/dtor.h"
 #include "utils/gettext.h"
+#include "utils/mathutils.h"
 
+#include <guichan/font.hpp>
 
 SetupItem::SetupItem(std::string text, std::string description,
                      std::string keyName, SetupTabScroll *parent,
@@ -591,10 +594,6 @@ void SetupItemDropDown::toWidget()
 }
 
 
-
-
-
-
 SetupItemSlider::SetupItemSlider(std::string text, std::string description,
                                  std::string keyName, SetupTabScroll *parent,
                                  std::string eventName, double min, double max,
@@ -686,3 +685,157 @@ void SetupItemSlider::apply(std::string eventName)
     fromWidget();
     save();
 }
+
+SetupItemSlider2::SetupItemSlider2(std::string text, std::string description,
+                                   std::string keyName, SetupTabScroll *parent,
+                                   std::string eventName, int min, int max,
+                                   SetupItemNames *values, bool mainConfig) :
+    SetupItem(text, description, keyName, parent, eventName, mainConfig),
+    mHorizont(nullptr),
+    mLabel(nullptr),
+    mLabel2(nullptr),
+    mSlider(nullptr),
+    mValues(values),
+    mMin(min),
+    mMax(max),
+    mInvert(false),
+    mInvertValue(0)
+{
+    mValueType = VSTR;
+    createControls();
+}
+
+SetupItemSlider2::SetupItemSlider2(std::string text, std::string description,
+                                   std::string keyName, SetupTabScroll *parent,
+                                   std::string eventName, int min, int max,
+                                   SetupItemNames *values, std::string def,
+                                   bool mainConfig) :
+    SetupItem(text, description, keyName, parent, eventName, def, mainConfig),
+    mHorizont(nullptr),
+    mLabel(nullptr),
+    mLabel2(nullptr),
+    mSlider(nullptr),
+    mValues(values),
+    mMin(min),
+    mMax(max),
+    mInvert(false),
+    mInvertValue(0)
+{
+    mValueType = VSTR;
+    createControls();
+}
+
+SetupItemSlider2::~SetupItemSlider2()
+{
+    mHorizont = nullptr;
+    mWidget = nullptr;
+    mSlider = nullptr;
+    mLabel = nullptr;
+}
+
+void SetupItemSlider2::createControls()
+{
+    load();
+    mHorizont = new HorizontContainer(32, 2);
+
+    int width = getMaxWidth();
+
+    mLabel = new Label(mText);
+    mLabel2 = new Label("");
+    mLabel2->setWidth(width);
+    mSlider = new Slider(mMin, mMax);
+    mSlider->setActionEventId(mEventName);
+    mSlider->addActionListener(mParent);
+    mSlider->setValue(atof(mValue.c_str()));
+    mSlider->setHeight(30);
+
+    mWidget = mSlider;
+    mSlider->setWidth(150);
+    mSlider->setHeight(40);
+    mHorizont->add(mLabel);
+    mHorizont->add(mSlider, -10);
+    mHorizont->add(mLabel2);
+
+    mParent->getContainer()->add2(mHorizont, true, 4);
+    mParent->addControl(this);
+    mParent->addActionListener(this);
+    mWidget->addActionListener(this);
+    updateLabel();
+}
+
+int SetupItemSlider2::getMaxWidth()
+{
+    if (!mValues || !gui)
+        return 1;
+
+    int maxWidth = 0;
+    SetupItemNamesConstIter it = mValues->begin();
+    SetupItemNamesConstIter it_end = mValues->end();
+    gcn::Font *font = gui->getFont();
+
+    while (it != it_end)
+    {
+        int w = font->getWidth(*it);
+        if (w > maxWidth)
+            maxWidth = w;
+
+        ++ it;
+    }
+    return maxWidth;
+}
+
+void SetupItemSlider2::fromWidget()
+{
+    if (!mSlider)
+        return;
+
+    int val = roundDouble(mSlider->getValue());
+    if (mInvert)
+        val = mInvertValue - val;
+    mValue = toString(val);
+}
+
+void SetupItemSlider2::toWidget()
+{
+    if (!mSlider)
+        return;
+
+    int val = roundDouble(atof(mValue.c_str()));
+    if (mInvert)
+        val = mInvertValue - val;
+    mSlider->setValue(val);
+    updateLabel();
+}
+
+void SetupItemSlider2::action(const gcn::ActionEvent &event A_UNUSED)
+{
+    fromWidget();
+    updateLabel();
+}
+
+void SetupItemSlider2::updateLabel()
+{
+    int val = mSlider->getValue() - mMin;
+    if (val < 0)
+        val = 0;
+    else if (val >= (signed)mValues->size())
+        val = (signed)mValues->size() - 1;
+    std::string str = mValues->at(val);
+    mLabel2->setCaption(str);
+}
+
+void SetupItemSlider2::apply(std::string eventName)
+{
+    if (eventName != mEventName)
+        return;
+
+    fromWidget();
+    save();
+}
+
+void SetupItemSlider2::setInvertValue(int v)
+{
+    mInvert = true;
+    mInvertValue = v;
+    toWidget();
+}
diff --git a/src/gui/widgets/setupitem.h b/src/gui/widgets/setupitem.h
index 220a55494..cf847f55d 100644
--- a/src/gui/widgets/setupitem.h
+++ b/src/gui/widgets/setupitem.h
@@ -92,7 +92,6 @@ class SetupItem : public gcn::ActionListener
         virtual void cancel(std::string eventName);
 
         virtual void externalUpdated(std::string eventName);
-//        virtual int add(ContainerPlacer &place, int x, int y, int width);
 
         bool isMainConfig() const
         { return mMainConfig; }
@@ -290,6 +289,8 @@ class SetupItemSlider : public SetupItem
 
         void apply(std::string eventName);
 
+        void updateLabel();
+
     protected:
         HorizontContainer *mHorizont;
         Label *mLabel;
@@ -298,4 +299,52 @@ class SetupItemSlider : public SetupItem
         double mMax;
 };
 
+typedef std::vector<std::string> SetupItemNames;
+typedef SetupItemNames::iterator SetupItemNamesIter;
+typedef SetupItemNames::const_iterator SetupItemNamesConstIter;
+
+class SetupItemSlider2 : public SetupItem
+{
+    public:
+        SetupItemSlider2(std::string text, std::string description,
+                         std::string keyName, SetupTabScroll *parent,
+                         std::string eventName, int min, int max,
+                         SetupItemNames *values, bool mainConfig = true);
+
+        SetupItemSlider2(std::string text, std::string description,
+                         std::string keyName, SetupTabScroll *parent,
+                         std::string eventName, int min, int max,
+                         SetupItemNames *values, std::string def,
+                         bool mainConfig = true);
+
+        ~SetupItemSlider2();
+
+        void createControls();
+
+        void fromWidget();
+
+        void toWidget();
+
+        void action(const gcn::ActionEvent &event);
+
+        void apply(std::string eventName);
+
+        void setInvertValue(int v);
+
+    protected:
+        void updateLabel();
+
+        int getMaxWidth();
+
+        HorizontContainer *mHorizont;
+        Label *mLabel;
+        Label *mLabel2;
+        Slider *mSlider;
+        SetupItemNames *mValues;
+        int mMin;
+        int mMax;
+        bool mInvert;
+        int mInvertValue;
+};
+
 #endif
diff --git a/src/utils/mathutils.h b/src/utils/mathutils.h
index 9f6818146..8ccd71e79 100644
--- a/src/utils/mathutils.h
+++ b/src/utils/mathutils.h
@@ -112,4 +112,9 @@ inline float weightedAverage(float n1, float n2, float w)
     return w * n2 + (1.0f - w) * n1;
 }
 
+inline int roundDouble(double v)
+{
+    return (v > 0.0) ? (v + 0.5) : (v - 0.5); 
+}
+
 #endif // UTILS_MATHUTILS_H
-- 
cgit v1.2.3-70-g09d2