Jump to content

king2

Members
  • Posts

    117
  • Joined

  • Last visited

  • Days Won

    1

Everything posted by king2

  1. I have changed something, so see new file attached. added possibility to use custom or default color for underline and strikethrough (added 2 new flags) changed flags names (see gdisp.h) fixed bug where background was not saved properly Now we can change widget style, and underline/strikethrough color will be changed accordingly with that style. Sure, we still can override that colors with our own custom ones. rich_text.zip
  2. Edit: This is 'work in progress'. Make sure you read the entire thread to get the latest version of this feature I wanted to get strikethrough effect for some part of my label's text, so I made modification to gdisp.c (added approximately 200 lines of code) and want to share this with other people. As this code inserted into GDISP, this feature can be used in any text found in different widgets, like buttons, checkboxes, lists and so on. You can see results below on screenshot attached, different styles in one text in one label. Sorry for bad photo, I cannot make screenshot from my hardware . This styling was made by inserting special control characters into text (0xf000..0xf0ff, this is Unicode Private User Area, so we do not breaking anything). Each control character changes current style of all following characters. 0xf000 means default style, and others, means corresponding styles from 1 to 255. Each of style can set: change color of text or not and to which color fill text background or not and with which color underline or not, and with which color strikethrough or not and with which color To turn on this feature you should define GDISP_RICH_TEXT in your gfxconf.h. How it looks from developer side (copied directly from firmware shown above (assuming that UTF-8 sequence 0xEF 0x80 0x81 is Unicode character 0xF001): rich_text_style_t rich_text_styles[] = { { Red, White, Green, 0, RICH_TEXT_CHANGECOLOR | RICH_TEXT_UNDERLINED | RICH_TEXT_FILLBACKGROUND }, { Blue, Yellow, 0, Red, RICH_TEXT_CHANGECOLOR | RICH_TEXT_STRIKETHROUGH | RICH_TEXT_FILLBACKGROUND } }; rich_text_transition_t style_buffer[16]; gdispRichTextSetStyles((rich_text_style_t *) &rich_text_styles, sizeof(rich_text_styles), style_buffer, sizeof(style_buffer)); sprintf(datetime_str, "%02d.\xEF\x80\x81%02d.%04d\xEF\x80\x80 %02d:\xEF\x80\x82%02d\xEF\x80\x80:%02d", timp.tm_mday, timp.tm_mon+1, timp.tm_year+1900, timp.tm_hour, timp.tm_min, timp.tm_sec); We should declare styles array, space for transitions, and initialize the 'engine'. It will scan each text for control characters and will build special list of transitions, removing control characters from text string (one function declared, used in gdispGDrawString(), gdispGFillString(), gdispGDrawStringBox() and gdispGFillStringBox() + another one to just strip characters, used in gdispGetStringWidthCount()). Transitions list contains array of structs with style start position and number of style that will be applied from this position, for each transition that will be found in text flow. Next, in drawcharglyph() and fillcharglyph() callbacks one more function called, and applies these styles to characters painted on screen. Number of transitions is limited by amount of memory given by uGFX user, line length can be up to 65535 characters. Developer can define and use to 255 styles. I have attached patch files for gdisp.c and gdisp.h as well as modified files itself. It has extreme level of commenting inside, so I think it will be not so hard to understand what's going on under the hood. If you will find this patch useful enough, I will not resist too much from including this into uGFX core. What are you thinking about this? Will it be useful? rich_text.zip
  3. I see that gwinSetText() and gwinSetStyle() function do updates always, even if values was not changed. I have tried to make my own functions, like this: void my_gwinSetText(GHandle gh, const char *text) { if (strcmp(text, gwinGetText(gh))) gwinSetText(gh, text, TRUE); } void my_gwinSetStyle(GHandle gh, const GWidgetStyle *pstyle) { if (pstyle != gwinGetStyle(gh)) gwinSetStyle(gh, pstyle); } After this I got significant increasing of GUI speed, because no need to check everything around was it changed or not, and some of my code become more readable and simple. This eliminates needs to have status of each widget in code, and allow just to set styles and text how they should be, in one loop, without determining exact widgets that was changed. If you have many widget with same type, this helps a lot. I propose to include some #define like GDISP_CHECK_SET_VALUES in main uGFX function, to check if value was actually changed instead of updating value always (and redraw widget, with huge time overhead over this check). If user do not want value to be checked automatically, he always can not enable this check. What do you think about this?
  4. #define is a function of preprocessor, so compiler will see just one function called with different parameters. Which conditional pointer you are referring to? As I see from function definition, they uses almost same arguments, and differs by initialization of GDisplay structure and calling clip/fillarea only. Maybe compiler will optimize parts of code, but I'm not sure. But I'm sure that similar functions in code will make further development more complicated and add codesize overhead. Chained callback everywhere will make changes almost impossible not for authors of library
  5. But you can just use two #define with function with last parameter set to one or zero, for example (fill or not)!
  6. Going deeper and deeper into uGFX. Some question was born when looking on font engine sources. 1. mf_justify.c, mf_render_aligned(). Rendering string with left align is simple, center alignment is just left render with some shit by calculated coordinates, but right alignment is different, using different approach, drawing character from right to left, from end to start. Why not calculate shift as it was done for center alignment and use same routine? 2. gdispGDrawString() and gdispGFillString() differs only by one line, why using two separate functions instead of one? Same with other *Box functions? 3. How everything works (assume that everything is simple and we are not using word wrapping): somebody calls gdispGDrawString(), here we are starting gdisp.c: gdispGDrawString() from calls mf_render_aligned with drawcharglyph() as callback mf_justify.c: mf_render_aligned() calls render_left() (for example) with same drawcharglyph() as callback mf_justify.c: render_left() calls callback drawcharglyph() for each character, giving coordinates of character and character itself gdisp.c: drawcharglyph() calls mf_render_character() giving drawcharline() as callback, with same arguments mf_font.c: mf_render_character() calls font->render_character(), which is for example mf_bwfont_render_character() mf_bwfont.c: mf_bwfont_render_character() calls render_char() mf_bwfont.c: render_char() makes some magic inside, calling its callback drawcharline() from time to time gdisp.c: drawcharline() takes out of its pocket current color we are using and paints a one line many times, many lines, with blending or not wow, we have painted one character Am I right? Everything goes this way? To be honest, in place of compiler and MCU I would broke my brain in the middle of this chain. I will not ask why everything was done this way, but at least, have I understood all this right way? Thanks you in advance!
  7. I have used progressbar that refreshes very fast. I see on screen something like a snow instead of progressbar's border. Need to say I'm using progressbar with image. Yes, progressbar can use image instead of just plain fill color. Giong deeper in sources gave me a chance to understand whats going on: it just paints inactive area then draws an image over filled area, and then paints border. Chaning border color 3 times per refresh gives effect of snow because of TFT refreshes picture line by line and not-synced with progressbar refresh rate. I have changed some coordinates and everything started to work fine. Changed function included (gwin_progressbar.c): #if GDISP_NEED_IMAGE void gwinProgressbarDraw_Image(GWidgetObject *gw, void *param) { #define gsw ((GProgressbarObject *)gw) #define gi ((gdispImage *)param) const GColorSet * pcol; coord_t z, v; if (gw->g.vmt != (gwinVMT *)&progressbarVMT) return; if ((gw->g.flags & GWIN_FLG_SYSENABLED)) pcol = &gw->pstyle->enabled; else pcol = &gw->pstyle->disabled; // Vertical progressbar if (gw->g.width < gw->g.height) { if (gsw->dpos != 0) // The unfilled area gdispGFillArea(gw->g.display, gw->g.x+1, gw->g.y+1, gw->g.width-2, gsw->dpos-1, gw->pstyle->enabled.progress); // Inactive area if (gsw->dpos != gw->g.height-1) { // The filled area for(z=gw->g.height, v=gi->height; z > gsw->dpos;) { z -= v; if (z < gsw->dpos) { v -= gsw->dpos - z; z = gsw->dpos; } gdispGImageDraw(gw->g.display, gi, gw->g.x+1, gw->g.y+z+1, gw->g.width-1, v-2, 0, gi->height-v); } } gdispGDrawBox(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, pcol->edge); // Edge gdispGDrawLine(gw->g.display, gw->g.x+1, gw->g.y+gsw->dpos, gw->g.x+gw->g.width-2, gw->g.y+gsw->dpos, pcol->edge); // Thumb // Horizontal progressbar } else { if (gsw->dpos != gw->g.width-1) // The unfilled area gdispGFillArea(gw->g.display, gw->g.x+gsw->dpos+1, gw->g.y+1, gw->g.width-gsw->dpos-2, gw->g.height-2, gw->pstyle->enabled.progress); // Inactive area if (gsw->dpos != 0) { // The filled area for(z=0, v=gi->width; z < gsw->dpos; z += v) { if (z+v > gsw->dpos) v -= z+v - gsw->dpos; gdispGImageDraw(gw->g.display, gi, gw->g.x+z+1, gw->g.y+1, v-1, gw->g.height-2, 0, 0); } } gdispGDrawBox(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, pcol->edge); // Edge gdispGDrawLine(gw->g.display, gw->g.x+gsw->dpos, gw->g.y+1, gw->g.x+gsw->dpos, gw->g.y+gw->g.height-2, pcol->edge); // Thumb } gdispGDrawStringBox(gw->g.display, gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, justifyCenter); #undef gsw } #endif /* GDISP_NEED_IMAGE */
  8. Please, imagine that you will rotate volume knob at your car audio, and it will change volume value on display only after you finished to rotate the knob. Would you like such user experience? I'm trying to understand how WM works. Which function does actual redrawing, is it only _gwinFlushRedraws() that calls WN_Redraw()? _gwinFlushRedraws() function can reload itself, but what if IMMEDIATE turned off and SINGLEOP turned on? It will not call TriggerRedraw(), so in which place it will be called next time to redraw again?
  9. BTW, gwinSetDefaultStyle() sets style that will be applied to all widgets with default style, but I want to apply it to some widgets only (labels within one of containers). Except this, I have placed counter to Redraw call in _gwinFlushRedraws(). If I shift switch to one position it displays 25 changes (redraws) which looks like a true: (1 container + 4 labels) x 5 lines = 25. Four position shifts = 100 redraws. But if I shift rotary switch too fast, it shows 50 redraws only, half of events was lost. I see this because sometimes at first position I have container with default style instead of custom (while labels at this position have new style). I think _gwinFlushRedraws() starts at 3->2 shift (when positions 1, 3, 4, 5 = default style, 2 = custom) to apply default style to position 1, then in other thread I apply new positon (positions 2..5 = default style, 1 = custom), this marks position 1 as needed to redraw. Then _gwinFlushRedraws() finishes to paint position 1, marks it as redrawn, and ooops, we have position 1 marked as valid and redrawn, but with previous style set on display (but new style in container's object). Is this behavior good? May be it is needed to add some locking to not allow updating of object's parameters if object is redrawing now and to redraw it if we updating parameters?
  10. I have tried to place DMA2D transfer at the end of _gwinFlushRedraws(), this removes any blanking, but adds delays. In default case I rotates rotary switch from 1 position to 5, and I can see positions 1,2,3,4 and finally 5 on screen. But if I use second videobuffer with DMA2D at end of _gwinFlushRedraws(), I can see 1 position on screen, and then position 5 in a part of second, like it delays everything. I think delay can be about 300..500ms. I have tried to place breakpoint before DMA2D transfer to catch if it waits previous DMA2D transfer to be completed, and it was not catched, so it is not DMA2D too busy. I have added additional transfer to SDRAM, this was not slowed down anything. I have removed audio transfer from SDRAM, speed also was not changed, so external SDRAM bandwidth is not an issue here. I have removed all lines where I change anything on screen, and indeed, breakpoint in _gwinFlushRedraws() was not fired if I do not touch rotary. So I have placed counter there and found that _gwinFlushRedraws() fires only two times - for position 1 and for position 5. Then I have returned videobuffer to default address, not touching DMA2D transfer that still copies entire content into another address. I clearly see on screen how selected position was moved from 1 to 2, 3, 4 and 5, and only then was fired _gwinFlushRedraws()'s releaselock for first time! I cannot understand what is going on: - which function (and why) painted selected positions 2, 3, 4, 5, before _gwinFlushRedraws() was fired - why _gwinFlushRedraws() was fired if we have all redrawn I have GWIN_REDRAW_IMMEDIATE set to FALSE and GWIN_REDRAW_SINGLEOP set to TRUE. Finally, I have found WM_Redraw() that redraws everything in addition to _gwinFlushRedraws(). I can imagine only one way how it can be - I changing selections too fast, so when it finished to paint one selection, it is another pending redraw ready from next selection, so it refreshes all objects one by one, and finishes at fifth selection (no more changes pending). If I copy buffer at end of _gwinFlushRedraws(), I will get exactly this behavior - normally it will display selections from 1 to 5, but if I will copy buffer at the end of function, it will copy buffer only one time and show me only 5th selection (final version). Having GWIN_REDRAW_SINGLEOP set to FALSE does not helps, this slows down all things instead, because I have too much objects to redraw (25 object in 1.5-2 seconds, i can see how they redraws one by one). Pixmaps will not help me, because it will be redrawn same way - draw final version, then update videobuffer, changing selection from 1 to 5, without positions 2, 3, 4 in between. As I understand, when it redraws container, it redraws container itself first, then marks all children to redraw, so I cannot catch moment where container and all its children was actually redrawn? This is a best moment to copy container with all its content into actual videobuffer.
  11. Thanks! I have tried to use DMA2, but forgot about 65535 words limit in one transfer May be there is a place inside uGFX where I can put DMA2D code to transfer data from uGFX videobuffer to real videobuffer? This magic place should: - be after entire area was redrawn - have coordinates of redrawn area So, for example, uGFX will draw container over all, then labels, buttons, and everything else, then I just copy all container's content into real videobuffer? This will reduce DMA transfer (because we will transfer only areas that has been updated), but will update things in one shot, without any blanking period.
  12. Ok, but if I will hide all page, it will disappear visually? I will see blinking of all page, isn't it? I have tried to turn off GWIN_REDRAW_IMMEDIATE, all things goes faster. In my case it runs quick enough even if I do 150 changes of styles (I did not removed it to get more advanced showcase). But I still have flickering on screen because it sill draws empty container first, then empty area for text, then text. I can see this on screen. I have tried to add DMA2D copying at end of _gwinFlushRedraws(), it slow down things, but removes blinking. I use SDRAM, so SDRAM bus used by LTDC, and by other thread to save audio data. I have tried to turn off audio, and this was not helped, so I think it is not bandwidth issue. I will try to use memory-to-memory DMA to copy videobuffer, to leave DMA2D for uGFX needs.
  13. I can see only two parameters of gwinSetStyle() - handler and style. Can you point me to exact place where I can apply custom style to all children of container? I have few places where I modifying content, in 3 threads. One thread updates date and time in header, one more thread will update USB flash free space, one more thread - everything else. Best strategy in my case will collect changes, and then call something like redrawAllPending(). More, I have much memory, so I can just redraw all display to another videobuffer, and change address of such buffer at end of LTDC display iteration (after last line was sent to display), so next frame will be displayed from new buffer with new contents. In y case I think it will be nice to: - change address of LTDC videobuffer to second one (will display copy of old content) - make whole page container invisible at old videobuffer, just to not redraw immediately - make all changes I want (styles, texts and so on), as I understand, nothing will be redrawed in this case - make page visible, redrawing all objects - change address of LTDC videobuffer back to first one (will display copy new content) - use DMA2D or DMA to copy all content from first to second videobuffer Is it best way? It will give me determinate time of changing content (in fact, it will be more if I have changed only one text or less if I was changed many styles in one shot). What will be If I (container and label styles is my_own_style): 1. change container's style to default 2. change label's styles (inside container) to default 3. change container's style to my_own_style 4. change label's styles (inside container) to my_own_style What will be done in asynchronous mode? 1. it will do from 1 to 4 2. it will do 3 and 4 3. it will do nothing because at the end nothing was changed? Can I use async mode with manual redrawing content? Can I redraw only changed things in this mode? Thank you!
  14. I think this behavior should be customisable (when creating it), because two cases of using: 1. One or two frames with almost static content, or frames that used often - it is better not to destory them 2. Many frames with dynamic content, which can take all memory - it is better to destroy them after using
  15. Finally, I have found a reason. This was stack overflow in ChibiOS, but it gave me such behavior even with CH_DBG_ENABLE_STACK_CHECK turned on..
  16. I got error "ownership failure (chMtxUnlock)" while trying to call gwinSetText() from second thread (its used to display free space on USB). In trace I see that this is chDbgAssert in chMtxUnlock(), where ctp == my second thread, and ctp->p_mtxlist->m_owner pointed to flash rom area of CPU (with no name of thread). I'm creating GUI from main(), not from any thread. What I'm doing wrong? What should I do to get access to labels from any place? Thanks!
  17. I have in my project 5 containers, and 4 labels in each. I want allow user to select active container, so now for each change I: - apply default style for all containers and labels (25 x gwinSetStyle) - apply my own style to active container and its labels (5 x gwinSetStyle) All this done in one shot. If I will rotate rotary switch very quick, I can see how active selection goes from 1 to 5, and this takes about 1 second, which is too much as for me. I understand that I can apply default style just to previous active one, but now I think how uGFX fast, taking about 1 second to make 150 changes on screen in 1 second, with average size of 10000 pixels each? This is about 1.5Mpix in a second, but hardware acceleration gives actual quantity much less than 1.5Mpix. I use STM32F429 at 168MHz, with 800x480 display size via LTDC driver with DMA2D in gdisp_lld_blit_area(). May be, I'm doing something wrong? How to speedup it?
  18. Thank you for describing potential problems with chips, I did not met them yet, but I will beware I glad that I have selected right way to implement interrupt. I think implementing entire interrupt method (without polling) is not so important, because we should implement queue of events in this case to make it right way. I was not met any problems yet with touch, so I think it is good to have this, but while full stack events will be implemented, as well as full stack WM, and other things linked to events queues, i.e. definitely not now and not at first priority. Thanks!
  19. I have touchpanel that raises EXTI interrupt when something was changed with touchpanel (pressed or depressed), but gmouse works in polling mode. So, now I just have global variable touch_panel_pressed, and this variable sets to true when EXTI interrupt was raised. In read_byte() I check this variable, if it is false, the function just return zero, so read_xyz() returns without actual I2C communication. If it was true, I set variable to false and do actual reading from touchpanel, so result can match read_byte() & 0x07 condition in read_xyz(). All changes was made in my custom gmouse_lld_FT5x06_board.h. What do you say about this approach? Is it good or I missed something important?
  20. Not in case of my config. STM32F429 while working with LTDC and SDRAM at one time simply cannot display both layers right way. I think that bus bandwidth is limited more than this is mentioned in documentation, so LTDC cannot access to new pixels to be displayed at same time when it wants to read them from both layer's SDRAM addresses. As result I have sync problems, snow on screen or something like this (each next line was shifted to right by few pixels), depending on third thing who want to access to SDRAM - my application writing to display layers
  21. Sorry, I have no 429 discovery, so I can only guess. I'm working with WaveShare Open429-I kit with 7-inch capacitive display, that works by LTDC only, without any needs to setup it via SPI. Yes, i using 8M SDRAM embedded into main CPU module of Open429, so I cannot use full power of STEmWin's double layers (STM32F429 cannot use double layers on 800x480 with SDRAM due to bus bandwidth limitation). I have tried STemWin, and it works, but as I tried to ask questions in their forum and got no answer, and I see that developers of uGFX really wants to make uGFX better, so I decided to switch to uGFX (except this, I can see uGFX sources ). About hardware acceleration.. I simply do not know. STM32F429 have DMA2D accelerator, and my display (and LTDC itself) cannot be used without videobuffer, so all acceleration can work with memory (video) buffer only. uGFX's LTDC driver uses DMA2D to fill areas.
  22. As I in same situation as you (writing project based on uGFX on STM32F429), let me try to answer some of your questions. SPI is a not part uGFX responsible for in your case, so this is question about ChibiOS HAL. To make LTDC working, I was copied board_STM32LTDC_template.h into $PROJ_DIR$/board_STM32LTDC.h, and added some defines into it: #define SDRAM_DEVICE_ADDR 0xd0000000 #define STM32F4 TRUE I have changed driverCfg in this file, because I'm using 800x480 display. Also, I included gdisp_lld_STM32LTDC.c into my project. I have not used file from demos, and in my case everything works fine with generic driver. What about win95-like interface, uFGX have widgets that looking better than Win95's (in my opinion), so I used them as is. You can use Studio as visual designer and get some files to start with. Note that Studio can be used not just as example generator, but as designer in full life cycle of application, so you can add or change something in your app, generate code and just recompile your application. Tectu told that 0.13 version of Studio (will be available ~15th of Feb) will allow to use custom fonts, this also will help (now you can use in Studio only fonts embedded into uGFX). So, you need: - uGFX gfx_mk.c file, to compile entire lib in your firmware - LTDC display driver as was mentioned above - gui.c, gui.h gfxconf.h and other files that will make Studio for you I'm not developer of uGFX, just a user, so everything above is just my opinion.
  23. No, I want to change status of button, for example, user presses button 'recording', then recording starts (or not). If everything is ok and recording was started, I want to change button image with recording symbol to red. Thank you very much!
  24. How to change image of button at runtime?
×
×
  • Create New...