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
Redesign main frame #365
Redesign main frame #365
Conversation
The branch check failed on AppVeyor while uploading the artifact, but the second build succeeded, so ignore the failed build please. |
@@ -91,19 +92,20 @@ def __init__(self, config): | |||
self.config = config | |||
|
|||
# Note: don't set position from config, since it's not yet loaded. | |||
wx.Frame.__init__(self, None, title=self.TITLE, | |||
mainframe = wx.Frame.__init__(self, None, title=self.TITLE, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need for this.
Instead of "stopped" we could change to Mirabai's suggestion of "disabled". Alternatively, I've used "suspended" and "paused" to describe Plover's not-running state. |
The problem is: it is still running, listening to keys, if you use a machine, the port is still in use. I think: "output enabled"/"output disabled" is the better terminology. |
Yes, I can agree with that. I may also rename, in this PR, "error" to "disconnected", since that's when the error message is used. |
What about in case of initialization error? |
All right, I updated. Removing the window title, it becomes clear that we'll need a secondary label. I'm all for folding in my checkbox change into this PR, with our updated terminology. So, we could do like the checkbox in the art thread:
Or perhaps a label & button?
Label and a button, short form?
For the icons, we should just render some bitmaps from some open icon repository, as Unicode support differs depending on the user's system font. The first two that come to mind are Google's Material Icons and Ionic's Ionicons. |
76ce82b
to
93b642f
Compare
Google's Material icons don't seem to have a standard play/pause, just stuff for snoozing notifications and pausing phone calls. The Ionicons look great. (We should do the notice & terms requirement of MIT code in the About dialog somewhere, probably.) |
This might seem arbitrary, but I have an aesthetic dislike of using
|
If we added a group, we'd have to group the other elements (machine status and configure/about buttons) as well. I'd like to try:
|
Could we split out the background color change from the "what buttons do we want" bit that's still under discussion? I'm all for getting the better background color in, that's an uncontroversial win AFAICT. |
4ce4622
to
ac4f1ee
Compare
I folded in my status button work into this PR. If I could get your feedback on functionality and code style, then we can get this done in time for the release. |
I like the screenshots in the description. Far clearer than what we have now. |
@Achim63 you can read through the art exchange if you'd like. There are various reasons for why we ended up on this design and I'm afraid that ultimately not everyone is going to be happy.
Finally, for the toggle button, I really recommend reading through this stack overflow response: http://ux.stackexchange.com/a/40954 As always, though, the code is iterative. If the feedback is overwhelming when we release a preview build, we can always change the user interface later. |
I haven't tried radio buttons, though, that might be worth a try.
|
I was in favor of giving radio buttons a shot, but I like the visual symmetry with all normal buttons now that I see that. @Achim63 A lot of UI stuff is hamstrung by using the lowest-common denominator of what wxWidgets has to offer via wxPython. It's frustrating. |
RUNNING_MESSAGE = "running" | ||
STOPPED_MESSAGE = "stopped" | ||
ERROR_MESSAGE = "error" | ||
STATUS_DISCONNECTED, STATUS_OUTPUT_ENABLED, STATUS_OUTPUT_DISABLED = range(3) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd expect these to be disconnected => -1, disabled => 0, enabled => 1, but since this isn't exposed outside the app yet, no big deal.
@benoit-pierre reports that this renders very badly on Ubuntu, so it will require additional work before we can merge it. |
@benoit-pierre Could you attach a screenshot of this under Ubuntu? |
TFW you think "not the default button, must be Cancel" and instead close a PR and leave the comment you were trying to cancel. |
So the issue if not as clear cut as "it never looks good on Ubuntu", this only happen when I use a configuration with only one small dictionary (for faster startup). It otherwise looks fine, except for the radio buttons that are a bit cramped (vertically) with my theme on Arch Linux: But this is a minor issue, so let's merge this. |
45b1a8f
to
0e58a9e
Compare
@benoit-pierre I rejigged the UI slightly to make it look good on Windows, I'll have to confirm Mac looks all right, does this also fix the crampedness on your machine? |
- Windows has a grey color for the main frame because that is Windows' default color. To fix this, you place a top-level panel in the frame. - Add a disabled state for the status button when a machine is disconnected. - Remove title status
0e58a9e
to
166a807
Compare
@morinted: yes. |
166a807
to
c7d63d5
Compare
With those additional changes, the layout is always correct, no matter the configuration, and whether I start with the keyboard and switch to another machine or vice versa: diff --git i/plover/gui/main.py w/plover/gui/main.py
index cd968a2..4afb9bb 100644
--- i/plover/gui/main.py
+++ w/plover/gui/main.py
@@ -99,34 +99,34 @@ class MainFrame(wx.Frame):
style=wx.DEFAULT_FRAME_STYLE & ~(wx.RESIZE_BORDER |
wx.RESIZE_BOX |
wx.MAXIMIZE_BOX))
- self.root = wx.Panel(self, style=wx.DEFAULT_FRAME_STYLE)
+ root = wx.Panel(self, style=wx.DEFAULT_FRAME_STYLE)
# Menu Bar
MenuBar = wx.MenuBar()
self.SetMenuBar(MenuBar)
# Configure button.
- self.configure_button = wx.Button(self.root,
+ self.configure_button = wx.Button(root,
label=self.CONFIGURE_BUTTON_LABEL)
self.configure_button.Bind(wx.EVT_BUTTON, self._show_config_dialog)
# About button.
- self.about_button = wx.Button(self.root, label=self.ABOUT_BUTTON_LABEL)
+ self.about_button = wx.Button(root, label=self.ABOUT_BUTTON_LABEL)
self.about_button.Bind(wx.EVT_BUTTON, self._show_about_dialog)
# Status radio buttons.
- self.radio_output_enable = wx.RadioButton(self.root,
+ self.radio_output_enable = wx.RadioButton(root,
label=self.ENABLE_OUTPUT_LABEL)
self.radio_output_enable.Bind(wx.EVT_RADIOBUTTON,
lambda e: self.steno_engine.set_is_running(True))
- self.radio_output_disable = wx.RadioButton(self.root,
+ self.radio_output_disable = wx.RadioButton(root,
label=self.DISABLE_OUTPUT_LABEL)
self.radio_output_disable.Bind(wx.EVT_RADIOBUTTON,
lambda e: self.steno_engine.set_is_running(False))
# Machine status.
# TODO: Figure out why spinner has darker gray background.
- self.spinner = wx.animate.GIFAnimationCtrl(self.root, -1, SPINNER_FILE)
+ self.spinner = wx.animate.GIFAnimationCtrl(root, -1, SPINNER_FILE)
self.spinner.GetPlayer().UseBackgroundColour(True)
self.spinner.Hide()
@@ -134,7 +134,7 @@ class MainFrame(wx.Frame):
wx.BITMAP_TYPE_PNG)
self.disconnected_bitmap = wx.Bitmap(self.DISCONNECTED_IMAGE_FILE,
wx.BITMAP_TYPE_PNG)
- self.connection_ctrl = wx.StaticBitmap(self.root,
+ self.connection_ctrl = wx.StaticBitmap(root,
bitmap=self.disconnected_bitmap)
border_flag = wx.SizerFlags(1).Border(wx.ALL, self.BORDER)
@@ -147,30 +147,30 @@ class MainFrame(wx.Frame):
settings_sizer.AddF(self.about_button, border_flag.Expand())
# Create Output Status Box
- box = wx.StaticBox(self.root, label=self.HEADER_OUTPUT)
+ box = wx.StaticBox(root, label=self.HEADER_OUTPUT)
status_sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
status_sizer.AddF(self.radio_output_enable, border_flag)
status_sizer.AddF(self.radio_output_disable, border_flag)
# Create Machine Status Box
- self.machine_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ machine_sizer = wx.BoxSizer(wx.HORIZONTAL)
center_flag =\
wx.SizerFlags()\
.Align(wx.ALIGN_CENTER_VERTICAL)\
.Border(wx.LEFT | wx.RIGHT, self.BORDER)
- self.machine_sizer.AddF(self.spinner, center_flag)
- self.machine_sizer.AddF(self.connection_ctrl, center_flag)
+ machine_sizer.AddF(self.spinner, center_flag)
+ machine_sizer.AddF(self.connection_ctrl, center_flag)
longest_machine = max(machine_registry.get_all_names(), key=len)
longest_state = max((STATE_ERROR, STATE_INITIALIZING, STATE_RUNNING),
key=len)
longest_machine_status = '%s: %s' % (longest_machine, longest_state)
- self.machine_status_text = wx.StaticText(self.root, label=longest_machine_status)
- self.machine_sizer.AddF(self.machine_status_text, center_flag)
- refresh_bitmap = wx.Bitmap(self.REFRESH_IMAGE_FILE, wx.BITMAP_TYPE_PNG)
- self.reconnect_button = wx.BitmapButton(self.root, bitmap=refresh_bitmap)
- self.machine_sizer.AddF(self.reconnect_button, center_flag)
+ self.machine_status_text = wx.StaticText(root, label=longest_machine_status)
+ machine_sizer.AddF(self.machine_status_text, center_flag)
+ refresh_bitmap = wx.Bitmap(self.REFRESH_IMAGE_FILE, wx.BITMAP_TYPE_PNG)
+ self.reconnect_button = wx.BitmapButton(root, bitmap=refresh_bitmap)
+ machine_sizer.AddF(self.reconnect_button, center_flag)
# Assemble main UI
global_sizer = wx.GridBagSizer(vgap=self.BORDER, hgap=self.BORDER)
@@ -183,7 +183,7 @@ class MainFrame(wx.Frame):
border=self.BORDER,
pos=(1, 0),
span=(1, 2))
- global_sizer.Add(self.machine_sizer,
+ global_sizer.Add(machine_sizer,
flag=wx.CENTER | wx.ALIGN_CENTER | wx.EXPAND | wx.LEFT,
pos=(2, 0),
border=self.BORDER,
@@ -193,8 +193,8 @@ class MainFrame(wx.Frame):
border = wx.BoxSizer()
border.AddF(global_sizer,
wx.SizerFlags(1).Border(wx.ALL, self.BORDER).Expand())
- border.Fit(self.root)
- self.SetSizerAndFit(border)
+ root.SetSizerAndFit(border)
+ border.SetSizeHints(self)
self.Bind(wx.EVT_CLOSE, self._quit)
self.Bind(wx.EVT_MOVE, self.on_move)
@@ -297,7 +297,6 @@ class MainFrame(wx.Frame):
self.connection_ctrl.SetBitmap(self.connected_bitmap)
elif state == STATE_ERROR:
self.connection_ctrl.SetBitmap(self.disconnected_bitmap)
- self.machine_sizer.Layout()
if not self.steno_engine.machine or self.steno_engine.machine.state is not STATE_RUNNING:
status = self.STATUS_DISCONNECTED
elif self.steno_engine.is_running: The important change is the |
And it works fine on Windows too, let's hope it does on Mac too... |
- Remove on/off Plover image - Set default focus to "Configuration..." instead of toggle - Implement status indicator as radio buttons - The machine refresh button is now statically placed on the right
c7d63d5
to
059347e
Compare
Yes, seems great, as usual. Thanks! It's been applied, works on Mac, and should be ready to submit. |
Here is the redesign: