slint-ui / slint

Slint is a declarative GUI toolkit to build native user interfaces for Rust, C++, or JavaScript apps.
https://slint.dev
Other
16.94k stars 568 forks source link

API to minimize and maximize window #4400

Closed PlanetTeamSpeakk closed 7 months ago

PlanetTeamSpeakk commented 8 months ago

In my application, I have hidden the frame and made my own control buttons instead. However, I have only managed to make my own close button which calls ui.window().hide(), for the other two, minimize and maximize, there doesn't seem to be a method in the API that can mimic that behaviour.

Hence, I'd like to request such methods to be added.

Vadoola commented 8 months ago

There has been some discussion on this before. I don't have time to dig back through and find them at the moment. It can be done but you would need to use the private slint api's. If you dig through the Issues and Discussions some you should be able to find some tips to how to do it currently.

ogoffart commented 8 months ago

This was kind of part of the meta issue https://github.com/slint-ui/slint/issues/333 but it is now closed. (There was also https://github.com/slint-ui/slint/issues/3331 but this was for fullscreen) So let's keep this issue open for it.

Currently, one way to do it is to use the private API of the i-slint-backend-winit crate to access the winit API.

In order to add this in Slint, we have to make the API for it. I guess the most sensible way to do it is to copy the API of winit with set_maximized / set_minimized.

Another API could be to merge them in some state API like Qt does. But note that a window can be both minimized and maximized at the same time (it means that if the user un-minimize the window, it will be restored as maximized) so the API should account for that.

Implementation-wise, it should be easy, just do the same as Window::set_fullscreen This is why i'm making this issue as a good first issue.

rminderhoud commented 7 months ago

After a bit of poking around, this is not as simple as Window::set_fullscreen. For this implementation we can maintain state inside WindowInner to track the fullscreen state since the only way to change it is programmatically through the app. Therefore we can localize changes to the update_window_properties.

However, minimize/maximize can be invoked by the user "nonprogramatically" through the window manager. Following the same pattern as set_fullscreen can result in the following:

Ideally the window minimized/maximized state should not be kept in slint to avoid these issues. For the Window -> WindowInner -> WindowAdapter chain to be fully stateless the WindowAdapter trait could be extended to support these actions directly but I'm not sure the appetite for changing a core trait like that? Alternatively, maybe the maximize/minimize events could be captured in Qt/winit/etc. and propagated in the notify chain but this can be error prone in my experience working on related issues with SDL.

ogoffart commented 7 months ago

Thanks @rminderhoud for your research. You're right, I overlooked the fact that the WM can set the state as well. (In fact, this is even possible for full screen, the user can select full screen from the plasma menu)

By the way, the way you suggest was how it was first implemented in https://github.com/slint-ui/slint/pull/4286 , but then we decided to go with the current API instead in https://github.com/slint-ui/slint/pull/4304

So that means that the backend have to call set_minimized() or set_maximized on the slint::Window when this happens. We probably receive an event when the user change the state.

Or we go back to an api where we add set_maximized(bool) , set_minimized(bool) and even set_fullscreen(bool) to the WindowAdaptor

We can also make it enum WindowState(Maximized, Minimized, Fullscreen) and have a set_window_state(WindowState, bool) Not sure what's best.

@tronical : opinion?

ogoffart commented 7 months ago

I had a quick chat with @tronical and the reason why we need to keep the state within the Slint's Window is to be able to easier provide a possibility to add a property later on the Window that can be used from Slint.

So my recommendation would be to still do the same as what set_fullscreen does. But the backend should notify Slint when the state changes by calling window::set_minimized when an event comes from the windowing system. (We also discussed the fact that we could add event to the WindowEvent enum for the notification, but since it would have practically the same effect as the faller on the window, i don't think it's needed)