Difference between revisions of "DROPDOWN - Custom (Sample)"

From SEGGER Wiki
Jump to: navigation, search
(Created page with "{| class="wikitable" style="float:right; margin-left: 10px; background-color: #f9f9f9;" ! colspan="2" style="font-weight:bold; font-size:17px; font-family:Arial, Helvetica, sa...")
 
Line 29: Line 29:
 
**********************************************************************
 
**********************************************************************
 
* *
 
* *
* (c) 1996 - 2020 SEGGER Microcontroller GmbH *
+
* (c) 1996 - 2022 SEGGER Microcontroller GmbH *
 
* *
 
* *
 
* Internet: www.segger.com Support: support@segger.com *
 
* Internet: www.segger.com Support: support@segger.com *
Line 35: Line 35:
 
**********************************************************************
 
**********************************************************************
   
** emWin V6.10 - Graphical user interface for embedded applications **
+
** emWin V6.22 - Graphical user interface for embedded applications **
 
emWin is protected by international copyright laws. Knowledge of the
 
emWin is protected by international copyright laws. Knowledge of the
 
source code may not be used to write a similar product. This file may
 
source code may not be used to write a similar product. This file may
Line 42: Line 42:
 
----------------------------------------------------------------------
 
----------------------------------------------------------------------
 
File : DROPDOWN_Custom.c
 
File : DROPDOWN_Custom.c
Purpose : This sample shows how to give a custom look to a DROPDOWN
+
Purpose : Sample that demonstrates how a custom look can be
widget.
+
applied to a DROPDOWN widget and its attached LISTBOX
  +
widget in emWin.
 
Requirements: WindowManager - (x)
 
Requirements: WindowManager - (x)
 
MemoryDevices - ( )
 
MemoryDevices - ( )
Line 50: Line 51:
 
PNG-Library - ( )
 
PNG-Library - ( )
 
TrueTypeFonts - ( )
 
TrueTypeFonts - ( )
  +
Wiki link : https://wiki.segger.com/DROPDOWN_-_Usage_(Sample)
 
---------------------------END-OF-HEADER------------------------------
 
---------------------------END-OF-HEADER------------------------------
 
*/
 
*/
Line 62: Line 64:
 
**********************************************************************
 
**********************************************************************
 
*/
 
*/
  +
#define LB_COLOR_SEL GUI_MAKE_COLOR(0x00F39621)
  +
//
  +
// For emWin versions below 6.22
  +
//
  +
#ifndef DROPDOWN_NOTIFICATION_EXPANDED
  +
#define DROPDOWN_NOTIFICATION_EXPANDED WM_NOTIFICATION_CLICKED
  +
#endif
  +
  +
/*********************************************************************
  +
*
  +
* Static data
  +
*
  +
**********************************************************************
  +
*/
  +
/*********************************************************************
  +
*
  +
* _acContent
  +
*/
  +
static const char * _acContent[] = {
  +
"English",
  +
"Deutsch",
  +
"Espanol",
  +
"Francais",
  +
"Italiano",
  +
"Dansk",
  +
"Eesti",
  +
"Hrvatski",
  +
"Portugues",
  +
"Suomi",
  +
"Afrikaans",
  +
"Swahili",
  +
"Arabic",
  +
"Esperanto",
  +
"Russian",
  +
};
  +
  +
/*********************************************************************
  +
*
  +
* _acangle_arrow
  +
*/
  +
static GUI_CONST_STORAGE unsigned char _acangle_arrow[] = {
  +
/* ABS: 003 Pixels @ 00,00 */ 0, 3, 0xAC, 0x23, 0xC8,
  +
/* RLE: 011 Pixels @ 03,00 */ 11, 0xFF,
  +
/* ABS: 007 Pixels @ 14,00 */ 0, 7, 0xC8, 0x23, 0xAC, 0x22, 0x00, 0x1C, 0xCE,
  +
/* RLE: 009 Pixels @ 04,01 */ 9, 0xFF,
  +
/* ABS: 010 Pixels @ 13,01 */ 0, 10, 0xCE, 0x1C, 0x00, 0x22, 0xC1, 0x17, 0x00, 0x16, 0xCC, 0xFE,
  +
/* RLE: 005 Pixels @ 06,02 */ 5, 0xFF,
  +
/* ABS: 012 Pixels @ 11,02 */ 0, 12, 0xFE, 0xCC, 0x16, 0x00, 0x17, 0xC1, 0xFF, 0xC1, 0x11, 0x00, 0x1E, 0xD0,
  +
/* RLE: 005 Pixels @ 06,03 */ 5, 0xFF,
  +
/* ABS: 021 Pixels @ 11,03 */ 0, 21, 0xD0, 0x1E, 0x00, 0x12, 0xC1, 0xFF, 0xFF, 0xFF, 0xBF, 0x18, 0x00, 0x16, 0xC9, 0xFE, 0xFF, 0xFE, 0xC9, 0x16, 0x00, 0x18, 0xBF,
  +
/* RLE: 005 Pixels @ 15,04 */ 5, 0xFF,
  +
/* ABS: 011 Pixels @ 03,05 */ 0, 11, 0xC3, 0x15, 0x00, 0x1C, 0xCC, 0xFF, 0xCC, 0x1C, 0x00, 0x15, 0xC4,
  +
/* RLE: 007 Pixels @ 14,05 */ 7, 0xFF,
  +
/* ABS: 009 Pixels @ 04,06 */ 0, 9, 0xC0, 0x18, 0x00, 0x13, 0x9D, 0x13, 0x00, 0x19, 0xC0,
  +
/* RLE: 009 Pixels @ 13,06 */ 9, 0xFF,
  +
/* ABS: 007 Pixels @ 05,07 */ 0, 7, 0xC4, 0x16, 0x00, 0x02, 0x00, 0x16, 0xC4,
  +
/* RLE: 011 Pixels @ 12,07 */ 11, 0xFF,
  +
/* ABS: 005 Pixels @ 06,08 */ 0, 5, 0xBC, 0x16, 0x00, 0x16, 0xBC,
  +
/* RLE: 013 Pixels @ 11,08 */ 13, 0xFF,
  +
/* ABS: 003 Pixels @ 07,09 */ 0, 3, 0xC1, 0x2C, 0xC1,
  +
/* RLE: 007 Pixels @ 10,09 */ 7, 0xFF,
  +
0
  +
}; // 129 bytes for 170 pixels
  +
  +
/*********************************************************************
  +
*
  +
* bmangle_arrow
  +
*/
  +
static GUI_CONST_STORAGE GUI_BITMAP bmangle_arrow = {
  +
17, // xSize
  +
10, // ySize
  +
17, // BytesPerLine
  +
GUI_COMPRESS_RLE8, // BitsPerPixel
  +
(const unsigned char*)_acangle_arrow, // Pointer to picture data
  +
NULL, // Pointer to palette
  +
GUI_DRAW_RLEALPHA
  +
};
   
 
/*********************************************************************
 
/*********************************************************************
Line 69: Line 148:
 
**********************************************************************
 
**********************************************************************
 
*/
 
*/
  +
/*********************************************************************
  +
*
  +
* _DrawRectFlat
  +
*/
  +
static void _DrawRectFlat(const GUI_RECT* pRect) {
  +
GUI_CONTEXT Context;
  +
GUI_SaveContext(&Context);
  +
//
  +
// Fill corners with white
  +
//
  +
GUI_SetColor(GUI_WHITE);
  +
GUI_DrawRoundedFrameEx(pRect, 1, 2);
  +
//
  +
// Draws a gray rounded frame
  +
//
  +
LCD_SetColor(GUI_GRAY_C0);
  +
GUI_SetPenSize(2);
  +
GUI_AA_DrawRoundedFrameEx(pRect, 8);
  +
//
  +
// Leftover pixels of rectangle
  +
//
  +
GUI_SetColor(0xFFD8D8D8);
  +
GUI_DrawPixel(pRect->x0 + 2, pRect->y0 + 2);
  +
GUI_DrawPixel(pRect->x0 + 2, pRect->y1 - 2);
  +
GUI_DrawPixel(pRect->x1 - 2, pRect->y1 - 2);
  +
GUI_DrawPixel(pRect->x1 - 2, pRect->y0 + 2);
  +
GUI_RestoreContext(&Context);
  +
}
   
 
/*********************************************************************
 
/*********************************************************************
 
*
 
*
  +
* _ListboxEffect
* _PropsEnabled: Properties for enabled state of dropdown
 
 
*/
 
*/
  +
static const WIDGET_EFFECT _ListboxEffect = {
static DROPDOWN_SKINFLEX_PROPS _Props = {
 
  +
2, // EffectSize
{ GUI_RED, GUI_LIGHTRED, GUI_GRAY_C0 }, // [0] Outer color of surrounding frame, [1] Inner color of surrounding frame, [2] Color of area between frame and inner area
 
  +
NULL, // pfDrawUp
{ GUI_GRAY_C0, GUI_GRAY_C8 }, // [0] First (upper) color of upper gradient, [1] Second (lower) color of upper gradient
 
  +
NULL, // pfDrawUpRect
{ GUI_GRAY_D0, GUI_GRAY_E7 }, // [0] First (upper) color of lower gradient, [1] Second(lower) color of lower gradient
 
{ GUI_RED }, // Color of arrow.
+
NULL, // pfDrawDown
  +
_DrawRectFlat, // pfDrawDownRect
{ GUI_YELLOW }, // Text color.
 
{ GUI_DARKBLUE }, // Color of separator.
+
NULL, // pfDrawFlat
5 // Radius of rounded corner.
+
NULL // pfDrawFlatRect
 
};
 
};
  +
  +
/*********************************************************************
  +
*
  +
* _DropdownSkin
  +
*/
  +
static int _DropdownSkin(const WIDGET_ITEM_DRAW_INFO* pInfo) {
  +
char acText[64];
  +
int Sel;
  +
  +
switch (pInfo->Cmd) {
  +
case WIDGET_ITEM_DRAW_ARROW:
  +
GUI_DrawBitmap(&bmangle_arrow, pInfo->x1 - 10 - bmangle_arrow.XSize, pInfo->y0 + 10);
  +
return 0;
  +
case WIDGET_ITEM_DRAW_BACKGROUND:
  +
//
  +
// Draw frame
  +
//
  +
GUI_SetColor(GUI_GRAY_C0);
  +
GUI_SetPenSize(2);
  +
GUI_AA_DrawRoundedFrame(pInfo->x0, pInfo->y0, pInfo->x1, pInfo->y1, 8);
  +
return 0;
  +
case WIDGET_ITEM_DRAW_TEXT:
  +
Sel = DROPDOWN_GetSel(pInfo->hWin);
  +
DROPDOWN_GetItemText(pInfo->hWin, Sel, acText, sizeof(acText));
  +
GUI_SetColor(GUI_BLACK);
  +
GUI_SetTextMode(GUI_TM_TRANS);
  +
GUI_SetFont(DROPDOWN_GetFont(pInfo->hWin));
  +
GUI_DispStringAt(acText, pInfo->x0 + 10, pInfo->y0 + 2);
  +
return 0;
  +
}
  +
return 0;
  +
}
  +
  +
/*********************************************************************
  +
*
  +
* _OwnerDrawListbox
  +
*/
  +
static int _OwnerDrawListbox(const WIDGET_ITEM_DRAW_INFO* pDrawItemInfo) {
  +
int Sel;
  +
char acBuffer[32];
  +
  +
switch (pDrawItemInfo->Cmd) {
  +
case WIDGET_ITEM_DRAW:
  +
//
  +
// Draw background
  +
//
  +
if (pDrawItemInfo->ItemIndex != -1) {
  +
Sel = LISTBOX_GetSel(pDrawItemInfo->hWin);
  +
if (pDrawItemInfo->ItemIndex == Sel) {
  +
GUI_SetColor(LB_COLOR_SEL);
  +
}
  +
else {
  +
GUI_SetColor(GUI_WHITE);
  +
}
  +
GUI_FillRect(pDrawItemInfo->x0, pDrawItemInfo->y0, pDrawItemInfo->x1, pDrawItemInfo->y1);
  +
//
  +
// Draw item text
  +
//
  +
LISTBOX_GetItemText(pDrawItemInfo->hWin, pDrawItemInfo->ItemIndex, acBuffer, sizeof(acBuffer));
  +
GUI_SetTextMode(GUI_TM_TRANS);
  +
if (pDrawItemInfo->ItemIndex == Sel) {
  +
GUI_SetColor(GUI_WHITE);
  +
}
  +
else {
  +
GUI_SetColor(GUI_BLACK);
  +
}
  +
GUI_DispStringAt(acBuffer, pDrawItemInfo->x0 + 8, pDrawItemInfo->y0);
  +
} else {
  +
GUI_SetColor(GUI_WHITE);
  +
GUI_FillRect(pDrawItemInfo->x0, pDrawItemInfo->y0, pDrawItemInfo->x1, pDrawItemInfo->y1);
  +
}
  +
return 0;
  +
default:
  +
return LISTBOX_OwnerDraw(pDrawItemInfo);
  +
}
  +
}
  +
  +
/*********************************************************************
  +
*
  +
* _cbWin
  +
*/
  +
static void _cbWin(WM_MESSAGE * pMsg) {
  +
char acBuffer[128];
  +
int Sel;
  +
static DROPDOWN_Handle hDropdown;
  +
int i;
  +
int NCode, Id;
  +
int NumItems;
  +
WM_HWIN hList;
  +
  +
switch (pMsg->MsgId) {
  +
case WM_CREATE:
  +
//
  +
// Create DROPDOWN widget
  +
//
  +
hDropdown = DROPDOWN_CreateEx(10, 10, 200, 130, pMsg->hWin, WM_CF_SHOW, 0, GUI_ID_DROPDOWN0);
  +
DROPDOWN_EnableMotion(hDropdown, 1);
  +
//
  +
// Add items to widget
  +
//
  +
for (i = 0; i < GUI_COUNTOF(_acContent); i++) {
  +
DROPDOWN_AddString(hDropdown, *(_acContent + i));
  +
}
  +
//
  +
// Change appearance of DROPDOWN
  +
//
  +
DROPDOWN_SetFont(hDropdown, &GUI_Font24_1);
  +
DROPDOWN_SetSkin(hDropdown, _DropdownSkin);
  +
break;
  +
case WM_PAINT:
  +
GUI_SetBkColor(GUI_WHITE);
  +
GUI_Clear();
  +
GUI_SetColor(GUI_BLACK);
  +
GUI_SetFont(&GUI_Font13B_1);
  +
GUI_SetTextMode(GUI_TM_TRANS);
  +
//
  +
// Display current selection
  +
//
  +
Sel = DROPDOWN_GetSel(hDropdown);
  +
sprintf(acBuffer, "Currently selected item (%d): %s", Sel, *(_acContent + Sel));
  +
GUI_DispStringAt(acBuffer, 250, 10);
  +
//
  +
// Display number of items
  +
//
  +
NumItems = DROPDOWN_GetNumItems(hDropdown);
  +
sprintf(acBuffer, "Number of items: %d", NumItems);
  +
GUI_DispStringAt(acBuffer, 250, 30);
  +
break;
  +
case WM_NOTIFY_PARENT:
  +
//
  +
// Save ID of sender window and notification code
  +
//
  +
Id = WM_GetId(pMsg->hWinSrc);
  +
NCode = pMsg->Data.v;
  +
switch (Id) {
  +
case GUI_ID_DROPDOWN0:
  +
switch (NCode) {
  +
case DROPDOWN_NOTIFICATION_EXPANDED:
  +
hList = DROPDOWN_GetListbox(hDropdown);
  +
if (hList) {
  +
//
  +
// Set custom appearance to LISTBOX
  +
//
  +
LISTBOX_SetOwnerDraw(hList, _OwnerDrawListbox);
  +
WIDGET_SetEffect(hList, &_ListboxEffect);
  +
}
  +
break;
  +
case WM_NOTIFICATION_SEL_CHANGED:
  +
//
  +
// Invalidate parent window when a new item has been selected to display the new selection.
  +
//
  +
WM_InvalidateWindow(pMsg->hWin);
  +
break;
  +
}
  +
break;
  +
}
  +
break;
  +
default:
  +
WM_DefaultProc(pMsg);
  +
break;
  +
}
  +
}
   
 
/*********************************************************************
 
/*********************************************************************
Line 95: Line 364:
 
*/
 
*/
 
void MainTask(void) {
 
void MainTask(void) {
WM_HWIN hDrop;
+
WM_HWIN hWin;
int i;
 
char acBuffer[32];
 
   
GUI_Init();
 
WM_SetDesktopColor(GUI_BLACK);
 
 
//
 
//
  +
// Init GUI
// Create and config DROPDOWN widget
 
 
//
 
//
  +
GUI_Init();
hDrop = DROPDOWN_CreateEx(10, 10, 150, 150, WM_HBKWIN, WM_CF_SHOW, 0, GUI_ID_DROPDOWN0);
 
  +
WM_MULTIBUF_Enable(1);
for(i = 0; i < 10; i++) {
 
sprintf(acBuffer, "Item %d", i);
 
DROPDOWN_AddString(hDrop, acBuffer);
 
}
 
 
//
 
//
  +
// Create parent window
// Set skinflex props to widget
 
// Different states can have the same props or different props for each state.
 
 
//
 
//
  +
hWin = WM_CreateWindowAsChild(0, 0, LCD_GetXSize(), LCD_GetYSize(), WM_HBKWIN, WM_CF_SHOW, _cbWin, 0);
DROPDOWN_SetSkinFlexProps(&_Props, DROPDOWN_SKINFLEX_PI_ENABLED);
 
DROPDOWN_SetSkinFlexProps(&_Props, DROPDOWN_SKINFLEX_PI_EXPANDED);
 
DROPDOWN_SetSkinFlexProps(&_Props, DROPDOWN_SKINFLEX_PI_FOCUSED);
 
   
 
while (1) {
 
while (1) {

Revision as of 15:22, 28 February 2022

DROPDOWN_Custom.c
DROPDOWN Custom.png
File(s) required
  • DROPDOWN_Custom.c
Runs in simulation Yes
Runs on target Yes
Download DROPDOWN_Custom.c

This sample demonstrates custom drawing of a DROPDOWN widget.

Code

/*********************************************************************
*                    SEGGER Microcontroller GmbH                     *
*        Solutions for real time microcontroller applications        *
**********************************************************************
*                                                                    *
*        (c) 1996 - 2022  SEGGER Microcontroller GmbH                *
*                                                                    *
*        Internet: www.segger.com    Support:  support@segger.com    *
*                                                                    *
**********************************************************************

** emWin V6.22 - Graphical user interface for embedded applications **
emWin is protected by international copyright laws.   Knowledge of the
source code may not be used to write a similar product.  This file may
only  be used  in accordance  with  a license  and should  not be  re-
distributed in any way. We appreciate your understanding and fairness.
----------------------------------------------------------------------
File        : DROPDOWN_Custom.c
Purpose     : Sample that demonstrates how a custom look can be
              applied to a DROPDOWN widget and its attached LISTBOX
              widget in emWin.
Requirements: WindowManager - (x)
              MemoryDevices - ( )
              AntiAliasing  - ( )
              VNC-Server    - ( )
              PNG-Library   - ( )
              TrueTypeFonts - ( )
Wiki link   : https://wiki.segger.com/DROPDOWN_-_Usage_(Sample)
---------------------------END-OF-HEADER------------------------------
*/

#include "DIALOG.h"
#include <stdio.h>

/*********************************************************************
*
*       Defines
*
**********************************************************************
*/
#define LB_COLOR_SEL GUI_MAKE_COLOR(0x00F39621)
//
// For emWin versions below 6.22
//
#ifndef DROPDOWN_NOTIFICATION_EXPANDED
  #define DROPDOWN_NOTIFICATION_EXPANDED  WM_NOTIFICATION_CLICKED
#endif

/*********************************************************************
*
*       Static data
*
**********************************************************************
*/
/*********************************************************************
*
*       _acContent
*/
static const char * _acContent[] = {
  "English",
  "Deutsch",
  "Espanol",
  "Francais",
  "Italiano",
  "Dansk",
  "Eesti",
  "Hrvatski",
  "Portugues",
  "Suomi",
  "Afrikaans",
  "Swahili",
  "Arabic",
  "Esperanto",
  "Russian",
};

/*********************************************************************
*
*       _acangle_arrow
*/
static GUI_CONST_STORAGE unsigned char _acangle_arrow[] = {
  /* ABS: 003 Pixels @ 00,00 */ 0, 3, 0xAC, 0x23, 0xC8,
  /* RLE: 011 Pixels @ 03,00 */ 11, 0xFF,
  /* ABS: 007 Pixels @ 14,00 */ 0, 7, 0xC8, 0x23, 0xAC, 0x22, 0x00, 0x1C, 0xCE,
  /* RLE: 009 Pixels @ 04,01 */ 9, 0xFF,
  /* ABS: 010 Pixels @ 13,01 */ 0, 10, 0xCE, 0x1C, 0x00, 0x22, 0xC1, 0x17, 0x00, 0x16, 0xCC, 0xFE,
  /* RLE: 005 Pixels @ 06,02 */ 5, 0xFF,
  /* ABS: 012 Pixels @ 11,02 */ 0, 12, 0xFE, 0xCC, 0x16, 0x00, 0x17, 0xC1, 0xFF, 0xC1, 0x11, 0x00, 0x1E, 0xD0,
  /* RLE: 005 Pixels @ 06,03 */ 5, 0xFF,
  /* ABS: 021 Pixels @ 11,03 */ 0, 21, 0xD0, 0x1E, 0x00, 0x12, 0xC1, 0xFF, 0xFF, 0xFF, 0xBF, 0x18, 0x00, 0x16, 0xC9, 0xFE, 0xFF, 0xFE, 0xC9, 0x16, 0x00, 0x18, 0xBF,
  /* RLE: 005 Pixels @ 15,04 */ 5, 0xFF,
  /* ABS: 011 Pixels @ 03,05 */ 0, 11, 0xC3, 0x15, 0x00, 0x1C, 0xCC, 0xFF, 0xCC, 0x1C, 0x00, 0x15, 0xC4,
  /* RLE: 007 Pixels @ 14,05 */ 7, 0xFF,
  /* ABS: 009 Pixels @ 04,06 */ 0, 9, 0xC0, 0x18, 0x00, 0x13, 0x9D, 0x13, 0x00, 0x19, 0xC0,
  /* RLE: 009 Pixels @ 13,06 */ 9, 0xFF,
  /* ABS: 007 Pixels @ 05,07 */ 0, 7, 0xC4, 0x16, 0x00, 0x02, 0x00, 0x16, 0xC4,
  /* RLE: 011 Pixels @ 12,07 */ 11, 0xFF,
  /* ABS: 005 Pixels @ 06,08 */ 0, 5, 0xBC, 0x16, 0x00, 0x16, 0xBC,
  /* RLE: 013 Pixels @ 11,08 */ 13, 0xFF,
  /* ABS: 003 Pixels @ 07,09 */ 0, 3, 0xC1, 0x2C, 0xC1,
  /* RLE: 007 Pixels @ 10,09 */ 7, 0xFF,
  0
};  // 129 bytes for 170 pixels

/*********************************************************************
*
*       bmangle_arrow
*/
static GUI_CONST_STORAGE GUI_BITMAP bmangle_arrow = {
  17, // xSize
  10, // ySize
  17, // BytesPerLine
  GUI_COMPRESS_RLE8, // BitsPerPixel
  (const unsigned char*)_acangle_arrow,  // Pointer to picture data
  NULL,  // Pointer to palette
  GUI_DRAW_RLEALPHA
};

/*********************************************************************
*
*       Static code
*
**********************************************************************
*/
/*********************************************************************
*
*       _DrawRectFlat
*/
static void _DrawRectFlat(const GUI_RECT* pRect) {
  GUI_CONTEXT Context;
  GUI_SaveContext(&Context);
  //
  // Fill corners with white
  //
  GUI_SetColor(GUI_WHITE);
  GUI_DrawRoundedFrameEx(pRect, 1, 2);
  //
  // Draws a gray rounded frame
  //
  LCD_SetColor(GUI_GRAY_C0);
  GUI_SetPenSize(2);
  GUI_AA_DrawRoundedFrameEx(pRect, 8);
  //
  // Leftover pixels of rectangle
  //
  GUI_SetColor(0xFFD8D8D8);
  GUI_DrawPixel(pRect->x0 + 2, pRect->y0 + 2);
  GUI_DrawPixel(pRect->x0 + 2, pRect->y1 - 2);
  GUI_DrawPixel(pRect->x1 - 2, pRect->y1 - 2);
  GUI_DrawPixel(pRect->x1 - 2, pRect->y0 + 2);
  GUI_RestoreContext(&Context);
}

/*********************************************************************
*
*       _ListboxEffect
*/
static const WIDGET_EFFECT _ListboxEffect = {
  2,             // EffectSize
  NULL,          // pfDrawUp
  NULL,          // pfDrawUpRect
  NULL,          // pfDrawDown
  _DrawRectFlat, // pfDrawDownRect
  NULL,          // pfDrawFlat
  NULL           // pfDrawFlatRect
};

/*********************************************************************
*
*       _DropdownSkin
*/
static int _DropdownSkin(const WIDGET_ITEM_DRAW_INFO* pInfo) {
  char acText[64];
  int  Sel;

  switch (pInfo->Cmd) {
  case WIDGET_ITEM_DRAW_ARROW:
    GUI_DrawBitmap(&bmangle_arrow, pInfo->x1 - 10 - bmangle_arrow.XSize, pInfo->y0 + 10);
    return 0;
  case WIDGET_ITEM_DRAW_BACKGROUND:
    //
    // Draw frame
    //
    GUI_SetColor(GUI_GRAY_C0);
    GUI_SetPenSize(2);
    GUI_AA_DrawRoundedFrame(pInfo->x0, pInfo->y0, pInfo->x1, pInfo->y1, 8);
    return 0;
  case WIDGET_ITEM_DRAW_TEXT:
    Sel = DROPDOWN_GetSel(pInfo->hWin);
    DROPDOWN_GetItemText(pInfo->hWin, Sel, acText, sizeof(acText));
    GUI_SetColor(GUI_BLACK);
    GUI_SetTextMode(GUI_TM_TRANS);
    GUI_SetFont(DROPDOWN_GetFont(pInfo->hWin));
    GUI_DispStringAt(acText, pInfo->x0 + 10, pInfo->y0 + 2);
    return 0;
  }
  return 0;
}

/*********************************************************************
*
*       _OwnerDrawListbox
*/
static int _OwnerDrawListbox(const WIDGET_ITEM_DRAW_INFO* pDrawItemInfo) {
  int  Sel;
  char acBuffer[32];

  switch (pDrawItemInfo->Cmd) {
  case WIDGET_ITEM_DRAW:
    //
    // Draw background
    //
    if (pDrawItemInfo->ItemIndex != -1) {
      Sel = LISTBOX_GetSel(pDrawItemInfo->hWin);
      if (pDrawItemInfo->ItemIndex == Sel) {
        GUI_SetColor(LB_COLOR_SEL);
      }
      else {
        GUI_SetColor(GUI_WHITE);
      }
      GUI_FillRect(pDrawItemInfo->x0, pDrawItemInfo->y0, pDrawItemInfo->x1, pDrawItemInfo->y1);
      //
      // Draw item text
      //
      LISTBOX_GetItemText(pDrawItemInfo->hWin, pDrawItemInfo->ItemIndex, acBuffer, sizeof(acBuffer));
      GUI_SetTextMode(GUI_TM_TRANS);
      if (pDrawItemInfo->ItemIndex == Sel) {
        GUI_SetColor(GUI_WHITE);
      }
      else {
        GUI_SetColor(GUI_BLACK);
      }
      GUI_DispStringAt(acBuffer, pDrawItemInfo->x0 + 8, pDrawItemInfo->y0);
    } else {
      GUI_SetColor(GUI_WHITE);
      GUI_FillRect(pDrawItemInfo->x0, pDrawItemInfo->y0, pDrawItemInfo->x1, pDrawItemInfo->y1);
    }
    return 0;
  default:
    return LISTBOX_OwnerDraw(pDrawItemInfo);
  }
}

/*********************************************************************
*
*       _cbWin
*/
static void _cbWin(WM_MESSAGE * pMsg) {
  char                   acBuffer[128];
  int                    Sel;
  static DROPDOWN_Handle hDropdown;
  int                    i;
  int                    NCode, Id;
  int                    NumItems;
  WM_HWIN                hList;

  switch (pMsg->MsgId) {
  case WM_CREATE:
    //
    // Create DROPDOWN widget
    //
    hDropdown = DROPDOWN_CreateEx(10, 10, 200, 130, pMsg->hWin, WM_CF_SHOW, 0, GUI_ID_DROPDOWN0);
    DROPDOWN_EnableMotion(hDropdown, 1);
    //
    // Add items to widget
    //
    for (i = 0; i < GUI_COUNTOF(_acContent); i++) {
      DROPDOWN_AddString(hDropdown, *(_acContent + i));
    }
    //
    // Change appearance of DROPDOWN
    //
    DROPDOWN_SetFont(hDropdown, &GUI_Font24_1);
    DROPDOWN_SetSkin(hDropdown, _DropdownSkin);
    break;
  case WM_PAINT:
    GUI_SetBkColor(GUI_WHITE);
    GUI_Clear();
    GUI_SetColor(GUI_BLACK);
    GUI_SetFont(&GUI_Font13B_1);
    GUI_SetTextMode(GUI_TM_TRANS);
    //
    // Display current selection
    //
    Sel = DROPDOWN_GetSel(hDropdown);
    sprintf(acBuffer, "Currently selected item (%d): %s", Sel, *(_acContent + Sel));
    GUI_DispStringAt(acBuffer, 250, 10);
    //
    // Display number of items
    //
    NumItems = DROPDOWN_GetNumItems(hDropdown);
    sprintf(acBuffer, "Number of items: %d", NumItems);
    GUI_DispStringAt(acBuffer, 250, 30);
    break;
  case WM_NOTIFY_PARENT:
    //
    // Save ID of sender window and notification code
    //
    Id    = WM_GetId(pMsg->hWinSrc);
    NCode = pMsg->Data.v;
    switch (Id) {
    case GUI_ID_DROPDOWN0:
      switch (NCode) {
      case DROPDOWN_NOTIFICATION_EXPANDED:
        hList = DROPDOWN_GetListbox(hDropdown);
        if (hList) {
          //
          // Set custom appearance to LISTBOX
          //
          LISTBOX_SetOwnerDraw(hList, _OwnerDrawListbox);
          WIDGET_SetEffect(hList, &_ListboxEffect);
        }
        break;
      case WM_NOTIFICATION_SEL_CHANGED:
        //
        // Invalidate parent window when a new item has been selected to display the new selection.
        //
        WM_InvalidateWindow(pMsg->hWin);
        break;
      }
      break;
    }
    break;
  default:
    WM_DefaultProc(pMsg);
    break;
  }
}

/*********************************************************************
*
*       Public code
*
**********************************************************************
*/
/*********************************************************************
*
*       MainTask
*/
void MainTask(void) {
  WM_HWIN hWin;

  //
  // Init GUI
  //
  GUI_Init();
  WM_MULTIBUF_Enable(1);
  //
  // Create parent window
  //
  hWin = WM_CreateWindowAsChild(0, 0, LCD_GetXSize(), LCD_GetYSize(), WM_HBKWIN, WM_CF_SHOW, _cbWin, 0);

  while (1) {
    GUI_Delay(100);
  }
}

/*************************** End of file ****************************/