Browse Source

Normalized scrollbar step size, by default on.
UI code cleanup.

Lasse Öörni 15 years ago
parent
commit
abc4b39adb

+ 8 - 3
Bin/Data/Scripts/GraphicsTest.as

@@ -487,10 +487,15 @@ void handleUpdate(StringHash eventType, VariantMap& eventData)
                 params.maxFilter = 1.0f;
             pipeline.setEdgeFilter(params);
         }
-        
-        if ((input.getKeyPress(KEY_ESC)) && (ui.getFocusElement() is null))
-            engine.exit();
     }
+    
+    if (input.getKeyPress(KEY_ESC))
+	{
+		if (ui.getFocusElement() is null)
+	        engine.exit();
+	    else
+		    console.setVisible(false);
+	}
 }
 
 void handleKeyDown(StringHash eventType, VariantMap& eventData)

+ 8 - 3
Bin/Data/Scripts/NinjaSnowWar.as

@@ -59,9 +59,6 @@ void start()
 void runFrame()
 {
     engine.runFrame(gameScene, gameCamera, !paused);
-
-    if (input.getKeyPress(KEY_ESC))
-        engine.exit();
 }
 
 void initAudio()
@@ -216,6 +213,14 @@ void handleUpdate(StringHash eventType, VariantMap& eventData)
             messageText.setText("");
     }
 
+    if (input.getKeyPress(KEY_ESC))
+	{
+		if (!console.isVisible())
+	        engine.exit();
+	    else
+		    console.setVisible(false);
+	}
+
     if (!paused)
         updateControls();
 }

+ 0 - 2
Bin/Data/UI/TestLayout.xml

@@ -31,8 +31,6 @@
         <wordwrap enable="true" />
     </element>
     <element type="ScrollView">
-        <position value="150 100" />
-        <size value="212 112" />
         <contentelement name="ScrollViewText" />
     </element>
     <element type="LineEdit">

+ 16 - 10
Bin/Data/UI/TestLayout3.xml

@@ -32,6 +32,13 @@
     </element>
     <element type="Element">
         <layout orientation="horizontal" horizontal="resizechildren" vertical="resizechildren" spacing="8" />
+    	<element type="Text" name="ScrollViewText" >
+	        <position value="1 0" />
+	        <minsize value="300 400" />
+	        <font name="times.ttf" size="15" />
+            <text value="At some point the fire had started.\n  There was total chaos. The locks of the wooden barracks had been blown apart by gunfire from shotguns and assault rifles, and the trainees were pouring out in confusion. But the primary target still lay ahead.\n  The administrative building. Where the identities and evaluations of the trainees were stored.\n  That was first class knowledge. If the Agents could bring that knowledge to the public, and cross-reference the records - mostly boys of young age - with lists of known missing persons, then they could prove the existence of SCEPTRE." />
+	        <wordwrap enable="true" />
+	    </element>
         <element type="Button">
             <element type="Text">
                 <text value="TEST4" />
@@ -39,6 +46,12 @@
                 <alignment horizontal="center" vertical="center" />
             </element>
         </element>
+    	<element type="ScrollView">
+	        <contentelement name="ScrollViewText" />
+	        <scrollpanel>
+	        	<layout orientation="vertical" horizontal="resizechildren" vertical="resizechildren" border="1 1 1 1" spacing="0" />
+	        </scrollpanel>
+	    </element>
         <element type="Button">
             <element type="Text">
                 <text value="TEST5" />
@@ -46,33 +59,26 @@
                 <alignment horizontal="center" vertical="center" />
             </element>
         </element>
-        <element type="Button">
-            <element type="Text">
-                <text value="TEST6" />
-                <font name="cour.ttf" size="12" />
-                <alignment horizontal="center" vertical="center" />
-            </element>
-        </element>
     </element>
     <element type="Element">
         <layout orientation="horizontal" horizontal="resizechildren" vertical="resizechildren" spacing="8" />
         <element type="Button">
             <element type="Text">
-                <text value="TEST7" />
+                <text value="TEST6" />
                 <font name="cour.ttf" size="12" />
                 <alignment horizontal="center" vertical="center" />
             </element>
         </element>
         <element type="Button">
             <element type="Text">
-                <text value="TEST8" />
+                <text value="TEST7" />
                 <font name="cour.ttf" size="12" />
                 <alignment horizontal="center" vertical="center" />
             </element>
         </element>
         <element type="Button">
             <element type="Text">
-                <text value="TEST9" />
+                <text value="TEST8" />
                 <font name="cour.ttf" size="12" />
                 <alignment horizontal="center" vertical="center" />
             </element>

+ 1 - 0
Engine/Engine/Console.cpp

@@ -67,6 +67,7 @@ Console::Console(Engine* engine) :
         
         mLineEdit = new LineEdit();
         mLineEdit->setColor(Color(0.0f, 0.0f, 0.0f, 0.5f));
+        mLineEdit->getTextElement()->setSelectionColor(Color(0.0f, 0.5f, 0.0f, 0.75f));
         mLineEdit->setFocusMode(FM_FOCUSABLE); // Do not allow defocus with ESC
         mBackground->addChild(mLineEdit);
         

+ 1 - 0
Engine/Engine/RegisterTemplates.h

@@ -490,6 +490,7 @@ template <class T> void registerUIElement(asIScriptEngine* engine, const char* c
     engine->RegisterObjectMethod(className, "UIElement@+ getChild(uint) const", asMETHODPR(T, getChild, (unsigned) const, UIElement*), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "UIElement@+ getChild(const string& in, bool) const", asMETHODPR(T, getChild, (const std::string&, bool) const, UIElement*), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "UIElement@+ getParent() const", asMETHOD(T, getParent), asCALL_THISCALL);
+    engine->RegisterObjectMethod(className, "UIElement@+ getOrigin() const", asMETHOD(T, getOrigin), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "UIElement@+ getRootElement() const", asMETHOD(T, getRootElement), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "XMLElement getStyleElement(XMLFile@+) const", asMETHODPR(T, getStyleElement, (XMLFile*) const, XMLElement), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "IntVector2 screenToElement(const IntVector2& in)", asMETHOD(T, screenToElement), asCALL_THISCALL);

+ 8 - 0
Engine/Engine/RegisterUI.cpp

@@ -123,6 +123,7 @@ static void registerSlider(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Slider", "void setOrientation(Orientation)", asMETHOD(Slider, setOrientation), asCALL_THISCALL);
     engine->RegisterObjectMethod("Slider", "void setRange(float)", asMETHOD(Slider, setRange), asCALL_THISCALL);
     engine->RegisterObjectMethod("Slider", "void setValue(float)", asMETHOD(Slider, setValue), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Slider", "void changeValue(float)", asMETHOD(Slider, changeValue), asCALL_THISCALL);
     engine->RegisterObjectMethod("Slider", "Orientation getOrientation() const", asMETHOD(Slider, getOrientation), asCALL_THISCALL);
     engine->RegisterObjectMethod("Slider", "float getRange() const", asMETHOD(Slider, getRange), asCALL_THISCALL);
     engine->RegisterObjectMethod("Slider", "float getValue() const", asMETHOD(Slider, getValue), asCALL_THISCALL);
@@ -136,11 +137,16 @@ static void registerScrollBar(asIScriptEngine* engine)
     engine->RegisterObjectMethod("ScrollBar", "void setOrientation(Orientation)", asMETHOD(ScrollBar, setOrientation), asCALL_THISCALL);
     engine->RegisterObjectMethod("ScrollBar", "void setRange(float)", asMETHOD(ScrollBar, setRange), asCALL_THISCALL);
     engine->RegisterObjectMethod("ScrollBar", "void setValue(float)", asMETHOD(ScrollBar, setValue), asCALL_THISCALL);
+    engine->RegisterObjectMethod("ScrollBar", "void changeValue(float)", asMETHOD(ScrollBar, changeValue), asCALL_THISCALL);
     engine->RegisterObjectMethod("ScrollBar", "void setScrollStep(float)", asMETHOD(ScrollBar, setScrollStep), asCALL_THISCALL);
+    engine->RegisterObjectMethod("ScrollBar", "void setNormalizeScrollStep(bool)", asMETHOD(ScrollBar, setNormalizeScrollStep), asCALL_THISCALL);
+    engine->RegisterObjectMethod("ScrollBar", "void stepBack()", asMETHOD(ScrollBar, stepBack), asCALL_THISCALL);
+    engine->RegisterObjectMethod("ScrollBar", "void stepForward()", asMETHOD(ScrollBar, stepForward), asCALL_THISCALL);
     engine->RegisterObjectMethod("ScrollBar", "Orientation getOrientation() const", asMETHOD(ScrollBar, getOrientation), asCALL_THISCALL);
     engine->RegisterObjectMethod("ScrollBar", "float getRange() const", asMETHOD(ScrollBar, getRange), asCALL_THISCALL);
     engine->RegisterObjectMethod("ScrollBar", "float getValue() const", asMETHOD(ScrollBar, getValue), asCALL_THISCALL);
     engine->RegisterObjectMethod("ScrollBar", "float getScrollStep() const", asMETHOD(ScrollBar, getScrollStep), asCALL_THISCALL);
+    engine->RegisterObjectMethod("ScrollBar", "bool getNormalizeScrollStep() const", asMETHOD(ScrollBar, getNormalizeScrollStep), asCALL_THISCALL);
     engine->RegisterObjectMethod("ScrollBar", "Button@+ getBackButton() const", asMETHOD(ScrollBar, getBackButton), asCALL_THISCALL);
     engine->RegisterObjectMethod("ScrollBar", "Button@+ getForwardButton() const", asMETHOD(ScrollBar, getForwardButton), asCALL_THISCALL);
     engine->RegisterObjectMethod("ScrollBar", "Slider@+ getSlider() const", asMETHOD(ScrollBar, getSlider), asCALL_THISCALL);
@@ -155,6 +161,7 @@ static void registerScrollView(asIScriptEngine* engine)
     engine->RegisterObjectMethod("ScrollView", "void setScrollBarsVisible(bool, bool)", asMETHOD(ScrollView, setScrollBarsVisible), asCALL_THISCALL);
     engine->RegisterObjectMethod("ScrollView", "void setScrollStep(float)", asMETHOD(ScrollView, setScrollStep), asCALL_THISCALL);
     engine->RegisterObjectMethod("ScrollView", "void setPageStep(float)", asMETHOD(ScrollView, setPageStep), asCALL_THISCALL);
+    engine->RegisterObjectMethod("ScrollView", "void setNormalizeScrollStep(bool)", asMETHOD(ScrollView, setNormalizeScrollStep), asCALL_THISCALL);
     engine->RegisterObjectMethod("ScrollView", "const IntVector2& getViewPosition() const", asMETHOD(ScrollView, getViewPosition), asCALL_THISCALL);
     engine->RegisterObjectMethod("ScrollView", "UIElement@+ getElement() const", asMETHOD(ScrollView, getElement), asCALL_THISCALL);
     engine->RegisterObjectMethod("ScrollView", "ScrollBar@+ getHorizontalScrollBar() const", asMETHOD(ScrollView, getHorizontalScrollBar), asCALL_THISCALL);
@@ -164,6 +171,7 @@ static void registerScrollView(asIScriptEngine* engine)
     engine->RegisterObjectMethod("ScrollView", "bool getVerticalScrollBarVisible() const", asMETHOD(ScrollView, getVerticalScrollBarVisible), asCALL_THISCALL);
     engine->RegisterObjectMethod("ScrollView", "float getScrollStep() const", asMETHOD(ScrollView, getScrollStep), asCALL_THISCALL);
     engine->RegisterObjectMethod("ScrollView", "float getPageStep() const", asMETHOD(ScrollView, getPageStep), asCALL_THISCALL);
+    engine->RegisterObjectMethod("ScrollView", "bool getNormalizeScrollStep() const", asMETHOD(ScrollView, getNormalizeScrollStep), asCALL_THISCALL);
     registerRefCasts<UIElement, ScrollView>(engine, "UIElement", "ScrollView");
 }
 

+ 44 - 9
Engine/UI/ScrollBar.cpp

@@ -27,12 +27,14 @@
 #include "Slider.h"
 #include "UIEvents.h"
 
+static const float DEFAULT_SCROLL_STEP = 0.05f;
 static const float DEFAULT_REPEAT_DELAY = 0.4f;
 static const float DEFAULT_REPEAT_RATE = 20.0f;
 
 ScrollBar::ScrollBar(const std::string& name) :
     UIElement(name),
-    mScrollStep(0.1f),
+    mScrollStep(DEFAULT_SCROLL_STEP),
+    mNormalizeScrollStep(true),
     mLeftRect(IntRect::sZero),
     mRightRect(IntRect::sZero),
     mUpRect(IntRect::sZero),
@@ -66,6 +68,17 @@ void ScrollBar::setStyle(const XMLElement& element, ResourceCache* cache)
 {
     UIElement::setStyle(element, cache);
     
+    if (element.hasChildElement("scrollstep"))
+        setScrollStep(element.getChildElement("scrollstep").getFloat("value"));
+    if (element.hasChildElement("normalizescrollstep"))
+        setNormalizeScrollStep(element.getChildElement("normalizescrollstep").getBool("enable"));
+    if (element.hasChildElement("range"))
+    {
+        XMLElement rangeElem = element.getChildElement("range");
+        setRange(rangeElem.getFloat("max"));
+        setValue(rangeElem.getFloat("value"));
+    }
+    
     XMLElement backButtonElem = element.getChildElement("backbutton");
     if (backButtonElem)
     {
@@ -98,12 +111,6 @@ void ScrollBar::setStyle(const XMLElement& element, ResourceCache* cache)
     if (sliderElem)
         mSlider->setStyle(sliderElem, cache);
     
-    if (element.hasChildElement("range"))
-    {
-        XMLElement rangeElem = element.getChildElement("range");
-        setRange(rangeElem.getFloat("max"));
-        setValue(rangeElem.getFloat("value"));
-    }
     if (element.hasChildElement("orientation"))
     {
         std::string orientation = element.getChildElement("orientation").getStringLower("value");
@@ -164,11 +171,31 @@ void ScrollBar::setValue(float value)
     mSlider->setValue(value);
 }
 
+void ScrollBar::changeValue(float delta)
+{
+    mSlider->changeValue(delta);
+}
+
 void ScrollBar::setScrollStep(float step)
 {
     mScrollStep = max(step, 0.0f);
 }
 
+void ScrollBar::setNormalizeScrollStep(bool enable)
+{
+    mNormalizeScrollStep = enable;
+}
+
+void ScrollBar::stepBack()
+{
+    mSlider->setValue(mSlider->getValue() - getEffectiveScrollStep());
+}
+
+void ScrollBar::stepForward()
+{
+    mSlider->setValue(mSlider->getValue() + getEffectiveScrollStep());
+}
+
 Orientation ScrollBar::getOrientation() const
 {
     return mSlider->getOrientation();
@@ -184,14 +211,22 @@ float ScrollBar::getValue() const
     return mSlider->getValue();
 }
 
+float ScrollBar::getEffectiveScrollStep() const
+{
+    if (!mNormalizeScrollStep)
+        return mScrollStep;
+    else
+        return mScrollStep * (mSlider->getRange() + 1.0f);
+}
+
 void ScrollBar::handleBackButtonPressed(StringHash eventType, VariantMap& eventData)
 {
-    mSlider->setValue(mSlider->getValue() - mScrollStep);
+    stepBack();
 }
 
 void ScrollBar::handleForwardButtonPressed(StringHash eventType, VariantMap& eventData)
 {
-    mSlider->setValue(mSlider->getValue() + mScrollStep);
+    stepForward();
 }
 
 void ScrollBar::handleSliderChanged(StringHash eventType, VariantMap& eventData)

+ 14 - 0
Engine/UI/ScrollBar.h

@@ -50,8 +50,16 @@ public:
     void setRange(float range);
     //! Set slider current value
     void setValue(float value);
+    //! Change slider current value by a delta
+    void changeValue(float delta);
     //! Set button scroll step
     void setScrollStep(float step);
+    //! Set whether scroll step is normalized to slider range
+    void setNormalizeScrollStep(bool enable);
+    //! Scroll back one step
+    void stepBack();
+    //! Scroll forward one step
+    void stepForward();
     
     //! Return orientation type
     Orientation getOrientation() const;
@@ -61,6 +69,10 @@ public:
     float getValue() const;
     //! Return button scroll step
     float getScrollStep() const { return mScrollStep; }
+    //! Return effective scroll step, taking possible normalization into account
+    float getEffectiveScrollStep() const;
+    //! Return whether scroll step is normalized to slider range
+    bool getNormalizeScrollStep() const { return mNormalizeScrollStep; }
     //! Return back button element
     Button* getBackButton() const { return mBackButton; }
     //! Return forward button element
@@ -77,6 +89,8 @@ protected:
     SharedPtr<Slider> mSlider;
     //! Scroll step
     float mScrollStep;
+    //! Normalize scroll step flag
+    bool mNormalizeScrollStep;
     //! Left button image rect
     IntRect mLeftRect;
     //! Right button image rect

+ 27 - 32
Engine/UI/ScrollView.cpp

@@ -34,9 +34,9 @@ ScrollView::ScrollView(const std::string& name) :
     UIElement(name),
     mViewPosition(IntVector2::sZero),
     mViewSize(IntVector2::sZero),
-    mScrollStep(0.1f),
     mPageStep(1.0f)
 {
+    mClipChildren = true;
     mEnabled = true;
     mFocusMode = FM_FOCUSABLE_DEFOCUSABLE;
     
@@ -58,7 +58,6 @@ ScrollView::ScrollView(const std::string& name) :
     subscribeToEvent(mHorizontalScrollBar, EVENT_VISIBLECHANGED, EVENT_HANDLER(ScrollView, handleScrollBarVisibleChanged));
     subscribeToEvent(mVerticalScrollBar, EVENT_SCROLLBARCHANGED, EVENT_HANDLER(ScrollView, handleScrollBarChanged));
     subscribeToEvent(mVerticalScrollBar, EVENT_VISIBLECHANGED, EVENT_HANDLER(ScrollView, handleScrollBarVisibleChanged));
-    subscribeToEvent(EVENT_TRYFOCUS, EVENT_HANDLER(ScrollView, handleTryFocus));
 }
 
 ScrollView::~ScrollView()
@@ -75,6 +74,8 @@ void ScrollView::setStyle(const XMLElement& element, ResourceCache* cache)
         setScrollStep(element.getChildElement("scrollstep").getFloat("value"));
     if (element.hasChildElement("pagestep"))
         setScrollStep(element.getChildElement("pagestep").getFloat("value"));
+    if (element.hasChildElement("normalizescrollstep"))
+        setNormalizeScrollStep(element.getChildElement("normalizescrollstep").getBool("enable"));
     
     XMLElement horizElem = element.getChildElement("horizontalscrollbar");
     if (horizElem)
@@ -106,7 +107,7 @@ void ScrollView::onKey(int key, int buttons, int qualifiers)
             if (qualifiers & QUAL_CTRL)
                 mHorizontalScrollBar->setValue(0.0f);
             else
-                mHorizontalScrollBar->setValue(mHorizontalScrollBar->getValue() - mScrollStep);
+                mHorizontalScrollBar->stepBack();
         }
         break;
         
@@ -116,7 +117,7 @@ void ScrollView::onKey(int key, int buttons, int qualifiers)
             if (qualifiers & QUAL_CTRL)
                 mHorizontalScrollBar->setValue(mHorizontalScrollBar->getRange());
             else
-                mHorizontalScrollBar->setValue(mHorizontalScrollBar->getValue() + mScrollStep);
+                mHorizontalScrollBar->stepForward();
         }
         break;
         
@@ -126,7 +127,7 @@ void ScrollView::onKey(int key, int buttons, int qualifiers)
             if (qualifiers & QUAL_CTRL)
                 mVerticalScrollBar->setValue(0.0f);
             else
-                mVerticalScrollBar->setValue(mVerticalScrollBar->getValue() - mScrollStep);
+                mVerticalScrollBar->stepBack();
         }
         break;
         
@@ -136,18 +137,18 @@ void ScrollView::onKey(int key, int buttons, int qualifiers)
             if (qualifiers & QUAL_CTRL)
                 mVerticalScrollBar->setValue(mVerticalScrollBar->getRange());
             else
-                mVerticalScrollBar->setValue(mVerticalScrollBar->getValue() + mScrollStep);
+                mVerticalScrollBar->stepForward();
         }
         break;
         
     case KEY_PAGEUP:
         if (mVerticalScrollBar)
-            mVerticalScrollBar->setValue(mVerticalScrollBar->getValue() - mPageStep);
+            mVerticalScrollBar->changeValue(-mPageStep);
         break;
         
     case KEY_PAGEDOWN:
         if (mVerticalScrollBar)
-            mVerticalScrollBar->setValue(mVerticalScrollBar->getValue() + mPageStep);
+            mVerticalScrollBar->changeValue(mPageStep);
         break;
     
     case KEY_HOME:
@@ -216,7 +217,8 @@ void ScrollView::setScrollBarsVisible(bool horizontal, bool vertical)
 
 void ScrollView::setScrollStep(float step)
 {
-    mScrollStep = max(step, 0.0f);
+    mHorizontalScrollBar->setScrollStep(step);
+    mVerticalScrollBar->setScrollStep(step);
 }
 
 void ScrollView::setPageStep(float step)
@@ -224,6 +226,12 @@ void ScrollView::setPageStep(float step)
     mPageStep = max(step, 0.0f);
 }
 
+void ScrollView::setNormalizeScrollStep(bool enable)
+{
+    mHorizontalScrollBar->setNormalizeScrollStep(enable);
+    mVerticalScrollBar->setNormalizeScrollStep(enable);
+}
+
 bool ScrollView::getHorizontalScrollBarVisible() const
 {
     return mHorizontalScrollBar->isVisible();
@@ -234,6 +242,16 @@ bool ScrollView::getVerticalScrollBarVisible() const
     return mVerticalScrollBar->isVisible();
 }
 
+float ScrollView::getScrollStep() const
+{
+    return mHorizontalScrollBar->getScrollStep();
+}
+
+bool ScrollView::getNormalizeScrollStep() const
+{
+    return mHorizontalScrollBar->getNormalizeScrollStep();
+}
+
 void ScrollView::updateViewSize()
 {
     IntVector2 size(IntVector2::sZero);
@@ -307,26 +325,3 @@ void ScrollView::handleElementResized(StringHash eventType, VariantMap& eventDat
 {
     updateViewSize();
 }
-
-void ScrollView::handleTryFocus(StringHash eventType, VariantMap& eventData)
-{
-    using namespace TryFocus;
-    
-    UIElement* focusElement = static_cast<UIElement*>(eventData[P_ELEMENT].getPtr());
-    if ((!focusElement) || (focusElement == this))
-        return;
-    
-    // If the element is a non-focusable child of the ScrollView, divert focus to the ScrollView
-    if (focusElement->getFocusMode() < FM_FOCUSABLE)
-    {
-        while (focusElement)
-        {
-            focusElement = focusElement->getParent();
-            if (focusElement == this)
-            {
-                eventData[P_ELEMENT] = (void*)this;
-                return;
-            }
-        }
-    }
-}

+ 7 - 5
Engine/UI/ScrollView.h

@@ -55,11 +55,13 @@ public:
     void setViewPosition(int x, int y);
     //! Set scrollbars' visibility
     void setScrollBarsVisible(bool horizontal, bool vertical);
-    //! Set arrow key scroll step
+    //! Set arrow key scroll step. Also sets it on the scrollbars
     void setScrollStep(float step);
     //! Set arrow key page step
     void setPageStep(float step);
-    
+    //! Set whether scroll step is normalized to content size
+    void setNormalizeScrollStep(bool enable);
+
     //! Return view offset from the top-left corner
     const IntVector2& getViewPosition() const { return mViewPosition; }
     //! Return content element
@@ -75,9 +77,11 @@ public:
     //! Return vertical scrollbar visibility
     bool getVerticalScrollBarVisible() const;
     //! Return arrow key scroll step
-    float getScrollStep() const { return mScrollStep; }
+    float getScrollStep() const;
     //! Return arrow key page step
     float getPageStep() const { return mPageStep; }
+    //! Return whether scroll step is normalized to content size
+    bool getNormalizeScrollStep() const;
     
 protected:
     //! Update view size from the content element
@@ -99,8 +103,6 @@ protected:
     IntVector2 mViewPosition;
     //! Total view size
     IntVector2 mViewSize;
-    //! Arrow key scroll step
-    float mScrollStep;
     //! Arrow key page step
     float mPageStep;
     //! Ignore scrollbar events flag. Used to prevent possible endless loop when setting position

+ 5 - 0
Engine/UI/Slider.cpp

@@ -161,6 +161,11 @@ void Slider::setValue(float value)
     }
 }
 
+void Slider::changeValue(float delta)
+{
+    setValue(mValue + delta);
+}
+
 void Slider::updateSlider()
 {
     if (mOrientation == O_HORIZONTAL)

+ 2 - 0
Engine/UI/Slider.h

@@ -58,6 +58,8 @@ public:
     void setRange(float range);
     //! Set slider current value
     void setValue(float value);
+    //! Change value by a delta
+    void changeValue(float delta);
     
     //! Return orientation type
     Orientation getOrientation() const { return mOrientation; }

+ 16 - 6
Engine/UI/UI.cpp

@@ -121,12 +121,22 @@ void UI::setFocusElement(UIElement* element)
     // The event receivers may divert the focus
     element = static_cast<UIElement*>(eventData[P_ELEMENT].getPtr());
     
-    // Return if already has focus
-    if ((element) && (element->hasFocus()))
-        return;
-    // Return if element can not be focused, and does not reset the focus either
-    if ((element) && (element->getFocusMode() == FM_NOTFOCUSABLE))
-        return;
+    if (element)
+    {
+        // Return if already has focus
+        if (element->hasFocus())
+            return;
+        // If element can not be focused, and does not reset the focus either, search toward the parent
+        for (;;)
+        {
+            if (element->getFocusMode() != FM_NOTFOCUSABLE)
+                break;
+            element = element->getParent();
+            // Return if did not find any parent element that changes the focus
+            if (!element)
+                return;
+        }
+    }
     
     std::vector<UIElement*> allChildren = mRootElement->getChildren(true);