Changing the cursor shape

Hi,

I’m trying to change the cursor shape (VariantVector), but it’s stuck on the Normal shape:

ResourceCache *cache_ = GetSubsystem<ResourceCache>();
XMLFile *style_ = cache_->GetResource<XMLFile>("UI/DefaultStyle.xml");
SharedPtr<Cursor> cursor_(new Cursor(context_));
cursor_->SetStyleAuto(style_);
cursor_->SetShape(CS_BUSY);
GetSubsystem<UI>()->SetCursor(cursor_);

Calling printf("%s\n", cursor_->GetShape().CString() ); returns Busy which looks correct, but the cursor image didn’t change to the Busy one.

I’m testing with the defaults Data/UI/DefaultStyle.xml and Data/Textures/UI.png.

Am I missing something there?

Thanks in advance.

EDIT: Found a workaround: creating a new style with a single shape (VariantVector):

<element type="CursorBusy">
    <attribute name="Shapes">
        <variant type="VariantVector" >
            <variant type="String" value="Normal" />
            <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>

And calling it with:

ResourceCache *cache_ = GetSubsystem<ResourceCache>();
XMLFile *style_ = cache_->GetResource<XMLFile>("UI/DefaultStyle.xml");
SharedPtr<Cursor> cursor_(new Cursor(context_));
cursor_->SetStyle("CursorBusy", style_);
GetSubsystem<UI>()->SetCursor(cursor_);
1 Like

Follow-up question.

Lets say I create an UI cursor (with the method bellow) and, later on, I need to remove it and return the control to the OS cursor:

void addCursor() {
    SharedPtr<Cursor> cursor_(new Cursor(context_));
    cursor_->SetStyleAuto();
    GetSubsystem<UI>()->SetCursor(cursor_);
}

Since the UI cursor doesn’t appear to be directly parented to the scene or the UI root, I can’t remove it with RemoveChild().

I couldn’t find a “UnsetCursor” analog to SetCursor on the UI documentation.

The best solution I found was trying to “unset” with:

void removeCursor() {
    GetSubsystem<UI>()->SetCursor(NULL);
}

But I think that will cause a memory leak (the previously created UI cursor is still on the memory), right?

Does anyone know if there’s a proper way to remove the UI cursor?
Or (if it’s not meant to be removed) another way to unset?
Or even just return the control to the OS cursor?

Thanks in advance.

Check out SetCursor() code, it removes old cursor when setting to null.

void UI::SetCursor(Cursor* cursor)
{
    if (cursor_ == cursor)
        return;

    // Remove old cursor (if any) and set new
    if (cursor_)
    {
        rootElement_->RemoveChild(cursor_);
        cursor_.Reset();
    }
    if (cursor)
    {
        rootElement_->AddChild(cursor);
        cursor_ = cursor;

        IntVector2 pos = cursor_->GetPosition();
        const IntVector2& rootSize = rootElement_->GetSize();
        const IntVector2& rootPos = rootElement_->GetPosition();
        pos.x_ = Clamp(pos.x_, rootPos.x_, rootPos.x_ + rootSize.x_ - 1);
        pos.y_ = Clamp(pos.y_, rootPos.y_, rootPos.y_ + rootSize.y_ - 1);
        cursor_->SetPosition(pos);
    }
}
2 Likes

@vmost, thank you so much!

Better use nullptr.

“If you have to name the null pointer, call it nullptr; that’s what it’s called in C++11. Then, “nullptr” will be a keyword.”Bjarne Stroustrup

3 Likes

@Modanung, thank you very much! I didn’t know that there was nullptr.

1 Like

It’s my favourite return value. :slightly_smiling_face:

1 Like