Jump to content

king2

Members
  • Posts

    117
  • Joined

  • Last visited

  • Days Won

    1

Posts posted by king2

  1. Sorry, but previous patch was a piece of junk. I was wrong modifying string 'in place', because it skips all rich text in all redraws except first one (I tested this on clock text, so everything looked ok). As this patch will be not included into main uGFX source code, I made another one, much simpler but still powerful, but it changes mcufont file.

    How it works: 

    • I use left-to-right rendering always, even with right justify
    • it initializes default style at each rendering start
    • it applies styles without transitions buffer and modifying source string, so it much simpler

    When initializing, you should use all as previous, but supplying transition buffer is not necessary, only styles description should be passed:

    rich_text_style_t rich_text_styles[] = {
        { Gray, 0, 0, 0, RT_CHANGE_TEXT_COLOR },
        { Red, 0, 0, 0, RT_CHANGE_TEXT_COLOR },
        { Gray, 0, 0, 0, RT_CHANGE_TEXT_COLOR|RT_STRIKETHROUGH },
        { Blue, Yellow, 0, Red, RT_STRIKETHROUGH | RT_CHANGE_BG_COLOR }
    };
    gdispRichTextSetStyles((rich_text_style_t *) &rich_text_styles, sizeof((rich_text_style_t *) rich_text_styles));

    Patch file included.

    Feel free to ask questions, if you will have problems with it.

    rich_text_patch2.zip

  2. I just decided to keep all files to be opened same way, with same type of variables and so on.

    Note that I'm telling about gdispImage type variables, generated by Studio for gui.c internal usage. It generates such variables for images that used in GUI, but not for additional ones (what I can understand, it do not knows what inside of such files, maybe not image at all). But I know for sure that I have only images there, so I made such hack for me.

    If you will make compressing, I still will define new gdispImage variables for additional files, and they still can be opened with:

    gdispImageOpenFile(<my generated gdispImage variable>, <ROMFS pathname>)

    I just take filename from romfs_files.h, change dashes to underscores and this is my new variable name. I add this variable into gui.c and into gui.h as extern, to be used in my main.c, just to keep all gdispImage variables definitions in one place (inside gui.c/gui.h).

    Sorry, if I misunderstood something.

  3. Thanks for answer!

    2. You can get kickstarter edition IAR for free with 32k code size limitation, I think it can be enough for just a warnings testing. If not, it will still compile, and just not link, so you will see all warnings anyway :)

    What about line endings, please tell me where you are preparing uGFX files for distribution (i.e. archives for downloading and folder to be placed in Studio distribution), and I will write simple script for you, that will scan all files in folder and convert them into one type. Just tell me iа you want me to do this, which type do you want to be basic for all files and which OSs are you using in prepare process.

    3 and 4. OK, I got it. So, if it was made this way for a reason, definitely it should be left as is, but it will be nice to make IAR not complaining about this. Maybe pragmas will help.

    If not, maybe it will be nice to document this behavior and make recommendations to users about which warning they can safely turn off in IAR (but this is worst case, because warning can be turned off only for entire project, this can produce false-negatives in source files not belonging to uGFX).

  4. I just copied guiCreate() that uses gdispImageOpenFile() to open images. Studio places additional files to romfs_files.h, but not declares variables to use these additional files. To place another one file into my firmware I do:

    • place button somewhere in window
    • assign new image file to it
    • generate code in Studio
    • copy generated .h file from rsc to my ../files folder
    • add its name into "Additional files" section in Studio
    • copy generated line with new file and gdispImageOpenFile() from gui.c to my main.c
    • remove temporary button with its image
    • re-generate code again
    • use this new file in my firmware to replace another button's image (when, for example, I want to show user that recording was turned on)

    Using variables collected from romfs_files.h and defining them as extern in gui.c/gui.h allows me to keep all image variables in one place, and keep them intact (in fact, re-generate each time by prepare script) when re-generating code by Studio. So, I have only one place where all my files located on disk, and only one place where files are defined in sources and so on.

    I think it will be nice to add possibility to Studio to assign more than one image file some widgets (not touching uGFX code, but associate these files in Studio project with widget, just creating additional image variables and gdispImageOpenFile() calls). It will allow get 'spare' images for widgets if user wanted to replace images at runtime and it will delete all widget's images automatically if such widget will be deleted from Studio project.

  5. Just to keep things in one place.. I just tested 2.5.

    1. It recognizes IAR as compiler #22, i.e. EDG, I have no idea why. I moved its detection to position upper than EDG, and it started to be #29, i.e. IAR.

    2. Many non-native line ending warnings, in uGFX files and Studio generated files. I think it will be better to keep line endings or UNIX-like, or CRLF, but one standard for all files.

    3. Also I have two warnings 'Warning[Pe301]: typedef name has already been declared (with same type)', it raises when compiling each file that uses header with structs:

    typedef struct point {
    	coord_t x;		/**< The x coordinate of the point. */
    	coord_t y;		/**< The y coordinate of the point. */
    } point, point_t;
    
    typedef struct GWindowObject {
    	#if GWIN_NEED_WINDOWMANAGER
    		// This MUST be the first member of the structure
    		gfxQueueASyncItem	wmq;				/**< The next window (for the window manager) */
    	#endif
    	const struct gwinVMT*	vmt;				/**< The VMT for this GWIN */
    	GDisplay *				display;			/**< The display this window is on */
    	coord_t					x;					/**< The position relative to the screen */
    	coord_t					y;					/**< The position relative to the screen */
    	coord_t					width;				/**< The width of this window */
    	coord_t					height;				/**< The height of this window */
    	color_t					color;				/**< The current foreground drawing color */
    	color_t					bgcolor;			/**< The current background drawing color */
    	uint32_t				flags;				/**< Window flags (the meaning is private to the GWIN class) */
    	#if GDISP_NEED_TEXT
    		font_t				font;				/**< The current font */
    	#endif
    	#if GWIN_NEED_CONTAINERS
    		GHandle				parent;				/**< The parent window */
    	#endif
    } GWindowObject, * GHandle;

    I have no idea how to eliminate those warnings, I know C not so much, but its a most boring and repeating warnings :(

    4. Warnings 'Warning[Pe083]: type qualifier specified more than once' about definitions like this: 

    typedef const struct GDriverVMT const GDriverVMTList[1];

    May be there is a reason to use const qualifier twice in same definition?

  6. When I saw uGFX and Studio for first time, Studio was just a example maker, i.e. you should start project in Studio, place widgets, see preview, generate code and.. that's all. If you need to shift some widget, change font or do something like this, you cannot, because you will lost all changes you made to sources. It is acceptable if you have small project and can do it manually by changing source code, but if your project is more complicated (like mine) or you want something special from uGFX (like me).. you simple cannot.

    Thanks to Tectu, he implemented some changes to Studio, so we can use Studio in all development process now! Mine process was more complicated at start, but I will describe below how I do this now.

    First of all, Studio can generate code for you. Lets see what we will get after code generation:

    • functions that creates all windows for you (CreatePage*() in gui.c)
    • guiShowPage() that will show selected window for you
    • guiCreate() that will load all fonts and images, init defaults, create all pages and show default page (window)
    • guiEventLoop() as example of events main loop
    • main_sample.c as example of your main.c
    • gfxconf.h with defines you selected in Studio
    • header files with color styles, files and other resources

    You can take all these files and use in your project as is, but you can't change anything in output directory, because you will lost all your changes if you will re-generate source with Studio. So, I selected other way, I will use code generated by Studio, but with some modifications:

    • main_sample.c not used
    • I'm using more than one image per widget, to show status of hardware to user by icons
    • guiCreate() copied from gui.c to my own application with little modifications, I'm not using supplied one (because I need specific startup with touch panel re-calibration by holding a key at start, and similar things)

    So, I need every resource to be defined as extern, CreatePage*() function as non-static and so on. Ok, lets accept this challenge!

    First, now we can generate header files with additional images, place them somewhere outside of output folder and set additional files in Settings->GFILE->Additional files. All these file will be included into romfs_files.h (but will not defined as variables).

    Second, we can use now post-generation script that will be called each time you pressed hammer icon in Studio just after all files were generated. You can do this by adding script to Settings->Generator->Scripts. You can use (or not) script for preview and for build actions. I wrote my own Perl script for post-build action.

    What is does:

    • scans gui.c for handlers names like ah<something>_X or ah<something>_X_Y and converts them into array variables, like GHandle ahButton_dt[5] or GHandle ahLabel_mem[5][4], also adding them as extern into gui.h
    • scans romfs_files.h for images, and adds them into gui.c as variables and to gui.h as extern variables (note again, additoinal files not defined as variables, so I should get them from this file)
    • converts all CreatePage*() functions to non-static, to be called from my own main.c
    • scans for fonts and also put them as extern into gui.h
    • defines all widget styles as extern
    • adds some custom defines into gfxconf.h, like GFX_USE_OS_CHIBIOS, GINPUT_TOUCH_USER_CALIBRATION_SAVE, GDISP_NEED_PIXELREAD, GFILE_MAX_GFILES and so on
    • rewrites LoadMouseCalibration() definition as __weak (I'm using my own function).

    Note again, that I'm using my own version of guiCreate(), so I should have access to all fonts, images, widgetstyles and other resources from my own main.c. If you satisfied with default created guiCreate(), you can use sources as is, without using script at all (or make your own, depending on your needs).

    Now we can add window, some widget, add/change font or shift our labels, then press hammer icon in Studio, then compile and run our modified GUI in hardware just in couple of clicks! 

    More important, we can use Studio in any step of our development, we can add some windows or widgets later, we can change everything even after firmware was finished. We are not limited by 'design GUI -> generate files -> develop firmware' sequence anymore!

  7. I have tested this, it is not working. It recognizes as compiler #22, i.e. EDG, I have no idea why. I moved its detection to position upper than EDG, and it started to be #29, i.e. IAR. I suggest to make this change in uGFX repo.

    Then I compiled entire project, warnings I got follows:

    gdisp_lld_STM32LTDC.c  
    Warning[Pa050]: non-native end of line sequence detected (this diagnostic is only issued once) \ugfx\drivers\gdisp\STM32LTDC\gdisp_lld_STM32LTDC.c 1 
    Warning[Pe301]: typedef name has already been declared (with same type) \ugfx\src\gdisp\gdisp.h 54 
    Warning[Pe301]: typedef name has already been declared (with same type) \ugfx\src\gwin\gwin.h 60 
    Warning[Pe083]: type qualifier specified more than once \ugfx\src\gdriver\gdriver.h 90 
    Warning[Pe083]: type qualifier specified more than once \ugfx\src\gdisp\gdisp_driver.h 731 
    
    gfx_mk.c  
    Warning[Pa050]: non-native end of line sequence detected (this diagnostic is only issued once) \ugfx\src\gfx_mk.c 1 
    Warning[Pe301]: typedef name has already been declared (with same type) \ugfx\src\gdisp\gdisp.h 54 
    Warning[Pe301]: typedef name has already been declared (with same type) \ugfx\src\gwin\gwin.h 60 
    Warning[Pe1105]: #warning directive: "GOS: Operating System initialization has been turned off. Make sure you call halInit() and chSysInit() before gfxInit() in your application!" \ugfx\src\gos\gos_chibios.c 52 
    Warning[Pe083]: type qualifier specified more than once \ugfx\src\gdriver\gdriver.h 90 
    Warning[Pe083]: type qualifier specified more than once \ugfx\src\gdisp\gdisp.c 585 
    Warning[Pa093]: implicit conversion from floating point to integer \ugfx\src\gdisp\gdisp.c 1728 
    Warning[Pa093]: implicit conversion from floating point to integer \ugfx\src\gdisp\gdisp.c 1729 
    Warning[Pa093]: implicit conversion from floating point to integer \ugfx\src\gdisp\gdisp.c 1855 
    Warning[Pa093]: implicit conversion from floating point to integer \ugfx\src\gdisp\gdisp.c 1856 
    Warning[Pe188]: enumerated type mixed with another type \ugfx\src\gdisp\gdisp.c 3308 
    Warning[Pe188]: enumerated type mixed with another type \ugfx\src\gdisp\gdisp.c 3368 
    Warning[Pe111]: statement is unreachable \ugfx\src\gtimer\gtimer.c 112 
    Warning[Pe111]: statement is unreachable \ugfx\src\gwin\gwin.c 330 
    Warning[Pe083]: type qualifier specified more than once \ugfx\src\ginput\ginput_mouse.c 91 
    Warning[Pe083]: type qualifier specified more than once \ugfx\src\ginput\ginput_mouse.c 110 
    Warning[Pe083]: type qualifier specified more than once \ugfx\src\ginput\ginput_mouse.c 121 
    Warning[Pe083]: type qualifier specified more than once \ugfx\src\ginput\ginput_mouse.c 122 
    Warning[Pe083]: type qualifier specified more than once \ugfx\src\ginput\ginput_mouse.c 122 
    Warning[Pe083]: type qualifier specified more than once \ugfx\src\ginput\ginput_mouse.c 123 
    Warning[Pe083]: type qualifier specified more than once \ugfx\src\ginput\ginput_mouse.c 124 
    Warning[Pe083]: type qualifier specified more than once \ugfx\src\ginput\ginput_mouse.c 127 
    Warning[Pe083]: type qualifier specified more than once \ugfx\src\ginput\ginput_mouse.c 128 
    Warning[Pe083]: type qualifier specified more than once \ugfx\src\ginput\ginput_mouse.c 134 
    Warning[Pe083]: type qualifier specified more than once \ugfx\src\ginput\ginput_mouse.c 169 
    Warning[Pe083]: type qualifier specified more than once \ugfx\src\ginput\ginput_mouse.c 235 
    Warning[Pe083]: type qualifier specified more than once \ugfx\src\ginput\ginput_mouse.c 235 
    Warning[Pe083]: type qualifier specified more than once \ugfx\src\ginput\ginput_mouse.c 294 
    Warning[Pe083]: type qualifier specified more than once \ugfx\src\ginput\ginput_mouse.c 327 
    Warning[Pe083]: type qualifier specified more than once \ugfx\src\ginput\ginput_mouse.c 474 
    Warning[Pe083]: type qualifier specified more than once \ugfx\src\ginput\ginput_mouse.c 499 
    Warning[Pe083]: type qualifier specified more than once \ugfx\src\ginput\ginput_mouse.c 545 
    Warning[Pe083]: type qualifier specified more than once \ugfx\src\ginput\ginput_mouse.c 549 
    Warning[Pe083]: type qualifier specified more than once \ugfx\src\ginput\ginput_mouse.c 549 
    Warning[Pe083]: type qualifier specified more than once \ugfx\src\ginput\ginput_mouse.c 612 
    Warning[Pe083]: type qualifier specified more than once \ugfx\src\ginput\ginput_mouse.c 613 
    Warning[Pe083]: type qualifier specified more than once \ugfx\src\ginput\ginput_mouse.c 650 
    Warning[Pe083]: type qualifier specified more than once \ugfx\src\ginput\ginput_mouse.c 672 
    Warning[Pe083]: type qualifier specified more than once \ugfx\src\ginput\ginput_mouse.c 677 
    Warning[Pe083]: type qualifier specified more than once \ugfx\src\ginput\ginput_mouse.c 697 
    Warning[Pe083]: type qualifier specified more than once \ugfx\src\ginput\ginput_mouse.c 703 
    Warning[Pe083]: type qualifier specified more than once \ugfx\src\ginput\ginput_mouse.c 703 
    Warning[Pe083]: type qualifier specified more than once \ugfx\src\ginput\ginput_mouse.c 762 
    Warning[Pe083]: type qualifier specified more than once \ugfx\src\ginput\ginput_mouse.c 798 
    Warning[Pe083]: type qualifier specified more than once \ugfx\src\gfile\gfile.c 37 
    Warning[Pe083]: type qualifier specified more than once \ugfx\src\gfile\gfile_fs_rom.c 37 
    
    gmouse_lld_FT5x06.c  
    Warning[Pa050]: non-native end of line sequence detected (this diagnostic is only issued once) \ugfx\drivers\ginput\touch\FT5x06\gmouse_lld_FT5x06.c 1 
    Warning[Pe301]: typedef name has already been declared (with same type) \ugfx\src\gdisp\gdisp.h 54 
    Warning[Pe301]: typedef name has already been declared (with same type) \ugfx\src\gwin\gwin.h 60 
    Warning[Pe083]: type qualifier specified more than once \ugfx\src\gdriver\gdriver.h 90 
    Warning[Pe083]: type qualifier specified more than once \ugfx\drivers\ginput\touch\FT5x06\gmouse_lld_FT5x06.c 102 
    
    gui.c  
    Warning[Pa050]: non-native end of line sequence detected (this diagnostic is only issued once) \ugfx\gfx.h 1 
    Warning[Pe301]: typedef name has already been declared (with same type) \ugfx\src\gdisp\gdisp.h 54 
    Warning[Pe301]: typedef name has already been declared (with same type) \ugfx\src\gwin\gwin.h 60 

     

  8. I'm using now fresh driver and get same warning.

    What about GDISP_NEED_PIXELREAD, I just have no idea where I should use it.

    From one point of view, it is property of display driver, so it should be set in driver's header file.

    I have tried this but at moment compiler get into my board_STM32LTDC.h, GDISP_NEED_PIXELREAD already set by gfx_options.h and I get 'incompatible redefinition' warning.

    From other side, in examples it used in gfxconf.h, so I just added it to my prepare script, as I cannot add it directly from Studio.

    This works for me and warning about GDISP_NEED_PIXELREAD was disappeared.

  9. I needed to get a buttons with image and texts on it (see http://community.ugfx.org/files/file/11-%C2%B5gfx-studio/, first screenshot), but I wanted text to be placed not at default center, so I made custom draw routine for this:

    // structure with custom text positioning
    typedef struct {
        gdispImage* image;
        coord_t     x;
        coord_t     y;
        coord_t     width;
        coord_t     height;
        justify_t   justify;
    } custom_button_t;
    
    // custom draw function
    void gwinButtonDraw_ImageText(GWidgetObject *gw, void *param) {
        coord_t sy;
    
        custom_button_t* params = (custom_button_t*)param;
        if (!params) {
            return;
        }
        const GColorSet* colors;
        if (!gwinGetEnabled((GHandle)gw)) {
            colors = &gw->pstyle->disabled;
            sy = 2 * gw->g.height;
        } else if ((gw->g.flags & GBUTTON_FLG_PRESSED)) {
            colors = &gw->pstyle->pressed;
            sy = gw->g.height;
        } else {
            colors = &gw->pstyle->enabled;
            sy = 0;
        }
        gdispGImageDraw(gw->g.display, params->image, gw->g.x, gw->g.y, gw->g.width, gw->g.height, 0, sy);
        gdispGDrawStringBox(gw->g.display, gw->g.x+1+params->x, gw->g.y+1+params->y, params->width-2, params->height-2, gw->text, gw->g.font, colors->text, params->justify);
    }
    
    // define text positions and justify
    custom_button_t param_rec_gray = { &button_rec_gray, 0, 45, 86, 40, justifyCenter };
    
    // usage
    gwinSetCustomDraw(ghButton_rec, gwinButtonDraw_ImageText, &param_rec_gray);

    This worked for me.

  10. Just place a ordinary button over everything that you want to turn into button. Than override draw routine of button with function that draws nothing. You're done.

    // define the function
    void gwinButtonDraw_Clean(GWidgetObject *gw, void *param) {} // draws a huge piece of best nothing we can get for free
    
    // use it
    gwinSetCustomDraw(ghButton_settings, gwinButtonDraw_Clean, NULL);

    Just receive events from this 'button' and do whatever you want to happen when user pressed, for example, a label.

  11. 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

  12. 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 :).

    rich_text.thumb.png.f8380e61cf968b2e75ff

    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

  13. 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?

  14. #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 :)

  15. 15 minutes ago, Joel Bodenmann said:

    The main reason for this is to keep the API consistent. All GDISP calls have a DrawXxx() and a FillXxx() equivalent. No need to break the API for the string functions. We like it consistent.
    Of course you could argue that one can have one function with a parameter that specifies that and then a wrapper function to save a little bit of code space but as mentioned in an earlier thread where this question showed up another reason for this is that some compilers have had very hard times working with conditional function pointers.

    But you can just use two #define with function with last parameter set to one or zero, for example (fill or not)!

  16. Going deeper and deeper into uGFX. Some question was born when looking on font engine sources.

    1. mf_justify.cmf_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.crender_left() calls callback drawcharglyph() for each character, giving coordinates of character and character itself
    • gdisp.cdrawcharglyph() 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.cdrawcharline() 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!

  17. 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 */

     

  18. 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?

  19. 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?

  20. 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.

  21. 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.

  22. 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.

×
×
  • Create New...