specialize a custom widget

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

    • specialize a custom widget

      Suppose to start from the custom widget described in AN03002
      Now suppose that you want to specialize in this widget, that you want to extend its functionality.

      you could write something like that:

      C Source Code

      1. /*********************************************************************
      2. *
      3. * MYWIDGETSPEC_Callback
      4. */
      5. void MYWIDGETSPEC_Callback(WM_MESSAGE * pMsg)
      6. {
      7. MYWIDGETSPEC_Handle hWin;
      8. MYWIDGETSPEC_Obj MyWidgetSpec;
      9. hWin = pMsg->hWin;
      10. MYWIDGET_GetUserData(hWin, &MyWidgetSpec, sizeof(MYWIDGETSPEC_Obj));
      11. switch (pMsg->MsgId) {
      12. /* some message handler to specialize the behaviour */
      13. default:
      14. MYWIDGET_Callback(pMsg);
      15. }
      16. }
      17. /*********************************************************************
      18. *
      19. * MYWIDGETSPEC_GetUserData
      20. */
      21. int MYWIDGETSPEC_GetUserData(MYWIDGETSPEC_Handle hWin, void *pDest, int SizeOfBuffer)
      22. {
      23. MYWIDGETSPEC_Obj MyWidgetSpec;
      24. int
      25. NumBytes;
      26. U8 * pExtraBytes;
      27. if (SizeOfBuffer <= 0) {
      28. return 0;
      29. }
      30. MYWIDGET_GetUserData(hWin, &MyWidgetSpec, sizeof(MYWIDGETSPEC_Obj));
      31. pExtraBytes =
      32. (U8 *) malloc(sizeof(MYWIDGETSPEC_Obj) + MyWidgetSpec.NumExtraBytes);
      33. if (pExtraBytes) {
      34. MYWIDGET_GetUserData(hWin, pExtraBytes,
      35. sizeof(MYWIDGETSPEC_Obj) + MyWidgetSpec.NumExtraBytes);
      36. if (SizeOfBuffer >= MyWidgetSpec.NumExtraBytes) {
      37. NumBytes = MyWidgetSpec.NumExtraBytes;
      38. } else {
      39. NumBytes = SizeOfBuffer;
      40. }
      41. GUI_MEMCPY(pDest, pExtraBytes + sizeof(MYWIDGETSPEC_Obj), NumBytes);
      42. free(pExtraBytes);
      43. return NumBytes;
      44. }
      45. return 0;
      46. }
      47. /*********************************************************************
      48. *
      49. * MYWIDGETSPEC_SetUserData
      50. */
      51. int MYWIDGETSPEC_SetUserData(MYWIDGETSPEC_Handle hWin, void *pSrc, int SizeOfBuffer)
      52. {
      53. MYWIDGETSPEC_Obj MyWidgetSpec;
      54. int
      55. NumBytes;
      56. U8 * pExtraBytes;
      57. if (SizeOfBuffer <= 0) {
      58. return 1;
      59. }
      60. MYWIDGET_GetUserData(hWin, &MyWidgetSpec, sizeof(MYWIDGETSPEC_Obj));
      61. pExtraBytes =
      62. (U8 *) malloc(sizeof(MYWIDGETSPEC_Obj) + MyWidgetSpec.NumExtraBytes);
      63. if (pExtraBytes) {
      64. MYWIDGET_GetUserData(hWin, pExtraBytes,
      65. sizeof(MYWIDGETSPEC_Obj) + MyWidgetSpec.NumExtraBytes);
      66. if (SizeOfBuffer >= MyWidgetSpec.NumExtraBytes) {
      67. NumBytes = MyWidgetSpec.NumExtraBytes;
      68. } else {
      69. NumBytes = SizeOfBuffer;
      70. }
      71. GUI_MEMCPY(pExtraBytes + sizeof(MYWIDGETSPEC_Obj), pSrc, NumBytes);
      72. MYWIDGET_SetUserData(hWin, pExtraBytes,
      73. sizeof(MYWIDGETSPEC_Obj) + MyWidgetSpec.NumExtraBytes);
      74. free(pExtraBytes);
      75. return 0;
      76. }
      77. return 1;
      78. }
      79. /*********************************************************************
      80. *
      81. * MYWIDGETSPEC_Create
      82. */
      83. MYWIDGETSPEC_Handle MYWIDGETSPEC_Create(int x0, int y0, int xSize, int ySize,
      84. WM_HWIN hWinParent, U32 Style, const char *pText,
      85. WM_CALLBACK * pfCallback, int NumExtraBytes)
      86. {
      87. MYWIDGETSPEC_Handle hWin;
      88. MYWIDGETSPEC_Obj MyWidgetSpec;
      89. WM_CALLBACK *pfUsed;
      90. if (pfCallback) {
      91. pfUsed = pfCallback;
      92. } else {
      93. pfUsed = MYWIDGETSPEC_Callback;
      94. }
      95. MyWidgetSpec = MYWIDGETSPEC_Default;
      96. MyWidgetSpec.NumExtraBytes = NumExtraBytes;
      97. if (pText) {
      98. MyWidgetSpec.pText = pText;
      99. }
      100. hWin = MYWIDGET_Create(x0, y0, xSize, ySize, hWinParent, Style,
      101. pfUsed,
      102. sizeof(MYWIDGETSPEC_Obj) + NumExtraBytes);
      103. MYWIDGET_SetUserData(hWin, &MyWidgetSpec, sizeof(MYWIDGETSPEC_Obj));
      104. return hWin;
      105. }
      Display All


      in the application code if you create this widget without specifing callback:

      C Source Code

      1. hWin = MYWIDGETSPEC_Create(10, 10, 100, 50, WM_HBKWIN, WM_CF_SHOW, NULL, /* callback */ NULL, 0);


      what happens is that a widget of the type MYWIDGET is created with callback MYWIDGETSPEC_Callback. At line 11 there is a call to the MYWIDGET_GetUserData function which, in turn, calls WM_GetUserData to access the MyWidget.NumExtraBytes field, which is not yet populated at the time of this call. Then a fault occurs.

      I solved this by postponing the callback assignment:

      C Source Code

      1. /*********************************************************************
      2. *
      3. * MYWIDGETSPEC_Create
      4. */
      5. MYWIDGETSPEC_Handle MYWIDGETSPEC_Create(int x0, int y0, int xSize, int ySize,
      6. WM_HWIN hWinParent, U32 Style, const char *pText,
      7. WM_CALLBACK * pfCallback, int NumExtraBytes)
      8. {
      9. MYWIDGETSPEC_Handle hWin;
      10. MYWIDGETSPEC_Obj MyWidgetSpec;
      11. WM_CALLBACK *pfUsed;
      12. if (pfCallback) {
      13. pfUsed = pfCallback;
      14. } else {
      15. pfUsed = MYWIDGETSPEC_Callback;
      16. }
      17. MyWidgetSpec = MYWIDGETSPEC_Default;
      18. MyWidgetSpec.NumExtraBytes = NumExtraBytes;
      19. if (pText) {
      20. MyWidgetSpec.pText = pText;
      21. }
      22. hWin = MYWIDGET_Create(x0, y0, xSize, ySize, hWinParent, Style,
      23. NULL,
      24. sizeof(MYWIDGETSPEC_Obj) + NumExtraBytes);
      25. WM_SetCallback(hWin, pfUsed); /* deferred callback assignmet */
      26. MYWIDGET_SetUserData(hWin, &MyWidgetSpec, sizeof(MYWIDGETSPEC_Obj));
      27. return hWin;
      28. }
      Display All


      I don't know, however, if this is the right way to do it, because it presupposes knowledge of the implementation of the widget you intend to specialize and extend. This is not always true (e.g. extending TEXT widgets). in addition, in the prototype of the MYWIDGET_Create function the pfCallback paramter is provided, so it seems counterintuitive and misleading to be forced to pass NULL and then postpone the assignment of the callback.
      Has Segger planned different ways to achieve this?

      How should I do, in general, to extend the functionality of a custom widget?

      best regards
      Max

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

    • Hi,

      On creation the window manager will send WM_CREATE message to window. Unfortunately, at this point you won't have any user data.

      With version 5.44 of emWin we have implemented a message which gets send to a widget when user data are getting set. This allows the user to react on the message and receive the user data.

      Depending on the version you are using you can use this message or define your own message and send it right after setting the user data. Inside the callback function you can react on this message and set a flag which signals that user data are valid or just receive them and save them in a static variable.

      Unfortunately, it is not possible to have the user already present if the callback recieve the WM_CREATE message.

      Regards
      Sven
    • Following this post I implemented MESSAGE_DATA_SET message handler, but in this way I have the same problem.
      This is because when I create the specialized custom widget, it calls MYWIDGET_Create() which in turns send the MESSAGE_DATA_SET, but the callback refers to specialized custom widget (MYWIDGETSPEC_Callback() is invoked), so at the time MESSAGE_DATA_SET is triggered for the first time only MYWIDGET_Obj is populated, whereas MYWIDGETGETSPEC_Obj still not, but MYWIDGETSPEC_Callback() expects MYWIDGETGETSPEC_Obj to be populated as well.
      I solved with dedicated MESSAGE_DATA_SET for every widget type in a chain of specialization (for example MESSAGE_DATA_SET_MYWIDGET and MESSAGE_DATA_SET_MYWIDGETSPEC) but, once again, I don't know if this is the most correct way.
      Could you tell me if SEGGER has thought about other ways to solve this problem?

      best regards
      Max