Browse Source

Replaced explicit image rect settings with offsets.
Added project() to Ray.

Lasse Öörni 15 years ago
parent
commit
cb4d88a8f2

BIN
Bin/Data/Textures/UI.png


+ 15 - 15
Bin/Data/UI/DefaultStyle.xml

@@ -2,29 +2,29 @@
     <element type="Button">
     <element type="Button">
         <size value="16 16" />
         <size value="16 16" />
         <texture name="Textures/UI.png" />
         <texture name="Textures/UI.png" />
-        <inactiverect value="16 0 32 16" />
-        <pressedrect value="32 0 48 16" />
+        <imagerect value="16 0 32 16" />
         <border value="4 4 4 4" />
         <border value="4 4 4 4" />
+        <pressedoffset value="16 0" />
         <hoveroffset value="0 16" />
         <hoveroffset value="0 16" />
         <labeloffset value="-1 1" />
         <labeloffset value="-1 1" />
     </element>
     </element>
     <element type="CheckBox">
     <element type="CheckBox">
         <size value="16 16" />
         <size value="16 16" />
         <texture name="Textures/UI.png" />
         <texture name="Textures/UI.png" />
-        <uncheckedrect value="64 0 80 16" />
-        <checkedrect value="80 0 96 16" />
+        <imagerect value="64 0 80 16" />
         <border value="4 4 4 4" />
         <border value="4 4 4 4" />
+        <checkedoffset value="16 0" />
         <hoveroffset value="0 16" />
         <hoveroffset value="0 16" />
     </element>
     </element>
     <element type="Cursor">
     <element type="Cursor">
-        <size value="16 24" />
+        <size value="12 24" />
         <texture name="Textures/UI.png" />
         <texture name="Textures/UI.png" />
-        <imagerect value="0 0 16 24" />
+        <imagerect value="0 0 12 24" />
         <hotspot value="0 0" />
         <hotspot value="0 0" />
     </element>
     </element>
     <element type="LineEdit">
     <element type="LineEdit">
         <texture name="Textures/UI.png" />
         <texture name="Textures/UI.png" />
-        <imagerect value="96 0 112 16" />
+        <imagerect value="112 0 128 16" />
         <border value="2 2 2 2" />
         <border value="2 2 2 2" />
         <clipborder value="1 1 1 1" />
         <clipborder value="1 1 1 1" />
         <hoveroffset value="0 16" />
         <hoveroffset value="0 16" />
@@ -36,32 +36,32 @@
         <cursor>
         <cursor>
             <size value="4 16" />
             <size value="4 16" />
             <texture name="Textures/UI.png" />
             <texture name="Textures/UI.png" />
-            <imagerect value="112 0 116 16" />
+            <imagerect value="12 0 16 16" />
         </cursor>
         </cursor>
     </element>
     </element>
     <element type="MenuItem">
     <element type="MenuItem">
         <texture name="Textures/UI.png" />
         <texture name="Textures/UI.png" />
-        <inactiverect value="98 2 110 14" />
-        <pressedrect value="96 0 112 16" />
+        <imagerect value="96 0 112 16" />
         <border value="2 2 2 2" />
         <border value="2 2 2 2" />
+        <pressedoffset value="16 0" />
         <hoveroffset value="0 16" />
         <hoveroffset value="0 16" />
     </element>
     </element>
     <element type="ScrollBar">
     <element type="ScrollBar">
         <backbutton>
         <backbutton>
             <size value="16 16" />
             <size value="16 16" />
             <texture name="Textures/UI.png" />
             <texture name="Textures/UI.png" />
-            <inactiverect vertical="0 32 16 48" horizontal="32 32 48 48" />
-            <pressedrect vertical="64 32 80 48" horizontal="96 32 112 48" />
+            <imagerect horizontal="32 32 48 48" vertical="0 32 16 48" />
             <border value="3 3 3 3" />
             <border value="3 3 3 3" />
+            <pressedoffset value="64 0" />
             <hoveroffset value="0 16" />
             <hoveroffset value="0 16" />
             <repeat delay="0.4" rate="20" />
             <repeat delay="0.4" rate="20" />
         </backbutton>
         </backbutton>
         <forwardbutton>
         <forwardbutton>
             <size value="16 16" />
             <size value="16 16" />
             <texture name="Textures/UI.png" />
             <texture name="Textures/UI.png" />
-            <inactiverect vertical="16 32 32 48" horizontal="48 32 64 48" />
-            <pressedrect vertical="80 32 96 48" horizontal="112 32 128 48" />
+            <imagerect horizontal="48 32 64 48" vertical="16 32 32 48" />
             <border value="3 3 3 3" />
             <border value="3 3 3 3" />
+            <pressedoffset value="64 0" />
             <hoveroffset value="0 16" />
             <hoveroffset value="0 16" />
             <repeat delay="0.4" rate="20" />
             <repeat delay="0.4" rate="20" />
         </forwardbutton>
         </forwardbutton>
@@ -81,7 +81,7 @@
     <element type="ScrollView">
     <element type="ScrollView">
         <size value="16 16" />
         <size value="16 16" />
         <texture name="Textures/UI.png" />
         <texture name="Textures/UI.png" />
-        <imagerect value="96 0 112 16" />
+        <imagerect value="112 0 128 16" />
         <border value="2 2 2 2" />
         <border value="2 2 2 2" />
         <clipborder value="1 1 1 1" />
         <clipborder value="1 1 1 1" />
     </element>
     </element>

+ 3 - 6
Engine/Engine/RegisterTemplates.h

@@ -522,15 +522,12 @@ template <class T> void registerBorderImage(asIScriptEngine* engine, const char*
 template <class T> void registerButton(asIScriptEngine* engine, const char* className)
 template <class T> void registerButton(asIScriptEngine* engine, const char* className)
 {
 {
     registerBorderImage<T>(engine, className);
     registerBorderImage<T>(engine, className);
-    engine->RegisterObjectMethod(className, "void setInactiveRect(const IntRect& in)", asMETHODPR(T, setInactiveRect, (const IntRect&), void), asCALL_THISCALL);
-    engine->RegisterObjectMethod(className, "void setInactiveRect(int, int, int, int)", asMETHODPR(T, setInactiveRect, (int, int, int, int), void), asCALL_THISCALL);
-    engine->RegisterObjectMethod(className, "void setPressedRect(const IntRect& in)", asMETHODPR(T, setPressedRect, (const IntRect&), void), asCALL_THISCALL);
-    engine->RegisterObjectMethod(className, "void setPressedRect(int, int, int, int)", asMETHODPR(T, setPressedRect, (int, int, int, int), void), asCALL_THISCALL);
+    engine->RegisterObjectMethod(className, "void setPressedOffset(const IntVector2& in)", asMETHODPR(T, setPressedOffset, (const IntVector2&), void), asCALL_THISCALL);
+    engine->RegisterObjectMethod(className, "void setPressedOffset(int, int)", asMETHODPR(T, setPressedOffset, (int, int), void), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void setLabelOffset(const IntVector2& in)", asMETHODPR(T, setLabelOffset, (const IntVector2&), void), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void setLabelOffset(const IntVector2& in)", asMETHODPR(T, setLabelOffset, (const IntVector2&), void), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void setLabelOffset(int, int)", asMETHODPR(T, setLabelOffset, (int, int), void), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void setLabelOffset(int, int)", asMETHODPR(T, setLabelOffset, (int, int), void), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void setRepeat(float, float)", asMETHOD(T, setRepeat), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void setRepeat(float, float)", asMETHOD(T, setRepeat), asCALL_THISCALL);
-    engine->RegisterObjectMethod(className, "const IntRect& getInactiveRect() const", asMETHOD(T, getInactiveRect), asCALL_THISCALL);
-    engine->RegisterObjectMethod(className, "const IntRect& getPressedRect() const", asMETHOD(T, getPressedRect), asCALL_THISCALL);
+    engine->RegisterObjectMethod(className, "const IntVector2& getPressedOffset() const", asMETHOD(T, getPressedOffset), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "const IntVector2& getLabelOffset() const", asMETHOD(T, getLabelOffset), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "const IntVector2& getLabelOffset() const", asMETHOD(T, getLabelOffset), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "float getRepeatDelay() const", asMETHOD(T, getRepeatDelay), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "float getRepeatDelay() const", asMETHOD(T, getRepeatDelay), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "float getRepeatRate() const", asMETHOD(T, getRepeatRate), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "float getRepeatRate() const", asMETHOD(T, getRepeatRate), asCALL_THISCALL);

+ 3 - 6
Engine/Engine/RegisterUI.cpp

@@ -110,13 +110,10 @@ static void registerCheckBox(asIScriptEngine* engine)
 {
 {
     registerBorderImage<CheckBox>(engine, "CheckBox");
     registerBorderImage<CheckBox>(engine, "CheckBox");
     engine->RegisterObjectMethod("CheckBox", "void setChecked(bool)", asMETHOD(CheckBox, setChecked), asCALL_THISCALL);
     engine->RegisterObjectMethod("CheckBox", "void setChecked(bool)", asMETHOD(CheckBox, setChecked), asCALL_THISCALL);
-    engine->RegisterObjectMethod("CheckBox", "void setUncheckedRect(const IntRect& in)", asMETHODPR(CheckBox, setUncheckedRect, (const IntRect&), void), asCALL_THISCALL);
-    engine->RegisterObjectMethod("CheckBox", "void setUncheckedRect(int, int, int, int)", asMETHODPR(CheckBox, setUncheckedRect, (int, int, int, int), void), asCALL_THISCALL);
-    engine->RegisterObjectMethod("CheckBox", "void setCheckedRect(const IntRect& in)", asMETHODPR(CheckBox, setCheckedRect, (const IntRect&), void), asCALL_THISCALL);
-    engine->RegisterObjectMethod("CheckBox", "void setCheckedRect(int, int, int, int)", asMETHODPR(CheckBox, setCheckedRect, (int, int, int, int), void), asCALL_THISCALL);
+    engine->RegisterObjectMethod("CheckBox", "void setCheckedOffset(const IntVector2& in)", asMETHODPR(CheckBox, setCheckedOffset, (const IntVector2&), void), asCALL_THISCALL);
+    engine->RegisterObjectMethod("CheckBox", "void setCheckedOffset(int, int)", asMETHODPR(CheckBox, setCheckedOffset, (int, int), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("CheckBox", "bool isChecked() const", asMETHOD(CheckBox, isChecked), asCALL_THISCALL);
     engine->RegisterObjectMethod("CheckBox", "bool isChecked() const", asMETHOD(CheckBox, isChecked), asCALL_THISCALL);
-    engine->RegisterObjectMethod("CheckBox", "const IntRect& getUncheckedRect() const", asMETHOD(CheckBox, getUncheckedRect), asCALL_THISCALL);
-    engine->RegisterObjectMethod("CheckBox", "const IntRect& getCheckedRect() const", asMETHOD(CheckBox, getCheckedRect), asCALL_THISCALL);
+    engine->RegisterObjectMethod("CheckBox", "const IntVector2& getCheckedOffset() const", asMETHOD(CheckBox, getCheckedOffset), asCALL_THISCALL);
     registerRefCasts<UIElement, CheckBox>(engine, "UIElement", "CheckBox");
     registerRefCasts<UIElement, CheckBox>(engine, "UIElement", "CheckBox");
 }
 }
 
 

+ 6 - 0
Engine/Math/Ray.cpp

@@ -24,6 +24,12 @@
 #include "Precompiled.h"
 #include "Precompiled.h"
 #include "Ray.h"
 #include "Ray.h"
 
 
+Vector3 Ray::project(const Vector3& point) const
+{
+    Vector3 offset = point - mOrigin;
+    return mOrigin + offset.dotProduct(mDirection) * mDirection;
+}
+
 float Ray::getDistance(const Vector3& v0, const Vector3& v1, const Vector3& v2) const
 float Ray::getDistance(const Vector3& v0, const Vector3& v1, const Vector3& v2) const
 {
 {
     // Based on Fast, Minimum Storage Ray/Triangle Intersection by Möller & Trumbore
     // Based on Fast, Minimum Storage Ray/Triangle Intersection by Möller & Trumbore

+ 2 - 0
Engine/Math/Ray.h

@@ -77,6 +77,8 @@ public:
         mDirection = direction.getNormalized();
         mDirection = direction.getNormalized();
     }
     }
     
     
+    //! Project a point on the ray
+    Vector3 project(const Vector3& point) const;
     //! Return minimum distance to a triangle, or infinity if no hit
     //! Return minimum distance to a triangle, or infinity if no hit
     float getDistance(const Vector3& v0, const Vector3& v1, const Vector3& v2) const;
     float getDistance(const Vector3& v0, const Vector3& v1, const Vector3& v2) const;
     //! Return minimum distance to a triangle mesh defined by vertex and index data
     //! Return minimum distance to a triangle mesh defined by vertex and index data

+ 61 - 60
Engine/UI/BorderImage.cpp

@@ -47,7 +47,11 @@ void BorderImage::setStyle(const XMLElement& element, ResourceCache* cache)
     if (element.hasChildElement("texture"))
     if (element.hasChildElement("texture"))
         setTexture(cache->getResource<Texture2D>(element.getChildElement("texture").getString("name")));
         setTexture(cache->getResource<Texture2D>(element.getChildElement("texture").getString("name")));
     if (element.hasChildElement("imagerect"))
     if (element.hasChildElement("imagerect"))
-        setImageRect(element.getChildElement("imagerect").getIntRect("value"));
+    {
+        XMLElement imageElem = element.getChildElement("imagerect");
+        if (imageElem.hasAttribute("value"))
+            setImageRect(imageElem.getIntRect("value"));
+    }
     if (element.hasChildElement("border"))
     if (element.hasChildElement("border"))
         setBorder(element.getChildElement("border").getIntRect("value"));
         setBorder(element.getChildElement("border").getIntRect("value"));
     if (element.hasChildElement("hoveroffset"))
     if (element.hasChildElement("hoveroffset"))
@@ -55,6 +59,61 @@ void BorderImage::setStyle(const XMLElement& element, ResourceCache* cache)
 }
 }
 
 
 void BorderImage::getBatches(std::vector<UIBatch>& batches, std::vector<UIQuad>& quads, const IntRect& currentScissor)
 void BorderImage::getBatches(std::vector<UIBatch>& batches, std::vector<UIQuad>& quads, const IntRect& currentScissor)
+{
+    if ((mHovering) || (mSelected))
+        getBatches(batches, quads, currentScissor, mHoverOffset);
+    else
+        getBatches(batches, quads, currentScissor, IntVector2::sZero);
+}
+
+void BorderImage::setTexture(Texture* texture)
+{
+    mTexture = texture;
+    if (mImageRect == IntRect::sZero)
+        setFullImageRect();
+}
+
+void BorderImage::setImageRect(const IntRect& rect)
+{
+    if (rect != IntRect::sZero)
+        mImageRect = rect;
+}
+
+void BorderImage::setImageRect(int left, int top, int right, int bottom)
+{
+    setImageRect(IntRect(left, top, right, bottom));
+}
+
+void BorderImage::setFullImageRect()
+{
+    if (mTexture)
+        setImageRect(IntRect(0, 0, mTexture->getWidth(), mTexture->getHeight()));
+}
+
+void BorderImage::setBorder(const IntRect& rect)
+{
+    mBorder.mLeft = max(rect.mLeft, 0);
+    mBorder.mTop = max(rect.mTop, 0);
+    mBorder.mRight = max(rect.mRight, 0);
+    mBorder.mBottom = max(rect.mBottom, 0);
+}
+
+void BorderImage::setBorder(int left, int top, int right, int bottom)
+{
+    setBorder(IntRect(left, top, right, bottom));
+}
+
+void BorderImage::setHoverOffset(const IntVector2& offset)
+{
+    mHoverOffset = offset;
+}
+
+void BorderImage::setHoverOffset(int x, int y)
+{
+    mHoverOffset = IntVector2(x, y);
+}
+
+void BorderImage::getBatches(std::vector<UIBatch>& batches, std::vector<UIQuad>& quads, const IntRect& currentScissor, const IntVector2& offset)
 {
 {
     bool allOpaque = true;
     bool allOpaque = true;
     if ((getDerivedOpacity() < 1.0f) || (mColor[C_TOPLEFT].mA < 1.0f) || (mColor[C_TOPRIGHT].mA < 1.0f) ||
     if ((getDerivedOpacity() < 1.0f) || (mColor[C_TOPLEFT].mA < 1.0f) || (mColor[C_TOPRIGHT].mA < 1.0f) ||
@@ -77,8 +136,7 @@ void BorderImage::getBatches(std::vector<UIBatch>& batches, std::vector<UIQuad>&
         max(mImageRect.mBottom - mImageRect.mTop - mBorder.mTop - mBorder.mBottom, 0));
         max(mImageRect.mBottom - mImageRect.mTop - mBorder.mTop - mBorder.mBottom, 0));
     
     
     IntVector2 topLeft(mImageRect.mLeft, mImageRect.mTop);
     IntVector2 topLeft(mImageRect.mLeft, mImageRect.mTop);
-    if ((mHovering) || (mSelected))
-        topLeft += mHoverOffset;
+    topLeft += offset;
     
     
     // Top
     // Top
     if (mBorder.mTop)
     if (mBorder.mTop)
@@ -127,60 +185,3 @@ void BorderImage::getBatches(std::vector<UIBatch>& batches, std::vector<UIQuad>&
     // Reset hovering for next frame
     // Reset hovering for next frame
     mHovering = false;
     mHovering = false;
 }
 }
-
-void BorderImage::setTexture(Texture* texture)
-{
-    mTexture = texture;
-    if (mImageRect == IntRect::sZero)
-        setFullImageRect();
-}
-
-void BorderImage::setImageRect(const IntRect& rect)
-{
-    mImageRect = rect;
-}
-
-void BorderImage::setImageRect(int left, int top, int right, int bottom)
-{
-    mImageRect.mLeft = left;
-    mImageRect.mTop = top;
-    mImageRect.mRight = right;
-    mImageRect.mBottom = bottom;
-}
-
-void BorderImage::setFullImageRect()
-{
-    if (mTexture)
-    {
-        mImageRect.mLeft = 0;
-        mImageRect.mTop = 0;
-        mImageRect.mRight = mTexture->getWidth();
-        mImageRect.mBottom = mTexture->getHeight();
-    }
-}
-
-void BorderImage::setBorder(const IntRect& rect)
-{
-    mBorder.mLeft = max(rect.mLeft, 0);
-    mBorder.mTop = max(rect.mTop, 0);
-    mBorder.mRight = max(rect.mRight, 0);
-    mBorder.mBottom = max(rect.mBottom, 0);
-}
-
-void BorderImage::setBorder(int left, int top, int right, int bottom)
-{
-    mBorder.mLeft = max(left, 0);
-    mBorder.mTop = max(top, 0);
-    mBorder.mRight = max(right, 0);
-    mBorder.mBottom = max(bottom, 0);
-}
-
-void BorderImage::setHoverOffset(const IntVector2& offset)
-{
-    mHoverOffset = offset;
-}
-
-void BorderImage::setHoverOffset(int x, int y)
-{
-    mHoverOffset = IntVector2(x, y);
-}

+ 3 - 0
Engine/UI/BorderImage.h

@@ -72,6 +72,9 @@ public:
     const IntVector2& getHoverOffset() const { return mHoverOffset; }
     const IntVector2& getHoverOffset() const { return mHoverOffset; }
     
     
 protected:
 protected:
+    //! Return UI rendering batches with offset to image rectangle
+    void getBatches(std::vector<UIBatch>& batches, std::vector<UIQuad>& quads, const IntRect& currentScissor, const IntVector2& offset);
+    
     //! Texture
     //! Texture
     SharedPtr<Texture> mTexture;
     SharedPtr<Texture> mTexture;
     //! Image rectangle
     //! Image rectangle

+ 12 - 23
Engine/UI/Button.cpp

@@ -30,8 +30,7 @@
 
 
 Button::Button(const std::string& name) :
 Button::Button(const std::string& name) :
     BorderImage(name),
     BorderImage(name),
-    mInactiveRect(IntRect::sZero),
-    mPressedRect(IntRect::sZero),
+    mPressedOffset(IntVector2::sZero),
     mLabelOffset(IntVector2::sZero),
     mLabelOffset(IntVector2::sZero),
     mRepeatDelay(1.0f),
     mRepeatDelay(1.0f),
     mRepeatRate(0.0f),
     mRepeatRate(0.0f),
@@ -49,10 +48,8 @@ void Button::setStyle(const XMLElement& element, ResourceCache* cache)
 {
 {
     BorderImage::setStyle(element, cache);
     BorderImage::setStyle(element, cache);
     
     
-    if (element.hasChildElement("inactiverect"))
-        setInactiveRect(element.getChildElement("inactiverect").getIntRect("value"));
-    if (element.hasChildElement("pressedrect"))
-        setPressedRect(element.getChildElement("pressedrect").getIntRect("value"));
+    if (element.hasChildElement("pressedoffset"))
+        setPressedOffset(element.getChildElement("pressedoffset").getIntVector2("value"));
     if (element.hasChildElement("labeloffset"))
     if (element.hasChildElement("labeloffset"))
         setLabelOffset(element.getChildElement("labeloffset").getIntVector2("value"));
         setLabelOffset(element.getChildElement("labeloffset").getIntVector2("value"));
     if (element.hasChildElement("repeat"))
     if (element.hasChildElement("repeat"))
@@ -86,12 +83,13 @@ void Button::update(float timeStep)
 
 
 void Button::getBatches(std::vector<UIBatch>& batches, std::vector<UIQuad>& quads, const IntRect& currentScissor)
 void Button::getBatches(std::vector<UIBatch>& batches, std::vector<UIQuad>& quads, const IntRect& currentScissor)
 {
 {
+    IntVector2 offset(IntVector2::sZero);
+    if ((mHovering) || (mSelected))
+        offset += mHoverOffset;
     if (mPressed)
     if (mPressed)
-        mImageRect = mPressedRect;
-    else
-        mImageRect = mInactiveRect;
+        offset += mPressedOffset;
     
     
-    BorderImage::getBatches(batches, quads, currentScissor);
+    BorderImage::getBatches(batches, quads, currentScissor, offset);
 }
 }
 
 
 void Button::onHover(const IntVector2& position, const IntVector2& screenPosition, int buttons, int qualifiers)
 void Button::onHover(const IntVector2& position, const IntVector2& screenPosition, int buttons, int qualifiers)
@@ -116,25 +114,16 @@ void Button::onClick(const IntVector2& position, const IntVector2& screenPositio
     }
     }
 }
 }
 
 
-void Button::setInactiveRect(const IntRect& rect)
+void Button::setPressedOffset(const IntVector2& offset)
 {
 {
-    mInactiveRect = rect;
+    mPressedOffset = offset;
 }
 }
 
 
-void Button::setInactiveRect(int left, int top, int right, int bottom)
+void Button::setPressedOffset(int x, int y)
 {
 {
-    mInactiveRect = IntRect(left, top, right, bottom);
+    mPressedOffset = IntVector2(x, y);
 }
 }
 
 
-void Button::setPressedRect(const IntRect& rect)
-{
-    mPressedRect = rect;
-}
-
-void Button::setPressedRect(int left, int top, int right, int bottom)
-{
-    mPressedRect = IntRect(left, top, right, bottom);
-}
 
 
 void Button::setLabelOffset(const IntVector2& offset)
 void Button::setLabelOffset(const IntVector2& offset)
 {
 {

+ 12 - 20
Engine/UI/Button.h

@@ -48,26 +48,20 @@ public:
     //! React to mouse click
     //! React to mouse click
     virtual void onClick(const IntVector2& position, const IntVector2& screenPosition, int buttons, int qualifiers);
     virtual void onClick(const IntVector2& position, const IntVector2& screenPosition, int buttons, int qualifiers);
     
     
-    //! Set inactive image rectangle
-    void setInactiveRect(const IntRect& rect);
-    //! Set inactive image rectangle
-    void setInactiveRect(int left, int top, int right, int bottom);
-    //! Set pressed image rectangle
-    void setPressedRect(const IntRect& rect);
-    //! Set pressed image rectangle
-    void setPressedRect(int left, int top, int right, int bottom);
-    //! Set label offset on press
+    //! Set pressed image offset
+    void setPressedOffset(const IntVector2& offset);
+    //! Set pressed image offset
+    void setPressedOffset(int x, int y);
+    //! Set pressed label offset
     void setLabelOffset(const IntVector2& offset);
     void setLabelOffset(const IntVector2& offset);
-    //! Set label offset on press
+    //! Set pressed label offset
     void setLabelOffset(int x, int y);
     void setLabelOffset(int x, int y);
     //! Set pressed event repeat. Rate 0 (default) disables repeat
     //! Set pressed event repeat. Rate 0 (default) disables repeat
     void setRepeat(float delay, float rate);
     void setRepeat(float delay, float rate);
     
     
-    //! Return inactive image rectangle
-    const IntRect& getInactiveRect() const { return mInactiveRect; }
-    //! Return pressed image rectangle
-    const IntRect& getPressedRect() const { return mPressedRect; }
-    //! Return label offset on press
+    //! Return pressed image offset
+    const IntVector2& getPressedOffset() const { return mPressedOffset; }
+    //! Return pressed label offset
     const IntVector2& getLabelOffset() const { return mLabelOffset; }
     const IntVector2& getLabelOffset() const { return mLabelOffset; }
     //! Return repeat delay
     //! Return repeat delay
     float getRepeatDelay() const { return mRepeatDelay; }
     float getRepeatDelay() const { return mRepeatDelay; }
@@ -78,11 +72,9 @@ protected:
     //! Set new pressed state
     //! Set new pressed state
     void setPressed(bool enable);
     void setPressed(bool enable);
     
     
-    //! Inactive image rectangle
-    IntRect mInactiveRect;
-    //! Pressed image rectangle
-    IntRect mPressedRect;
-    //! Label offset on press
+    //! Pressed image offset
+    IntVector2 mPressedOffset;
+    //! Pressed label offset
     IntVector2 mLabelOffset;
     IntVector2 mLabelOffset;
     //! Repeat delay
     //! Repeat delay
     float mRepeatDelay;
     float mRepeatDelay;

+ 19 - 31
Engine/UI/CheckBox.cpp

@@ -30,8 +30,7 @@
 
 
 CheckBox::CheckBox(const std::string& name) :
 CheckBox::CheckBox(const std::string& name) :
     BorderImage(name),
     BorderImage(name),
-    mUncheckedRect(IntRect::sZero),
-    mCheckedRect(IntRect::sZero),
+    mCheckedOffset(IntVector2::sZero),
     mChecked(false)
     mChecked(false)
 {
 {
     mEnabled = true;
     mEnabled = true;
@@ -45,27 +44,32 @@ void CheckBox::setStyle(const XMLElement& element, ResourceCache* cache)
 {
 {
     BorderImage::setStyle(element, cache);
     BorderImage::setStyle(element, cache);
     
     
-    if (element.hasChildElement("uncheckedrect"))
-        setUncheckedRect(element.getChildElement("uncheckedrect").getIntRect("value"));
-    if (element.hasChildElement("checkedrect"))
-        setCheckedRect(element.getChildElement("checkedrect").getIntRect("value"));
+    if (element.hasChildElement("checkedoffset"))
+        setCheckedOffset(element.getChildElement("checkedoffset").getIntVector2("value"));
 }
 }
 
 
 void CheckBox::getBatches(std::vector<UIBatch>& batches, std::vector<UIQuad>& quads, const IntRect& currentScissor)
 void CheckBox::getBatches(std::vector<UIBatch>& batches, std::vector<UIQuad>& quads, const IntRect& currentScissor)
 {
 {
+    IntVector2 offset(IntVector2::sZero);
+    if ((mHovering) || (mSelected))
+        offset += mHoverOffset;
     if (mChecked)
     if (mChecked)
-        mImageRect = mCheckedRect;
-    else
-        mImageRect = mUncheckedRect;
+        offset += mCheckedOffset;
     
     
-    BorderImage::getBatches(batches, quads, currentScissor);
+    BorderImage::getBatches(batches, quads, currentScissor, offset);
 }
 }
 
 
 void CheckBox::onClick(const IntVector2& position, const IntVector2& screenPosition, int buttons, int qualifiers)
 void CheckBox::onClick(const IntVector2& position, const IntVector2& screenPosition, int buttons, int qualifiers)
 {
 {
     if (buttons & MOUSEB_LEFT)
     if (buttons & MOUSEB_LEFT)
+        setChecked(!mChecked);
+}
+
+void CheckBox::setChecked(bool enable)
+{
+    if (enable != mChecked)
     {
     {
-        mChecked = !mChecked;
+        mChecked = enable;
         
         
         using namespace Toggled;
         using namespace Toggled;
         
         
@@ -76,28 +80,12 @@ void CheckBox::onClick(const IntVector2& position, const IntVector2& screenPosit
     }
     }
 }
 }
 
 
-void CheckBox::setChecked(bool enable)
-{
-    // Note: event is intentionally not sent when manually set
-    mChecked = enable;
-}
-
-void CheckBox::setUncheckedRect(const IntRect& rect)
-{
-    mUncheckedRect = rect;
-}
-
-void CheckBox::setUncheckedRect(int left, int top, int right, int bottom)
-{
-    mUncheckedRect = IntRect(left, top, right, bottom);
-}
-
-void CheckBox::setCheckedRect(const IntRect& rect)
+void CheckBox::setCheckedOffset(const IntVector2& offset)
 {
 {
-    mCheckedRect = rect;
+    mCheckedOffset = offset;
 }
 }
 
 
-void CheckBox::setCheckedRect(int left, int top, int right, int bottom)
+void CheckBox::setCheckedOffset(int x, int y)
 {
 {
-    mCheckedRect = IntRect(left, top, right, bottom);
+    mCheckedOffset = IntVector2(x, y);
 }
 }

+ 8 - 16
Engine/UI/CheckBox.h

@@ -46,27 +46,19 @@ public:
     
     
     //! Set checked state
     //! Set checked state
     void setChecked(bool enable);
     void setChecked(bool enable);
-    //! Set unchecked image rectangle
-    void setUncheckedRect(const IntRect& rect);
-    //! Set unchecked image rectangle
-    void setUncheckedRect(int left, int top, int right, int bottom);
-    //! Set checked image rectangle
-    void setCheckedRect(const IntRect& rect);
-    //! Set checked image rectangle
-    void setCheckedRect(int left, int top, int right, int bottom);
+    //! Set checked image offset
+    void setCheckedOffset(const IntVector2& rect);
+    //! Set checked image offset
+    void setCheckedOffset(int x, int y);
     
     
     //! Return whether is checked
     //! Return whether is checked
     bool isChecked() const { return mChecked; }
     bool isChecked() const { return mChecked; }
-    //! Return unchecked image rectangle
-    const IntRect& getUncheckedRect() const { return mUncheckedRect; }
-    //! Return checked image rectangle
-    const IntRect& getCheckedRect() const { return mCheckedRect; }
+    //! Return checked image offset
+    const IntVector2& getCheckedOffset() const { return mCheckedOffset; }
     
     
 protected:
 protected:
-    //! Unchecked image rectangle
-    IntRect mUncheckedRect;
-    //! Checked image rectangle
-    IntRect mCheckedRect;
+    //! Checked image offset
+    IntVector2 mCheckedOffset;
     //! Current checked state
     //! Current checked state
     bool mChecked;
     bool mChecked;
 };
 };

+ 33 - 37
Engine/UI/ScrollBar.cpp

@@ -29,7 +29,11 @@
 
 
 ScrollBar::ScrollBar(const std::string& name) :
 ScrollBar::ScrollBar(const std::string& name) :
     UIElement(name),
     UIElement(name),
-    mScrollStep(0.1f)
+    mScrollStep(0.1f),
+    mLeftRect(IntRect::sZero),
+    mRightRect(IntRect::sZero),
+    mUpRect(IntRect::sZero),
+    mDownRect(IntRect::sZero)
 {
 {
     mEnabled = true;
     mEnabled = true;
     mBackButton = new Button();
     mBackButton = new Button();
@@ -59,14 +63,30 @@ void ScrollBar::setStyle(const XMLElement& element, ResourceCache* cache)
     XMLElement backButtonElem = element.getChildElement("backbutton");
     XMLElement backButtonElem = element.getChildElement("backbutton");
     if (backButtonElem)
     if (backButtonElem)
     {
     {
+        XMLElement imageElem = backButtonElem.getChildElement("imagerect");
+        if (imageElem.hasAttribute("horizontal"))
+            mLeftRect = imageElem.getIntRect("horizontal");
+        if (imageElem.hasAttribute("vertical"))
+            mUpRect = imageElem.getIntRect("vertical");
+        if (imageElem.hasAttribute("h"))
+            mLeftRect = imageElem.getIntRect("h");
+        if (imageElem.hasAttribute("v"))
+            mUpRect = imageElem.getIntRect("v");
         mBackButton->setStyle(backButtonElem, cache);
         mBackButton->setStyle(backButtonElem, cache);
-        setButtonStyle(0, backButtonElem);
     }
     }
     XMLElement forwardButtonElem = element.getChildElement("forwardbutton");
     XMLElement forwardButtonElem = element.getChildElement("forwardbutton");
     if (forwardButtonElem)
     if (forwardButtonElem)
     {
     {
+        XMLElement imageElem = forwardButtonElem.getChildElement("imagerect");
+        if (imageElem.hasAttribute("horizontal"))
+            mRightRect = imageElem.getIntRect("horizontal");
+        if (imageElem.hasAttribute("vertical"))
+            mDownRect = imageElem.getIntRect("vertical");
+        if (imageElem.hasAttribute("h"))
+            mRightRect = imageElem.getIntRect("h");
+        if (imageElem.hasAttribute("v"))
+            mDownRect = imageElem.getIntRect("v");
         mForwardButton->setStyle(forwardButtonElem, cache);
         mForwardButton->setStyle(forwardButtonElem, cache);
-        setButtonStyle(1, forwardButtonElem);
     }
     }
     XMLElement sliderElem = element.getChildElement("slider");
     XMLElement sliderElem = element.getChildElement("slider");
     if (sliderElem)
     if (sliderElem)
@@ -111,11 +131,16 @@ void ScrollBar::setOrientation(Orientation orientation)
 {
 {
     mSlider->setOrientation(orientation);
     mSlider->setOrientation(orientation);
     
     
-    unsigned orient = (unsigned)orientation;
-    mBackButton->setInactiveRect(mInactiveRects[orient][0]);
-    mBackButton->setPressedRect(mPressedRects[orient][0]);
-    mForwardButton->setInactiveRect(mInactiveRects[orient][1]);
-    mForwardButton->setPressedRect(mPressedRects[orient][1]);
+    if (orientation == O_HORIZONTAL)
+    {
+        mBackButton->setImageRect(mLeftRect);
+        mForwardButton->setImageRect(mRightRect);
+    }
+    else
+    {
+        mBackButton->setImageRect(mUpRect);
+        mForwardButton->setImageRect(mDownRect);
+    }
     
     
     onResize();
     onResize();
     setLayout(orientation, LM_RESIZECHILDREN, LM_RESIZECHILDREN);
     setLayout(orientation, LM_RESIZECHILDREN, LM_RESIZECHILDREN);
@@ -151,35 +176,6 @@ float ScrollBar::getValue() const
     return mSlider->getValue();
     return mSlider->getValue();
 }
 }
 
 
-void ScrollBar::setButtonStyle(unsigned index, const XMLElement& buttonElem)
-{
-    Button* button = index ? mForwardButton : mBackButton;
-    unsigned orient = (unsigned)getType();
-    
-    XMLElement inactiveRectElem = buttonElem.getChildElement("inactiverect");
-    if (inactiveRectElem.hasAttribute("horizontal"))
-        mInactiveRects[0][index] = inactiveRectElem.getIntRect("horizontal");
-    if (inactiveRectElem.hasAttribute("h"))
-        mInactiveRects[0][index] = inactiveRectElem.getIntRect("h");
-    if (inactiveRectElem.hasAttribute("vertical"))
-        mInactiveRects[1][index] = inactiveRectElem.getIntRect("vertical");
-    if (inactiveRectElem.hasAttribute("v"))
-        mInactiveRects[1][index] = inactiveRectElem.getIntRect("v");
-    
-    XMLElement pressedRectElem = buttonElem.getChildElement("pressedrect");
-    if (pressedRectElem.hasAttribute("horizontal"))
-        mPressedRects[0][index] = pressedRectElem.getIntRect("horizontal");
-    if (pressedRectElem.hasAttribute("h"))
-        mPressedRects[0][index] = pressedRectElem.getIntRect("h");
-    if (inactiveRectElem.hasAttribute("vertical"))
-        mPressedRects[1][index] = pressedRectElem.getIntRect("vertical");
-    if (inactiveRectElem.hasAttribute("v"))
-        mPressedRects[1][index] = pressedRectElem.getIntRect("v");
-    
-    button->setInactiveRect(mInactiveRects[orient][index]);
-    button->setPressedRect(mPressedRects[orient][index]);
-}
-
 void ScrollBar::handleBackButtonPressed(StringHash eventType, VariantMap& eventData)
 void ScrollBar::handleBackButtonPressed(StringHash eventType, VariantMap& eventData)
 {
 {
     mSlider->setValue(mSlider->getValue() - mScrollStep);
     mSlider->setValue(mSlider->getValue() - mScrollStep);

+ 8 - 8
Engine/UI/ScrollBar.h

@@ -69,9 +69,6 @@ public:
     Slider* getSlider() const { return mSlider; }
     Slider* getSlider() const { return mSlider; }
     
     
 protected:
 protected:
-    //! Store/setup style of a button. Index 0 = back, 1 = forward
-    void setButtonStyle(unsigned index, const XMLElement& buttonElem);
-    
     //! Back button
     //! Back button
     SharedPtr<Button> mBackButton;
     SharedPtr<Button> mBackButton;
     //! Forward button
     //! Forward button
@@ -80,11 +77,14 @@ protected:
     SharedPtr<Slider> mSlider;
     SharedPtr<Slider> mSlider;
     //! Scroll step
     //! Scroll step
     float mScrollStep;
     float mScrollStep;
-    
-    //! Inactive rects for buttons
-    IntRect mInactiveRects[2][2];
-    //! Pressed rects for buttons
-    IntRect mPressedRects[2][2];
+    //! Left button image rect
+    IntRect mLeftRect;
+    //! Right button image rect
+    IntRect mRightRect;
+    //! Up button image rect
+    IntRect mUpRect;
+    //! Down button image rect
+    IntRect mDownRect;
     
     
 private:
 private:
     //! Handle back button pressed
     //! Handle back button pressed

+ 13 - 15
Engine/UI/UIElement.cpp

@@ -655,7 +655,7 @@ void UIElement::updateLayout()
                 if (!mChildren[i]->isVisible())
                 if (!mChildren[i]->isVisible())
                     continue;
                     continue;
                 mChildren[i]->setHorizontalAlignment(HA_LEFT);
                 mChildren[i]->setHorizontalAlignment(HA_LEFT);
-                mChildren[i]->setPosition(position, getLayoutChildYPosition(mChildren[i]));
+                mChildren[i]->setPosition(position, getLayoutChildPosition(mChildren[i]).mY);
                 if (mVerticalLayoutMode == LM_RESIZECHILDREN)
                 if (mVerticalLayoutMode == LM_RESIZECHILDREN)
                     mChildren[i]->setHeight(getHeight() - mLayoutBorder.mTop - mLayoutBorder.mBottom);
                     mChildren[i]->setHeight(getHeight() - mLayoutBorder.mTop - mLayoutBorder.mBottom);
                 position += mChildren[i]->getWidth();
                 position += mChildren[i]->getWidth();
@@ -688,7 +688,7 @@ void UIElement::updateLayout()
                 if (!mChildren[i]->isVisible())
                 if (!mChildren[i]->isVisible())
                     continue;
                     continue;
                 mChildren[i]->setHorizontalAlignment(HA_LEFT);
                 mChildren[i]->setHorizontalAlignment(HA_LEFT);
-                mChildren[i]->setPosition(positions[idx], getLayoutChildYPosition(mChildren[i]));
+                mChildren[i]->setPosition(positions[idx], getLayoutChildPosition(mChildren[i]).mY);
                 mChildren[i]->setSize(sizes[idx], mVerticalLayoutMode == LM_RESIZECHILDREN ? getHeight() - mLayoutBorder.mTop -
                 mChildren[i]->setSize(sizes[idx], mVerticalLayoutMode == LM_RESIZECHILDREN ? getHeight() - mLayoutBorder.mTop -
                     mLayoutBorder.mBottom : mChildren[i]->getHeight());
                     mLayoutBorder.mBottom : mChildren[i]->getHeight());
                 ++idx;
                 ++idx;
@@ -719,7 +719,7 @@ void UIElement::updateLayout()
                 if (!mChildren[i]->isVisible())
                 if (!mChildren[i]->isVisible())
                     continue;
                     continue;
                 mChildren[i]->setVerticalAlignment(VA_TOP);
                 mChildren[i]->setVerticalAlignment(VA_TOP);
-                mChildren[i]->setPosition(getLayoutChildXPosition(mChildren[i]), position);
+                mChildren[i]->setPosition(getLayoutChildPosition(mChildren[i]).mX, position);
                 if (mHorizontalLayoutMode == LM_RESIZECHILDREN)
                 if (mHorizontalLayoutMode == LM_RESIZECHILDREN)
                     mChildren[i]->setWidth(getWidth() - mLayoutBorder.mLeft - mLayoutBorder.mRight);
                     mChildren[i]->setWidth(getWidth() - mLayoutBorder.mLeft - mLayoutBorder.mRight);
                 position += mChildren[i]->getHeight();
                 position += mChildren[i]->getHeight();
@@ -751,7 +751,7 @@ void UIElement::updateLayout()
                 if (!mChildren[i]->isVisible())
                 if (!mChildren[i]->isVisible())
                     continue;
                     continue;
                 mChildren[i]->setVerticalAlignment(VA_TOP);
                 mChildren[i]->setVerticalAlignment(VA_TOP);
-                mChildren[i]->setPosition(getLayoutChildXPosition(mChildren[i]), positions[idx]);
+                mChildren[i]->setPosition(getLayoutChildPosition(mChildren[i]).mX, positions[idx]);
                 mChildren[i]->setSize(mHorizontalLayoutMode == LM_RESIZECHILDREN ? getWidth() - mLayoutBorder.mLeft -
                 mChildren[i]->setSize(mHorizontalLayoutMode == LM_RESIZECHILDREN ? getWidth() - mLayoutBorder.mLeft -
                     mLayoutBorder.mRight : mChildren[i]->getWidth(), sizes[idx]);
                     mLayoutBorder.mRight : mChildren[i]->getWidth(), sizes[idx]);
                 ++idx;
                 ++idx;
@@ -1143,31 +1143,29 @@ void UIElement::calculateLayout(std::vector<int>& positions, std::vector<int>& s
     }
     }
 }
 }
 
 
-int UIElement::getLayoutChildXPosition(UIElement* child)
+IntVector2 UIElement::getLayoutChildPosition(UIElement* child)
 {
 {
+    IntVector2 ret(IntVector2::sZero);
+    
     HorizontalAlignment ha = child->getHorizontalAlignment();
     HorizontalAlignment ha = child->getHorizontalAlignment();
     switch (ha)
     switch (ha)
     {
     {
     case HA_LEFT:
     case HA_LEFT:
-        return mLayoutBorder.mLeft;
+        ret.mX = mLayoutBorder.mLeft;
         
         
     case HA_RIGHT:
     case HA_RIGHT:
-        return -mLayoutBorder.mRight;
+        ret.mX -mLayoutBorder.mRight;
     }
     }
-    return 0;
-}
-
-int UIElement::getLayoutChildYPosition(UIElement* child)
-{
+    
     VerticalAlignment va = child->getVerticalAlignment();
     VerticalAlignment va = child->getVerticalAlignment();
     switch (va)
     switch (va)
     {
     {
     case VA_TOP:
     case VA_TOP:
-        return mLayoutBorder.mTop;
+        ret.mY = mLayoutBorder.mTop;
         
         
     case VA_BOTTOM:
     case VA_BOTTOM:
-        return -mLayoutBorder.mBottom;
+        ret.mY = mLayoutBorder.mBottom;
     }
     }
-    return 0;
+    return ret;
 }
 }
 
 

+ 2 - 4
Engine/UI/UIElement.h

@@ -392,10 +392,8 @@ private:
     //! Calculate child widths/positions in the layout
     //! Calculate child widths/positions in the layout
     void calculateLayout(std::vector<int>& positions, std::vector<int>& sizes, const std::vector<int>& minSizes,
     void calculateLayout(std::vector<int>& positions, std::vector<int>& sizes, const std::vector<int>& minSizes,
         const std::vector<int>& maxSizes, int targetWidth, int begin, int end, int spacing);
         const std::vector<int>& maxSizes, int targetWidth, int begin, int end, int spacing);
-    //! Get child element X position in a vertical layout
-    int getLayoutChildXPosition(UIElement* child);
-    //! Get child element Y position in a horizontal layout
-    int getLayoutChildYPosition(UIElement* child);
+    //! Get child element constant position in a layout
+    IntVector2 getLayoutChildPosition(UIElement* child);
     
     
     //! Position
     //! Position
     IntVector2 mPosition;
     IntVector2 mPosition;