P2GUI framework
Hello all!
For the past few months I've been developing a gui framework for the ILI9341 TFTs (240x320) based on a library I created for Arduino several years back, since I have a few of these displays laying around that I normally use for some projects. I was so fortunate to find out that @Cluso99, @mwroberts, @"Greg LaPolla" and @ManAtWork have developed a driver for the P2 that also included a touchscreen driver for the XPT2046, which coincidentally is the controller used on my screens. With the latest modifications by @ManAtWork I could adapt the driver to fit the requirements of my framework.
The framework is functional enough to develop applications that require the use of one of these TFT's. However it is still in development so somethings might need to be modified down the road as I learn more about Propeller 2, Spin2 and PASM2. The framework was developed in PropellerTool but I have been cross-testing it in FlexProp. As of today, it mostly works in FlexProp although some things still need more troubleshooting.
The framework implements several workarounds to overcome some of the limitations of the Spin2 language when compared with the capabilities of C++ (which was used for the original Arduino project), since there is no concept of classes/inheritance. As I learn more about Spin2 and PASM2 I might be able to improve on these. Some of these workaround turned into idiosyncrasies that I am documenting in a GDocs document as I go.
Currently the framework provides an implementation for the following widgets:
- Button - Momentary or toggle button
- Icon Button - A button whose visual representation is an image
- Text Display - A gui element to display text or a value
- Multiline Display - A gui element to display several lines of text separated by new line character (10)
- Image - A gui element to display an image
- Trend Control - A gui element to plot an array of values with some controls for examining data
- Gauge Indicator - Vertical bar value indicator
- Dial Indicator - Radial value indicator
- Numbers Keypad - keypad to enter integer values
Additional widgets can be created from scratch or might be compounded into one widget (Trend Control).
P2GUI also uses screen objects that act as containers of other widgets and can also be contained within the main GUI object. This allows for an application to have multiple screens and implement other type of gui elements such as a menu or pop-up.
The GUI object also implements a screen saver functionality to clear the screen after a period of time without detecting touch events.
Application functionality is implemented in two places: main loop and event handlers. In your main loop program you must invoke gui's scan() method. This method will catch any touch event and will pass it down to any child widgets or screens it contains. Every screen will also pass the event down to its widgets. Events will then be handled by the widgets. To handle an event you must register an event handler for each widget that requires a touch event. You then add your application logic inside each event handler.
P2GUI is a work in progress and I hesitated to bring it out to the community, but I realized that it will never be complete enough for my own expectations and I don't really have all the time in the world to dedicate to it. I will be happy if it turns out to be useful to anyone else. Also I'm open for suggestions for improvements.
Releases:
v0.2.0 https://github.com/jrullan/P2GUI/releases
Comments
Nice work!
I was able to get it running on a "generic" AliExpress-purchased 3.2 TFT SPI 240X320 V1.0 LCD display... I did have to modify the detects_valid_touch() function of LCD Graphics Driver.spin2. This particular display's interface returned a flipped X touch coordinate. So, I had to subtract the X value from the screen width (240) to get a proper X coordinate. I also modified Numkey.spin2 to get ">" to show up correctly (it is $3E, not $3C)...
Thanks!
dgately
I'm glad it worked for you! Thanks for testing it and for providing feedback.
@jrullan Looks good! A GUI framework should be very useful to operate "stand alone" device that require more than just pushing one or two buttons.
I thought that flipping the coordinate system to get the right orientation would already be handled by using the calibration functions for the touch screen. It calculates a gain and an offset values for each coordinate of two test points. If the sign is flipped gain becomes negative. So Get_TS_XY() should return the calibrated, correct orientation even if the raw data is flipped. That didn't work?
Thank you @ManAtWork for the improvements made recently on the driver.
I think I didn't expose the calibration method on the main GUI object. I will have to check on this and update it. Also I need to figure out how to add support for other touchscreen chipsets that I remember I had to support on my Arduino version (STMPE610 and FT6206).
@dgately
I just updated the initialization of the Gui object:
gui.set_TFT_pins()
andgui.set_TS_pins()
gui.init()
to invoke the calibration routine of the driver (There's a debug statement to show the values for your display, so you can use those values inGUI.configure_display()
)In the demonstration application:
Figured out what happened. My guess is you used FlexProp. It had an issue with using two ternary operators consecutively. Fixed it by adding parenthesis. In PropTool it worked ok. (Btw, $3C is a left arrow, indicating backspace to delete the last digit entered).
Has anyone tried using the image converter ? It seems to be a rabbit hole. The more I fix the more it breaks.
@"Greg LaPolla" the image converter is a Processing sketch. I used version 3.5. You can download it from processing.org/releases.
(Sorry I didn't answer before, I was on vacations and hasn't been around here in a couple of months)
I have now published a pre-release version 0.1.0 in github.
This shall be the base release.
https://github.com/jrullan/P2GUI/releases
That's just so darn cool @jrullan !
I have a use case that requires interacting with the UI without using the touchscreen. These videos show a rough draft of a modified version of the framework that is totally controlled using only the encoder. The touchscreen isn't even enabled in this version. It is a proof of concept still but looks promising for non-touch enabled HMI applications using Propeller 2.
In this test example there is a navigation bar at the top to change between two screens. The first one has a trend widget, a dial widget and a text display widget. There is also a non-functional button at the bottom of the screen to test focus changes between container (gui) and subcontainers (screen). There is also another screen, for now empty and with a different background color, this one is white. The left button at the top shows the first screen and the right button shows the second screen. The dial has an event handler method assigned that adds the selected value on the dial to the trend and updates the trend.
https://youtube.com/shorts/X16Al9t70ME
and
https://youtube.com/shorts/VAigncCvLz0
@jrullan Have you done much testing in landscape mode ? I am trying to display a 320x240 image in landscape mode and it tries to load in portrait mode in the upper right hand corner.
I am currently working on an html tool to help develop the GUIs graphically. For now it helps create the .configure lines. Here's a Youtube video demonstrating. Eventually I would like it to create most of the application to speed up development with GUIs.
https://youtu.be/xDU5aIwZvp4
It has already been added to the github source.
@"Greg LaPolla" I'm mostly using it in Portrait mode but I thought I tested that some time ago. I'll look into it.
@"Greg LaPolla" I will test it more for sure later on, but with this quick test using the keyboard widget (which uses an image) it shows it correctly in Portrait and Landscape mode.:
I'm experimenting with a fork of the framework that uses an external encoder, instead of the touchscreen, as the only method of interaction. It occurs to me that there are many use cases where you would like to protect the screen behind a glass or clear plastic and the screen wont be able to detect the touch events. Also, these kind of displays are not very big and it could be difficult to press exactly the area of the screen you need to. The rotary encoder is much more precise and is reasonably fast to interact with the widgets.
Here is a demonstration of the interaction with most of the widgets so far.
Just added release 0.2.0 which now includes optimizations to the underlying driver using drawFastXLine and fillCircle methods. See link in first post.
@jrullan
I found a bug I think. You can only have 6 text widgets on a screen after 6 they don't display. I cant seem to find any code that limits it.