Change mouse pointer when resizing childwindow

Started by RitoonL, 06 July 2020, 12:32:54

RitoonL

Hello Texus,

I'm searching how to change the mouse pointer when resizing childwindow. I have searched but did not found anything so far.

Is it possible to change the mouse pointer into double arrows when the position of the pointer is ResizableBorderWidth coordinates ?

Thanks by advance,

RLF

texus

It's currently not possible.

I once looked into it, but one issue was that linux doesn't support the double arrow (https://github.com/SFML/SFML/blob/master/include/SFML/Window/Cursor.hpp#L65-L66).
Linux uses a single arrows (so it has a different arrow for each corner and window side), Windows only has double arrows and macOS supports both single or double arrows. Ideally you would be able to ask SFML for a single arrows and have it fall back to the double arrow on windows, but SFML only supports the double arrows (and thus can't display the native linux arrows).

Another (larger) issue, is that I don't know how to design the API for it. Some might want the system cursors (e.g. likely when you want a cursor on top of an edit box), while others might want a custom cursor (which is also possible with SFML). The API should somehow provide a callback that the cursor should be changed, but in what cases should it be send? Resizable child windows are the most obvious, but I imagine there might also be interest in an edit icon when hovering EditBox or TextBox. Some people might also want a hand icon when hovering buttons, but I imagine other won't want that at all, and I'm not sure how to handle that difference properly.
Maybe I should have a look at how other GUIs handle this.

texus

#2
I've been thinking about how to design it, and this is what I came up with so far. Note that since this is not a small change, it would be added to 0.9-dev, not in the 0.8 branch.

I will only support cursors that are available on all platforms for now, but I will add the Linux implementation of the resize arrows in my own code so that resize cursors are also supported on all platforms.

There would be a Cursor class where you can change the look of each cursor type:
Code (cpp) Select

class Cursor
{
public:
    enum class Type
    {
        Arrow,                  //!< Arrow cursor (default)
        Text,                   //!< I-beam, cursor when hovering over a text field
        Hand,                   //!< Pointing hand cursor
        SizeLeft,               //!< Left arrow on Linux, horizontal double arrow cursor on Windows and macOS
        SizeRight,              //!< Right arrow on Linux, horizontal double arrow cursor on Windows and macOS
        SizeTop,                //!< Up arrow on Linux, vertical double arrow cursor on Windows and macOS
        SizeBottom,             //!< Down arrow on Linux, vertical double arrow cursor on Windows and macOS
        SizeTopLeft             //!< Top-left arrow on Linux, double arrow cursor going from top-left to bottom-right on Windows and macOS
        SizeBottomRight,        //!< Bottom-right arrow on Linux, double arrow cursor going from top-left to bottom-right on Windows and
        SizeBottomLeft,         //!< Bottom-left arrow on Linux, double arrow cursor going from bottom-left to top-right on Windows and macOS
        SizeTopRight,           //!< Top-right arrow on Linux, double arrow cursor going from bottom-left to top-right on Windows and macOS
        Cross,                  //!< Crosshair cursor
        Help,                   //!< Help cursor
        NotAllowed              //!< Action not allowed cursor
    }

    // Changes cursor until restoreOverrideCursor() is called, calls to setOverrideCursor stack (design taken from Qt)
    void setOverrideCursor(Type);
   
    // Undo last setOverrideCursor call
    void restoreOverrideCursor();

    // Changes how the mouse cursor of a specific type should look like. By default the system cursors are used,
    // but you can use this function if you want to change them to bitmaps.
    void setCursorLook(Type, sf::Cursor);

    // Function called by TGUI to change the cursor. If you call this yourself then the cursor will change, but it will
    // revert back when you move the mouse (since TGUI changes it)
    void setCursor(Type);
}


Each widget would have a setMouseCursor function where you tell it to change the mouse cursor on hover. The downside of this approach is that it has to be called on each widget separately, but it does provide full control over which widgets should change the cursor. It also allows e.g. setting a NotAllowed cursor on a disabled button, so you are not limited to only a hand icon for buttons.
Code (cpp) Select
editBox->setMouseCursor(tgui::Cursor::Text);

For child windows (the part that you are interested in), there would be a function to enable/disable the resize cursors. I think I'll enable the option by default, because you probably always want this for resizable windows.
Code (cpp) Select
childWindow->enableResizeMouseCursors(true);

RitoonL

Hello, thanx for your answer.

Did I say double arrow???

Well, the current issue for me is to have resizing arrow whatever they look like. As the program aims to be windows/Linux cross-platform it's not a problem that cursors are Linux style. I did not even noticed that resizing system was so different between Linux and windows.

We started to develop on 0.8 branch... Stables are much more psychologically relaxing, I guess... But if you add these mouse methods on 0.9 branche we'll move into it. I'm a little afraid of retro compatibility between 0.8 and 0.9,  do you think we'll have to re-write a lot or is it can be used as is?

I'm impressed on how you handle feedbacks and did not expected you to develop a new class for us... We're really grateful for this... I'll keep on monitoring changelog to see when it's ready.

Thanx.

RLF


texus

QuoteI'm a little afraid of retro compatibility between 0.8 and 0.9,  do you think we'll have to re-write a lot or is it can be used as is?
There have been quite some changes. A large part of the API remained the same, but e.g. connecting callbacks are different and some parameter types were changed. Updating should be possible within a couple hours, but it might be annoying work. If you are loading all your widgets from a text file then I can't recommend updating as there is no way to import 0.8 files in 0.9 (although if you don't mind boring work they can easily be updated manually in less than a day, I had to update the screens in the gui builder itself by hand too).

QuoteI'm impressed on how you handle feedbacks
I definitely try to work on stuff that people suggest, but you also need to have some luck to get a feature implemented. Things get asked for often without them being implemented (usually due to lack of time). This wasn't the first time (nor the second time...) this functionality was requested, I even knew I needed it when I originally added support to resize the child windows. So it was something that I have known to be a limitation for quite some time and I had already given it a lot of thought (not necessarily in exact implementation, but about what challenges there would be and which ways I shouldn't implement it). That combined with the fact that I was almost finished with a large change for 0.9 and was looking for the next thing to do caused this to appear high on the todo list. I just finished what I was working on yesterday (reorganising some code, making widgets even less dependent on SFML), so I'm actually planning on looking into the cursor thing this weekend.

texus

It's probably not going to be finished this weekend. The implementation is a bit more complicated than expected (e.g. the mouse cursor is tied to a window and therefore to a specific Gui object). Because of this I decided to add the cursor code together with a larger change, so it will take a bit longer.

texus

TGUI 0.9-dev will now change the mouse cursor when hovering over the borders of a child window (if setResizable(true) was called).
The code was a lot more complicated that I originally thought so there is no chance at all that this would be backported to 0.8.

More information about the final design can be found in the announcement I made in Discord:
QuoteTGUI 0.9-dev now supports changing the mouse cursor.
There are 3 ways the mouse cursors are used:

1) Resize cursors will automatically be shown when hovering over the borders of a resizable child window. The default invisible border width has also been increased from 5 to 10 pixels. Those changes make resizing a child window a lot easier.

2) A setMouseCursor function has been added to the Widget class. The requested mouse cursor will be shown when the mouse hovers over the widget. The following line would cause the I-beam cursor to be visible when hovering over an edit box:
editBox->setMouseCursor(tgui::Cursor::Type::Text);

3) You can set a mouse cursor that will be used anywhere on the window and which overrides the cursor from the previous two methods. To do this, call the setOverrideMouseCursor on the Gui object. Call the restoreOverrideMouseCursor() function later to let the gui change the cursor automatically again based on the widget below the mouse.

Styling the cursors:
System cursors are used by default. Bitmaps are also supported by using the static tgui::Cursor::setStyle(Type type, const std::uint8_t* pixels, Vector2u size, Vector2u hotspot) method.

Changes to building TGUI:
- Minimum SFML version was increased from 2.3.2 to 2.5.0
- TGUI will now links to X11 on Linux to work around a limitation in SFML