diff --git a/README.md b/README.md index dc0f375..7f0427b 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ of some display drivers. 4.1 [Class methods](./README.md#41-class-methods) 4.2 [Constructor](./README.md#42-constructor) 4.3 [Callback methods](./README.md#43-callback-methods) Methods which run in response to events. - 4.4 [Method](./README.md#44-method) Optional interface to usayncio code. + 4.4 [Method](./README.md#44-method) Optional interface to uasyncio code. 5. [Window class](./README.md#5-window-class) 5.1 [Constructor](./README.md#51-constructor) 5.2 [Class method](./README.md#52-class-method) @@ -374,6 +374,10 @@ files in `gui/core` are: * `colors.py` Constants including colors and shapes. * `ugui.py` The main GUI code. * `writer.py` Supports the `Writer` and `CWriter` classes. + * `framebuf_utils.mpy` Accelerator for the `CWriter` class. This optional file + is compiled for STM hardware. It is specific to Pyboards (1.x and D) and will + be ignored on other ports. Details may be found + [here](https://github.com/peterhinch/micropython-font-to-py/blob/master/writer/WRITER.md#224-a-performance-boost). The `gui/primitives` directory contains the following files: * `switch.py` Interface to physical pushbuttons. @@ -2207,12 +2211,17 @@ have the following bound variables, which should be considered read-only: * `width` Ditto. * `mrow` Maximum absolute row occupied by the widget. * `mcol` Maximum absolute col occupied by the widget. + +A further aid to metrics is the `Writer` method `.stringlen(s)`. This takes a +string as its arg and returns its length in pixels when rendered using that +`Writer` instance's font. The `mrow` and `mcol` values enable other widgets to be positioned relative to the one previously instantiated. In the cases of sliders, `Dial` and `Meter` widgets these take account of space ocupied by legends or labels. -The `aclock.py` demo provides a simple example of this approach. +The `aclock.py` and `linked_sliders.py` demos provide simple examples of this +approach. ## Use of graphics primitives diff --git a/gui/core/framebuf_utils.mpy b/gui/core/framebuf_utils.mpy new file mode 100644 index 0000000..6bb1398 Binary files /dev/null and b/gui/core/framebuf_utils.mpy differ diff --git a/gui/demos/dialog.py b/gui/demos/dialog.py index d1551fb..76ee574 100644 --- a/gui/demos/dialog.py +++ b/gui/demos/dialog.py @@ -32,7 +32,7 @@ class BaseScreen(Screen): # Trailing spaces ensure Label is wide enough to show results self.lbl = Label(wri, row, col, 'Dialog box test ') # DialogBox constructor arguments. Here we pass all as keyword wargs. - kwargs = {'writer' : wri, + kwargs = {'writer' : wri, 'row': 20, 'col' : 2, 'elements' : (('Yes', GREEN), ('No', RED), ('Foo', YELLOW)), 'label' : 'Test dialog', } diff --git a/gui/demos/dropdown.py b/gui/demos/dropdown.py index 29b464b..c17e5ae 100644 --- a/gui/demos/dropdown.py +++ b/gui/demos/dropdown.py @@ -13,7 +13,7 @@ from gui.widgets.dropdown import Dropdown from gui.core.writer import CWriter # Font for CWriter -import gui.fonts.font10 as font +import gui.fonts.arial10 as font from gui.core.colors import * @@ -26,14 +26,17 @@ class BaseScreen(Screen): col = 2 row = 2 - Dropdown(wri, row, col, - elements = ('hydrogen', 'helium', 'neon', 'xenon', 'radon'), - bdcolor = GREEN, bgcolor = DARKGREEN, - callback=self.ddcb) + self.dd = Dropdown(wri, row, col, + elements = ('hydrogen', 'helium', 'neon', 'xenon', 'radon'), + bdcolor = GREEN, bgcolor = DARKGREEN, + callback=self.ddcb) row += 30 - self.lbl = Label(wri, row, col, 90, bdcolor=RED) + self.lbl = Label(wri, row, col, self.dd.width, bdcolor=RED) CloseButton(wri) # Quit the application + def after_open(self): + self.lbl.value(self.dd.textvalue()) + def ddcb(self, dd): if hasattr(self, 'lbl'): self.lbl.value(dd.textvalue()) diff --git a/gui/demos/linked_sliders.py b/gui/demos/linked_sliders.py index 2b8681d..332b5cc 100644 --- a/gui/demos/linked_sliders.py +++ b/gui/demos/linked_sliders.py @@ -12,7 +12,7 @@ from gui.widgets.sliders import Slider from gui.core.writer import CWriter # Font for CWriter -import gui.fonts.arial10 as arial10 +import gui.fonts.arial10 as font from gui.core.colors import * @@ -22,19 +22,18 @@ class BaseScreen(Screen): args = { 'bdcolor' : RED, 'slotcolor' : BLUE, - 'legends' : ('0.0', '0.5', '1.0'), + 'legends' : ('0', '5', '10'), 'value' : 0.5, } super().__init__() - wri = CWriter(ssd, arial10, GREEN, BLACK, verbose=False) + wri = CWriter(ssd, font, GREEN, BLACK, verbose=False) col = 2 row = 2 - dc = 45 # Note: callback runs now, but other sliders have not yet been instantiated. self.s0 = Slider(wri, row, col, callback=self.slider_cb, **args) - col += dc + col = self.s0.mcol + 2 self.s1 = Slider(wri, row, col, **args) - col += dc + col = self.s1.mcol + 2 self.s2 = Slider(wri, row, col, **args) CloseButton(wri) diff --git a/gui/demos/screen_change.py b/gui/demos/screen_change.py index e766506..f4b02d2 100644 --- a/gui/demos/screen_change.py +++ b/gui/demos/screen_change.py @@ -12,7 +12,7 @@ from gui.widgets.label import Label from gui.core.writer import CWriter # Font for CWriter -import gui.fonts.font10 as font10 +import gui.fonts.arial10 as font from gui.core.colors import * # Defining a button in this way enables it to be re-used on @@ -22,11 +22,11 @@ def fwdbutton(wri, row, col, cls_screen, text='Next'): def fwd(button): Screen.change(cls_screen) # Callback - Button(wri, row, col, height = 30, callback = fwd, + Button(wri, row, col, callback = fwd, fgcolor = BLACK, bgcolor = GREEN, - text = text, shape = RECTANGLE, width = 100) + text = text, shape = RECTANGLE) -wri = CWriter(ssd, font10, GREEN, BLACK, verbose=False) +wri = CWriter(ssd, font, GREEN, BLACK, verbose=False) # This screen overlays BaseScreen. class BackScreen(Screen): diff --git a/gui/demos/simple.py b/gui/demos/simple.py index 37003f8..ca69222 100644 --- a/gui/demos/simple.py +++ b/gui/demos/simple.py @@ -29,7 +29,7 @@ class BaseScreen(Screen): col = 2 row = 2 Label(wri, row, col, 'Simple Demo') - row = 20 + row = 50 Button(wri, row, col, text='Yes', callback=my_callback, args=('Yes',)) col += 60 Button(wri, row, col, text='No', callback=my_callback, args=('No',)) diff --git a/gui/demos/tbox.py b/gui/demos/tbox.py index 5bb54ca..5a09367 100644 --- a/gui/demos/tbox.py +++ b/gui/demos/tbox.py @@ -21,13 +21,13 @@ from gui.widgets.buttons import Button, CloseButton wri = CWriter(ssd, arial10, verbose=False) -def fwdbutton(wri, row, col, cls_screen, width, text='Next'): +def fwdbutton(wri, row, col, cls_screen, text='Next'): def fwd(button): Screen.change(cls_screen) - Button(wri, row, col, height = 20, width = width, + b = Button(wri, row, col, callback = fwd, fgcolor = BLACK, bgcolor = GREEN, text = text, shape = RECTANGLE) - return width + return b.mrow async def wrap(tb): @@ -53,7 +53,7 @@ async def clip(tb): # Args for textboxes # Positional -pargs = (2, 2, 124, 7) # Row, Col, Width, nlines +pargs = (2, 2, 100, 7) # Row, Col, Width, nlines # Keyword tbargs = {'fgcolor' : YELLOW, @@ -103,10 +103,10 @@ class MainScreen(Screen): super().__init__() Label(wri, 2, 2, 'Select test to run') col = 2 - row = 60 - col += fwdbutton(wri, row, col, TBWScreen, 50, 'Wrap') + 10 - col += fwdbutton(wri, row, col, TBCScreen, 50, 'Clip') + 10 - fwdbutton(wri, row, col, TBUScreen, 50, 'Scroll') + row = 20 + row = fwdbutton(wri, row, col, TBWScreen, 'Wrap') + 2 + row = fwdbutton(wri, row, col, TBCScreen, 'Clip') + 2 + fwdbutton(wri, row, col, TBUScreen, 'Scroll') CloseButton(wri) diff --git a/gui/widgets/dialog.py b/gui/widgets/dialog.py index 8b0efac..e67b576 100644 --- a/gui/widgets/dialog.py +++ b/gui/widgets/dialog.py @@ -24,7 +24,7 @@ class DialogBox(Window): callback(Window, *args) height = 80 - spacing = 10 + spacing = 5 buttonwidth = max(max(writer.stringlen(e[0]) for e in elements) + 14, buttonwidth) buttonheight = max(writer.height, 15) nelements = len(elements) diff --git a/hardware_setup.py b/hardware_setup.py index df02c1b..5e4bd58 100644 --- a/hardware_setup.py +++ b/hardware_setup.py @@ -1,54 +1,60 @@ -# ili9341_pico.py Customise for your hardware config +# st7735r144_setup.py For my PCB with 1.44 inch 128*128 TFT Customise for your hardware config # Released under the MIT License (MIT). See LICENSE. -# Copyright (c) 2021 Peter Hinch +# Copyright (c) 2020 Peter Hinch # As written, supports: -# ili9341 240x320 displays on Pi Pico -# Edit the driver import for other displays. +# Adfruit 1.44 inch Color TFT LCD display with MicroSD Card Breakout: +# https://www.adafruit.com/product/2088 -# Demo of initialisation procedure designed to minimise risk of memory fail -# when instantiating the frame buffer. The aim is to do this as early as -# possible before importing other modules. +# WIRING (Adafruit pin nos and names). +# Pyb SSD +# Gnd Gnd +# 3V3 Vcc +# Y11 RESET +# Y12 D/C +# W32 TFT_CS +# Y8 MOSI +# Y6 SCK +# Vin LITE (10) Backlight -# WIRING -# Pico Display -# GPIO Pin -# 3v3 36 Vin -# IO6 9 CLK Hardware SPI0 -# IO7 10 DATA (AKA SI MOSI) -# IO8 11 DC -# IO9 12 Rst -# Gnd 13 Gnd -# IO10 14 CS +# Switch wiring +# X1 Next +# X2 Sel +# X3 Prev +# X4 Increase +# X5 Decrease -# Pushbuttons are wired between the pin and Gnd -# Pico pin Meaning -# 16 Operate current control -# 17 Decrease value of current control -# 18 Select previous control -# 19 Select next control -# 20 Increase value of current control - -from machine import Pin, SPI, freq +import machine import gc -from drivers.ili93xx.ili9341 import ILI9341 as SSD -freq(250_000_000) # RP2 overclock -# Create and export an SSD instance -pdc = Pin(8, Pin.OUT, value=0) # Arbitrary pins -prst = Pin(9, Pin.OUT, value=1) -pcs = Pin(10, Pin.OUT, value=1) -spi = SPI(0, baudrate=30_000_000) -gc.collect() # Precaution before instantiating framebuf -ssd = SSD(spi, pcs, pdc, prst, usd=True) +from machine import Pin, SPI +import gc +import time +from drivers.st7735r.st7735r144_4bit import ST7735R as SSD +pp = Pin('EN_3V3') +pp(1) +time.sleep(1) + +pdc = Pin('Y12', Pin.OUT_PP, value=0) +pcs = Pin('W32', Pin.OUT_PP, value=1) +prst = Pin('Y11', Pin.OUT_PP, value=1) +spi = SPI(2, baudrate=6_000_000) +gc.collect() # Precaution before instantiating framebuf +ssd = SSD(spi, pcs, pdc, prst) # Create a display instance from gui.core.ugui import Display + # Create and export a Display instance # Define control buttons -nxt = Pin(19, Pin.IN, Pin.PULL_UP) # Move to next control -sel = Pin(16, Pin.IN, Pin.PULL_UP) # Operate current control -prev = Pin(18, Pin.IN, Pin.PULL_UP) # Move to previous control -increase = Pin(20, Pin.IN, Pin.PULL_UP) # Increase control's value -decrease = Pin(17, Pin.IN, Pin.PULL_UP) # Decrease control's value +nxt = Pin(Pin.board.X5, Pin.IN, Pin.PULL_UP) # Move to next control +sel = Pin(Pin.board.X1, Pin.IN, Pin.PULL_UP) # Operate current control +prev = Pin(Pin.board.X4, Pin.IN, Pin.PULL_UP) # Move to previous control +increase = Pin(Pin.board.X2, Pin.IN, Pin.PULL_UP) # Increase control's value +decrease = Pin(Pin.board.X3, Pin.IN, Pin.PULL_UP) # Decrease control's value display = Display(ssd, nxt, sel, prev, increase, decrease) + + + + +