|
@@ -39,50 +39,77 @@ namespace Urho3D
|
|
|
static const char* shapeNames[] =
|
|
static const char* shapeNames[] =
|
|
|
{
|
|
{
|
|
|
"Normal",
|
|
"Normal",
|
|
|
|
|
+ "IBeam",
|
|
|
|
|
+ "Cross",
|
|
|
"ResizeVertical",
|
|
"ResizeVertical",
|
|
|
"ResizeDiagonalTopRight",
|
|
"ResizeDiagonalTopRight",
|
|
|
"ResizeHorizontal",
|
|
"ResizeHorizontal",
|
|
|
"ResizeDiagonalTopLeft",
|
|
"ResizeDiagonalTopLeft",
|
|
|
|
|
+ "ResizeAll",
|
|
|
"AcceptDrop",
|
|
"AcceptDrop",
|
|
|
"RejectDrop",
|
|
"RejectDrop",
|
|
|
"Busy",
|
|
"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
|
|
/// OS cursor shape lookup table matching cursor shape enumeration
|
|
|
static const int osCursorLookup[CS_MAX_SHAPES] =
|
|
static const int osCursorLookup[CS_MAX_SHAPES] =
|
|
|
{
|
|
{
|
|
|
SDL_SYSTEM_CURSOR_ARROW, // CS_NORMAL
|
|
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_SIZENS, // CS_RESIZEVERTICAL
|
|
|
SDL_SYSTEM_CURSOR_SIZENESW, // CS_RESIZEDIAGONAL_TOPRIGHT
|
|
SDL_SYSTEM_CURSOR_SIZENESW, // CS_RESIZEDIAGONAL_TOPRIGHT
|
|
|
SDL_SYSTEM_CURSOR_SIZEWE, // CS_RESIZEHORIZONTAL
|
|
SDL_SYSTEM_CURSOR_SIZEWE, // CS_RESIZEHORIZONTAL
|
|
|
SDL_SYSTEM_CURSOR_SIZENWSE, // CS_RESIZEDIAGONAL_TOPLEFT
|
|
SDL_SYSTEM_CURSOR_SIZENWSE, // CS_RESIZEDIAGONAL_TOPLEFT
|
|
|
|
|
+ SDL_SYSTEM_CURSOR_SIZEALL, // CS_RESIZE_ALL
|
|
|
SDL_SYSTEM_CURSOR_HAND, // CS_ACCEPTDROP
|
|
SDL_SYSTEM_CURSOR_HAND, // CS_ACCEPTDROP
|
|
|
SDL_SYSTEM_CURSOR_NO, // CS_REJECTDROP
|
|
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;
|
|
extern const char* UI_CATEGORY;
|
|
|
|
|
|
|
|
Cursor::Cursor(Context* context) :
|
|
Cursor::Cursor(Context* context) :
|
|
|
BorderImage(context),
|
|
BorderImage(context),
|
|
|
- shape_(CS_NORMAL),
|
|
|
|
|
|
|
+ shape_(shapeHashes[CS_NORMAL]),
|
|
|
useSystemShapes_(false),
|
|
useSystemShapes_(false),
|
|
|
osShapeDirty_(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
|
|
// Subscribe to OS mouse cursor visibility changes to be able to reapply the cursor shape
|
|
|
SubscribeToEvent(E_MOUSEVISIBLECHANGED, HANDLER(Cursor, HandleMouseVisibleChanged));
|
|
SubscribeToEvent(E_MOUSEVISIBLECHANGED, HANDLER(Cursor, HandleMouseVisibleChanged));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
Cursor::~Cursor()
|
|
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;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ DefineShape(shapeNames[shape], image, imageRect, hotSpot);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void Cursor::DefineShape(const String& shape, Image* image, const IntRect& imageRect, const IntVector2& hotSpot)
|
|
|
|
|
+{
|
|
|
if (!image)
|
|
if (!image)
|
|
|
return;
|
|
return;
|
|
|
|
|
|
|
|
ResourceCache* cache = GetSubsystem<ResourceCache>();
|
|
ResourceCache* cache = GetSubsystem<ResourceCache>();
|
|
|
|
|
+
|
|
|
|
|
+ if (!shapeInfos_.Contains(shape))
|
|
|
|
|
+ shapeInfos_[shape] = CursorShapeInfo(shape);
|
|
|
|
|
+
|
|
|
CursorShapeInfo& info = shapeInfos_[shape];
|
|
CursorShapeInfo& info = shapeInfos_[shape];
|
|
|
|
|
|
|
|
// Prefer to get the texture with same name from cache to prevent creating several copies of the texture
|
|
// 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
|
|
// Reset current shape if it was edited
|
|
|
- if (shape == shape_)
|
|
|
|
|
|
|
+ if (shape_ == shape)
|
|
|
{
|
|
{
|
|
|
- shape_ = CS_MAX_SHAPES;
|
|
|
|
|
|
|
+ shape_ = StringHash::ZERO;
|
|
|
SetShape(shape);
|
|
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;
|
|
return;
|
|
|
|
|
|
|
|
shape_ = shape;
|
|
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
|
|
// 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
|
|
// busy shape, set it immediately as we may block before that
|
|
|
osShapeDirty_ = true;
|
|
osShapeDirty_ = true;
|
|
|
- if (shape_ == CS_BUSY)
|
|
|
|
|
|
|
+ if (shape_ == shapeHashes[CS_BUSY])
|
|
|
ApplyOSCursorShape();
|
|
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)
|
|
void Cursor::SetUseSystemShapes(bool enable)
|
|
|
{
|
|
{
|
|
|
if (enable != useSystemShapes_)
|
|
if (enable != useSystemShapes_)
|
|
@@ -188,19 +233,17 @@ void Cursor::SetShapesAttr(const VariantVector& value)
|
|
|
if (!value.Size())
|
|
if (!value.Size())
|
|
|
return;
|
|
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;
|
|
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_)
|
|
if (!info.osCursor_)
|
|
|
{
|
|
{
|
|
|
// Create a system default shape
|
|
// 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;
|
|
info.systemDefined_ = true;
|
|
|
if (!info.osCursor_)
|
|
if (!info.osCursor_)
|
|
|
LOGERROR("Could not create system cursor");
|
|
LOGERROR("Could not create system cursor");
|