-
Posts
2,639 -
Joined
-
Last visited
-
Days Won
2
-
Definitely on the ToDo list to check this out. Have to get the v2.10 release out first tho (pretty much done at this point).
-
Does that mean your patch changes font rendering (the actual painting) to use gdispGStreamStart(), gdispGStreamColor() and gdispGStreamStop()? And then on top of that giving gdispGStreamColor() an additional "count" parameter? Apologies if I'm way off here - totally buried at the moment.
-
We had a short internal discussion about this. We'll gladly have a look at your patch but we'll need a bit more time as we're quite busy at the moment. In general, we're quite keen on this additional/improvement if it is not restrictive to a particular type of driver.
-
Woah - that is awesome - good work! Is this the default dashboard for all BELAZ trucks or is this a retrofit that you're offering? If you like you can "showcase" your project in the "User Projects" section of this forum. That is always appreciated: https://community.ugfx.io/forum/6-user-projects/
-
You seem to have been patient with me.... thank you In your initial post you mentioned that the problem you're encountering happens when changing pages. Is this by any chance related to this?
-
Don't hesitate to ask if you have any other questions
-
Joel Bodenmann started following Pressed and unpressed Buttons , FillString flicker , RA8875 on Cube IDE and 1 other
-
Hello & welcome to the µGFX community! This is a common issue with graphics rendering not only specific to font rendering. Common solutions include: Render the entire element before pushing it to the framebuffer. In µGFX terms that would mean rendering into a pixmap and then blitting to the real display. Using global double buffering: You render to an off-screen buffer and once your rendering operation(s) are complete you swap the display's framebuffer. I'll need some time to get back to this as it has been a while since I was last digging in the internals of font rendering. One thing that comes to mind is that fillarea() tends to be a fast operation as this is an operation commonly supported by hardware acceleration. If you can propose a patch that handles the kerning issue I'd be more than happy to look into it.
-
Hello & Welcome to the µGFX community! The µGFX library can be integrated into an existing project through four different mechanisms: CMake Makefile Single-File-Include Manually adding all files the old fashioned way See https://wiki.ugfx.io/index.php/Getting_Started for more information STM32 CubeMX allows to generate projects using either Makefile or CMake - the latter being a very recent addition. I'd recommend that you get a basic project up and running without including µGFX to make sure that your environment & tooling are working as expected. Once you have a working project, you can include the µGFX library using any of the available mechanisms. In your case that will most likely be via Makefiles. Don't hesitate to ask if you have any questions. We're happy to help wherever we can.
-
Have a look at the command(s) passed to the compiler to verify that STM32LTDC_USE_DMA2D=GFXON is being passed as expected. This should definitely work (both based one existing customer projects as well as a quick test on our end).
-
Just had a quick look and the STM32LTDC_USE_DMA2D define/setting seems to work as intended. Firstly, make sure that you define STM32LTDC_USE_DMA2D as GFXON (i.e. not just defining it, but also assigning the value to it). Secondly, have you tried setting STM32LTDC_USE_DMA2D to GFXON in your build system (makefile, cmake, ...) instead of gfxconf.h?
-
Happy to hear that you have the STM32LTDC driver up and running The hardware accelerated area filling is handled by the DMA2D peripheral. From the µGFX side of things, the only thing you have to do is setting `STM32LTDC_USE_DMA2D` define to `GFXON`. More information regarding the STM32LTDC driver can be found in the corresponding driver readme: https://git.ugfx.io/uGFX/ugfx/src/branch/master/drivers/gdisp/STM32LTDC/readme.md Note: We strongly recommend that you use the latest master branch of the official µGFX v2.x git repository if you're using the LTDC driver. It has been reworked/improved substantially since the last official release.
-
Here's a simple example which demonstrates the concept: It has three different pages and a menubar which is always visible. The pages contain buttons to switch to different pages. I intentionally kept this very simple when it comes to managing the handles, display pages and events processing. A real application would likely introduce a new type/structure for a display page as well as a controller which can handle any number of display pages. Furthermore, you'd typically setup a more generic way of handling "switch to display page N" events so you don´t have that ugly per-button logic. Example: #include <gfx.h> #define MENUBAR_HEIGHT 30; // Menu bar (always visible) GHandle ghMenubar; // Display page 0 GHandle ghPage0; GHandle ghPage0_Label; GHandle ghPage0_ButtonA; GHandle ghPage0_ButtonB; GHandle ghPage0_ButtonGotoPage1; GHandle ghPage0_ButtonGotoPage2; // Display page 1 GHandle ghPage1; GHandle ghPage1_Label; GHandle ghPage1_ButtonGotoPage0; // Display page 2 GHandle ghPage2; GHandle ghPage2_Label; GHandle ghPage2_ButtonGotoPage0; GHandle ghPage2_ButtonGotoPage1; static void createWidgets() { GWidgetInit wi; // Menubar { gwinWidgetClearInit(&wi); // Menubar wi.g.show = TRUE; wi.g.width = gdispGetWidth(); wi.g.height = MENUBAR_HEIGHT; wi.g.x = 0; wi.g.y = 0; wi.text = "MenuBar - Always visible!"; ghMenubar = gwinLabelCreate(0, &wi); } // Display page 0 { gwinWidgetClearInit(&wi); // Page container wi.g.show = FALSE; wi.g.width = gdispGetWidth(); wi.g.height = gdispGetHeight() - MENUBAR_HEIGHT; wi.g.y = MENUBAR_HEIGHT; wi.g.x = 0; wi.text = "Display Page 1"; ghPage0 = gwinContainerCreate(0, &wi, GWIN_CONTAINER_BORDER); wi.g.show = TRUE; // Label wi.g.width = 100; wi.g.height = 30; wi.g.x = 10; wi.g.y = 10; wi.text = "Page 0"; wi.g.parent = ghPage0; ghPage0_Label = gwinLabelCreate(0, &wi); // Button A wi.g.width = 180; wi.g.height = 30; wi.g.x = 50; wi.g.y = 50; wi.text = "Button A"; wi.g.parent = ghPage0; ghPage0_ButtonA = gwinButtonCreate(0, &wi); // Button B wi.g.width = 180; wi.g.height = 30; wi.g.x = 50; wi.g.y = 100; wi.text = "Button B"; wi.g.parent = ghPage0; ghPage0_ButtonB = gwinButtonCreate(0, &wi); // Button GotoPage1 wi.g.width = 180; wi.g.height = 30; wi.g.x = 50; wi.g.y = 150; wi.text = "Goto Page 1"; wi.g.parent = ghPage0; ghPage0_ButtonGotoPage1 = gwinButtonCreate(0, &wi); // Button GotoPage1 wi.g.width = 180; wi.g.height = 30; wi.g.x = 50; wi.g.y = 200; wi.text = "Goto Page 2"; wi.g.parent = ghPage0; ghPage0_ButtonGotoPage2 = gwinButtonCreate(0, &wi); } // Display page 1 { gwinWidgetClearInit(&wi); // Page container wi.g.show = FALSE; wi.g.width = gdispGetWidth(); wi.g.height = gdispGetHeight() - MENUBAR_HEIGHT; wi.g.y = MENUBAR_HEIGHT; wi.g.x = 0; wi.text = "Display Page 1"; ghPage1 = gwinContainerCreate(0, &wi, GWIN_CONTAINER_BORDER); wi.g.show = TRUE; // Label wi.g.width = 100; wi.g.height = 30; wi.g.x = 10; wi.g.y = 10; wi.text = "Page 1"; wi.g.parent = ghPage1; ghPage1_Label = gwinLabelCreate(0, &wi); // Button GotoPage1 wi.g.width = 180; wi.g.height = 30; wi.g.x = 50; wi.g.y = 150; wi.text = "Goto Page 0"; wi.g.parent = ghPage1; ghPage1_ButtonGotoPage0 = gwinButtonCreate(0, &wi); } // Display page 2 { gwinWidgetClearInit(&wi); // Page container wi.g.show = FALSE; wi.g.width = gdispGetWidth(); wi.g.height = gdispGetHeight() - MENUBAR_HEIGHT; wi.g.y = MENUBAR_HEIGHT; wi.g.x = 0; wi.text = "Display Page 2"; ghPage2 = gwinContainerCreate(0, &wi, GWIN_CONTAINER_BORDER); wi.g.show = TRUE; // Label wi.g.width = 100; wi.g.height = 30; wi.g.x = 10; wi.g.y = 10; wi.text = "Page 2"; wi.g.parent = ghPage2; ghPage2_Label = gwinLabelCreate(0, &wi); // Button GotoPage0 wi.g.width = 180; wi.g.height = 30; wi.g.x = 50; wi.g.y = 150; wi.text = "Goto Page 0"; wi.g.parent = ghPage2; ghPage2_ButtonGotoPage0 = gwinButtonCreate(0, &wi); // Button GotoPage1 wi.g.width = 180; wi.g.height = 30; wi.g.x = 50; wi.g.y = 150; wi.text = "Goto Page 1"; wi.g.parent = ghPage2; ghPage2_ButtonGotoPage1 = gwinButtonCreate(0, &wi); } } static void showPage(const unsigned idx) { // Hide all gwinHide(ghPage0); gwinHide(ghPage1); gwinHide(ghPage2); // Show switch (idx) { case 0: gwinShow(ghPage0); break; case 1: gwinShow(ghPage1); break; case 2: gwinShow(ghPage2); break; default: break; } } static GListener gl; int main() { // Initialize µGFX gfxInit(); // Setup widgets stuff gwinSetDefaultFont(gdispOpenFont("*")); gwinSetDefaultStyle(&WhiteWidgetStyle, FALSE); gdispClear(White); // Create widgets createWidgets(); // Listen for widget events geventListenerInit(&gl); gwinAttachListener(&gl); // Show first page showPage(0); while (1) { GEvent* evt; // Process events evt = geventEventWait(&gl, TIME_INFINITE); switch (evt->type) { case GEVENT_GWIN_BUTTON: { GHandle button = (GHandle)((GEventGWinButton*)evt)->gwin; // Goto Page 0 if (button == ghPage1_ButtonGotoPage0 || button == ghPage2_ButtonGotoPage0) showPage(0); // Goto Page 1 else if (button == ghPage0_ButtonGotoPage1 || button == ghPage2_ButtonGotoPage1) showPage(1); // Goto Page 2 else if (button == ghPage0_ButtonGotoPage2) showPage(2); break; } } } }
-
Hey, While I haven't studied your code yet: The way you'd typically do this is to have one container per "display page" which you use as the parent for any widget inside of that page. This allows you to show different display pages containing different UI elements / widgets. From what I can tell, you already have that up and running. Then you simply hide all display pages except for the one you want to be visible. The GWIN module should take care of enabling/disabling widget visibility, events etc for you. Whether or not you create/destroy the various display pages dynamically or whether you have enough memory to keep them around is an implementation detail. With the above, I do think that this is the correct approach. What leads you to believe that maybe it isn't? I'll try to find some time to create a simple, minimal example.
-
Yes, this is generally possible. The basic concept consists of: Using gdispGetDisplay() to get the two buffers Using gdispControl() / gdispGControl() to tell the driver which buffer to show (i.e. when to swap buffers) Using the various 'G' prefixed versions of the GDISP rendering API (or setting the currently active GDISP globally whenever you swap) Note that this requires implementing this capability in your corresponding GDISP driver. Look at the STM32LTDC driver in the current master branch. It supports double buffering the same way (i.e. the display controller provides more than one buffer and µGFX simply switches from one to the other): https://git.ugfx.io/uGFX/ugfx/src/branch/master/drivers/gdisp/STM32LTDC The readme in there might be useful too. Actually using it would look like this: #include "gfx.h" static GDisplay* _display1; static GDisplay* _display2; // Requests a buffer swap on the driver level static void _setActiveBuffer(GDisplay* g) { gdispGControl(g, STM32LTDC_CONTROL_SHOW_BUFFER, NULL); } int main(void) { // Initialize uGFX library gfxInit(); // Get the two buffers _display1 = gdispGetDisplay(0); if (!_display1) gfxHalt("could not get display 1"); _display2 = gdispGetDisplay(1); if (!_display2) gfxHalt("could not get display 2"); // Render to each buffer gdispGClear(_display1, GFX_BLUE); gdispGClear(_display2, GFX_RED); // Switch between buffers while (gTrue) { gfxSleepMilliseconds(800); _setActiveBuffer(_display1); gfxSleepMilliseconds(800); _setActiveBuffer(_display2); } return 0; }
-
Unfortunately, there is no way around modifying both src/gdisp/gdisp_driver.h and src/gdisp/gdisp.c You can either maintain a patch yourself for subsequent updates of the µGFX library or consider contributing changes to back so they'll be incorporated