Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Window Button Styles #6675

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open

Conversation

TheColorRed
Copy link
Contributor

@TheColorRed TheColorRed commented Oct 28, 2024

fixes #6669

Adds three types of window button styles naming was taken from here.

There are a few winit restrictions.

  • Wayland / X11 / Orbital: Not implemented.
  • Web / iOS / Android: Unsupported.

Usage

let app = AppWindow::new()?;
app.window().set_window_button_style(slint::WindowButtonStyle::All); // Default
app.window().set_window_button_style(slint::WindowButtonStyle::None);
app.window().set_window_button_style(slint::WindowButtonStyle::Close);
app.window().set_window_button_style(slint::WindowButtonStyle::Minimize);
app.window().set_window_button_style(slint::WindowButtonStyle::Maximize);
app.window().set_window_button_style(slint::WindowButtonStyle::MinimizeClose);
app.window().set_window_button_style(slint::WindowButtonStyle::MaximizeClose);
app.window().set_window_button_style(slint::WindowButtonStyle::MinimizeMaximize);

Output

Full

image

Close

image

None

Note: On windows the x is still there just not clickable (not sure about on a different OS)

image

MinimizeMaximize

image

@TheColorRed TheColorRed marked this pull request as ready for review October 28, 2024 16:34
@ogoffart
Copy link
Member

Thanks for the PR.

I'm just wondering if an enum is really appropriate vs 3 boolean to hide specific buttons. Would it not be simpler?

@TheColorRed
Copy link
Contributor Author

TheColorRed commented Oct 29, 2024

@ogoffart You mean something like this? I didn't think of booleans, I think this look better than my implementation.

let min = false;
let max = false;
let close = true;
app.window().set_window_buttons(min, max, close);

@ogoffart
Copy link
Member

No, I meant something like
app.window().set_button_maximize_visible(true); and so on.
But that's not really great.

A function with 3 boolean is quite confusing because people will write set_window_buttons(true, false, true); and that's unreadable and also easy to mix arguments.(boolean trap)

Another possibility:
app.window().set_button_visible(WindowButton::Maximize, true)
I think I like that.

There is also the choice to take she same API as winit with Flags.

I think your choice with an enum with 8 state is not that bad if there is only 3 buttons, but we have to think about extensibility. What if we want to add another button in the future without breaking the API? There is some WM with extra button. (Help, Menu, ...)

So I don't know exactly which API is the best that combine simplicity and extensibility. Perhaps the winit API with flags is the nicest. But flags in rust are a bit awkward to do.

@Enyium
Copy link
Contributor

Enyium commented Oct 30, 2024

Shouldn't these be component properties?

export component AppWindow inherits Window {
    has-minimize-button: false;
    has-maximize-button: false;
    has-close-button: false;
}

Dialog should also make them available, but use different defaults (only close-button).

Why should you have to do this in the backend language?

@TheColorRed
Copy link
Contributor Author

TheColorRed commented Oct 30, 2024

@ogoffart I have updated the implementation:

app.window().set_window_button_enabled(WindowButton::Minimize, true);
app.window().set_window_button_enabled(WindowButton::Maximize, true);
app.window().set_window_button_enabled(WindowButton::Close, true);

@Enyium

I am not sure that would fall in line with the current structure of the library, as you cannot make the window maximized from slint either, so this follows the current implementation of how setting a window to maximized works:

app.window().set_maximized(true);

@Enyium
Copy link
Contributor

Enyium commented Oct 30, 2024

I am not sure that would fall in line with the current structure of the library, as you cannot make the window maximized from slint either

It's about what the user should be allowed to do! This is similar to the initial-size and resizing topic: You use Slint properties to define whether the user should be allowed to resize the window. (Docs: "Setting the width will result in a fixed width... The initial width can be controlled with the preferred-width property.")

You can't compare something like Window::set_window_button_enabled(WindowButton::Maximize, ...) to Window::set_size() and Window::set_maximize()! The latter are for immediate acions, not to manifest a framework of allowed user actions.

Do you want to disable the minimize- and maximize-button for the Window of every new Dialog component instance? It belongs to the design. It shares in defining the kind of dialog presented, and is unlikely to change during the lifetime of a window.

@ogoffart
Copy link
Member

It is not always easy to figure out if this should be part of the native API vs. what should be part of the slint code API.
The rule of thumbs is that if it is part of the design, then it should be in .slint, but if it is part of the logic, then it should be in the native code.
Maximizing or Minimizing a window, when not done by the user is done by the programmer as a result of something.
But maybe the appearance of the title bar is indeed something that should be described in the .slint file, it seems.
So i tend to agree with @Enyium

@TheColorRed
Copy link
Contributor Author

@ogoffart, @Enyium I have moved the code out of the API and into .slint. I wasn't sure on the name, so I went no-**-button as the default of a property seems to be false which when the value isn't set in the .slint, it automatically turns the button off which is why I didn't go with has-**-button .

@Enyium
Copy link
Contributor

Enyium commented Nov 1, 2024

no-**-button

Please "Avoid Negative...Names". I also recommended this regarding the existing no-frame in #5882 - although built-in has-... properties always seem to be out-properties. Perhaps this would be a good time to think of whether has-... should also be used for properties that aren't exclusively out-properties, or whether Slint could use another positive phrasing for properties that are at least partly in-properties.

the default of a property seems to be false which when the value isn't set in the .slint, it automatically turns the button off

I don't think there's a problem defining true as the default. If it's not overwritten and not part of a two-way binding, the default of true should be kept.


According to GPT-4o, dialogs with hidden minimize- and maximize-button are more common and Dialog should hide them by default.

Copy link
Member

@ogoffart ogoffart left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry to take so long to react to your PR.
It may seem picky, but we really should try hard to get the right API and naming, and this is something that can take several iteration.
Thank you so much for contributing. I think the feature is valuable. And the implementation looks good.

I've added some comments especially regarding naming.
We should use consistently either something like "visible" or "enabled" for these buttons. Winit uses "enabled", but I wonder if these shouldn't be "visible" instead. I'm a bit unsure about that.

(Also, the implementation in the Qt backend is missing. That can be done with QWidget::setWindowFlags. But this can be done in a followup)

@@ -407,6 +413,17 @@ struct WindowPinnedFields {
text_input_focused: Property<bool>,
}

#[derive(Debug, Copy, Clone, PartialEq)]
/// The state of each window button
pub struct WindowButtonState {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we consider marking this struct as #[non_exhaustive]?

Naming-wise, i believe the struct should probably be called WindowButtonVisibility as it is about the visibility of these buttons rather than their state. Or the value should say minimize_button_visible or has_minimize_button

window.set_enabled_buttons(enabled_buttons);
}
Self::None(attributes) => {
attributes.borrow_mut().enabled_buttons = WindowButtons::all()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why set all buttons here?


/// The widow style
/// Returns a tuple of three booleans: (minimize, maximize, close)
pub fn window_buttons_enabled(&self) -> WindowButtonState {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it maybe visibility rather than enabled

Comment on lines +1067 to +1069
- **`no-minimize-button`** (_in_ _bool_): Whether the window should have a minimize button in the title bar. Default is `false` to show the minimize button.
- **`no-maximize-button`** (_in_ _bool_): Whether the window should have a maximize button in the title bar. Default is `false` to show the maximize button.
- **`no-close-button`** (_in_ _bool_): Whether the window should have a close button in the title bar. Default is `false` to show the close button.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think Enyium has a point. It probably should be has-maximize-button or maximize-button-visible or maximize-button-enabled (and default to true which can be done in the builtins.slint)

@Enyium
Copy link
Contributor

Enyium commented Nov 7, 2024

We should use consistently either something like "visible" or "enabled" for these buttons. Winit uses "enabled", but I wonder if these shouldn't be "visible" instead. I'm a bit unsure about that. [@ogoffart]

Note that this is already inconsistent under Windows. StackOverflow:

CS_NOCLOSE disables the close button (and [system] menu entry), but it will not remove it.

...

The only way to remove the button is to give up on the system menu completely. You have to omit the WS_SYSMENU style flag in your CreateWindowEx() call.

In contrast, other styles like WS_MAXIMIZEBOX and WS_MINIMIZEBOX can really set the button visibility. But this is also dependent on the configuration: The minimize- or the maximize-button may also be just disabled.

But I don't know whether winit even uses a window class per window at all, or reuses OS-level window classes. (CS_NOCLOSE is a class style, not a window style.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Ability to configure minimize/maximize/restore buttons
3 participants