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 maximize & minimize API functionality #1857

Open
ItsCubeTime opened this issue Apr 10, 2023 · 8 comments · May be fixed by #2473
Open

Window maximize & minimize API functionality #1857

ItsCubeTime opened this issue Apr 10, 2023 · 8 comments · May be fixed by #2473
Labels
enhancement New features, or improvements to existing features.

Comments

@ItsCubeTime
Copy link
Contributor

ItsCubeTime commented Apr 10, 2023

What is the problem or limitation you are having?

I would like to be able to maximize & minimize toga windows programmatically on desktop platforms

Describe the solution you'd like

I believe the maintainers of this repo probably knows better what the API for this would look like, but perhaps something like:

togaApp.main_window.state = "maximized" # Maximizes window
togaApp.main_window.state = "minimize" # Minimizes window
togaApp.main_window.state = "normal" # Removes "maximization" if maximized, un-minimize if minimized.

or:

togaApp.main_window.minimize() # Minimizes window
togaApp.main_window.maximize() # Maximizes window
togaApp.main_window.restore() # unminimize, unmaximize

Im not very picky about the implementation details.

Heres a simple demonstration of the sort of behavior I'm after:
https://youtu.be/zB-f6CAmww8

from __future__ import annotations
import toga
from toga.style import Pack
from toga.style.pack import COLUMN, ROW


class HelloWorld(toga.App):

    def startup(self):
        """
        Construct and show the Toga application.

        Usually, you would add your application to a main content box.
        We then create a main window (with a name matching the app), and
        show the main window.
        """
        main_box = toga.Box()

        def minimize(a=None):
            from toga_winforms.libs import WinForms
            helloWorld.main_window._impl.native.WindowState = helloWorld.main_window._impl.native.WindowState.Minimized

        def maximize(a=None):
            from toga_winforms.libs import WinForms
            helloWorld.main_window._impl.native.WindowState = helloWorld.main_window._impl.native.WindowState.Maximized if helloWorld.main_window._impl.native.WindowState != helloWorld.main_window._impl.native.WindowState.Maximized else helloWorld.main_window._impl.native.WindowState.Normal
        main_box.add(toga.Button("Minimize", on_press=minimize))
        main_box.add(toga.Button("Maximize", on_press=maximize))
        self.main_window = toga.MainWindow(title=self.formal_name)
        self.main_window.content = main_box


helloWorld: HelloWorld = None


def main():
    global helloWorld
    helloWorld = HelloWorld("foobar",
                            "org.foo.bar")
    return helloWorld


main().main_loop()

Describe alternatives you've considered

Not sure if this would be implementable on all desktop platforms

Additional context

No response

@ItsCubeTime ItsCubeTime added the enhancement New features, or improvements to existing features. label Apr 10, 2023
@ItsCubeTime
Copy link
Contributor Author

@freakboy3742 is there any interest in having something like this in Toga, or is it out of scope?

@freakboy3742
Copy link
Member

We already have an API for full_screen; maximise and minimise are fairly universal concepts for desktop platforms, so it makes sense that we have an API for them.

As for the exact shape of the API - although min/max/fullscreen are mutually exclusive, state = 'maximised' isn't a great API - firstly because "state" is a very generic term, and secondly because the "magic word" of "maximised" isn't obvious.

On that basis, my suggestion would be window.maximized = True/False and window.minimized = True/False. There's a complex interplay between maximized, minimized and full_screen; we need to make sure those transitions are all tested (e.g, setting window.maximized unsets window.minimized, etc).

I can see the idea behind a restore() API, but I'm not wild about the name - "restore" could refer to any number of features being "restored". I'm not sure I have a better name, though.

@ItsCubeTime
Copy link
Contributor Author

ItsCubeTime commented Apr 10, 2023

I also think window.maximized = True & window.minimized = True sounds good. I would assume the behavior would then be that calling window.maximized = True would then also un-minimize the window.

For the windows platform implementation though, it would be less code going for a "state" type of system as thats what Winforms is using (see my example above). Does MacOS & Linux do something similar? If they do, perhaps the ._impl for each platform should use something like togaApp.main_window._impl.set_state("maximized") togaApp.main_window._impl.get_state() to reduce code for each platform implementation (I also think "state" is a little undescriptive, so if you have a better suggestion for naming the property let me know)?

@ItsCubeTime
Copy link
Contributor Author

^ If above sounds good to you I can start working on a PR for https://github.com/beeware/toga/blob/main/core/src/toga/window.py & https://github.com/beeware/toga/blob/main/winforms/src/toga_winforms/window.py . Unfortunately Im not familiar with developing for other platforms.

@ItsCubeTime
Copy link
Contributor Author

I should mention btw that one could use string literals to provide code editor auto completion for string literals, I came across this comment recently: zauberzeug/nicegui#117 (comment) , not saying we should use it, but just in case you never seen that before

@freakboy3742
Copy link
Member

I also think window.maximized = True & window.minimized = True sounds good. I would assume the behavior would then be that calling window.maximized = True would then also un-minimize the window.

That would be my thought as well.

For the windows platform implementation though, it would be less code going for a "state" type of system as thats what Winforms is using (see my example above). Does MacOS & Linux do something similar? If they do, perhaps the ._impl for each platform should use something like togaApp.main_window._impl.set_state("maximized") togaApp.main_window._impl.get_state() to reduce code for each platform implementation (I also think "state" is a little undescriptive, so if you have a better suggestion for naming the property let me know)?

To be clear "less code" is a desirable goal; but when when faced with "more implementation code" and "simpler user-facing interface", we're going to opt for "simpler user-facing interface" every time.

In terms of what other macOS and GTK do:

  • macOS has explicit isZoomed/setIsZoomed() and isMiniaturized/`setIsMiniaturized()" APIs on NSWindow
  • GTK has some weird disparities. There are iconify()/deiconify() and maximize()/unmaximize() APIs; and there's a is-maximized property... but no obvious is_iconified or equivalent (but I might be missing something). All the docs I'm seeing say you need to listen to the window-state-event.

So - GTK property details notwithstanding, on those platforms implementing direct maximized=True will be less code :-)

That said, from a conceptual point of view, a window can only assume a single value - so it makes some sense that it can be retrieved by a single property. My only objection is the term "state"... but GTK and Winforms explicit use the term "state" to describe min/max, and macOS talks about "Zoomed state", "standard state", "miniaturized state", ... so maybe "state" isn't such a bad term after all.

It's worth noting that a state-based and min/max-based approach could* coexist - with maximized=True being a proxy for state = maximized. The only question then is whether the backend API is set_state or set_minimized etc. The more I think about it, this might be my preferred approach - it allows discoverability because there's a literal "minimze" API; but those API docs can reference the broader "state" APIs.

@freakboy3742
Copy link
Member

I should mention btw that one could use string literals to provide code editor auto completion for string literals, I came across this comment recently: zauberzeug/nicegui#117 (comment) , not saying we should use it, but just in case you never seen that before

Type-annotation based discovery is a nice trick, but it's still misleading. The state isn't a string - it's using a string as a token. If you want to use a token, you should be using an constant - and if there are constant values, they should be defined in an enum.

@freakboy3742
Copy link
Member

^ If above sounds good to you I can start working on a PR for https://github.com/beeware/toga/blob/main/core/src/toga/window.py & https://github.com/beeware/toga/blob/main/winforms/src/toga_winforms/window.py . Unfortunately Im not familiar with developing for other platforms.

That's fine - you don't need to provide a full implementation for all platforms. However, you do need to provide a stub for all platforms that logs a "not implemented" message so that anyone using the platform knows why an API isn't working.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New features, or improvements to existing features.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants