From 9fcdba8dbf1aef820dae38bb804545f268a21d51 Mon Sep 17 00:00:00 2001 From: Peter Hinch Date: Thu, 24 Jun 2021 09:58:57 +0100 Subject: [PATCH] Improve Button appearance. Fix Label bug where value too long. --- README.md | 16 +++++++++------- gui/core/ugui.py | 21 +++++++++++---------- gui/core/writer.py | 2 +- gui/widgets/buttons.py | 8 ++++---- gui/widgets/dialog.py | 2 +- gui/widgets/label.py | 3 +++ 6 files changed, 29 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 3ceb28f..13e4b8c 100644 --- a/README.md +++ b/README.md @@ -53,11 +53,15 @@ Code is new and issues are likely: please report any found. This document is under review. I plan to add further demos and to upgrade the performance of some display drivers. +An issue under investigation is that a soft reset is required after a GUI +application is run and before running another. Otherwise the second application +displays correctly but is unresponsive. + # 0. Contents 1. [Basic concepts](./README.md#1-basic-concepts) Including installation and test. 1.1 [Coordinates](./README.md#11-coordinates) The GUI's coordinate system. - 1.2 [Screen Window and Widget objects](./README.md#12-Screen-window-and-widget-objects) + 1.2 [Screen Window and Widget objects](./README.md#12-Screen-window-and-widget-objects) Basic GUI classes. 1.3 [Fonts](./README.md#13-fonts) 1.4 [Navigation](./README.md#14-navigation) How the GUI navigates between widgets. 1.5 [Hardware definition](./README.md#15-hardware-definition) How to configure your hardware. @@ -396,9 +400,11 @@ minimal and aim to demonstrate a single technique. * `slider.py` A `Slider` whose color varies with its value. * `slider_label.py` A `Slider` updating a `Label`. Good for trying precision mode. - * `linked_slider.py` One slider updating two others, and a coding "wrinkle" + * `linked_slider.py` One `Slider` updating two others, and a coding "wrinkle" required for doing this. - * `screen_change.py` A `Pushbutton` causing a screen change. + * `dialog.py` `DialogBox` demo. Illustrates the screen change mechanism. + * `screen_change.py` A `Pushbutton` causing a screen change using a re-usable + "forward" button. * `tbox.py` Text boxes and user-controlled scrolling. ### 1.11.2 Test scripts @@ -643,10 +649,6 @@ In normal use the following methods only are required: passing positional and keyword arguments to the constructor of the new, user defined, screen. * `back(cls)` Restore previous screen. - * `value(cls, val=None)` The `val` arg can be any Python type. It allows - widgets on a `Screen` to store information in a way which can be accessed from - the calling screen. This typically occurs after the screen has closed and no - longer exists as an instance, hence the use of a classmethod. These are uncommon:__ * `shutdown(cls)` Clear the screen and shut down the GUI. Normally done by a diff --git a/gui/core/ugui.py b/gui/core/ugui.py index a2ee710..b7c28fd 100644 --- a/gui/core/ugui.py +++ b/gui/core/ugui.py @@ -202,15 +202,6 @@ class Display: class Screen: current_screen = None is_shutdown = Event() - _value = None - - # Allow a Screen to store an arbitrary object. Retrieval may be - # done by caller, after the Screen instance was deleted - @classmethod - def value(cls, val=None): - if val is not None: - cls._value = val - return cls._value @classmethod def next_ctrl(cls): @@ -490,9 +481,19 @@ class Screen: gc.threshold(gc.mem_free() // 4 + gc.mem_alloc()) #print(gc.mem_free()) -# Very basic window class. Cuts a rectangular hole in a screen on which content may be drawn +# Very basic window class. Cuts a rectangular hole in a screen on which +# content may be drawn. class Window(Screen): + _value = None + # Allow a Window to store an arbitrary object. Retrieval may be + # done by caller, after the Window instance was deleted + @classmethod + def value(cls, val=None): + if val is not None: + cls._value = val + return cls._value + def __init__(self, row, col, height, width, *, draw_border=True, bgcolor=None, fgcolor=None): Screen.__init__(self) self.row = row diff --git a/gui/core/writer.py b/gui/core/writer.py index 3430924..a4c2a1c 100644 --- a/gui/core/writer.py +++ b/gui/core/writer.py @@ -264,7 +264,7 @@ class Writer(): def setcolor(self, *_): return self.fgcolor, self.bgcolor -# Writer for colour displays or upside down rendering +# Writer for colour displays class CWriter(Writer): diff --git a/gui/widgets/buttons.py b/gui/widgets/buttons.py index 7c1a856..c890b8e 100644 --- a/gui/widgets/buttons.py +++ b/gui/widgets/buttons.py @@ -21,7 +21,7 @@ class Button(Widget): width = max(sl, height) height = width else: - width = max(sl, width) + width = max(sl + 10, width) # Allow 5 pixels before and after text super().__init__(writer, row, col, height, width, fgcolor, bgcolor, bdcolor, False, True) self.shape = shape self.radius = height // 2 @@ -100,9 +100,9 @@ class Button(Widget): class CloseButton(Button): def __init__(self, writer, width=0, callback=dolittle, args=(), bgcolor=RED): scr = Screen.current_screen - # The factor of 2 is an empirical fix to make it look OK over - # the range of fonts in use. - wd = width if width else writer.stringlen('X') * 2 + # Calculate the button width if not provided. Button allows + # 5 pixels either side. + wd = width if width else (writer.stringlen('X') + 10) self.user_cb = callback self.user_args = args super().__init__(writer, *scr.locn(4, scr.width - wd - 4), diff --git a/gui/widgets/dialog.py b/gui/widgets/dialog.py index bd8a9e9..8b0efac 100644 --- a/gui/widgets/dialog.py +++ b/gui/widgets/dialog.py @@ -25,7 +25,7 @@ class DialogBox(Window): height = 80 spacing = 10 - buttonwidth = max(max(writer.stringlen(e[0]) for e in elements) + 4, buttonwidth) + buttonwidth = max(max(writer.stringlen(e[0]) for e in elements) + 14, buttonwidth) buttonheight = max(writer.height, 15) nelements = len(elements) width = spacing + (buttonwidth + spacing) * nelements diff --git a/gui/widgets/label.py b/gui/widgets/label.py index 0e5aae2..449c67b 100644 --- a/gui/widgets/label.py +++ b/gui/widgets/label.py @@ -9,6 +9,7 @@ from gui.core.colors import * # text: str display string int save width class Label(Widget): def __init__(self, writer, row, col, text, invert=False, fgcolor=None, bgcolor=BLACK, bdcolor=False): + self.writer = writer # Determine width of object if isinstance(text, int): width = text @@ -22,6 +23,8 @@ class Label(Widget): self.value(text, invert) def value(self, text=None, invert=False, fgcolor=None, bgcolor=None, bdcolor=None): + if self.writer.stringlen(text) > self.width: + raise ValueError('Label.value() string is too long.') txt = super().value(text) # Sets .draw ensuring refresh # Redraw even if no text supplied: colors may have changed. self.invert = invert