2 * Acess2 Window Manager v3
3 * - By John Hodge (thePowersGang)
6 * - Pop-up menu window class/renderer
9 #include <wm_renderer.h>
10 #include <menu_messages.h>
11 #include <wm_messages.h>
16 typedef struct sMenuItem
33 typedef struct sMenuWindowInfo
47 void Renderer_Menu_Init(void);
48 tWindow *Renderer_Menu_Create(int Argument);
49 void Renderer_Menu_Redraw(tWindow *Window);
50 int Renderer_Menu_HandleMessage(tWindow *Window, int Msg, int Length, void *Data);
53 const int ciMenu_Gap = 10; // Gap between label and shortcut
54 const int ciMenu_TopPadding = 2;
55 const int ciMenu_BottomPadding = 2;
56 const int ciMenu_LeftPadding = 2;
57 const int ciMenu_RightPadding = 2;
58 const int ciMenu_FontHeight = 16;
59 const int ciMenu_ItemHeight = 20;
60 const int ciMenu_SpacerHeight = 5;
61 const tColour cMenu_BackgroundColour = 0xCCCCCC;
62 const tColour cMenu_BorderColour = 0x000000;
63 const tColour cMenu_SpacerColour = 0x404040;
64 const tColour cMenu_LabelColour = 0x000000;
65 const tColour cMenu_ShortcutColour = 0x404040;
66 const tColour cMenu_HilightColour = 0xE0E0E0;
69 tWMRenderer gRenderer_Menu = {
71 .CreateWindow = Renderer_Menu_Create,
72 .Redraw = Renderer_Menu_Redraw,
73 .HandleMessage = Renderer_Menu_HandleMessage
75 tFont *gMenu_Font = NULL; // System monospace
78 void Renderer_Menu_Init(void)
80 WM_RegisterRenderer(&gRenderer_Menu);
83 tWindow *Renderer_Menu_Create(int Argument)
86 tMenuWindowInfo *info;
88 if(Argument < 5) Argument = 5;
89 if(Argument > 200) Argument = 200;
91 ret = WM_CreateWindowStruct(sizeof(*info) + Argument*sizeof(info->Items[0]));
92 info = ret->RendererInfo;
93 info->MaxItems = Argument;
94 info->HilightedItem = -1;
96 _SysDebug("Renderer_Menu_Create: ->MaxItems = %i", info->MaxItems);
101 void Renderer_Menu_Redraw(tWindow *Window)
103 tMenuWindowInfo *info = Window->RendererInfo;
105 _SysDebug("TODO: Implement Renderer_Menu_Redraw");
107 // _SysDebug("info->nItems = %i", info->nItems);
110 h = ciMenu_TopPadding + ciMenu_BottomPadding;
111 for( i = 0; i < info->nItems; i ++ )
113 if( !info->Items[i] ) continue;
115 if(info->Items[i]->Label)
116 h += ciMenu_ItemHeight;
118 h += ciMenu_SpacerHeight;
121 // _SysDebug("w = %i, h = %i", w, h);
123 // - Resize window to contain all items
124 WM_ResizeWindow(Window, w, h);
126 // - Move the window such that it is on screen
127 // > Make sure to catch if the menu can't fit fully onscreen
130 WM_Render_FillRect(Window, 0, 0, w, h, cMenu_BackgroundColour);
131 WM_Render_DrawRect(Window, 0, 0, w, h, cMenu_BorderColour);
133 // - Render each item
134 y = ciMenu_TopPadding;
135 for( i = 0; i < info->nItems; i ++ )
137 tMenuItem *item = info->Items[i];
145 WM_Render_FillRect(Window,
146 1, y + ciMenu_SpacerHeight/2,
150 y += ciMenu_SpacerHeight;
155 if( info->HilightedItem == i )
157 WM_Render_FillRect(Window,
159 w-2, ciMenu_ItemHeight,
165 WM_Render_DrawText(Window,
166 ciMenu_LeftPadding, y,
167 w, ciMenu_ItemHeight,
175 WM_Render_FillRect(Window,
176 ciMenu_LeftPadding + item->UnderlineX, y + ciMenu_FontHeight + 1,
185 WM_Render_DrawText(Window,
186 w - item->ShortcutWidth - ciMenu_RightPadding, y,
187 w, ciMenu_ItemHeight,
189 cMenu_ShortcutColour,
194 y += ciMenu_ItemHeight;
198 int Renderer_Menu_int_AddItem(tWindow *Window, int Length, void *Data)
200 tMenuWindowInfo *info = Window->RendererInfo;
201 tMenuMsg_AddItem *req = Data;
206 if(Length < sizeof(*req) + 1 || req->Label[Length-sizeof(*req)-1] != '\0') {
207 _SysDebug("Renderer_Menu_int_AddItem: Size checks failed");
211 if(req->ID >= info->MaxItems) {
212 _SysDebug("Renderer_Menu_int_AddItem: ID (%i) >= MaxItems (%i)",
213 req->ID, info->MaxItems);
218 if(info->Items[req->ID]) return 0;
220 if(req->ID >= info->nItems) info->nItems = req->ID + 1;
222 item = malloc(sizeof(tMenuItem)+strlen(req->Label));
223 info->Items[req->ID] = item;
225 if(req->Label[0] == '\0')
234 char *dest = item->Data;
235 char *src = req->Label;
239 item->KeyOffset = -1;
241 for(ofs = 0; *src && *src != '\t'; ofs ++)
245 item->KeyOffset = ofs;
253 // - Key combo / Shortcut
257 item->Shortcut = dest;
258 strcpy(item->Shortcut, src);
262 item->Shortcut = NULL;
266 // - Underline (hotkey)
267 if(item->KeyOffset == -1)
269 item->UnderlineX = 0;
270 item->UnderlineW = 0;
274 char tmp = item->Label[item->KeyOffset];
275 // Get width of preceding substring
276 item->Label[item->KeyOffset] = '\0';
277 WM_Render_GetTextDims(NULL, item->Label, &item->UnderlineX, NULL);
278 // Get the width of the underlined character
279 // TODO: Fix for high UTF-8 characters
280 item->Label[item->KeyOffset] = tmp;
281 tmp = item->Label[item->KeyOffset+1];
282 item->Label[item->KeyOffset+1] = '\0';
283 WM_Render_GetTextDims(
284 NULL, item->Label+item->KeyOffset,
285 &item->UnderlineW, NULL
287 item->Label[item->KeyOffset+1] = tmp;
290 WM_Render_GetTextDims(NULL, item->Label, &item->LabelWidth, NULL);
292 WM_Render_GetTextDims(NULL, item->Shortcut, &item->ShortcutWidth, NULL);
294 item->ShortcutWidth = 0;
296 if( item->LabelWidth > info->MaxLabelWidth )
297 info->MaxLabelWidth = item->LabelWidth;
298 if( item->ShortcutWidth > info->MaxShortcutWidth )
299 info->MaxShortcutWidth = item->ShortcutWidth;
301 if( info->MaxLabelWidth + info->MaxShortcutWidth + ciMenu_Gap > info->CachedW )
303 info->CachedW = ciMenu_LeftPadding + info->MaxLabelWidth
304 + ciMenu_Gap + info->MaxShortcutWidth
305 + ciMenu_RightPadding;
306 // TODO: Smarter height?
307 WM_ResizeWindow(Window, info->CachedW, info->nItems*ciMenu_ItemHeight);
313 int Renderer_Menu_HandleMessage(tWindow *Window, int Msg, int Length, void *Data)
317 case WNDMSG_MOUSEMOVE: {
318 tMenuWindowInfo *info = Window->RendererInfo;
319 struct sWndMsg_MouseMove *msg = Data;
322 if(Length < sizeof(*msg)) return -1;
324 if( msg->X < 0 || msg->X >= Window->W )
333 for( i = 0; i < info->nItems; i ++ )
335 if( !info->Items[i] ) continue;
337 if( !info->Items[i]->Label )
339 // Spacer - doesn't hilight
340 if(y < ciMenu_SpacerHeight) {
344 y -= ciMenu_SpacerHeight;
348 // Normal item, set the hilight
349 if(y < ciMenu_ItemHeight) {
353 y -= ciMenu_ItemHeight;
358 if( new_hilight != info->HilightedItem )
360 info->HilightedItem = new_hilight;
361 WM_Invalidate(Window);
366 // Manipulation messages
367 case MSG_MENU_ADDITEM:
368 _SysDebug("MSG_MENU_ADDITEM");
369 return Renderer_Menu_int_AddItem(Window, Length, Data);
371 // Only message to pass to client
372 case MSG_MENU_SELECT: