Browse Source

Added dynamic cursor definitions while keeping the original enum definitions for backwards compatibility, ui subsystems and sdl. Revised the serialization system for cursors as well which is a breaking change and requires wrapping each old style cursor definition in a <variant type="VariantVector></variant>.

Alex Parlett 11 years ago
parent
commit
cd099df50f

+ 48 - 33
Bin/Data/UI/DefaultStyle.xml

@@ -26,39 +26,54 @@
     </element>
     <element type="Cursor">
         <attribute name="Shapes">
-            <variant type="Int" value="8" />
-            <variant type="String" value="Normal" />
-            <variant type="ResourceRef" value="Image;Textures/UI.png" />
-            <variant type="IntRect" value="0 0 12 24" />
-            <variant type="IntVector2" value="0 0" />
-            <variant type="String" value="ResizeVertical" />
-            <variant type="ResourceRef" value="Image;Textures/UI.png" />
-            <variant type="IntRect" value="0 64 20 84" />
-            <variant type="IntVector2" value="9 9" />
-            <variant type="String" value="ResizeDiagonalTopRight" />
-            <variant type="ResourceRef" value="Image;Textures/UI.png" />
-            <variant type="IntRect" value="20 64 40 84" />
-            <variant type="IntVector2" value="9 9" />
-            <variant type="String" value="ResizeHorizontal" />
-            <variant type="ResourceRef" value="Image;Textures/UI.png" />
-            <variant type="IntRect" value="40 64 60 84" />
-            <variant type="IntVector2" value="9 9" />
-            <variant type="String" value="ResizeDiagonalTopLeft" />
-            <variant type="ResourceRef" value="Image;Textures/UI.png" />
-            <variant type="IntRect" value="60 64 80 84" />
-            <variant type="IntVector2" value="9 9" />
-            <variant type="String" value="RejectDrop" />
-            <variant type="ResourceRef" value="Image;Textures/UI.png" />
-            <variant type="IntRect" value="80 64 100 84" />
-            <variant type="IntVector2" value="9 9" />
-            <variant type="String" value="AcceptDrop" />
-            <variant type="ResourceRef" value="Image;Textures/UI.png" />
-            <variant type="IntRect" value="100 64 128 90" />
-            <variant type="IntVector2" value="0 0" />
-            <variant type="String" value="Busy" />
-            <variant type="ResourceRef" value="Image;Textures/UI.png" />
-            <variant type="IntRect" value="128 64 148 85" />
-            <variant type="IntVector2" value="9 9" />
+            <variant type="VariantVector" >
+                <variant type="String" value="Normal" />
+                <variant type="ResourceRef" value="Image;Textures/UI.png" />
+                <variant type="IntRect" value="0 0 12 24" />
+                <variant type="IntVector2" value="0 0" />
+            </variant>           
+            <variant type="VariantVector" >
+                <variant type="String" value="ResizeVertical" />
+                <variant type="ResourceRef" value="Image;Textures/UI.png" />
+                <variant type="IntRect" value="0 64 20 84" />
+                <variant type="IntVector2" value="9 9" />
+            </variant>
+            <variant type="VariantVector" >     
+                <variant type="String" value="ResizeDiagonalTopRight" />
+                <variant type="ResourceRef" value="Image;Textures/UI.png" />
+                <variant type="IntRect" value="20 64 40 84" />
+                <variant type="IntVector2" value="9 9" />
+            </variant>
+            <variant type="VariantVector" >
+                <variant type="String" value="ResizeHorizontal" />
+                <variant type="ResourceRef" value="Image;Textures/UI.png" />
+                <variant type="IntRect" value="40 64 60 84" />
+                <variant type="IntVector2" value="9 9" />
+            </variant>
+            <variant type="VariantVector" >             
+                <variant type="String" value="ResizeDiagonalTopLeft" />
+                <variant type="ResourceRef" value="Image;Textures/UI.png" />
+                <variant type="IntRect" value="60 64 80 84" />
+                <variant type="IntVector2" value="9 9" />
+            </variant>
+            <variant type="VariantVector" >        
+                <variant type="String" value="RejectDrop" />
+                <variant type="ResourceRef" value="Image;Textures/UI.png" />
+                <variant type="IntRect" value="80 64 100 84" />
+                <variant type="IntVector2" value="9 9" />
+            </variant>
+            <variant type="VariantVector" >         
+                <variant type="String" value="AcceptDrop" />
+                <variant type="ResourceRef" value="Image;Textures/UI.png" />
+                <variant type="IntRect" value="100 64 128 90" />
+                <variant type="IntVector2" value="0 0" />
+            </variant>
+            <variant type="VariantVector" >
+                <variant type="String" value="Busy" />
+                <variant type="ResourceRef" value="Image;Textures/UI.png" />
+                <variant type="IntRect" value="128 64 148 85" />
+                <variant type="IntVector2" value="9 9" />
+            </variant>              
         </attribute>
     </element>
     <element type="DropDownList" style="BorderImage">

+ 1 - 1
Source/Engine/Audio/SoundSource.cpp

@@ -478,7 +478,7 @@ int SoundSource::GetPositionAttr() const
 
 SoundType SoundSource::GetSoundTypeAttr() const
 {
-    for (int i; i < MAX_SOUND_TYPES; i++)
+    for (int i = 0; i < MAX_SOUND_TYPES; i++)
     {
         if (soundType_ == soundTypeHashes[i])
             return static_cast<SoundType>(i);

+ 9 - 3
Source/Engine/LuaScript/pkgs/UI/Cursor.pkg

@@ -3,13 +3,17 @@ $#include "Cursor.h"
 enum CursorShape
 {
     CS_NORMAL = 0,
+    CS_IBEAM,
+    CS_CROSS,
     CS_RESIZEVERTICAL,
     CS_RESIZEDIAGONAL_TOPRIGHT,
     CS_RESIZEHORIZONTAL,
     CS_RESIZEDIAGONAL_TOPLEFT,
+    CS_RESIZE_ALL,
     CS_ACCEPTDROP,
     CS_REJECTDROP,
     CS_BUSY,
+    CS_BUSY_ARROW,
     CS_MAX_SHAPES
 };
 
@@ -17,15 +21,17 @@ class Cursor : public BorderImage
 {
     Cursor();
     virtual ~Cursor();
-    
+
+    void DefineShape(const String& shape, Image* image, const IntRect& imageRect, const IntVector2& hotSpot);
     void DefineShape(CursorShape shape, Image* image, const IntRect& imageRect, const IntVector2& hotSpot);
     
     void SetShape(CursorShape shape);
+    void SetShape(const StringHash& shape);
     void SetUseSystemShapes(bool enable);
-    CursorShape GetShape() const;
+    StringHash GetShape() const;
     bool GetUseSystemShapes() const;
 
-    tolua_property__get_set CursorShape shape;
+    tolua_property__get_set StringHash shape;
     tolua_property__get_set bool useSystemShapes;
 };
 

+ 10 - 3
Source/Engine/Script/UIAPI.cpp

@@ -154,18 +154,25 @@ static void RegisterCursor(asIScriptEngine* engine)
 {
     engine->RegisterEnum("CursorShape");
     engine->RegisterEnumValue("CursorShape", "CS_NORMAL", CS_NORMAL);
+    engine->RegisterEnumValue("CursorShape", "CS_IBEAM", CS_IBEAM);
+    engine->RegisterEnumValue("CursorShape", "CS_CROSS", CS_CROSS);
     engine->RegisterEnumValue("CursorShape", "CS_RESIZEVERTICAL", CS_RESIZEVERTICAL);
     engine->RegisterEnumValue("CursorShape", "CS_RESIZEDIAGONAL_TOPRIGHT", CS_RESIZEDIAGONAL_TOPRIGHT);
     engine->RegisterEnumValue("CursorShape", "CS_RESIZEHORIZONTAL", CS_RESIZEHORIZONTAL);
     engine->RegisterEnumValue("CursorShape", "CS_RESIZEDIAGONAL_TOPLEFT", CS_RESIZEDIAGONAL_TOPLEFT);
+    engine->RegisterEnumValue("CursorShape", "CS_RESIZE_ALL", CS_RESIZE_ALL);
     engine->RegisterEnumValue("CursorShape", "CS_ACCEPTDROP", CS_ACCEPTDROP);
     engine->RegisterEnumValue("CursorShape", "CS_REJECTDROP", CS_REJECTDROP);
     engine->RegisterEnumValue("CursorShape", "CS_BUSY", CS_BUSY);
+    engine->RegisterEnumValue("CursorShape", "CS_BUSY_ARROW", CS_BUSY_ARROW);
 
     RegisterBorderImage<Cursor>(engine, "Cursor");
-    engine->RegisterObjectMethod("Cursor", "void DefineShape(CursorShape, Texture@+, const IntRect&in, const IntVector2&in)", asMETHOD(Cursor, DefineShape), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Cursor", "void set_shape(CursorShape)", asMETHOD(Cursor, SetShape), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Cursor", "CursorShape get_shape() const", asMETHOD(Cursor, GetShape), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Cursor", "void DefineShape(const String&in, Texture@+, const IntRect&in, const IntVector2&in)", asMETHODPR(Cursor, DefineShape, (CursorShape, Image*, const IntRect&, const IntVector2&), void), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Cursor", "void DefineShape(CursorShape, Texture@+, const IntRect&in, const IntVector2&in)", asMETHODPR(Cursor, DefineShape, (const String&, Image*, const IntRect&, const IntVector2&), void), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Cursor", "void SetShape(const StringHash&in)", asMETHODPR(Cursor, SetShape, (const StringHash&), void), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Cursor", "void SetShape(CursorShape)", asMETHODPR(Cursor, SetShape, (CursorShape), void), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Cursor", "void set_shape(const StringHash&in)", asMETHODPR(Cursor, SetShape, (const StringHash&), void), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Cursor", "StringHash get_shape() const", asMETHOD(Cursor, GetShape), asCALL_THISCALL);
     engine->RegisterObjectMethod("Cursor", "void set_useSystemShapes(bool)", asMETHOD(Cursor, SetUseSystemShapes), asCALL_THISCALL);
     engine->RegisterObjectMethod("Cursor", "bool get_useSystemShapes() const", asMETHOD(Cursor, GetUseSystemShapes), asCALL_THISCALL);
 }

+ 80 - 41
Source/Engine/UI/Cursor.cpp

@@ -39,50 +39,77 @@ namespace Urho3D
 static const char* shapeNames[] =
 {
     "Normal",
+    "IBeam",
+    "Cross",
     "ResizeVertical",
     "ResizeDiagonalTopRight",
     "ResizeHorizontal",
     "ResizeDiagonalTopLeft",
+    "ResizeAll",
     "AcceptDrop",
     "RejectDrop",
     "Busy",
-    0
+    "BusyArrow"
+};
+
+static const StringHash shapeHashes[] =
+{
+    "Normal",
+    "IBeam",
+    "Cross",
+    "ResizeVertical",
+    "ResizeDiagonalTopRight",
+    "ResizeHorizontal",
+    "ResizeDiagonalTopLeft",
+    "ResizeAll",
+    "AcceptDrop",
+    "RejectDrop",
+    "Busy",
+    "BusyArrow"
 };
 
 /// OS cursor shape lookup table matching cursor shape enumeration
 static const int osCursorLookup[CS_MAX_SHAPES] =
 {
     SDL_SYSTEM_CURSOR_ARROW,    // CS_NORMAL
+    SDL_SYSTEM_CURSOR_IBEAM,     // CS_IBEAM
+    SDL_SYSTEM_CURSOR_CROSSHAIR, // CS_CROSS
     SDL_SYSTEM_CURSOR_SIZENS,   // CS_RESIZEVERTICAL
     SDL_SYSTEM_CURSOR_SIZENESW, // CS_RESIZEDIAGONAL_TOPRIGHT
     SDL_SYSTEM_CURSOR_SIZEWE,   // CS_RESIZEHORIZONTAL
     SDL_SYSTEM_CURSOR_SIZENWSE, // CS_RESIZEDIAGONAL_TOPLEFT
+    SDL_SYSTEM_CURSOR_SIZEALL,   // CS_RESIZE_ALL
     SDL_SYSTEM_CURSOR_HAND,     // CS_ACCEPTDROP
     SDL_SYSTEM_CURSOR_NO,       // CS_REJECTDROP
-    SDL_SYSTEM_CURSOR_WAIT      // CS_BUSY
+    SDL_SYSTEM_CURSOR_WAIT,   // CS_BUSY
+    SDL_SYSTEM_CURSOR_WAITARROW // CS_BUSY_ARROW
 };
 
 extern const char* UI_CATEGORY;
 
 Cursor::Cursor(Context* context) :
     BorderImage(context),
-    shape_(CS_NORMAL),
+    shape_(shapeHashes[CS_NORMAL]),
     useSystemShapes_(false),
     osShapeDirty_(false)
 {
+    // Define the defaults for system cursor usage.
+    for (unsigned i = 0; i < CS_MAX_SHAPES; i++)
+        shapeInfos_[shapeHashes[i]] = CursorShapeInfo(shapeNames[i], i);
+
     // Subscribe to OS mouse cursor visibility changes to be able to reapply the cursor shape
     SubscribeToEvent(E_MOUSEVISIBLECHANGED, HANDLER(Cursor, HandleMouseVisibleChanged));
 }
 
 Cursor::~Cursor()
 {
-    for (unsigned i = 0; i < CS_MAX_SHAPES; ++i)
+    HashMap<StringHash, CursorShapeInfo>::Iterator iter = shapeInfos_.Begin();
+    for (iter; iter != shapeInfos_.End(); iter++)
     {
-        CursorShapeInfo& info = shapeInfos_[i];
-        if (info.osCursor_)
+        if (iter->second_.osCursor_)
         {
-            SDL_FreeCursor(info.osCursor_);
-            info.osCursor_ = 0;
+            SDL_FreeCursor(iter->second_.osCursor_);
+            iter->second_.osCursor_ = 0;
         }
     }
 }
@@ -119,10 +146,19 @@ void Cursor::DefineShape(CursorShape shape, Image* image, const IntRect& imageRe
         return;
     }
 
+    DefineShape(shapeNames[shape], image, imageRect, hotSpot);
+}
+
+void Cursor::DefineShape(const String& shape, Image* image, const IntRect& imageRect, const IntVector2& hotSpot)
+{
     if (!image)
         return;
 
     ResourceCache* cache = GetSubsystem<ResourceCache>();
+    
+    if (!shapeInfos_.Contains(shape))
+        shapeInfos_[shape] = CursorShapeInfo(shape);
+
     CursorShapeInfo& info = shapeInfos_[shape];
 
     // Prefer to get the texture with same name from cache to prevent creating several copies of the texture
@@ -146,16 +182,17 @@ void Cursor::DefineShape(CursorShape shape, Image* image, const IntRect& imageRe
     }
 
     // Reset current shape if it was edited
-    if (shape == shape_)
+    if (shape_ == shape)
     {
-        shape_ = CS_MAX_SHAPES;
+        shape_ = StringHash::ZERO;
         SetShape(shape);
     }
 }
 
-void Cursor::SetShape(CursorShape shape)
+
+void Cursor::SetShape(const StringHash& shape)
 {
-    if (shape_ == shape || shape < CS_NORMAL || shape >= CS_MAX_SHAPES)
+    if (shape_ == shape || !shapeInfos_.Contains(shape))
         return;
 
     shape_ = shape;
@@ -168,10 +205,18 @@ void Cursor::SetShape(CursorShape shape)
     // To avoid flicker, the UI subsystem will apply the OS shape once per frame. Exception: if we are using the
     // busy shape, set it immediately as we may block before that
     osShapeDirty_ = true;
-    if (shape_ == CS_BUSY)
+    if (shape_ == shapeHashes[CS_BUSY])
         ApplyOSCursorShape();
 }
 
+void Cursor::SetShape(CursorShape shape)
+{
+    if (shape_ == shapeHashes[shape] || shape < CS_NORMAL || shape >= CS_MAX_SHAPES)
+        return;
+
+    SetShape(shapeHashes[shape]);
+}
+
 void Cursor::SetUseSystemShapes(bool enable)
 {
     if (enable != useSystemShapes_)
@@ -188,19 +233,17 @@ void Cursor::SetShapesAttr(const VariantVector& value)
     if (!value.Size())
         return;
 
-    unsigned numShapes = value[index++].GetUInt();
-    while (numShapes-- && (index + 4) <= value.Size())
+    VariantVector::ConstIterator iter = value.Begin();
+    for (iter; iter != value.End(); iter++)
     {
-        CursorShape shape = (CursorShape)GetStringListIndex(value[index++].GetString().CString(), shapeNames, CS_MAX_SHAPES);
-        if (shape != CS_MAX_SHAPES)
-        {
-            ResourceRef ref = value[index++].GetResourceRef();
-            IntRect imageRect = value[index++].GetIntRect();
-            IntVector2 hotSpot = value[index++].GetIntVector2();
-            DefineShape(shape, GetSubsystem<ResourceCache>()->GetResource<Image>(ref.name_), imageRect, hotSpot);
-        }
-        else
-            index += 3;
+        VariantVector shapeVector = iter->GetVariantVector();
+
+        String shape = shapeVector[0].GetString();
+        ResourceRef ref = shapeVector[1].GetResourceRef();
+        IntRect imageRect = shapeVector[2].GetIntRect();
+        IntVector2 hotSpot = shapeVector[3].GetIntVector2();
+
+        DefineShape(shape, GetSubsystem<ResourceCache>()->GetResource<Image>(ref.name_), imageRect, hotSpot);
     }
 }
 
@@ -208,22 +251,18 @@ VariantVector Cursor::GetShapesAttr() const
 {
     VariantVector ret;
 
-    unsigned numShapes = 0;
-    for (unsigned i = 0; i < CS_MAX_SHAPES; ++i)
-    {
-        if (shapeInfos_[i].imageRect_ != IntRect::ZERO)
-            ++numShapes;
-    }
-
-    ret.Push(numShapes);
-    for (unsigned i = 0; i < CS_MAX_SHAPES; ++i)
+    HashMap<StringHash, CursorShapeInfo>::ConstIterator iter = shapeInfos_.Begin();
+    for (iter; iter != shapeInfos_.End(); iter++)
     {
-        if (shapeInfos_[i].imageRect_ != IntRect::ZERO)
+        if (iter->second_.imageRect_ != IntRect::ZERO)
         {
-            ret.Push(String(shapeNames[i]));
-            ret.Push(GetResourceRef(shapeInfos_[i].texture_, Texture2D::GetTypeStatic()));
-            ret.Push(shapeInfos_[i].imageRect_);
-            ret.Push(shapeInfos_[i].hotSpot_);
+            // Could use a map but this simplifies the UI xml.
+            VariantVector shape;
+            shape.Push(iter->second_.name_);
+            shape.Push(GetResourceRef(iter->second_.texture_, Texture2D::GetTypeStatic()));
+            shape.Push(iter->second_.imageRect_);
+            shape.Push(iter->second_.hotSpot_);
+            ret.Push(shape);
         }
     }
 
@@ -250,9 +289,9 @@ void Cursor::ApplyOSCursorShape()
     if (!info.osCursor_)
     {
         // Create a system default shape
-        if (useSystemShapes_)
+        if (useSystemShapes_ && info.systemCursor_ >= 0 && info.systemCursor_ < CS_MAX_SHAPES)
         {
-            info.osCursor_ = SDL_CreateSystemCursor((SDL_SystemCursor)osCursorLookup[shape_]);
+            info.osCursor_ = SDL_CreateSystemCursor((SDL_SystemCursor)osCursorLookup[info.systemCursor_]);
             info.systemDefined_ = true;
             if (!info.osCursor_)
                 LOGERROR("Could not create system cursor");

+ 40 - 4
Source/Engine/UI/Cursor.h

@@ -35,13 +35,17 @@ namespace Urho3D
 enum CursorShape
 {
     CS_NORMAL = 0,
+    CS_IBEAM,
+    CS_CROSS,
     CS_RESIZEVERTICAL,
     CS_RESIZEDIAGONAL_TOPRIGHT,
     CS_RESIZEHORIZONTAL,
     CS_RESIZEDIAGONAL_TOPLEFT,
+    CS_RESIZE_ALL,
     CS_ACCEPTDROP,
     CS_REJECTDROP,
     CS_BUSY,
+    CS_BUSY_ARROW,
     CS_MAX_SHAPES
 };
 
@@ -50,13 +54,39 @@ struct URHO3D_API CursorShapeInfo
 {
     /// Construct with defaults.
     CursorShapeInfo() :
+    name_(String::EMPTY),
         imageRect_(IntRect::ZERO),
         hotSpot_(IntVector2::ZERO),
         osCursor_(0),
-        systemDefined_(false)
+        systemDefined_(false),
+        systemCursor_(-1)
     {
     }
 
+    /// Construct with name.
+    CursorShapeInfo(const String& name) :
+        name_(name),
+        imageRect_(IntRect::ZERO),
+        hotSpot_(IntVector2::ZERO),
+        osCursor_(0),
+        systemDefined_(false),
+        systemCursor_(-1)
+    {
+    }
+
+    /// Construct with name.
+    CursorShapeInfo(const String& name, int systemCursor) :
+        name_(name),
+        imageRect_(IntRect::ZERO),
+        hotSpot_(IntVector2::ZERO),
+        osCursor_(0),
+        systemDefined_(false),
+        systemCursor_(systemCursor)
+    {
+    }
+
+    /// Name.
+    String name_;
     /// Image.
     SharedPtr<Image> image_;
     /// Texture.
@@ -65,6 +95,8 @@ struct URHO3D_API CursorShapeInfo
     IntRect imageRect_;
     /// Hotspot coordinates.
     IntVector2 hotSpot_;
+    /// System cursor index.
+    int systemCursor_;
     /// OS cursor.
     SDL_Cursor* osCursor_;
     /// Whether the OS cursor is system defined.
@@ -87,14 +119,18 @@ public:
     /// Return UI rendering batches.
     virtual void GetBatches(PODVector<UIBatch>& batches, PODVector<float>& vertexData, const IntRect& currentScissor);
 
+    /// Define a shape.
+    void DefineShape(const String& shape, Image* image, const IntRect& imageRect, const IntVector2& hotSpot);
     /// Define a shape.
     void DefineShape(CursorShape shape, Image* image, const IntRect& imageRect, const IntVector2& hotSpot);
     /// Set current shape.
+    void SetShape(const StringHash& shape);
+    /// Set current shape.
     void SetShape(CursorShape shape);
     /// Set whether to use system default shapes. Is only possible when the OS mouse cursor has been set visible from the Input subsystem.
     void SetUseSystemShapes(bool enable);
     /// Get current shape.
-    CursorShape GetShape() const { return shape_; }
+    StringHash GetShape() const { return shape_; }
     /// Return whether is using system default shapes.
     bool GetUseSystemShapes() const { return useSystemShapes_; }
 
@@ -110,9 +146,9 @@ protected:
     void HandleMouseVisibleChanged(StringHash eventType, VariantMap& eventData);
 
     /// Current shape index.
-    CursorShape shape_;
+    StringHash shape_;
     /// Shape definitions.
-    CursorShapeInfo shapeInfos_[CS_MAX_SHAPES];
+    HashMap<StringHash, CursorShapeInfo> shapeInfos_;
     /// Use system default shapes flag.
     bool useSystemShapes_;
     /// OS cursor shape needs update flag.