2
0
Эх сурвалжийг харах

Further UI refactoring. A hover color modification is now defined for all UI elements.

Lasse Öörni 15 жил өмнө
parent
commit
ec14f7a3a2

BIN
Bin/Data/Textures/UI.png


+ 6 - 5
Bin/Data/UI/UI.xml

@@ -7,15 +7,16 @@
     </element>
     </element>
     <element name="Button">
     <element name="Button">
         <texture name="Textures/UI.png" />
         <texture name="Textures/UI.png" />
+        <color value="0.85 0.85 0.85" />
+        <hovercolor value="0.15 0.15 0.15" />
         <inactiverect value="16 0 32 16" />
         <inactiverect value="16 0 32 16" />
-        <hoverrect value="32 0 48 16" />
-        <pressedrect value="48 0 64 16" />
-        <border value="5 5 5 5" />
-        <labeloffset value="0 0" />
+        <pressedrect value="32 0 48 16" />
+        <border value="4 4 4 4" />
+        <labeloffset value="-1 1" />
     </element>
     </element>
     <element name="Window">
     <element name="Window">
         <texture name="Textures/UI.png" />
         <texture name="Textures/UI.png" />
-        <imagerect value="64 0 80 16" />
+        <imagerect value="48 0 64 16" />
         <border value="3 3 3 3" />
         <border value="3 3 3 3" />
         <resizeborder value="8 8 8 8" />
         <resizeborder value="8 8 8 8" />
         <movable enable="true" />
         <movable enable="true" />

+ 0 - 3
Engine/Audio/Audio.h

@@ -154,7 +154,4 @@ private:
     Quaternion mListenerRotation;
     Quaternion mListenerRotation;
 };
 };
 
 
-//! Return Audio instance
-Audio* getAudio();
-
 #endif // AUDIO_AUDIO_H
 #endif // AUDIO_AUDIO_H

+ 20 - 4
Engine/Common/Color.h

@@ -93,6 +93,22 @@ public:
         return Color(mR * rhs, mG * rhs, mB * rhs, mA * rhs);
         return Color(mR * rhs, mG * rhs, mB * rhs, mA * rhs);
     }
     }
     
     
+    //! Add a color
+    Color operator + (const Color& rhs) const
+    {
+        return Color(mR + rhs.mR, mG + rhs.mG, mB + rhs.mB, mA + rhs.mA);
+    }
+    
+    //! Add-assign a color
+    Color& operator += (const Color& rhs)
+    {
+        mR += rhs.mR;
+        mG += rhs.mG;
+        mB += rhs.mB;
+        mA += rhs.mA;
+        return *this;
+    }
+    
     //! Return float data
     //! Return float data
     const float* getData() const { return &mR; }
     const float* getData() const { return &mR; }
     //! Return RGB values as a Vector3
     //! Return RGB values as a Vector3
@@ -167,10 +183,10 @@ public:
 //! Return color packed to a 32-bit integer
 //! Return color packed to a 32-bit integer
 inline unsigned getD3DColor(const Color& color)
 inline unsigned getD3DColor(const Color& color)
 {
 {
-    unsigned r = (unsigned)(color.mR * 255.0f);
-    unsigned g = (unsigned)(color.mG * 255.0f);
-    unsigned b = (unsigned)(color.mB * 255.0f);
-    unsigned a = (unsigned)(color.mA * 255.0f);
+    unsigned r = (unsigned)(clamp(color.mR * 255.0f, 0.0f, 255.0f));
+    unsigned g = (unsigned)(clamp(color.mG * 255.0f, 0.0f, 255.0f));
+    unsigned b = (unsigned)(clamp(color.mB * 255.0f, 0.0f, 255.0f));
+    unsigned a = (unsigned)(clamp(color.mA * 255.0f, 0.0f, 255.0f));
     
     
     return (((a) & 0xff) << 24) | (((r) & 0xff) << 16) | (((g) & 0xff) << 8) | ((b) & 0xff);
     return (((a) & 0xff) << 24) | (((r) & 0xff) << 16) | (((g) & 0xff) << 8) | ((b) & 0xff);
 }
 }

+ 0 - 3
Engine/Engine/Client.h

@@ -246,7 +246,4 @@ private:
     VariantMap mPendingLoginData;
     VariantMap mPendingLoginData;
 };
 };
 
 
-//! Return Client instance
-Client* getClient();
-
 #endif // ENGINE_CLIENT_H
 #endif // ENGINE_CLIENT_H

+ 3 - 2
Engine/Engine/RegisterTemplates.h

@@ -353,9 +353,8 @@ template <class T> void registerUIElement(asIScriptEngine* engine, const char* c
     engine->RegisterObjectMethod(className, "void setHorizontalAlignment(HorizontalAlignment)", asMETHOD(T, setHorizontalAlignment), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void setHorizontalAlignment(HorizontalAlignment)", asMETHOD(T, setHorizontalAlignment), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void setVerticalAlignment(VerticalAlignment)", asMETHOD(T, setVerticalAlignment), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void setVerticalAlignment(VerticalAlignment)", asMETHOD(T, setVerticalAlignment), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void setColor(const Color& in)", asMETHODPR(T, setColor, (const Color&), void), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void setColor(const Color& in)", asMETHODPR(T, setColor, (const Color&), void), asCALL_THISCALL);
-    engine->RegisterObjectMethod(className, "void setColor(float, float, float)", asMETHODPR(T, setColor, (float, float, float), void), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void setColor(UIElementCorner, const Color& in)", asMETHODPR(T, setColor, (UIElementCorner, const Color&), void), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void setColor(UIElementCorner, const Color& in)", asMETHODPR(T, setColor, (UIElementCorner, const Color&), void), asCALL_THISCALL);
-    engine->RegisterObjectMethod(className, "void setColor(UIElementCorner, float, float, float)", asMETHODPR(T, setColor, (UIElementCorner, float, float, float), void), asCALL_THISCALL);
+    engine->RegisterObjectMethod(className, "void setHoverColor(const Color& in)", asMETHOD(T, setHoverColor), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void setPriority(int)", asMETHOD(T, setPriority), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void setPriority(int)", asMETHOD(T, setPriority), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void setOpacity(float)", asMETHOD(T, setOpacity), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void setOpacity(float)", asMETHOD(T, setOpacity), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void setBringToFront(bool)", asMETHOD(T, setBringToFront), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void setBringToFront(bool)", asMETHOD(T, setBringToFront), asCALL_THISCALL);
@@ -375,6 +374,7 @@ template <class T> void registerUIElement(asIScriptEngine* engine, const char* c
     engine->RegisterObjectMethod(className, "HorizontalAlignment getHorizontalAlignment() const", asMETHOD(T, getHorizontalAlignment), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "HorizontalAlignment getHorizontalAlignment() const", asMETHOD(T, getHorizontalAlignment), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "VerticalAlignment getVerticalAlignment() const", asMETHOD(T, getVerticalAlignment), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "VerticalAlignment getVerticalAlignment() const", asMETHOD(T, getVerticalAlignment), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "const Color& getColor(UIElementCorner) const", asMETHOD(T, getColor), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "const Color& getColor(UIElementCorner) const", asMETHOD(T, getColor), asCALL_THISCALL);
+    engine->RegisterObjectMethod(className, "const Color& getHoverColor() const", asMETHOD(T, getHoverColor), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "int getPriority() const", asMETHOD(T, getPriority), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "int getPriority() const", asMETHOD(T, getPriority), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "float getOpacity() const", asMETHOD(T, getOpacity), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "float getOpacity() const", asMETHOD(T, getOpacity), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "bool getBringToFront() const", asMETHOD(T, getBringToFront), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "bool getBringToFront() const", asMETHOD(T, getBringToFront), asCALL_THISCALL);
@@ -383,6 +383,7 @@ template <class T> void registerUIElement(asIScriptEngine* engine, const char* c
     engine->RegisterObjectMethod(className, "bool isFocusable() const", asMETHOD(T, isFocusable), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "bool isFocusable() const", asMETHOD(T, isFocusable), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "bool hasFocus() const", asMETHOD(T, hasFocus), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "bool hasFocus() const", asMETHOD(T, hasFocus), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "bool isVisible() const", asMETHOD(T, isVisible), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "bool isVisible() const", asMETHOD(T, isVisible), asCALL_THISCALL);
+    engine->RegisterObjectMethod(className, "bool isHovering() const", asMETHOD(T, isHovering), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "bool hasColorGradient() const", asMETHOD(T, hasColorGradient), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "bool hasColorGradient() const", asMETHOD(T, hasColorGradient), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "uint getNumChildren(bool) const", asMETHOD(T, getNumChildren), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "uint getNumChildren(bool) const", asMETHOD(T, getNumChildren), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "UIElement@+ getChild(uint) const", asMETHODPR(T, getChild, (unsigned) const, UIElement*), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "UIElement@+ getChild(uint) const", asMETHODPR(T, getChild, (unsigned) const, UIElement*), asCALL_THISCALL);

+ 0 - 3
Engine/Engine/RegisterUI.cpp

@@ -117,15 +117,12 @@ static void registerButton(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Button", "void loadParameters(XMLFile@+, const string& in)", asFUNCTION(UIElementLoadParameters), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("Button", "void loadParameters(XMLFile@+, const string& in)", asFUNCTION(UIElementLoadParameters), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("Button", "void setInactiveRect(const IntRect& in)", asMETHODPR(Button, setInactiveRect, (const IntRect&), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("Button", "void setInactiveRect(const IntRect& in)", asMETHODPR(Button, setInactiveRect, (const IntRect&), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("Button", "void setInactiveRect(int, int, int, int)", asMETHODPR(Button, setInactiveRect, (int, int, int, int), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("Button", "void setInactiveRect(int, int, int, int)", asMETHODPR(Button, setInactiveRect, (int, int, int, int), void), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Button", "void setHoverRect(const IntRect& in)", asMETHODPR(Button, setHoverRect, (const IntRect&), void), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Button", "void setHoverRect(int, int, int, int)", asMETHODPR(Button, setHoverRect, (int, int, int, int), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("Button", "void setPressedRect(const IntRect& in)", asMETHODPR(Button, setPressedRect, (const IntRect&), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("Button", "void setPressedRect(const IntRect& in)", asMETHODPR(Button, setPressedRect, (const IntRect&), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("Button", "void setPressedRect(int, int, int, int)", asMETHODPR(Button, setPressedRect, (int, int, int, int), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("Button", "void setPressedRect(int, int, int, int)", asMETHODPR(Button, setPressedRect, (int, int, int, int), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("Button", "void setLabel(UIElement@+)", asMETHOD(Button, setLabel), asCALL_THISCALL);
     engine->RegisterObjectMethod("Button", "void setLabel(UIElement@+)", asMETHOD(Button, setLabel), asCALL_THISCALL);
     engine->RegisterObjectMethod("Button", "void setLabelOffset(const IntVector2& in)", asMETHODPR(Button, setLabelOffset, (const IntVector2&), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("Button", "void setLabelOffset(const IntVector2& in)", asMETHODPR(Button, setLabelOffset, (const IntVector2&), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("Button", "void setLabelOffset(int, int)", asMETHODPR(Button, setLabelOffset, (int, int), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("Button", "void setLabelOffset(int, int)", asMETHODPR(Button, setLabelOffset, (int, int), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("Button", "const IntRect& getInactiveRect() const", asMETHOD(Button, getInactiveRect), asCALL_THISCALL);
     engine->RegisterObjectMethod("Button", "const IntRect& getInactiveRect() const", asMETHOD(Button, getInactiveRect), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Button", "const IntRect& getHoverRect() const", asMETHOD(Button, getHoverRect), asCALL_THISCALL);
     engine->RegisterObjectMethod("Button", "const IntRect& getPressedRect() const", asMETHOD(Button, getPressedRect), asCALL_THISCALL);
     engine->RegisterObjectMethod("Button", "const IntRect& getPressedRect() const", asMETHOD(Button, getPressedRect), asCALL_THISCALL);
     engine->RegisterObjectMethod("Button", "UIElement@+ getLabel() const", asMETHOD(Button, getLabel), asCALL_THISCALL);
     engine->RegisterObjectMethod("Button", "UIElement@+ getLabel() const", asMETHOD(Button, getLabel), asCALL_THISCALL);
     engine->RegisterObjectMethod("Button", "const IntVector2& getLabelOffset() const", asMETHOD(Button, getLabelOffset), asCALL_THISCALL);
     engine->RegisterObjectMethod("Button", "const IntVector2& getLabelOffset() const", asMETHOD(Button, getLabelOffset), asCALL_THISCALL);

+ 0 - 3
Engine/Engine/Server.h

@@ -139,7 +139,4 @@ private:
     int mStayRelevantTime;
     int mStayRelevantTime;
 };
 };
 
 
-//! Return Server instance
-Server* getServer();
-
 #endif // ENGINE_SERVER_H
 #endif // ENGINE_SERVER_H

+ 0 - 3
Engine/Input/Input.h

@@ -103,7 +103,4 @@ private:
     bool mActivated;
     bool mActivated;
 };
 };
 
 
-//! Return Input instance
-Input* getInput();
-
 #endif // INPUT_INPUT_H
 #endif // INPUT_INPUT_H

+ 0 - 3
Engine/Renderer/Pipeline.h

@@ -332,7 +332,4 @@ private:
     FrameInfo mFrame;
     FrameInfo mFrame;
 };
 };
 
 
-//! Return Pipeline instance
-Pipeline* getPipeline();
-
 #endif // RENDERER_PIPELINE_H
 #endif // RENDERER_PIPELINE_H

+ 0 - 3
Engine/Renderer/Renderer.h

@@ -501,7 +501,4 @@ private:
     TextureFilterMode mDefaultTextureFilterMode;
     TextureFilterMode mDefaultTextureFilterMode;
 };
 };
 
 
-//! Return Renderer instance
-Renderer* getRenderer();
-
 #endif // RENDERER_RENDERER_H
 #endif // RENDERER_RENDERER_H

+ 5 - 2
Engine/Renderer/RendererDefs.h

@@ -122,7 +122,11 @@ enum VertexElement
     ELEMENT_TANGENT,
     ELEMENT_TANGENT,
     ELEMENT_BLENDWEIGHTS,
     ELEMENT_BLENDWEIGHTS,
     ELEMENT_BLENDINDICES,
     ELEMENT_BLENDINDICES,
-    ELEMENT_INSTANCENUMBER
+    ELEMENT_INSTANCENUMBER,
+    ELEMENT_INSTANCEMATRIX1,
+    ELEMENT_INSTANCEMATRIX2,
+    ELEMENT_INSTANCEMATRIX3,
+    MAX_VERTEX_ELEMENTS
 };
 };
 
 
 //! Texture filtering mode
 //! Texture filtering mode
@@ -201,7 +205,6 @@ static const unsigned CLEAR_STENCIL = 4;
 static const unsigned MAX_RENDERTARGETS = 4;
 static const unsigned MAX_RENDERTARGETS = 4;
 static const unsigned MAX_TEXTURE_UNITS = 8;
 static const unsigned MAX_TEXTURE_UNITS = 8;
 static const unsigned MAX_VERTEX_STREAMS = 4;
 static const unsigned MAX_VERTEX_STREAMS = 4;
-static const unsigned MAX_VERTEX_ELEMENTS = 14;
 static const unsigned MAX_SKIN_MATRICES = 64;
 static const unsigned MAX_SKIN_MATRICES = 64;
 static const unsigned MAX_INSTANCES_PER_BATCH = 32;
 static const unsigned MAX_INSTANCES_PER_BATCH = 32;
 
 

+ 1 - 1
Engine/Renderer/VertexDeclaration.cpp

@@ -81,7 +81,7 @@ const BYTE d3dElementUsageIndex[] =
     2, // Instancenumber
     2, // Instancenumber
     2, // Instancematrix1
     2, // Instancematrix1
     3, // Instancematrix2
     3, // Instancematrix2
-    4, // Instancematrix3
+    4 // Instancematrix3
 };
 };
 
 
 VertexDeclaration::VertexDeclaration(Renderer* renderer, unsigned elementMask) :
 VertexDeclaration::VertexDeclaration(Renderer* renderer, unsigned elementMask) :

+ 0 - 3
Engine/Resource/ResourceCache.h

@@ -162,7 +162,4 @@ template <class T> std::vector<T*> ResourceCache::getResources()
     return ret;
     return ret;
 }
 }
 
 
-//! Return ResourceCache instance
-ResourceCache* getResourceCache();
-
 #endif // RESOURCE_RESOURCECACHE_H
 #endif // RESOURCE_RESOURCECACHE_H

+ 0 - 3
Engine/Script/ScriptEngine.h

@@ -57,7 +57,4 @@ private:
     asIScriptContext* mImmediateContext;
     asIScriptContext* mImmediateContext;
 };
 };
 
 
-//! Return the ScriptEngine instance
-ScriptEngine* getScriptEngine();
-
 #endif // SCRIPT_SCRIPTENGINE_H
 #endif // SCRIPT_SCRIPTENGINE_H

+ 14 - 33
Engine/UI/Button.cpp

@@ -33,14 +33,14 @@
 Button::Button(const std::string& name) :
 Button::Button(const std::string& name) :
     BorderImage(name),
     BorderImage(name),
     mInactiveRect(0, 0, 0, 0),
     mInactiveRect(0, 0, 0, 0),
-    mHoverRect(0, 0, 0, 0),
     mPressedRect(0, 0, 0, 0),
     mPressedRect(0, 0, 0, 0),
     mLabelOffset(0, 0),
     mLabelOffset(0, 0),
-    mState(BUTTON_INACTIVE),
-    mHoveringThisFrame(false)
+    mState(BUTTON_INACTIVE)
 {
 {
     mClipChildren = true;
     mClipChildren = true;
     mEnabled = true;
     mEnabled = true;
+    mLabelContainer = new UIElement();
+    addChild(mLabelContainer);
 }
 }
 
 
 Button::~Button()
 Button::~Button()
@@ -53,8 +53,6 @@ XMLElement Button::loadParameters(XMLFile* file, const std::string& elementName,
     
     
     if (paramElem.hasChildElement("inactiverect"))
     if (paramElem.hasChildElement("inactiverect"))
         setInactiveRect(paramElem.getChildElement("inactiverect").getIntRect("value"));
         setInactiveRect(paramElem.getChildElement("inactiverect").getIntRect("value"));
-    if (paramElem.hasChildElement("hoverrect"))
-        setHoverRect(paramElem.getChildElement("hoverrect").getIntRect("value"));
     if (paramElem.hasChildElement("pressedrect"))
     if (paramElem.hasChildElement("pressedrect"))
         setPressedRect(paramElem.getChildElement("pressedrect").getIntRect("value"));
         setPressedRect(paramElem.getChildElement("pressedrect").getIntRect("value"));
     if (paramElem.hasChildElement("labeloffset"))
     if (paramElem.hasChildElement("labeloffset"))
@@ -65,10 +63,10 @@ XMLElement Button::loadParameters(XMLFile* file, const std::string& elementName,
 
 
 void Button::update(float timeStep)
 void Button::update(float timeStep)
 {
 {
-    if (!mHoveringThisFrame)
+    if (!mHovering)
         setState(BUTTON_INACTIVE);
         setState(BUTTON_INACTIVE);
-    
-    mHoveringThisFrame = false;
+    if (mLabelContainer->getSize() != getSize())
+        mLabelContainer->setSize(getSize());
 }
 }
 
 
 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)
@@ -79,16 +77,13 @@ void Button::getBatches(std::vector<UIBatch>& batches, std::vector<UIQuad>& quad
         mImageRect = mInactiveRect;
         mImageRect = mInactiveRect;
         break;
         break;
         
         
-    case BUTTON_HOVER:
-        mImageRect = mHoverRect;
-        break;
-        
     case BUTTON_PRESSED:
     case BUTTON_PRESSED:
         mImageRect = mPressedRect;
         mImageRect = mPressedRect;
         break;
         break;
     }
     }
     
     
     BorderImage::getBatches(batches, quads, currentScissor);
     BorderImage::getBatches(batches, quads, currentScissor);
+    mHovering = false;
 }
 }
 
 
 void Button::onHover(const IntVector2& position, const IntVector2& screenPosition, unsigned buttons)
 void Button::onHover(const IntVector2& position, const IntVector2& screenPosition, unsigned buttons)
@@ -96,9 +91,8 @@ void Button::onHover(const IntVector2& position, const IntVector2& screenPositio
     if (buttons & MOUSEB_LEFT)
     if (buttons & MOUSEB_LEFT)
         setState(BUTTON_PRESSED);
         setState(BUTTON_PRESSED);
     else
     else
-        setState(BUTTON_HOVER);
-    
-    mHoveringThisFrame = true;
+        setState(BUTTON_INACTIVE);
+    mHovering = true;
 }
 }
 
 
 void Button::onClick(const IntVector2& position, const IntVector2& screenPosition, unsigned buttons)
 void Button::onClick(const IntVector2& position, const IntVector2& screenPosition, unsigned buttons)
@@ -106,7 +100,7 @@ void Button::onClick(const IntVector2& position, const IntVector2& screenPositio
     if (buttons & MOUSEB_LEFT)
     if (buttons & MOUSEB_LEFT)
     {
     {
         setState(BUTTON_PRESSED);
         setState(BUTTON_PRESSED);
-        mHoveringThisFrame = true;
+        mHovering = true;
         
         
         using namespace Pressed;
         using namespace Pressed;
         
         
@@ -126,16 +120,6 @@ void Button::setInactiveRect(int left, int top, int right, int bottom)
     mInactiveRect = IntRect(left, top, right, bottom);
     mInactiveRect = IntRect(left, top, right, bottom);
 }
 }
 
 
-void Button::setHoverRect(const IntRect& rect)
-{
-    mHoverRect = rect;
-}
-
-void Button::setHoverRect(int left, int top, int right, int bottom)
-{
-    mHoverRect = IntRect(left, top, right, bottom);
-}
-
 void Button::setPressedRect(const IntRect& rect)
 void Button::setPressedRect(const IntRect& rect)
 {
 {
     mPressedRect = rect;
     mPressedRect = rect;
@@ -148,11 +132,11 @@ void Button::setPressedRect(int left, int top, int right, int bottom)
 
 
 void Button::setLabel(UIElement* label)
 void Button::setLabel(UIElement* label)
 {
 {
-    removeChild(mLabel);
+    mLabelContainer->removeChild(mLabel);
     mLabel = label;
     mLabel = label;
     if (mLabel)
     if (mLabel)
     {
     {
-        addChild(mLabel);
+        mLabelContainer->addChild(mLabel);
         // Center the label element on the button forcibly
         // Center the label element on the button forcibly
         mLabel->setAlignment(HA_CENTER, VA_CENTER);
         mLabel->setAlignment(HA_CENTER, VA_CENTER);
         updateLabelOffset();
         updateLabelOffset();
@@ -180,11 +164,8 @@ void Button::setState(ButtonState state)
 
 
 void Button::updateLabelOffset()
 void Button::updateLabelOffset()
 {
 {
-    if (!mLabel)
-        return;
-    
     if (mState == BUTTON_PRESSED)
     if (mState == BUTTON_PRESSED)
-        mLabel->setPosition(mLabelOffset);
+        mLabelContainer->setPosition(mLabelOffset);
     else
     else
-        mLabel->setPosition(IntVector2::sZero);
+        mLabelContainer->setPosition(IntVector2::sZero);
 }
 }

+ 2 - 11
Engine/UI/Button.h

@@ -30,7 +30,6 @@
 enum ButtonState
 enum ButtonState
 {
 {
     BUTTON_INACTIVE = 0,
     BUTTON_INACTIVE = 0,
-    BUTTON_HOVER,
     BUTTON_PRESSED
     BUTTON_PRESSED
 };
 };
 
 
@@ -58,10 +57,6 @@ public:
     void setInactiveRect(const IntRect& rect);
     void setInactiveRect(const IntRect& rect);
     //! Set inactive image rectangle
     //! Set inactive image rectangle
     void setInactiveRect(int left, int top, int right, int bottom);
     void setInactiveRect(int left, int top, int right, int bottom);
-    //! Set hovering image rectangle
-    void setHoverRect(const IntRect& rect);
-    //! Set hovering image rectangle
-    void setHoverRect(int left, int top, int right, int bottom);
     //! Set pressed image rectangle
     //! Set pressed image rectangle
     void setPressedRect(const IntRect& rect);
     void setPressedRect(const IntRect& rect);
     //! Set pressed image rectangle
     //! Set pressed image rectangle
@@ -75,8 +70,6 @@ public:
     
     
     //! Return inactive image rectangle
     //! Return inactive image rectangle
     const IntRect& getInactiveRect() const { return mInactiveRect; }
     const IntRect& getInactiveRect() const { return mInactiveRect; }
-    //! Return hovering image rectangle
-    const IntRect& getHoverRect() const { return mHoverRect; }
     //! Return pressed image rectangle
     //! Return pressed image rectangle
     const IntRect& getPressedRect() const { return mPressedRect; }
     const IntRect& getPressedRect() const { return mPressedRect; }
     //! Return label UI element
     //! Return label UI element
@@ -92,18 +85,16 @@ protected:
     
     
     //! Label UI element
     //! Label UI element
     SharedPtr<UIElement> mLabel;
     SharedPtr<UIElement> mLabel;
+    //! Label container for offsetting
+    SharedPtr<UIElement> mLabelContainer;
     //! Inactive image rectangle
     //! Inactive image rectangle
     IntRect mInactiveRect;
     IntRect mInactiveRect;
-    //! Hovering image rectangle
-    IntRect mHoverRect;
     //! Pressed image rectangle
     //! Pressed image rectangle
     IntRect mPressedRect;
     IntRect mPressedRect;
     //! Label offset on press
     //! Label offset on press
     IntVector2 mLabelOffset;
     IntVector2 mLabelOffset;
     //! Current state
     //! Current state
     ButtonState mState;
     ButtonState mState;
-    //! Hovering flag
-    bool mHoveringThisFrame;
 };
 };
 
 
 #endif // UI_BUTTON_H
 #endif // UI_BUTTON_H

+ 0 - 3
Engine/UI/UI.h

@@ -119,7 +119,4 @@ private:
     unsigned mMouseButtons;
     unsigned mMouseButtons;
 };
 };
 
 
-//! Return UI instance
-UI* getUI();
-
 #endif // UI_UI_H
 #endif // UI_UI_H

+ 27 - 15
Engine/UI/UIBatch.cpp

@@ -66,12 +66,15 @@ void UIBatch::addQuad(UIElement& element, int x, int y, int width, int height, i
     }
     }
     else
     else
     {
     {
-        const Color& color = element.getColor(C_TOPLEFT);
-        unsigned finalColor = getD3DColor(Color(color.mR, color.mG, color.mB, element.getDerivedOpacity()));
-        quad.mTopLeftColor = finalColor;
-        quad.mTopRightColor = finalColor;
-        quad.mBottomLeftColor = finalColor;
-        quad.mBottomRightColor = finalColor;
+        Color color = element.getColor(C_TOPLEFT);
+        if (element.isHovering())
+            color += element.getHoverColor();
+        color.mA = element.getDerivedOpacity();
+        unsigned uintColor = getD3DColor(color);
+        quad.mTopLeftColor = uintColor;
+        quad.mTopRightColor = uintColor;
+        quad.mBottomLeftColor = uintColor;
+        quad.mBottomRightColor = uintColor;
     }
     }
     
     
     mQuads->push_back(quad);
     mQuads->push_back(quad);
@@ -104,12 +107,15 @@ void UIBatch::addQuad(UIElement& element, int x, int y, int width, int height, i
     }
     }
     else
     else
     {
     {
-        const Color& color = element.getColor(C_TOPLEFT);
-        unsigned finalColor = getD3DColor(Color(color.mR, color.mG, color.mB, element.getDerivedOpacity()));
-        quad.mTopLeftColor = finalColor;
-        quad.mTopRightColor = finalColor;
-        quad.mBottomLeftColor = finalColor;
-        quad.mBottomRightColor = finalColor;
+        Color color = element.getColor(C_TOPLEFT);
+        if (element.isHovering())
+            color += element.getHoverColor();
+        color.mA = element.getDerivedOpacity();
+        unsigned uintColor = getD3DColor(color);
+        quad.mTopLeftColor = uintColor;
+        quad.mTopRightColor = uintColor;
+        quad.mBottomLeftColor = uintColor;
+        quad.mBottomRightColor = uintColor;
     }
     }
     
     
     mQuads->push_back(quad);
     mQuads->push_back(quad);
@@ -256,11 +262,17 @@ unsigned UIBatch::getInterpolatedColor(UIElement& element, int x, int y)
         Color topColor = element.getColor(C_TOPLEFT).lerp(element.getColor(C_TOPRIGHT), cLerpX);
         Color topColor = element.getColor(C_TOPLEFT).lerp(element.getColor(C_TOPRIGHT), cLerpX);
         Color bottomColor = element.getColor(C_BOTTOMLEFT).lerp(element.getColor(C_BOTTOMRIGHT), cLerpX);
         Color bottomColor = element.getColor(C_BOTTOMLEFT).lerp(element.getColor(C_BOTTOMRIGHT), cLerpX);
         Color color = topColor.lerp(bottomColor, cLerpY);
         Color color = topColor.lerp(bottomColor, cLerpY);
-        return getD3DColor(Color(color.mR, color.mG, color.mB, element.getDerivedOpacity()));
+        if (element.isHovering())
+            color += element.getHoverColor();
+        color.mA = element.getDerivedOpacity();
+        return getD3DColor(color);
     }
     }
     else
     else
     {
     {
-        const Color& color = element.getColor(C_TOPLEFT);
-        return getD3DColor(Color(color.mR, color.mG, color.mB, element.getDerivedOpacity()));
+        Color color = element.getColor(C_TOPLEFT);
+        if (element.isHovering())
+            color += element.getHoverColor();
+        color.mA = element.getDerivedOpacity();
+        return getD3DColor(color);
     }
     }
 }
 }

+ 19 - 12
Engine/UI/UIElement.cpp

@@ -37,6 +37,7 @@ UIElement::UIElement(const std::string& name) :
     mSize(IntVector2::sZero),
     mSize(IntVector2::sZero),
     mHorizontalAlignment(HA_LEFT),
     mHorizontalAlignment(HA_LEFT),
     mVerticalAlignment(VA_TOP),
     mVerticalAlignment(VA_TOP),
+    mHoverColor(Color(0.0f, 0.0f, 0.0f)),
     mPriority(0),
     mPriority(0),
     mOpacity(1.0f),
     mOpacity(1.0f),
     mBringToFront(false),
     mBringToFront(false),
@@ -45,6 +46,7 @@ UIElement::UIElement(const std::string& name) :
     mFocusable(false),
     mFocusable(false),
     mFocus(false),
     mFocus(false),
     mVisible(true),
     mVisible(true),
+    mHovering(false),
     mScreenPositionDirty(true),
     mScreenPositionDirty(true),
     mDerivedOpacityDirty(true),
     mDerivedOpacityDirty(true),
     mHasColorGradient(false)
     mHasColorGradient(false)
@@ -135,6 +137,8 @@ XMLElement UIElement::loadParameters(XMLFile* file, const std::string& elementNa
         if (colorElem.hasAttribute("bottomright"))
         if (colorElem.hasAttribute("bottomright"))
             setColor(C_BOTTOMRIGHT, colorElem.getColor("bottomright"));
             setColor(C_BOTTOMRIGHT, colorElem.getColor("bottomright"));
     }
     }
+    if (paramElem.hasChildElement("hovercolor"))
+        setHoverColor(paramElem.getChildElement("hovercolor").getColor("value"));
     if (paramElem.hasChildElement("bringtofront"))
     if (paramElem.hasChildElement("bringtofront"))
         setBringToFront(paramElem.getChildElement("bringtofront").getBool("enable"));
         setBringToFront(paramElem.getChildElement("bringtofront").getBool("enable"));
     if (paramElem.hasChildElement("clipchildren"))
     if (paramElem.hasChildElement("clipchildren"))
@@ -155,6 +159,7 @@ void UIElement::update(float timeStep)
 
 
 void UIElement::getBatches(std::vector<UIBatch>& batches, std::vector<UIQuad>& quads, const IntRect& currentScissor)
 void UIElement::getBatches(std::vector<UIBatch>& batches, std::vector<UIQuad>& quads, const IntRect& currentScissor)
 {
 {
+    mHovering = false;
 }
 }
 
 
 IntVector2 UIElement::getScreenPosition()
 IntVector2 UIElement::getScreenPosition()
@@ -233,6 +238,7 @@ void UIElement::onChar(unsigned key)
 
 
 void UIElement::onHover(const IntVector2& position, const IntVector2& screenPosition, unsigned buttons)
 void UIElement::onHover(const IntVector2& position, const IntVector2& screenPosition, unsigned buttons)
 {
 {
+    mHovering = true;
 }
 }
 
 
 void UIElement::onClick(const IntVector2& position, const IntVector2& screenPosition, unsigned buttons)
 void UIElement::onClick(const IntVector2& position, const IntVector2& screenPosition, unsigned buttons)
@@ -258,8 +264,11 @@ void UIElement::setName(const std::string& name)
 
 
 void UIElement::setPosition(const IntVector2& position)
 void UIElement::setPosition(const IntVector2& position)
 {
 {
-    mPosition = position;
-    markDirty();
+    if (position != mPosition)
+    {
+        mPosition = position;
+        markDirty();
+    }
 }
 }
 
 
 void UIElement::setPosition(int x, int y)
 void UIElement::setPosition(int x, int y)
@@ -269,9 +278,12 @@ void UIElement::setPosition(int x, int y)
 
 
 void UIElement::setSize(const IntVector2& size)
 void UIElement::setSize(const IntVector2& size)
 {
 {
-    mSize.mX = max(size.mX, 0);
-    mSize.mY = max(size.mY, 0);
-    markDirty();
+    if (size != mSize)
+    {
+        mSize.mX = max(size.mX, 0);
+        mSize.mY = max(size.mY, 0);
+        markDirty();
+    }
 }
 }
 
 
 void UIElement::setSize(int width, int height)
 void UIElement::setSize(int width, int height)
@@ -315,11 +327,6 @@ void UIElement::setColor(const Color& color)
     mHasColorGradient = false;
     mHasColorGradient = false;
 }
 }
 
 
-void UIElement::setColor(float r, float g, float b)
-{
-    setColor(Color(r, g, b));
-}
-
 void UIElement::setColor(UIElementCorner corner, const Color& color)
 void UIElement::setColor(UIElementCorner corner, const Color& color)
 {
 {
     mColor[corner] = color;
     mColor[corner] = color;
@@ -332,9 +339,9 @@ void UIElement::setColor(UIElementCorner corner, const Color& color)
     }
     }
 }
 }
 
 
-void UIElement::setColor(UIElementCorner corner, float r, float g, float b)
+void UIElement::setHoverColor(const Color& color)
 {
 {
-    setColor(corner, Color(r, g, b));
+    mHoverColor = color;
 }
 }
 
 
 void UIElement::setPriority(int priority)
 void UIElement::setPriority(int priority)

+ 10 - 4
Engine/UI/UIElement.h

@@ -114,12 +114,10 @@ public:
     void setVerticalAlignment(VerticalAlignment align);
     void setVerticalAlignment(VerticalAlignment align);
     //! Set color on all corners
     //! Set color on all corners
     void setColor(const Color& color);
     void setColor(const Color& color);
-    //! Set color on all corners
-    void setColor(float r, float g, float b);
     //! Set color on one corner
     //! Set color on one corner
     void setColor(UIElementCorner corner, const Color& color);
     void setColor(UIElementCorner corner, const Color& color);
-    //! Set color on one corner
-    void setColor(UIElementCorner corner, float r, float g, float b);
+    //! Set hover color modification
+    void setHoverColor(const Color& color);
     //! Set priority
     //! Set priority
     void setPriority(int priority);
     void setPriority(int priority);
     //! Set opacity
     //! Set opacity
@@ -159,6 +157,8 @@ public:
     VerticalAlignment getVerticalAlignment() const { return mVerticalAlignment; }
     VerticalAlignment getVerticalAlignment() const { return mVerticalAlignment; }
     //! Return corner color
     //! Return corner color
     const Color& getColor(UIElementCorner corner) const { return mColor[corner]; }
     const Color& getColor(UIElementCorner corner) const { return mColor[corner]; }
+    //! Return hover color modification
+    const Color& getHoverColor() { return mHoverColor; }
     //! Return priority
     //! Return priority
     int getPriority() const { return mPriority; }
     int getPriority() const { return mPriority; }
     //! Return opacity
     //! Return opacity
@@ -175,6 +175,8 @@ public:
     bool hasFocus() const { return mFocus; }
     bool hasFocus() const { return mFocus; }
     //! Return whether is visible
     //! Return whether is visible
     bool isVisible() const { return mVisible; }
     bool isVisible() const { return mVisible; }
+    //! Return whether the cursor is hovering on this element
+    bool isHovering() const { return mHovering; }
     //! Return whether has different color in at least one corner
     //! Return whether has different color in at least one corner
     bool hasColorGradient() const { return mHasColorGradient; }
     bool hasColorGradient() const { return mHasColorGradient; }
     //! Return number of child elements
     //! Return number of child elements
@@ -208,6 +210,8 @@ protected:
     UIElement* mParent;
     UIElement* mParent;
     //! Colors
     //! Colors
     Color mColor[NUM_UIELEMENT_CORNERS];
     Color mColor[NUM_UIELEMENT_CORNERS];
+    //! Hover color modification
+    Color mHoverColor;
     //! Priority
     //! Priority
     int mPriority;
     int mPriority;
     //! Bring to front when focused flag
     //! Bring to front when focused flag
@@ -222,6 +226,8 @@ protected:
     bool mFocus;
     bool mFocus;
     //! Visible flag
     //! Visible flag
     bool mVisible;
     bool mVisible;
+    //! Hovering flag
+    bool mHovering;
     
     
 private:
 private:
     //! Return child elements recursively
     //! Return child elements recursively

+ 13 - 1
Examples/Test/Application.cpp

@@ -205,6 +205,15 @@ void Application::init()
     cursor->setPosition(renderer->getWidth() / 2, renderer->getHeight() / 2);
     cursor->setPosition(renderer->getWidth() / 2, renderer->getHeight() / 2);
     ui->setCursor(cursor);
     ui->setCursor(cursor);
     
     
+    //Button* button = new Button("Testbutton");
+    //button->loadParameters(uiSetup, "Button", mCache);
+    //Text* text = new Text("TEST");
+    //text->setFont(mCache->getResource<Font>("cour.ttf"), 12);
+    //button->setLabel(text);
+    //button->setAlignment(HA_CENTER, VA_CENTER);
+    //button->setSize(100, 40);
+    //uiRoot->addChild(button);
+    
     mScene = mEngine->createScene();
     mScene = mEngine->createScene();
     PhysicsWorld* world = mScene->getExtension<PhysicsWorld>();
     PhysicsWorld* world = mScene->getExtension<PhysicsWorld>();
     world->setGravity(Vector3(0.0f, -9.81f, 0.0f));
     world->setGravity(Vector3(0.0f, -9.81f, 0.0f));
@@ -792,7 +801,10 @@ void Application::handleMouseButtonDown(StringHash eventType, VariantMap& eventD
         if (cursor)
         if (cursor)
             cursor->setVisible(false);
             cursor->setVisible(false);
     }
     }
-    if (button == MOUSEB_LEFT)
+    
+    UI* ui = mEngine->getUI();
+    
+    if ((button == MOUSEB_LEFT) && (!ui->getElementAt(ui->getCursorPosition())))
     {
     {
         // Test creating a new physics object
         // Test creating a new physics object
         if (mCameraEntity)
         if (mCameraEntity)