IMAGE widget: how to manage the bitmap change

This site uses cookies. By continuing to browse this site, you are agreeing to our Cookie Policy.

  • IMAGE widget: how to manage the bitmap change

    I have an IMAGE widget. The associated bitmap could change at runtime. I use IMAGE_SetBitmap() for that in the main loop.

    I'd like to avoid calling IMAGE_SetBitmap() if the bitmap is already correct. The immediate solution is to use a variable:

    Source Code

    1. if ((image_to_show == IMAGE_1) && (image_shown != IMAGE_1) Image_SetBitmap(...)
    2. else if ((image_to_show == IMAGE_2) && (image_shown != IMAGE_2) Image_SetBitmap(...)
    3. else if (...)
    4. image_shown = image_to_show;



    I could avoid using the variable image_shown if the IMAGE widget API supports a IMAGE_GetBitmap() function, but it's not the case. I think it could be a good functionality to add. In this case, I could write:

    Source Code

    1. const GUI_BITMAP *bmp_to_show = ...;
    2. const GUI_BITMAP *bmp_shown;
    3. if (bmp_to_show != IMAGE_GetBitmap(hImg)) {
    4. IMAGE_SetBitmap(hImg, bmp_to_show);
    5. }



    Maybe I miss something?
  • I created two simple wrappers functions that use window user data to save and restore the current bitmap of a Widget.

    Source Code

    1. IMAGE_Handle IMAGEd_CreateEx(int x0, int y0, int xSize, int ySize, WM_HWIN hParent, int WinFlags, int ExFlags, int Id) {
    2. IMAGE_Handle hImg;
    3. const GUI_BITMAP *bmp = NULL;
    4. hImg = IMAGE_CreateUser(x0, y0, xSize, ySize, hParent, WinFlags, ExFlags, Id, sizeof(bmp));
    5. WM_SetUserData(hImg, &bmp, sizeof(bmp));
    6. return hImg;
    7. }
    8. void IMAGEd_SetBitmap(IMAGE_Handle hWin, const GUI_BITMAP * pBitmap){
    9. const GUI_BITMAP *bmp;
    10. WM_GetUserData(hWin, &bmp, sizeof(bmp));
    11. if (bmp != pBitmap) {
    12. IMAGE_SetBitmap(hWin, pBitmap);
    13. bmp = pBitmap;
    14. WM_SetUserData(hWin, &bmp, sizeof(bmp));
    15. }
    16. }
    Display All


    The GUI usually shows many variables that could change at run-time. For example, a temperature value, the raising of an alarm, and so on. I found useful to have a gui_refresh() function that is called on a regular basis, for example every 20/100ms. In the gui_refresh() it would be simple to set the graphical parameters (text/colors of TEXT widgets, bitmap of IMAGE widgets and so on), without worrying about the old value. Of course, it would be nice if the library takes automatically care about the variation and avoid redrawing windows if the new graphical parameter doesn't change the appearence, for example because we are setting the same bitmap of an IMAGE widget, or we are setting the same front color of a TEXT widget.

    However this library behaviour isn't clear. After my experince, I understood IMAGE_SetBitmap() forces a redraw even if I set the same bitmap. What happens with TEXT_SetColor() or TEXT_SetText() and so on?

    The post was edited 1 time, last by giusloq ().

  • Hello,

    In most cases changing widget properties using emWin API functions will invalidate the according widget only in case properties in fact have been changed.

    If you feel there is a function which does not work this way, please let us know. Thank you.

    Best regards,
    Adrian
  • "If you feel there is a function which does not work this way, please let us know. Thank you."
    It seems to me that at least two functions doesn't work this way: WM_SetCallBack() and IMAGE_SetBitmap().

    I use WM_SetCallBack() to set a callback that set a specific color of an alpha-channel image by calling GUI_SetColor() in WM_PAINT message and after calling default IMAGE_Callback (as you suggested in another post). The color changes at run-time, so I continuously call WM_SetCallBack() to set the current color. If the callback is the same, the WM_PAINT message is forced, even if it isn't needed.
  • Hello,

    Yes, it is true that WM_SetCallback() invalidates the given window, since it is assumed that the newly set callback function changes its appearance. Please note that the function WM_SetCallback() is not able to verify if the WM_PAINT event has been overwritten.

    I would recommend using a static color variable in your custom callback function, so it can be changed without having to set a new callback function. In order to change the color I would suggest using an application defined message. So, instead of setting a new callback function, it should be sufficient to just send a message to the according window:

    C Source Code

    1. WM_SendMessageNoPara(hWin, MSG_SET_ALPHA_COLOR_BLUE);
    2. switch (pMsg->MsgId) {
    3. case MSG_SET_ALPHA_COLOR_BLUE:
    4. Color = GUI_BLUE;
    5. break;
    6. case MSG_SET_ALPHA_COLOR_GREEN:
    7. Color = GUI_GREEN;
    8. break;
    9. case MSG_SET_ALPHA_COLOR_RED:
    10. Color = GUI_RED;
    11. break;
    12. case WM_PAINT:
    13. GUI_SetColor(Color);
    14. IMAGE_Callback(pMsg);
    15. break;
    16. default:
    17. IMAGE_Callback(pMsg);
    18. }
    Display All


    Best regards,
    Adrian
  • I would recommend using a static color variable in your custom callback function, [...]
    I'm trying to use user data associated with Windows (and IMAGE widgets too) to save the currect color of alpha channel images. In this way, I can reuse the same callback function for all alpha-channel images. The callback extracts the current color for that image by reading user data.

    What about TEXT_SetTextAlign() and IMAGE_SetBitmap()?
  • Hello,

    Yes, of course. Utilizing the user data for that is even better.

    Both functions TEXT_SetTextAlign() and IMAGE_SetBitmap() invalidate the respective widget without verifying if the given parameters differ from the current state of the widget.

    Please note that this can be verified by overwriting the callback function of the given widget as follows:

    C Source Code

    1. switch (pMsg->MsgId) {
    2. case WM_PAINT:
    3. <WIDGET>_Callback(pMsg); // <- Set breakpoint here
    4. break;
    5. default
    6. <WIDGET>_Callback(pMsg);
    7. }

    Best regards,
    Adrian
  • Both functions TEXT_SetTextAlign() and IMAGE_SetBitmap() invalidate the respective widget without verifying if the given parameters differ from the current state of the widget.
    Do you think this behaviour is correct? You wrote:
    In most cases changing widget properties using emWin API functions will invalidate the according widget only in case properties in fact have been changed.
    If you feel there is a function which does not work this way, please let us know. Thank you.
    In order to solve this unexpected behaviour, I'm implementing my custom widgets that uses User Data to store the current graphical parameters and call emWin standard function only if the parameter is really changed. It's an annoying task :(
  • Hello,

    You could use a wrapper function to set the text alignment and the bitmap.
    These functions verify if the given property (alignment or bitmap) is already set.
    If not the according <WIDGET>_Set...() function is called.

    For example a code snippet for you:

    C Source Code

    1. struct TEXTDATA {
    2. I16 Align;
    3. };
    4. struct IMAGEDATA {
    5. const GUI_BITMAP * pData;
    6. };
    7. /*********************************************************************
    8. *
    9. * _TEXT_SetTextAlign
    10. *
    11. */
    12. static void _TEXT_SetTextAlign(TEXT_Handle hObj, int Align) {
    13. TEXTDATA UserData;
    14. TEXT_GetUserData(hObj, &UserData, sizeof(UserData));
    15. if (UserData.Align != Align){
    16. UserData.Align = Align;
    17. TEXT_SetTextAlign(hObj, Align);
    18. TEXT_SetUserData(hObj, &UserData, sizeof(UserData));
    19. }
    20. }
    21. /*********************************************************************
    22. *
    23. * _IMAGE_SetBitmap
    24. *
    25. */
    26. static void _IMAGE_SetBitmap(IMAGE_Handle hObj, const GUI_BITMAP * pBitmap) {
    27. IMAGEDATA UserData;
    28. IMAGE_GetUserData(hObj, &UserData, sizeof(UserData));
    29. if (UserData.pData != pBitmap){
    30. UserData.pData = pBitmap;
    31. IMAGE_SetBitmap(hObj, pBitmap);
    32. IMAGE_SetUserData(hObj, &UserData, sizeof(UserData));
    33. }
    34. }
    35. /*********************************************************************
    36. *
    37. * MainTask
    38. *
    39. */
    40. void MainTask(void) {
    41. WM_HWIN hImage, hText;
    42. int i = 0;
    43. GUI_Init();
    44. hImage = IMAGE_CreateUser(0, 0, LCD_GetXSize(), 30, WM_HBKWIN, WM_CF_SHOW, 0, GUI_ID_IMAGE0, sizeof(IMAGEDATA));
    45. hText = TEXT_CreateUser(0, 30, LCD_GetXSize(), 50, WM_HBKWIN, WM_CF_SHOW, 0, GUI_ID_TEXT0, "Test", sizeof(TEXTDATA));
    46. TEXT_SetBkColor(hText, GUI_RED);
    47. _TEXT_SetTextAlign(hText, GUI_TA_CENTER);
    48. _IMAGE_SetBitmap(hImage, &bmBitmap);
    49. while(1) {
    50. GUI_Delay(100);
    51. if (i % 50) {
    52. _TEXT_SetTextAlign(hText, GUI_TA_RIGHT);
    53. } else {
    54. _TEXT_SetTextAlign(hText, GUI_TA_CENTER);
    55. i = 0;
    56. }
    57. _IMAGE_SetBitmap(hImage, &bmBitmap);
    58. i++;
    59. }
    60. }
    Display All


    Best regards,
    Thorsten