AxWin3 - Heaps of bugfixes to RichText renderer
[tpg/acess2.git] / Usermode / Applications / axwin3_src / WM / renderers / widget.c
1 /*
2  * Acess2 Window Manager v3
3  * - By John Hodge (thePowersGang)
4  *
5  * render_widget.c
6  * - AxWin2 Widget port
7  */
8 #include <common.h>
9 #include <wm_renderer.h>
10 #include <renderer_widget.h>
11 #include <string.h>
12 #include <wm_messages.h>
13 #include <stdlib.h>
14 #include "widget/common.h"
15
16 #define DEFAULT_ELETABLE_SIZE   64
17 #define BORDER_EVERYTHING       0
18
19 // === PROTOTYPES ===
20  int    Renderer_Widget_Init(void);
21 tWindow *Renderer_Widget_Create(int Flags);
22 void    Renderer_Widget_Redraw(tWindow *Window);
23
24 void    Widget_RenderWidget(tWindow *Window, tElement *Element);
25 void    Widget_UpdateDimensions(tElement *Element);
26 void    Widget_UpdatePosition(tElement *Element);
27 // --- Messages
28 tElement        *Widget_GetElementById(tWidgetWin *Info, uint32_t ID);
29 void    Widget_NewWidget(tWidgetWin *Info, size_t Len, const tWidgetMsg_Create *Msg);
30 void    Widget_SetFlags(tWidgetWin *Info, int Len, const tWidgetMsg_SetFlags *Msg);
31 void    Widget_SetSize(tWidgetWin *Info, int Len, const tWidgetMsg_SetSize *Msg);
32 void    Widget_SetText(tWidgetWin *Info, int Len, const tWidgetMsg_SetText *Msg);
33  int    Renderer_Widget_HandleMessage(tWindow *Target, int Msg, int Len, const void *Data);
34
35 // === GLOBALS ===
36 tWMRenderer     gRenderer_Widget = {
37         .Name = "Widget",
38         .CreateWindow = Renderer_Widget_Create,
39         .Redraw = Renderer_Widget_Redraw,
40         .HandleMessage = Renderer_Widget_HandleMessage
41 };
42         
43 // --- Element callbacks
44 tWidgetDef      *gaWM_WidgetTypes[NUM_ELETYPES];
45 const int       ciWM_NumWidgetTypes = sizeof(gaWM_WidgetTypes)/sizeof(gaWM_WidgetTypes[0]);
46 tWidgetDef      gWidget_NullWidgetDef;
47
48 // === CODE ===
49 int Renderer_Widget_Init(void)
50 {
51          int    i;
52         WM_RegisterRenderer(&gRenderer_Widget); 
53
54         for(i = 0; i < ciWM_NumWidgetTypes; i ++)
55         {
56                 if(gaWM_WidgetTypes[i] != NULL) continue;
57                 
58                 gaWM_WidgetTypes[i] = &gWidget_NullWidgetDef;
59         }
60
61         return 0;
62 }
63
64 void Widget_int_SetTypeDef(int Type, tWidgetDef *Ptr)
65 {
66         if( Type < 0 || Type >= ciWM_NumWidgetTypes ) {
67                 _SysDebug("ERROR - Widget ID %i out of range (from %p)",
68                         Type, __builtin_return_address(0)
69                         );
70                 return ;
71         }
72         
73         if( gaWM_WidgetTypes[Type] && gaWM_WidgetTypes[Type] != &gWidget_NullWidgetDef )
74         {
75                 _SysDebug("ERROR - Widget ID %i redefined by %p",
76                         Type, __builtin_return_address(0)
77                         );
78                 return ;
79         }
80         
81         gaWM_WidgetTypes[Type] = Ptr;
82 }
83
84 tWindow *Renderer_Widget_Create(int Flags)
85 {
86         tWindow *ret;
87         tWidgetWin      *info;
88          int    eletable_size = DEFAULT_ELETABLE_SIZE;
89
90         //_SysDebug("Renderer_Widget_Create: (Flags = 0x%x)", Flags);
91
92         // TODO: Use `Flags` as default element count?
93         // - Actaully, it's taken by the root ele flags
94         // - Use the upper bits?
95
96         ret = WM_CreateWindowStruct( sizeof(tWidgetWin) + sizeof(tElement*)*eletable_size );
97         info = ret->RendererInfo;
98         
99         info->TableSize = eletable_size;
100         info->FocusedElement = &info->RootElement;
101         info->RootElement.Window = ret;
102         info->RootElement.ID = -1;
103         info->RootElement.BackgroundColour = 0xCCCCCC;
104         info->RootElement.Flags = Flags;
105         info->RootElement.PaddingT = 2;
106         info->RootElement.PaddingB = 2;
107         info->RootElement.PaddingL = 2;
108         info->RootElement.PaddingR = 2;
109         
110         return ret;
111 }
112
113 void Renderer_Widget_Redraw(tWindow *Window)
114 {
115         tWidgetWin      *info = Window->RendererInfo;
116         WM_Render_FillRect(Window, 0, 0, Window->W, Window->H, info->RootElement.BackgroundColour);
117
118         Widget_UpdateDimensions(&info->RootElement);
119         Widget_UpdatePosition(&info->RootElement);
120
121         Widget_RenderWidget(Window, &info->RootElement);
122 }
123
124 // --- Render / Resize ---
125 void Widget_RenderWidget(tWindow *Window, tElement *Element)
126 {
127         tElement        *child;
128         
129         if( Element->Flags & ELEFLAG_NORENDER ) return ;
130         if( Element->Flags & ELEFLAG_INVISIBLE )        return ;
131
132         #if BORDER_EVERYTHING
133         WM_Render_DrawRect(
134                 Window,
135                 Element->CachedX, Element->CachedY,
136                 Element->CachedW, Element->CachedH,
137                 0
138                 );
139         #endif  
140
141         if(gaWM_WidgetTypes[Element->Type]->Render)
142         {
143                 gaWM_WidgetTypes[Element->Type]->Render(Window, Element);
144         }
145         
146         for(child = Element->FirstChild; child; child = child->NextSibling)
147         {
148                 Widget_RenderWidget(Window, child);
149         }
150 }
151
152 void Widget_UpdateDimensions(tElement *Element)
153 {
154         tElement        *child;
155          int    nChildren = 0;
156          int    nFixed = 0;
157          int    maxCross = 0;
158          int    fixedSize = 0;
159          int    fullCross, dynWith = 0;
160          int    bVertical = Element->Flags & ELEFLAG_VERTICAL;
161
162         // Check if this element can have children
163         if( (gaWM_WidgetTypes[Element->Type]->Flags & WIDGETTYPE_FLAG_NOCHILDREN) )
164                 return ;
165         
166         // Pass 1
167         // - Get the fixed and minimum sizes of the element
168         for( child = Element->FirstChild; child; child = child->NextSibling )
169         {
170                  int    minWith  = bVertical ? child->MinH : child->MinW;
171                  int    minCross = bVertical ? child->MinW : child->MinH;
172
173                 // Ignore elements that will not be rendered
174                 if( child->Flags & ELEFLAG_NORENDER )   continue ;
175                 
176                 // Absolutely positioned elements don't affect dimensions
177                 if( child->Flags & ELEFLAG_ABSOLUTEPOS )        continue ;
178         
179                 // Fixed width elements 
180                 if( child->FixedWith )
181                 {
182                         nFixed ++;
183                         fixedSize += child->FixedWith;
184                 }
185                 else if( child->Flags & ELEFLAG_NOSTRETCH )
186                 {
187                         nFixed ++;
188                         fixedSize += minWith;
189                 }
190                 
191                 if( maxCross < child->FixedCross )      maxCross = child->FixedCross;
192                 if( maxCross < minCross )       maxCross = minCross;
193                 nChildren ++;
194         }
195
196         // Get the dynamic with size from the unused space in the element
197         if( nChildren > nFixed ) {
198                 if( bVertical )
199                         dynWith = Element->CachedH - Element->PaddingT - Element->PaddingB;
200                 else
201                         dynWith = Element->CachedW - Element->PaddingL - Element->PaddingR;
202                 dynWith -= fixedSize;
203                 dynWith -= Element->GapSize * (nChildren-1);
204                 if( dynWith < 0 )       return ;
205                 dynWith /= nChildren - nFixed;
206         }
207         else {
208                 dynWith = 0;
209         }
210         
211         // Get the cross size
212         if( bVertical )
213                 fullCross = Element->CachedW - Element->PaddingL - Element->PaddingR;
214         else
215                 fullCross = Element->CachedH - Element->PaddingT - Element->PaddingB;
216
217         //_SysDebug("%i (p=%i) - WxH=%ix%i",
218         //      Element->ID, (Element->Parent ? Element->Parent->ID : -1),
219         //      Element->CachedW, Element->CachedH
220         //      );
221         //_SysDebug("  %s dynWith = %i, fullCross = %i",
222         //      (Element->Flags & ELEFLAG_VERTICAL ? "Vert" : "Horiz"),
223         //      dynWith, fullCross
224         //      );
225         
226         // Pass 2 - Set sizes and recurse
227         for( child = Element->FirstChild; child; child = child->NextSibling )
228         {
229                  int    w, h;
230
231                 // Ignore elements that will not be rendered
232                 if( child->Flags & ELEFLAG_NORENDER )   continue ;
233                 // Don't resize floating elements
234                 if( child->Flags & ELEFLAG_ABSOLUTEPOS )        continue ;
235                 
236                 // --- Width ---
237                 if( child->Flags & ELEFLAG_NOEXPAND )
238                         w = child->MinW;
239                 else if( bVertical )
240                         w = child->FixedCross ? child->FixedCross : fullCross;
241                 else
242                         w = child->FixedWith ? child->FixedWith : dynWith;
243         
244                 // --- Height ---
245                 if( child->Flags & ELEFLAG_NOSTRETCH )
246                         h = child->MinH;
247                 else if( bVertical )
248                         h = child->FixedWith ? child->FixedWith : dynWith;
249                 else
250                         h = child->FixedCross ? child->FixedCross : fullCross;
251
252                 if(w < child->MinW)     w = child->MinW;
253                 if(h < child->MinH)     h = child->MinH;
254         
255 //              _SysDebug("Child %ix%i (min %ix%i)", w, h, child->MinW, child->MinH);
256         
257                 // Update the dimensions if they have changed
258                 if( child->CachedW == w && child->CachedH == h )
259                         continue ;
260                 child->CachedW = w;
261                 child->CachedH = h;
262                 
263                 // Force the positions of child elements to be recalculated
264                 child->CachedX = -1;
265         
266                 // Recurse down so the child elements can be updated    
267                 Widget_UpdateDimensions(child);
268         }
269         
270 }
271
272 /**
273  * \brief Update the position of child elements
274  */
275 void Widget_UpdatePosition(tElement *Element)
276 {
277         tElement        *child;
278          int    x, y;
279         
280         if( Element->Flags & ELEFLAG_NORENDER ) return ;
281
282         // Check if this element can have children
283         if( (gaWM_WidgetTypes[Element->Type]->Flags & WIDGETTYPE_FLAG_NOCHILDREN) )
284                 return ;
285
286 //      _SysDebug("Widget_UpdatePosition: (Element=%p(%i Type=%i Flags=0x%x))",
287 //              Element, Element->ID, Element->Type, Element->Flags);
288         
289         // Initialise
290         x = Element->CachedX + Element->PaddingL;
291         y = Element->CachedY + Element->PaddingT;
292         
293         // Update each child
294         for(child = Element->FirstChild; child; child = child->NextSibling)
295         {
296                  int    newX, newY;
297                 // Ignore elements that will not be rendered
298                 if( child->Flags & ELEFLAG_NORENDER )   continue ;
299
300                 newX = x; newY = y;
301                 
302                 // Handle alignment (across parent)
303                 if( Element->Flags & ELEFLAG_ALIGN_CENTER ) {
304                         if(Element->Flags & ELEFLAG_VERTICAL)
305                                 newX += Element->CachedW/2 - child->CachedW/2;
306                         else
307                                 newY += Element->CachedH/2 - child->CachedH/2;
308                 }
309                 else if( Element->Flags & ELEFLAG_ALIGN_END ) {
310                         if(Element->Flags & ELEFLAG_VERTICAL )
311                                 newX += Element->CachedW - child->CachedW
312                                         - Element->PaddingL - Element->PaddingR;
313                         else
314                                 newY += Element->CachedH - child->CachedH
315                                         - Element->PaddingT - Element->PaddingB;
316                 }
317
318 //              _SysDebug(" Widget_UpdatePosition[%i]: newX = %i, newY = %i", Element->ID, newX, newY);
319
320                 // Check for changes, and don't update if there was no change
321                 if( newX != child->CachedX || newY != child->CachedY )
322                 {
323                         child->CachedX = newX;
324                         child->CachedY = newY;
325                         // Update child's children positions
326                         Widget_UpdatePosition(child);
327                 }
328                 
329                 // Increment
330                 if(Element->Flags & ELEFLAG_VERTICAL ) {
331                         y += child->CachedH + Element->GapSize;
332                 }
333                 else {
334                         x += child->CachedW + Element->GapSize;
335                 }
336         }
337 }
338
339 /**
340  * \brief Update the minimum dimensions of the element
341  * \note Called after a child's minimum dimensions have changed
342  */
343 void Widget_UpdateMinDims(tElement *Element)
344 {
345         tElement        *child;
346          int    minW, minH;
347          int    nChildren;
348         
349         if(!Element)    return;
350         
351         minW = 0;
352         minH = 0;
353         nChildren = 0;
354         
355         for(child = Element->FirstChild; child; child = child->NextSibling)
356         {
357                  int    cross;
358                 
359                 if(Element->Flags & ELEFLAG_NORENDER)   continue ;
360                 
361                 if( (Element->Flags & ELEFLAG_VERTICAL) )
362                 {
363                         cross = child->FixedCross ? child->FixedCross : child->MinW;
364                         if(minW < cross)        minW = cross;
365                         minH += child->FixedWith  ? child->FixedWith  : child->MinH;
366                 }
367                 else
368                 {
369                         cross = child->FixedCross ? child->FixedCross : child->MinH;
370                         minW += child->FixedWith  ? child->FixedWith  : child->MinW;
371                         if(minH < cross)        minH = cross;
372                 }
373 //              _SysDebug("%i/%i cross = %i", Element->ID, child->ID, cross);
374         
375                 nChildren ++;
376         }
377         
378         if( Element->Flags & ELEFLAG_VERTICAL )
379                 minH += (nChildren - 1) * Element->GapSize;
380         else
381                 minW += (nChildren - 1) * Element->GapSize;
382
383         Element->MinW = Element->PaddingL + minW + Element->PaddingR;
384         Element->MinH = Element->PaddingT + minH + Element->PaddingB;
385
386         // Recurse upwards
387         Widget_UpdateMinDims(Element->Parent);
388 }
389
390 tElement *Widget_GetElementByPos(tWidgetWin *Info, int X, int Y)
391 {
392         tElement        *ret, *next, *ele;
393         
394         next = &Info->RootElement;
395         do
396         {
397                 ret = next;
398                 next = NULL;
399                 for(ele = ret->FirstChild; ele; ele = ele->NextSibling)
400                 {
401                         if(ele->Flags & ELEFLAG_NORENDER)       continue;
402                         if(X < ele->CachedX)    continue;
403                         if(Y < ele->CachedY)    continue;
404                         if(X >= ele->CachedX + ele->CachedW)    continue;
405                         if(Y >= ele->CachedY + ele->CachedH)    continue;
406                         next = ele;
407                 }
408         } while(next);
409         return ret;
410 }
411
412 // --- Helpers ---
413 tElement *Widget_GetElementById(tWidgetWin *Info, uint32_t ID)
414 {
415         tElement        *ele;
416
417         if( ID == -1 )  return &Info->RootElement;
418         
419         if( ID < Info->TableSize )      return Info->ElementTable[ID];
420
421         ele = Info->ElementTable[ID % Info->TableSize];
422         while(ele && ele->ID != ID)     ele = ele->ListNext;
423         return ele;
424 }
425
426 tElement *Widget_int_Create(tWidgetWin *Info, tElement *Parent, int ID, int Type, int Flags)
427 {
428         if( Widget_GetElementById(Info, ID) )
429                 return NULL;
430
431         // Create new element
432         tElement *new = calloc(sizeof(tElement), 1);
433         new->Window = Parent->Window;
434         new->ID = ID;
435         new->Type = Type;
436         new->Parent = Parent;
437         new->Flags = Flags;
438         new->PaddingT = 2;
439         new->PaddingB = 2;
440         new->PaddingL = 2;
441         new->PaddingR = 2;
442         new->CachedX = -1;
443         
444         if( gaWM_WidgetTypes[Type]->Init )
445                 gaWM_WidgetTypes[Type]->Init(new);
446         
447         // Add to parent's list
448         if(Parent->LastChild)
449                 Parent->LastChild->NextSibling = new;
450         else
451                 Parent->FirstChild = new;
452         Parent->LastChild = new;
453
454         // Add to info
455         {
456                 tElement        *ele, *prev = NULL;
457                 for(ele = Info->ElementTable[new->ID % Info->TableSize]; ele; prev = ele, ele = ele->ListNext);
458                 if(prev)
459                         prev->ListNext = new;
460                 else
461                         Info->ElementTable[new->ID % Info->TableSize] = new;
462         }
463         
464         return new;
465 }
466
467 // --- Message Handlers ---
468 void Widget_NewWidget(tWidgetWin *Info, size_t Len, const tWidgetMsg_Create *Msg)
469 {
470         const int       max_debugname_len = Len - sizeof(tWidgetMsg_Create);
471         tElement        *parent;
472
473         // Sanity check
474         if( Len < sizeof(*Msg) )
475                 return ;
476         if( strnlen(Msg->DebugName, max_debugname_len) == max_debugname_len )
477                 return ;
478         
479         _SysDebug("Widget_NewWidget (%i %i Type %i Flags 0x%x)",
480                 Msg->Parent, Msg->NewID, Msg->Type, Msg->Flags);
481         
482         if(Msg->Type >= ciWM_NumWidgetTypes)
483         {
484                 _SysDebug("Widget_NewWidget - Bad widget type %i", Msg->Type);
485                 return ;
486         }
487
488         // Create
489         parent = Widget_GetElementById(Info, Msg->Parent);
490         if(!parent)
491         {
492                 _SysDebug("Widget_NewWidget - Bad parent ID %i", Msg->Parent);
493                 return ;
494         }
495
496         Widget_int_Create(Info, parent, Msg->NewID, Msg->Type, Msg->Flags);
497
498         Widget_UpdateMinDims(parent);
499 }
500
501 void Widget_NewWidgetSubwin(tWidgetWin *Info, size_t Len, const tWidgetMsg_CreateSubWin *Msg)
502 {
503         const int       max_debugname_len = Len - sizeof(tWidgetMsg_CreateSubWin);
504         tElement        *parent, *new;
505
506         // Sanity check
507         if( Len < sizeof(*Msg) )
508                 return ;
509         if( strnlen(Msg->DebugName, max_debugname_len) == max_debugname_len )
510                 return ;
511         
512         parent = Widget_GetElementById(Info, Msg->Parent);
513         if(!parent)     return;
514         if( Widget_GetElementById(Info, Msg->NewID) )   return ;
515         
516         new = Widget_int_Create(Info, parent, Msg->NewID, Msg->Type, Msg->Flags);
517         new->Data = WM_GetWindowByID(parent->Window, Msg->WindowHandle);
518         Widget_UpdateMinDims(parent);
519 }
520
521 void Widget_SetFocus(tWidgetWin *Info, tElement *Ele)
522 {
523         // TODO: Callbacks
524
525         Info->FocusedElement = Ele;
526 }
527
528 void Widget_SetFlags(tWidgetWin *Info, int Len, const tWidgetMsg_SetFlags *Msg)
529 {
530         tElement        *ele;
531         
532         if( Len < sizeof(*Msg) )
533                 return ;
534
535         _SysDebug("Widget_SetFlags: (%i 0x%x 0x%x)", Msg->WidgetID, Msg->Value, Msg->Mask);
536         
537         ele = Widget_GetElementById(Info, Msg->WidgetID);
538         if(!ele)        return;
539
540         ele->Flags &= ~Msg->Mask;
541         ele->Flags |= Msg->Value & Msg->Mask;
542 }
543
544 void Widget_SetSize(tWidgetWin *Info, int Len, const tWidgetMsg_SetSize *Msg)
545 {
546         tElement        *ele;
547         
548         if( Len < sizeof(*Msg) )
549                 return ;
550         
551         ele = Widget_GetElementById(Info, Msg->WidgetID);
552         if(!ele)        return ;
553         
554         ele->FixedWith = Msg->Value;
555 }
556
557 void Widget_SetText(tWidgetWin *Info, int Len, const tWidgetMsg_SetText *Msg)
558 {
559         tElement        *ele;
560         
561         if( Len < sizeof(*Msg) + 1 )
562                 return ;
563         if( Msg->Text[Len - sizeof(*Msg) - 1] != '\0' )
564                 return ;
565
566         ele = Widget_GetElementById(Info, Msg->WidgetID);
567         if(!ele)        return ;
568
569
570         if( gaWM_WidgetTypes[ele->Type]->UpdateText )
571         {
572                 gaWM_WidgetTypes[ele->Type]->UpdateText( ele, Msg->Text );
573         }
574 //      else
575 //      {
576 //              if(ele->Text)   free(ele->Text);
577 //              ele->Text = strdup(Msg->Text);
578 //      }
579 }
580
581 int Widget_GetText(tWidgetWin *Info, int Len, const tWidgetMsg_SetText *Msg)
582 {
583         if( Len < sizeof(*Msg) )
584                 return 0;
585         if( Len > sizeof(*Msg) )
586                 return 1;       // Pass to user
587         
588         const char      *text = NULL;
589         tElement *ele = Widget_GetElementById(Info, Msg->WidgetID);
590         if(ele)
591                 text = ele->Text;
592         
593         char    buf[sizeof(tWidgetMsg_SetText) + strlen(text?text:"") + 1];
594         tWidgetMsg_SetText      *omsg = (void*)buf;
595         
596         if( text ) {
597                 omsg->WidgetID = Msg->WidgetID;
598                 strcpy(omsg->Text, text);
599         }
600         else {
601                 omsg->WidgetID = -1;
602                 omsg->Text[0] = 0;
603         }
604         
605         WM_SendMessage(Info->RootElement.Window, Info->RootElement.Window, MSG_WIDGET_GETTEXT, sizeof(buf), buf);
606         return 0;
607 }
608
609 int Renderer_Widget_HandleMessage(tWindow *Target, int Msg, int Len, const void *Data)
610 {
611         tWidgetWin      *info = Target->RendererInfo;
612         tElement        *ele;
613         switch(Msg)
614         {
615         case WNDMSG_RESIZE: {
616                 const struct sWndMsg_Resize     *msg = Data;
617                 if(Len < sizeof(*msg))  return -1;              
618
619                 info->RootElement.CachedW = msg->W;             
620                 info->RootElement.CachedH = msg->H;
621                 
622                 // TODO: Update dimensions of all child elements?
623                 
624                 return 0; }
625
626         case WNDMSG_MOUSEMOVE: {
627 //              _SysDebug("TODO: Support widget mouse move events");
628                 return 0; }
629
630         case WNDMSG_MOUSEBTN: {
631                 const struct sWndMsg_MouseButton        *msg = Data;
632                 tWidgetMsg_MouseBtn     client_msg;
633                  int    x, y;
634                  int    rv;
635                 
636                 if(Len < sizeof(*msg))  return -1;
637
638                 x = msg->X; y = msg->Y;
639                 client_msg.Button = msg->Button;
640                 client_msg.bPressed = msg->bPressed;
641
642                 ele = Widget_GetElementByPos(info, x, y);
643                 Widget_SetFocus(info, ele);
644                 // Send event to all elements from `ele` upwards
645                 for( ; ele; ele = ele->Parent )
646                 {
647                         if(gaWM_WidgetTypes[ele->Type]->MouseButton)
648                         {
649                                 rv = gaWM_WidgetTypes[ele->Type]->MouseButton(
650                                         ele,
651                                         x - ele->CachedX, y - ele->CachedY,
652                                         msg->Button, msg->bPressed
653                                         );
654                                 // Allow a type to trap the input from going any higher
655                                 if(rv == 0)     break;
656                         }
657                         else
658                         {
659                                 // Pass to user
660                                 client_msg.X = x - ele->CachedX;
661                                 client_msg.Y = y - ele->CachedY;
662                                 client_msg.WidgetID = ele->ID;
663                                 WM_SendMessage(Target, Target, MSG_WIDGET_MOUSEBTN, sizeof(client_msg), &client_msg);
664                         }
665                 }
666                 return 0; }
667
668         case WNDMSG_KEYDOWN: {
669                 const struct sWndMsg_KeyAction  *msg = Data;
670                 if(Len < sizeof(*msg))  return -1;
671                 
672                 if(!info->FocusedElement)       return 0;
673                 ele = info->FocusedElement;
674
675                 if(gaWM_WidgetTypes[ele->Type]->KeyDown)
676                         gaWM_WidgetTypes[ele->Type]->KeyDown(ele, msg->KeySym, msg->UCS32);
677                 else
678                 {
679                         // TODO: Pass to user
680                 }       
681
682                 return 0; }
683         
684         case WNDMSG_KEYFIRE: {
685                 const struct sWndMsg_KeyAction  *msg = Data;
686                 if(Len < sizeof(*msg))  return -1;
687                 
688                 if(!info->FocusedElement)       return 0;
689                 ele = info->FocusedElement;
690
691                 if(gaWM_WidgetTypes[ele->Type]->KeyFire)
692                         gaWM_WidgetTypes[ele->Type]->KeyFire(ele, msg->KeySym, msg->UCS32);
693                 else
694                 {
695                         // TODO: Pass the buck
696                 }
697                 return 0; }
698         
699         case WNDMSG_KEYUP: {
700                 const struct sWndMsg_KeyAction  *msg = Data;
701                 if(Len < sizeof(*msg))  return -1;
702                 
703                 if(!info->FocusedElement)       return 0;
704                 ele = info->FocusedElement;
705
706                 if(gaWM_WidgetTypes[ele->Type]->KeyUp)
707                         gaWM_WidgetTypes[ele->Type]->KeyUp(ele, msg->KeySym);
708                 else
709                 {
710                         // TODO: Pass the buck
711                 }
712                 return 0; }
713
714         // New Widget
715         case MSG_WIDGET_CREATE:
716                 Widget_NewWidget(info, Len, Data);
717                 return 0;
718         case MSG_WIDGET_CREATESUBWIN:
719                 Widget_NewWidgetSubwin(info, Len, Data);
720                 return 0;
721
722         // Delete a widget
723         case MSG_WIDGET_DELETE:
724                 _SysDebug("TODO: Implement MSG_WIDGET_DELETE");
725                 return 0;
726
727         // Set focused widget
728         case MSG_WIDGET_SETFOCUS: {
729                 tElement        *ele;
730                 const tWidgetMsg_SetFocus       *msg = Data;
731                 if(Len < sizeof(*msg))  return -1;
732                 
733                 ele = Widget_GetElementById(info, msg->WidgetID);
734                 Widget_SetFocus(info, ele);
735                 return 0; }
736
737         // Set Flags
738         case MSG_WIDGET_SETFLAGS:
739                 Widget_SetFlags(info, Len, Data);
740                 return 0;
741         
742         // Set length
743         case MSG_WIDGET_SETSIZE:
744                 Widget_SetSize(info, Len, Data);
745                 return 0;
746         
747         // Set text
748         case MSG_WIDGET_SETTEXT:
749                 Widget_SetText(info, Len, Data);
750                 return 0;
751         case MSG_WIDGET_GETTEXT:
752                 return Widget_GetText(info, Len, Data);
753         
754         // 
755         default:
756                 return 1;       // Unhandled, pass to user
757         }
758 }
759
760 void Widget_Fire(tElement *Element)
761 {
762         tWidgetMsg_Fire msg;
763         msg.WidgetID = Element->ID;
764         WM_SendMessage(Element->Window, Element->Window, MSG_WIDGET_FIRE, sizeof(msg), &msg);
765 }
766

UCC git Repository :: git.ucc.asn.au