Explorar el Código

Refactored the system cursor shape definition inside Cursor class; use SetUseSystemShapes() to enable.
Define OS cursors on demand when setting the shape; removed OS cursor visible parameter from Cursor::DefineShape().

Lasse Öörni hace 12 años
padre
commit
adf668b386

+ 2 - 2
Docs/ScriptAPI.dox

@@ -4047,7 +4047,7 @@ Methods:<br>
 - bool IsInsideCombined(IntVector2, bool)
 - void SetFullImageRect()
 - void SetHoverOffset(int, int)
-- void DefineShape(CursorShape, Texture@, const IntRect&, const IntVector2&, bool arg4 = false)
+- void DefineShape(CursorShape, Texture@, const IntRect&, const IntVector2&)
 
 Properties:<br>
 - int refs (readonly)
@@ -4121,6 +4121,7 @@ Properties:<br>
 - BlendMode blendMode
 - bool tiled
 - CursorShape shape
+- bool useSystemShapes
 
 
 Slider
@@ -5522,7 +5523,6 @@ Properties:<br>
 - String category (readonly)
 - Cursor@ cursor
 - IntVector2 cursorPosition (readonly)
-- CursorShape cursorShape (writeonly)
 - UIElement@ focusElement
 - UIElement@ frontElement (readonly)
 - UIElement@ root (readonly)

+ 6 - 0
Engine/Input/Input.cpp

@@ -196,6 +196,12 @@ void Input::SetMouseVisible(bool enable)
             else
                 SDL_ShowCursor(SDL_TRUE);
         }
+        
+        using namespace MouseVisibleChanged;
+        
+        VariantMap eventData;
+        eventData[P_VISIBLE] = mouseVisible_;
+        SendEvent(E_MOUSEVISIBLECHANGED, eventData);
     }
 }
 

+ 6 - 0
Engine/Input/InputEvents.h

@@ -155,6 +155,12 @@ EVENT(E_INPUTFOCUS, InputFocus)
     PARAM(P_MINIMIZED, Minimized);          // bool
 }
 
+/// OS mouse cursor visibility changed.
+EVENT(E_MOUSEVISIBLECHANGED, MouseVisibleChanged)
+{
+    PARAM(P_VISIBLE, Visible);              // bool
+}
+
 /// Application exit requested.
 EVENT(E_EXITREQUESTED, ExitRequested)
 {

+ 3 - 2
Engine/Script/UIAPI.cpp

@@ -146,9 +146,11 @@ static void RegisterCursor(asIScriptEngine* engine)
     engine->RegisterEnumValue("CursorShape", "CS_BUSY", CS_BUSY);
 
     RegisterBorderImage<Cursor>(engine, "Cursor");
-    engine->RegisterObjectMethod("Cursor", "void DefineShape(CursorShape, Texture@+, const IntRect&in, const IntVector2&in, bool arg4 = false)", asMETHOD(Cursor, DefineShape), asCALL_THISCALL);
+    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 set_useSystemShapes(bool)", asMETHOD(Cursor, SetUseSystemShapes), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Cursor", "bool get_useSystemShapes() const", asMETHOD(Cursor, GetUseSystemShapes), asCALL_THISCALL);
 }
 
 static void RegisterButton(asIScriptEngine* engine)
@@ -574,7 +576,6 @@ static void RegisterUI(asIScriptEngine* engine)
     engine->RegisterObjectMethod("UI", "void set_cursor(Cursor@+)", asMETHOD(UI, SetCursor), asCALL_THISCALL);
     engine->RegisterObjectMethod("UI", "Cursor@+ get_cursor() const", asMETHOD(UI, GetCursor), asCALL_THISCALL);
     engine->RegisterObjectMethod("UI", "IntVector2 get_cursorPosition() const", asMETHOD(UI, GetCursorPosition), asCALL_THISCALL);
-    engine->RegisterObjectMethod("UI", "void set_cursorShape(CursorShape)", asMETHOD(UI, SetCursorShape), asCALL_THISCALL);
     engine->RegisterObjectMethod("UI", "void set_focusElement(UIElement@+)", asMETHOD(UI, SetFocusElement), asCALL_THISCALL);
     engine->RegisterObjectMethod("UI", "UIElement@+ get_focusElement() const", asMETHOD(UI, GetFocusElement), asCALL_THISCALL);
     engine->RegisterObjectMethod("UI", "UIElement@+ get_frontElement() const", asMETHOD(UI, GetFrontElement), asCALL_THISCALL);

+ 121 - 56
Engine/UI/Cursor.cpp

@@ -24,10 +24,13 @@
 #include "Context.h"
 #include "Cursor.h"
 #include "Input.h"
+#include "InputEvents.h"
+#include "Log.h"
 #include "Ptr.h"
 #include "ResourceCache.h"
 #include "StringUtils.h"
 #include "Texture2D.h"
+#include "UI.h"
 
 #include "DebugNew.h"
 
@@ -47,22 +50,31 @@ static const char* shapeNames[] =
     0
 };
 
+/// 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_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_HAND,     // CS_ACCEPTDROP
+    SDL_SYSTEM_CURSOR_NO,       // CS_REJECTDROP
+    SDL_SYSTEM_CURSOR_WAIT      // CS_BUSY
+};
+
 extern const char* UI_CATEGORY;
 
 Cursor::Cursor(Context* context) :
     BorderImage(context),
-    shape_(CS_NORMAL)
+    shape_(CS_NORMAL),
+    useSystemShapes_(false)
 {
     // Show on top of all other UI elements
     priority_ = M_MAX_INT;
-
-    for (unsigned i = 0; i < CS_MAX_SHAPES; ++i)
-    {
-        CursorShapeInfo& info = shapeInfos_[i];
-        info.imageRect_ = IntRect::ZERO;
-        info.hotSpot_ = IntVector2::ZERO;
-        info.osCursor_ = 0;
-    }
+    
+    // Subscribe to OS mouse cursor visibility changes to be able to reapply the cursor shape
+    SubscribeToEvent(E_MOUSEVISIBLECHANGED, HANDLER(Cursor, HandleMouseVisibleChanged));
 }
 
 Cursor::~Cursor()
@@ -84,11 +96,29 @@ void Cursor::RegisterObject(Context* context)
 
     COPY_BASE_ATTRIBUTES(Cursor, BorderImage);
     UPDATE_ATTRIBUTE_DEFAULT_VALUE(Cursor, "Priority", M_MAX_INT);
+    ACCESSOR_ATTRIBUTE(Cursor, VAR_BOOL, "Use System Shapes", GetUseSystemShapes, SetUseSystemShapes, bool, false, AM_FILE);
     ACCESSOR_ATTRIBUTE(Cursor, VAR_VARIANTVECTOR, "Shapes", GetShapesAttr, SetShapesAttr, VariantVector, Variant::emptyVariantVector, AM_FILE);
 }
 
-void Cursor::DefineShape(CursorShape shape, Image* image, const IntRect& imageRect, const IntVector2& hotSpot, bool osMouseVisible)
+void Cursor::SetUseSystemShapes(bool enable)
+{
+    if (enable != useSystemShapes_)
+    {
+        useSystemShapes_ = enable;
+        
+        // Reapply current shape
+        ApplyShape();
+    }
+}
+
+void Cursor::DefineShape(CursorShape shape, Image* image, const IntRect& imageRect, const IntVector2& hotSpot)
 {
+    if (shape < CS_NORMAL || shape >= CS_MAX_SHAPES)
+    {
+        LOGERROR("Shape index out of bounds, can not define cursor shape");
+        return;
+    }
+    
     if (!image)
         return;
     
@@ -105,65 +135,29 @@ void Cursor::DefineShape(CursorShape shape, Image* image, const IntRect& imageRe
         info.texture_ = texture;
     }
     
+    info.image_ = image;
     info.imageRect_ = imageRect;
     info.hotSpot_ = hotSpot;
+    
+    // Remove existing SDL cursor
     if (info.osCursor_)
     {
         SDL_FreeCursor(info.osCursor_);
         info.osCursor_ = 0;
     }
 
-    if (osMouseVisible)
-    {
-        unsigned comp = image->GetComponents();
-        int imageWidth = image->GetWidth();
-        int width = imageRect.Width();
-        int height = imageRect.Height();
-
-        // Assume little-endian for all the supported platforms
-        unsigned rMask = 0x000000ff;
-        unsigned gMask = 0x0000ff00;
-        unsigned bMask = 0x00ff0000;
-        unsigned aMask = 0xff000000;
-
-        SDL_Surface* surface = (comp >= 3 ? SDL_CreateRGBSurface(0, width, height, comp * 8, rMask, gMask, bMask, aMask) : 0);
-        if (surface)
-        {
-            unsigned char* destination = reinterpret_cast<unsigned char*>(surface->pixels);
-            unsigned char* source = image->GetData() + comp * (imageWidth * imageRect.top_ + imageRect.left_);
-            for (int i = 0; i < height; ++i)
-            {
-                memcpy(destination, source, comp * width);
-                destination += comp * width;
-                source += comp * imageWidth;
-            }
-            info.osCursor_ = SDL_CreateColorCursor(surface, info.hotSpot_.x_, info.hotSpot_.y_);
-            SDL_FreeSurface(surface);
-        }
-    }
-
     // Reset current shape if it was edited
     if (shape == shape_)
-    {
-        shape_ = CS_MAX_SHAPES;
-        SetShape(shape);
-    }
+        ApplyShape();
 }
 
 void Cursor::SetShape(CursorShape shape)
 {
-    if (shape == shape_ || shape < CS_NORMAL || shape >= CS_MAX_SHAPES)
+    if (shape_ == shape || shape < CS_NORMAL || shape >= CS_MAX_SHAPES)
         return;
 
     shape_ = shape;
-
-    CursorShapeInfo& info = shapeInfos_[shape_];
-    texture_ = info.texture_;
-    imageRect_ = info.imageRect_;
-    SetSize(info.imageRect_.Size());
-
-    if (info.osCursor_)
-        SDL_SetCursor(info.osCursor_);
+    ApplyShape();
 }
 
 void Cursor::SetShapesAttr(VariantVector value)
@@ -172,9 +166,6 @@ void Cursor::SetShapesAttr(VariantVector value)
     if (!value.Size())
         return;
 
-    Input* input = GetSubsystem<Input>();
-    bool osMouseVisible = input->IsMouseVisible();
-
     unsigned numShapes = value[index++].GetUInt();
     while (numShapes-- && (index + 4) <= value.Size())
     {
@@ -184,7 +175,7 @@ void Cursor::SetShapesAttr(VariantVector value)
             ResourceRef ref = value[index++].GetResourceRef();
             IntRect imageRect = value[index++].GetIntRect();
             IntVector2 hotSpot = value[index++].GetIntVector2();
-            DefineShape(shape, GetSubsystem<ResourceCache>()->GetResource<Image>(ref.id_), imageRect, hotSpot, osMouseVisible);
+            DefineShape(shape, GetSubsystem<ResourceCache>()->GetResource<Image>(ref.id_), imageRect, hotSpot);
         }
         else
             index += 3;
@@ -231,4 +222,78 @@ void Cursor::GetBatches(PODVector<UIBatch>& batches, PODVector<float>& vertexDat
     }
 }
 
+void Cursor::ApplyShape()
+{
+    CursorShapeInfo& info = shapeInfos_[shape_];
+    texture_ = info.texture_;
+    imageRect_ = info.imageRect_;
+    SetSize(info.imageRect_.Size());
+
+    // If the OS cursor is being shown, define/set SDL cursor shape if necessary
+    // Only do this when we are the active UI cursor
+    if (GetSubsystem<Input>()->IsMouseVisible() && GetSubsystem<UI>()->GetCursor() == this)
+    {
+        // Remove existing SDL cursor if is not a system shape while we should be using those, or vice versa
+        if (info.osCursor_ && info.systemDefined_ != useSystemShapes_)
+        {
+            SDL_FreeCursor(info.osCursor_);
+            info.osCursor_ = 0;
+        }
+        
+        // Create SDL cursor now if necessary
+        if (!info.osCursor_)
+        {
+            // Create from image
+            if (!useSystemShapes_ && info.image_)
+            {
+                unsigned comp = info.image_->GetComponents();
+                int imageWidth = info.image_->GetWidth();
+                int width = imageRect_.Width();
+                int height = imageRect_.Height();
+
+                // Assume little-endian for all the supported platforms
+                unsigned rMask = 0x000000ff;
+                unsigned gMask = 0x0000ff00;
+                unsigned bMask = 0x00ff0000;
+                unsigned aMask = 0xff000000;
+
+                SDL_Surface* surface = (comp >= 3 ? SDL_CreateRGBSurface(0, width, height, comp * 8, rMask, gMask, bMask, aMask) : 0);
+                if (surface)
+                {
+                    unsigned char* destination = reinterpret_cast<unsigned char*>(surface->pixels);
+                    unsigned char* source = info.image_->GetData() + comp * (imageWidth * imageRect_.top_ + imageRect_.left_);
+                    for (int i = 0; i < height; ++i)
+                    {
+                        memcpy(destination, source, comp * width);
+                        destination += comp * width;
+                        source += comp * imageWidth;
+                    }
+                    info.osCursor_ = SDL_CreateColorCursor(surface, info.hotSpot_.x_, info.hotSpot_.y_);
+                    info.systemDefined_ = false;
+                    if (!info.osCursor_)
+                        LOGERROR("Could not create cursor from image " + info.image_->GetName());
+                    SDL_FreeSurface(surface);
+                }
+            }
+            
+            // Create a system default shape
+            if (useSystemShapes_)
+            {
+                info.osCursor_ = SDL_CreateSystemCursor((SDL_SystemCursor)osCursorLookup[shape_]);
+                info.systemDefined_ = true;
+                if (!info.osCursor_)
+                    LOGERROR("Could not create system cursor");
+            }
+        }
+        
+        if (info.osCursor_)
+            SDL_SetCursor(info.osCursor_);
+    }
+}
+
+void Cursor::HandleMouseVisibleChanged(StringHash eventType, VariantMap& eventData)
+{
+    ApplyShape();
+}
+
 }

+ 26 - 1
Engine/UI/Cursor.h

@@ -24,6 +24,7 @@
 
 #include "BorderImage.h"
 #include "Image.h"
+#include "Texture.h"
 
 #include <SDL_mouse.h>
 
@@ -47,6 +48,17 @@ enum CursorShape
 /// %Cursor image and hotspot information.
 struct CursorShapeInfo
 {
+    /// Construct with defaults.
+    CursorShapeInfo() :
+        imageRect_(IntRect::ZERO),
+        hotSpot_(IntVector2::ZERO),
+        osCursor_(0),
+        systemDefined_(false)
+    {
+    }
+    
+    /// Image.
+    SharedPtr<Image> image_;
     /// Texture.
     SharedPtr<Texture> texture_;
     /// Image rectangle.
@@ -55,6 +67,8 @@ struct CursorShapeInfo
     IntVector2 hotSpot_;
     /// OS cursor.
     SDL_Cursor* osCursor_;
+    /// Whether the OS cursor is system defined.
+    bool systemDefined_;
 };
 
 /// Mouse cursor %UI element.
@@ -74,11 +88,15 @@ public:
     virtual void GetBatches(PODVector<UIBatch>& batches, PODVector<float>& vertexData, const IntRect& currentScissor);
     
     /// Define a shape.
-    void DefineShape(CursorShape shape, Image* image, const IntRect& imageRect, const IntVector2& hotSpot, bool osMouseVisible = false);
+    void DefineShape(CursorShape shape, Image* image, const IntRect& imageRect, const IntVector2& hotSpot);
     /// 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_; }
+    /// Return whether is using system default shapes.
+    bool GetUseSystemShapes() const { return useSystemShapes_; }
     
     /// Set shapes attribute.
     void SetShapesAttr(VariantVector value);
@@ -86,10 +104,17 @@ public:
     VariantVector GetShapesAttr() const;
 
 protected:
+    /// Apply the current shape.
+    void ApplyShape();
+    /// Handle operating system mouse cursor visibility change event.
+    void HandleMouseVisibleChanged(StringHash eventType, VariantMap& eventData);
+    
     /// Current shape index.
     CursorShape shape_;
     /// Shape definitions.
     CursorShapeInfo shapeInfos_[CS_MAX_SHAPES];
+    /// Use system default shapes flag.
+    bool useSystemShapes_;
 };
 
 }

+ 0 - 29
Engine/UI/UI.cpp

@@ -57,19 +57,6 @@
 namespace Urho3D
 {
 
-/// OS cursor shape lookup table matching the %Cursor CursorShape enumeration
-static const int osCursorLookup[CS_MAX_SHAPES] =
-{
-    SDL_SYSTEM_CURSOR_ARROW,    // CS_NORMAL
-    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_HAND,     // CS_ACCEPTDROP
-    SDL_SYSTEM_CURSOR_NO,       // CS_REJECTDROP
-    SDL_SYSTEM_CURSOR_WAIT      // CS_BUSY
-};
-
 ShortStringHash VAR_ORIGIN("Origin");
 const ShortStringHash VAR_ORIGINAL_PARENT("OriginalParent");
 const ShortStringHash VAR_ORIGINAL_CHILD_INDEX("OriginalChildIndex");
@@ -819,22 +806,6 @@ void UI::SetCursorShape(CursorShape shape)
 {
     if (cursor_)
         cursor_->SetShape(shape);
-    else
-    {
-        // Check now: Cursor's SetShape does this check too, so avoids checking twice.
-        if (shape < CS_NORMAL || shape >= CS_MAX_SHAPES)
-            return;
-        
-        if (!osCursorShapes_[shape])
-        {
-            // Create OS cursor corresponding to specified CursorShape
-            osCursorShapes_[shape] = SDL_CreateSystemCursor((SDL_SystemCursor)osCursorLookup[shape]);
-            if (!osCursorShapes_[shape])
-                LOGERROR("Could not create system cursor!");
-        }
-        
-        SDL_SetCursor(osCursorShapes_[shape]);
-    }
 }
 
 void UI::SendDragEvent(StringHash eventType, UIElement* element, const IntVector2& screenPos)

+ 2 - 2
Engine/UI/UI.h

@@ -51,8 +51,6 @@ public:
 
     /// Set cursor UI element.
     void SetCursor(Cursor* cursor);
-    /// Set active cursor's shape if it exists, system OS cursor shape otherwise.
-    void SetCursorShape(CursorShape shape);
     /// Set focused UI element.
     void SetFocusElement(UIElement* element);
     /// Set modal element. Until all the modal elements are dismissed, all the inputs and events are only sent to them. Return true when successful.
@@ -125,6 +123,8 @@ private:
     UIElement* GetFocusableElement(UIElement* element);
     /// Return cursor position and visibility either from the cursor element, or the Input subsystem.
     void GetCursorPositionAndVisible(IntVector2& pos, bool& visible);
+    /// Set active cursor's shape.
+    void SetCursorShape(CursorShape shape);
     /// Send a UI element drag event.
     void SendDragEvent(StringHash eventType, UIElement* element, const IntVector2& screenPos);
     /// Handle screen mode event.

+ 0 - 2
Engine/UI/Window.cpp

@@ -334,8 +334,6 @@ void Window::SetCursorShape(WindowDragMode mode, Cursor* cursor) const
 
     if (cursor)
         cursor->SetShape(shape);
-    else
-        GetSubsystem<UI>()->SetCursorShape(shape);
 }
 
 void Window::ValidatePosition()

+ 5 - 2
Extras/LuaScript/pkgs/UI/Cursor.pkg

@@ -18,10 +18,13 @@ class Cursor : public BorderImage
     Cursor(Context* context);
     virtual ~Cursor();
     
-    void DefineShape(CursorShape shape, Image* image, const IntRect& imageRect, const IntVector2& hotSpot, bool osMouseVisible = false);
+    void DefineShape(CursorShape shape, Image* image, const IntRect& imageRect, const IntVector2& hotSpot);
     
     void SetShape(CursorShape shape);
+    void SetUseSystemShapes(bool enable);
     CursorShape GetShape() const;
-    
+    bool GetUseSystemShapes() const;
+
     tolua_property__get_set CursorShape shape;
+    tolua_property__get_set bool useSystemShapes;
 };