High level GUI lib/framework

All ESP32 boards running MicroPython.
Target audience: MicroPython users with an ESP32 board.
rogierlodewijks
Posts: 5
Joined: Sat Jul 15, 2017 7:13 pm

High level GUI lib/framework

Post by rogierlodewijks » Sun Nov 18, 2018 8:46 pm

Hi fellow MicroPythonians,

I'm in the process of planning/building an app for a device that boasts a GUI (320x240 TFT) and has mostly button-driven inputs. It uses Micropython for its main application logic. I really like the full-featuredness of uP and especially the availability of the async functionality is great! This together with the support for my platform of choice (ESP32 + pSRAM) made going for uP a no-brainer.

I am pretty used to and confident writing embedded C code. If have not yet made a native (C) uP module, but I'm certainly not shying away from writing some supporting modules or device drivers in C (planning to do so when needed).

For the GUI part however, this is a bit more complex:

Performance really matters here (shoving a lot of data), so having a fast native module is essential IMO. I'd like to have a somewhat pleasant development experience, so the goal is to have a high(er) level GUI api available in uP. I'm not looking (only) for the lower level routines i.e. a raw framebuffer or some loose line/circle/fill methods.

I found two interesting libs/frameworks that probably would do the job (possibly with some modifications): uGIO from Achim Doebler (https://github.com/achimdoebler/UGUI) and GUISlice (https://github.com/ImpulseAdventure/GUIslice). The latter being the more comprehensive.

Both are written in pure C and it should be relatively easy to get going on the ESP32 (GUISlice even has "official" support for the ESP32 platform!)

As both modules model a GUI, they tend to use OO programming paradigms, with lots of C structs etc. And have a relatively large code base (compare to for instance a simple driver).

My question is:

How would you go about wrapping one of these libs up in a uP module whilst fitting the C object model as neatly as possible into uP?
e.g. having "Window", "button" and "Textbox" classes in uP, that more more less map directly map onto the objects in the C libs. Would this be possible without essentially (re)building the full GUI object model in uP (and as a result only having a low level graphics driver left over in native C code)?

User avatar
mattyt
Posts: 233
Joined: Mon Jan 23, 2017 6:39 am

Re: High level GUI lib/framework

Post by mattyt » Mon Nov 19, 2018 5:43 am

I've also been looking at GUI framework options for MicroPython. There are a number of C UI libraries that could be leveraged but I'm hoping to write most of the code in MicroPython itself. The SPI comms to most display drivers is already fast in MicroPython and manipulating pixels in framebuffers should also be relatively efficient. Need to measure it obviously but I want to drop into C only if measurements dictate that it's necessary.

Worth noting that Adafruit are cooking up something; their upcoming version of CircuitPython adds a displayio module though it's not clear what they're intending to do with it yet...

Other libraries of interest: Peter Hinch's micropython-nano-gui. Loboris' display module (needs his LoBo MicroPython fork). As well as uGIO and GUISlice there's also cfGUI and littlevGL in the C-space.

I've already started building some basic menu widgets and a progress bar but this is all still quite experimental and built on top of Loboris' display module. When it becomes a little more mature I will share the code!
IMG_5784 (Phone).JPG
IMG_5784 (Phone).JPG (25.17 KiB) Viewed 2305 times

User avatar
pythoncoder
Posts: 3503
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: High level GUI lib/framework

Post by pythoncoder » Mon Nov 19, 2018 11:05 am

In addition to nano GUI there is also this for SSD1963 displays and this for official LCD160cr.

The first is for OLED displays and is output only as these lack a touch overlay. The other two are touchscreen interfaces. As a general point it is possible to achieve decent responsiveness in Python, although the SSD1963 driver for large displays employs advanced techniques courtesy of @Robert_hh who contributed the low level driver code.

My point here is not to promote these drivers which may not match your intended use case but to suggest that using C may be unnecessary.
Peter Hinch

rogierlodewijks
Posts: 5
Joined: Sat Jul 15, 2017 7:13 pm

Re: High level GUI lib/framework

Post by rogierlodewijks » Wed Nov 21, 2018 8:50 am

Thanks for the replies! Bit off topic but, I have to say it: one of the reasons for coming to uP is the vibrant community with some very nice and active people. It always thrills me seeing open source working in the wild!

Anyways, thanks for the handles regarding the UI.. now I have even more options to consider.. ;)
Does anyone happen to know if any of the given GUI-options work nicely together with an async/await-based application (i.e. implements the IO async, or push off to a thread where the heavy work is done in background)?

Part of my question was, although it probably deserves its own topic on the forum, how to integrate C modules/libs that use a lot of OO-style C coding. With OO-style I mean with a lot of structs pointing to other structs, to which one would like to have a nice representation mirrored in Python objects.

Maybe there are some good examples showing this already (probably in the GUI space?) of which the code can be studied (any suggestions)? IMO the whole C modules "advanced" uP topic is a bit underexposed in the documentation. For those of you who're reading along, I found this talk from Nick Moore in regards to how a C module is made highly enlightening, recommended!

rogierlodewijks
Posts: 5
Joined: Sat Jul 15, 2017 7:13 pm

Re: High level GUI lib/framework

Post by rogierlodewijks » Wed Nov 21, 2018 10:23 am

@mattyt I would be interested in your library (on top of Loboris's), as it looks like the kind of UI I would be making (3-button type).
I've already started building some basic menu widgets and a progress bar but this is all still quite experimental and built on top of Loboris' display module. When it becomes a little more mature I will share the code!
Hey, don't be shy it's never too early to share code on github! :D

Btw. I'd would probably just (try to) extract the display driver from LoBo's port to include it in either mainline or the pfalcon uP port. as they support pSRAM now and seem more stable and are less a "one man show" than the LoBo port. I also have my doubts on development process and stability (I see a lot of issues like this: "Hey, in version x.y I suddenly get a coredump when starting xyz").

OutoftheBOTS_
Posts: 627
Joined: Mon Nov 20, 2017 10:18 am

Re: High level GUI lib/framework

Post by OutoftheBOTS_ » Wed Nov 21, 2018 10:25 am

Slightly off topic but related.

Lately I have been making UI using the this https://github.com/jczic/MicroWebSrv with websockets. I basically make a HTML page that is served up that has Javascript with the UI then any needed output from the UI is sent back to the ESP32 via a websocket. The Websocket has a callback on the ESP32. Sometimes I use this call back to run code but most of the time I mainly just use it to alter global variables that I use in my main program.

This way my GUI is on my tablet in my hand and it is wireless to the project.

User avatar
mattyt
Posts: 233
Joined: Mon Jan 23, 2017 6:39 am

Re: High level GUI lib/framework

Post by mattyt » Wed Nov 21, 2018 2:52 pm

You might also want to check out a presentation Damien gave at our MicroPython Meetup back in June: Wrap a C module in MicroPython. I'm pressing him to do a follow-up that would explain more about how to neatly push data across the C/MicroPython boundary (it's not obvious how you'd allow keyword arguments to appear on the C side for example).

Best advice right now is to take a look at one of the APIs that's sort-of like what you need and copy it as a starting point. Documentation for C module development will come but perhaps not quickly!

I will release the code soon, but it's so immature and in flux at the moment I don't want to let it out in case someone starts using it! Give me a little while longer to figure out how I want to make it work... :)

I did start with mainline and a driver (Jeff Mer's, though I looked at Deshipu's too) but the LoBo fork had more primitives that I wanted. Shouldn't be too hard to replace later.

And yeah, it's fantastic that Boris is ripping into implementing stuff quickly but mainline should be stable and it's ok to move a little slower.

User avatar
Mike Teachman
Posts: 69
Joined: Mon Jun 13, 2016 3:19 pm
Location: Victoria, BC, Canada

Re: High level GUI lib/framework

Post by Mike Teachman » Wed Nov 21, 2018 3:01 pm

rogierlodewijks wrote:
Wed Nov 21, 2018 8:50 am
IMO the whole C modules "advanced" uP topic is a bit underexposed in the documentation.
Something related that might be useful to those writing modules in C.... As part of my learning how to write uPy modules in C I wrote a C file providing examples of the patterns used to map uPy calls to C, for both module functions and class methods.

https://github.com/MikeTeachman/MicroPy ... examples.c

This file can be compiled into a build. I developed it on the ESP32/Lobo port, but I expect it will work for all uPy ports.

Each example shows:
  • uPy interface to the function or method, with all positional and keyword argument variants
  • C implementation with uPy<->C bindings
Sample ....

Code: Select all

// Method Example 3:
//      variable number of positional arguments, specified by min and max,
//      NOTE: for a method call, MIN_NUM_METHOD_ARGS must never be zero
//
//      class Argex:
//          m_min_max(self, [pos1]):
//
//      from argex import Argex
//      a = Argex(True, 7)
//      a.m_min_max()
//      a.m_min_max(False)

#define MIN_NUM_METHOD_ARGS (1)  // self
#define MAX_NUM_METHOD_ARGS (2)  // self + one Optional positional argument
STATIC mp_obj_t method_min_max_args(size_t n_args, const mp_obj_t *args) {
    argex_obj_t *self = MP_OBJ_TO_PTR(args[0]);

    // important notes:
    //      'n_args' refers to the count of positional args, and +1 for the class instance self
    printf("n_args = %u\n", n_args);

    if (n_args == 1) {
        // when n_args equals 1 it means that ONLY argument passed is the class instance self
        return mp_obj_new_int(self->var1);
    } else {
        self->var1 = mp_obj_get_int(args[1]);
        return mp_const_none;
    }
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(method_min_max_args_obj, MIN_NUM_METHOD_ARGS, MAX_NUM_METHOD_ARGS, method_min_max_args);

User avatar
mattyt
Posts: 233
Joined: Mon Jan 23, 2017 6:39 am

Re: High level GUI lib/framework

Post by mattyt » Sat Nov 24, 2018 11:06 pm

Mike Teachman wrote:
Wed Nov 21, 2018 3:01 pm
rogierlodewijks wrote:
Wed Nov 21, 2018 8:50 am
IMO the whole C modules "advanced" uP topic is a bit underexposed in the documentation.
Something related that might be useful to those writing modules in C.... As part of my learning how to write uPy modules in C I wrote a C file providing examples of the patterns used to map uPy calls to C, for both module functions and class methods.

https://github.com/MikeTeachman/MicroPy ... examples.c
This is a fantastic resource, thanks Mike! Just what I needed. :)

User avatar
pythoncoder
Posts: 3503
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: High level GUI lib/framework

Post by pythoncoder » Sun Nov 25, 2018 8:10 am

rogierlodewijks wrote:
Wed Nov 21, 2018 8:50 am
...
Does anyone happen to know if any of the given GUI-options work nicely together with an async/await-based application (i.e. implements the IO async, or push off to a thread where the heavy work is done in background)?...
The three GUI's I wrote and cited above are based on uasyncio.
Peter Hinch

Post Reply