Merge branch 'master' of git://localhost/acess2
[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 // --- Message Handlers ---
427 void Widget_NewWidget(tWidgetWin *Info, size_t Len, const tWidgetMsg_Create *Msg)
428 {
429         const int       max_debugname_len = Len - sizeof(tWidgetMsg_Create);
430         tElement        *parent, *new;
431
432         // Sanity check
433         if( Len < sizeof(*Msg) )
434                 return ;
435         if( strnlen(Msg->DebugName, max_debugname_len) == max_debugname_len )
436                 return ;
437         
438         _SysDebug("Widget_NewWidget (%i %i Type %i Flags 0x%x)",
439                 Msg->Parent, Msg->NewID, Msg->Type, Msg->Flags);
440         
441         if(Msg->Type >= ciWM_NumWidgetTypes)
442         {
443                 _SysDebug("Widget_NewWidget - Bad widget type %i", Msg->Type);
444                 return ;
445         }
446
447         // Create
448         parent = Widget_GetElementById(Info, Msg->Parent);
449         if(!parent)
450         {
451                 _SysDebug("Widget_NewWidget - Bad parent ID %i", Msg->Parent);
452                 return ;
453         }
454
455         // Check if the ID is already in use
456         if( Widget_GetElementById(Info, Msg->NewID) )
457                 return ;
458
459         // Create new element
460         new = calloc(sizeof(tElement), 1);
461         new->Window = parent->Window;
462         new->ID = Msg->NewID;
463         new->Type = Msg->Type;
464         new->Parent = parent;
465         new->Flags = Msg->Flags;
466         new->PaddingT = 2;
467         new->PaddingB = 2;
468         new->PaddingL = 2;
469         new->PaddingR = 2;
470         new->CachedX = -1;
471         
472         if( gaWM_WidgetTypes[new->Type]->Init )
473                 gaWM_WidgetTypes[new->Type]->Init(new);
474         
475         // Add to parent's list
476         if(parent->LastChild)
477                 parent->LastChild->NextSibling = new;
478         else
479                 parent->FirstChild = new;
480         parent->LastChild = new;
481
482         // Add to info
483         {
484                 tElement        *ele, *prev = NULL;
485                 for(ele = Info->ElementTable[new->ID % Info->TableSize]; ele; prev = ele, ele = ele->ListNext);
486                 if(prev)
487                         prev->ListNext = new;
488                 else
489                         Info->ElementTable[new->ID % Info->TableSize] = new;
490         }
491
492         Widget_UpdateMinDims(parent);
493 }
494
495 void Widget_SetFocus(tWidgetWin *Info, tElement *Ele)
496 {
497         // TODO: Callbacks
498
499         Info->FocusedElement = Ele;
500 }
501
502 void Widget_SetFlags(tWidgetWin *Info, int Len, const tWidgetMsg_SetFlags *Msg)
503 {
504         tElement        *ele;
505         
506         if( Len < sizeof(*Msg) )
507                 return ;
508
509         _SysDebug("Widget_SetFlags: (%i 0x%x 0x%x)", Msg->WidgetID, Msg->Value, Msg->Mask);
510         
511         ele = Widget_GetElementById(Info, Msg->WidgetID);
512         if(!ele)        return;
513
514         ele->Flags &= ~Msg->Mask;
515         ele->Flags |= Msg->Value & Msg->Mask;
516 }
517
518 void Widget_SetSize(tWidgetWin *Info, int Len, const tWidgetMsg_SetSize *Msg)
519 {
520         tElement        *ele;
521         
522         if( Len < sizeof(*Msg) )
523                 return ;
524         
525         ele = Widget_GetElementById(Info, Msg->WidgetID);
526         if(!ele)        return ;
527         
528         ele->FixedWith = Msg->Value;
529 }
530
531 void Widget_SetText(tWidgetWin *Info, int Len, const tWidgetMsg_SetText *Msg)
532 {
533         tElement        *ele;
534         
535         if( Len < sizeof(*Msg) + 1 )
536                 return ;
537         if( Msg->Text[Len - sizeof(*Msg) - 1] != '\0' )
538                 return ;
539
540         ele = Widget_GetElementById(Info, Msg->WidgetID);
541         if(!ele)        return ;
542
543
544         if( gaWM_WidgetTypes[ele->Type]->UpdateText )
545         {
546                 gaWM_WidgetTypes[ele->Type]->UpdateText( ele, Msg->Text );
547         }
548 //      else
549 //      {
550 //              if(ele->Text)   free(ele->Text);
551 //              ele->Text = strdup(Msg->Text);
552 //      }
553 }
554
555 int Widget_GetText(tWidgetWin *Info, int Len, const tWidgetMsg_SetText *Msg)
556 {
557         if( Len < sizeof(*Msg) )
558                 return 0;
559         if( Len > sizeof(*Msg) )
560                 return 1;       // Pass to user
561         
562         const char      *text = NULL;
563         tElement *ele = Widget_GetElementById(Info, Msg->WidgetID);
564         if(ele)
565                 text = ele->Text;
566         
567         char    buf[sizeof(tWidgetMsg_SetText) + strlen(text?text:"") + 1];
568         tWidgetMsg_SetText      *omsg = (void*)buf;
569         
570         if( text ) {
571                 omsg->WidgetID = Msg->WidgetID;
572                 strcpy(omsg->Text, text);
573         }
574         else {
575                 omsg->WidgetID = -1;
576                 omsg->Text[0] = 0;
577         }
578         
579         WM_SendMessage(Info->RootElement.Window, Info->RootElement.Window, MSG_WIDGET_GETTEXT, sizeof(buf), buf);
580         return 0;
581 }
582
583 int Renderer_Widget_HandleMessage(tWindow *Target, int Msg, int Len, const void *Data)
584 {
585         tWidgetWin      *info = Target->RendererInfo;
586         tElement        *ele;
587         switch(Msg)
588         {
589         case WNDMSG_RESIZE: {
590                 const struct sWndMsg_Resize     *msg = Data;
591                 if(Len < sizeof(*msg))  return -1;              
592
593                 info->RootElement.CachedW = msg->W;             
594                 info->RootElement.CachedH = msg->H;
595                 
596                 // TODO: Update dimensions of all child elements?
597                 
598                 return 0; }
599
600         case WNDMSG_MOUSEMOVE: {
601 //              _SysDebug("TODO: Support widget mouse move events");
602                 return 0; }
603
604         case WNDMSG_MOUSEBTN: {
605                 const struct sWndMsg_MouseButton        *msg = Data;
606                 tWidgetMsg_MouseBtn     client_msg;
607                  int    x, y;
608                  int    rv;
609                 
610                 if(Len < sizeof(*msg))  return -1;
611
612                 x = msg->X; y = msg->Y;
613                 client_msg.Button = msg->Button;
614                 client_msg.bPressed = msg->bPressed;
615
616                 ele = Widget_GetElementByPos(info, x, y);
617                 Widget_SetFocus(info, ele);
618                 // Send event to all elements from `ele` upwards
619                 for( ; ele; ele = ele->Parent )
620                 {
621                         if(gaWM_WidgetTypes[ele->Type]->MouseButton)
622                         {
623                                 rv = gaWM_WidgetTypes[ele->Type]->MouseButton(
624                                         ele,
625                                         x - ele->CachedX, y - ele->CachedY,
626                                         msg->Button, msg->bPressed
627                                         );
628                                 // Allow a type to trap the input from going any higher
629                                 if(rv == 0)     break;
630                         }
631                         else
632                         {
633                                 // Pass to user
634                                 client_msg.X = x - ele->CachedX;
635                                 client_msg.Y = y - ele->CachedY;
636                                 client_msg.WidgetID = ele->ID;
637                                 WM_SendMessage(Target, Target, MSG_WIDGET_MOUSEBTN, sizeof(client_msg), &client_msg);
638                         }
639                 }
640                 return 0; }
641
642         case WNDMSG_KEYDOWN: {
643                 const struct sWndMsg_KeyAction  *msg = Data;
644                 if(Len < sizeof(*msg))  return -1;
645                 
646                 if(!info->FocusedElement)       return 0;
647                 ele = info->FocusedElement;
648
649                 if(gaWM_WidgetTypes[ele->Type]->KeyDown)
650                         gaWM_WidgetTypes[ele->Type]->KeyDown(ele, msg->KeySym, msg->UCS32);
651                 else
652                 {
653                         // TODO: Pass to user
654                 }       
655
656                 return 0; }
657         
658         case WNDMSG_KEYFIRE: {
659                 const struct sWndMsg_KeyAction  *msg = Data;
660                 if(Len < sizeof(*msg))  return -1;
661                 
662                 if(!info->FocusedElement)       return 0;
663                 ele = info->FocusedElement;
664
665                 if(gaWM_WidgetTypes[ele->Type]->KeyFire)
666                         gaWM_WidgetTypes[ele->Type]->KeyFire(ele, msg->KeySym, msg->UCS32);
667                 else
668                 {
669                         // TODO: Pass the buck
670                 }
671                 return 0; }
672         
673         case WNDMSG_KEYUP: {
674                 const struct sWndMsg_KeyAction  *msg = Data;
675                 if(Len < sizeof(*msg))  return -1;
676                 
677                 if(!info->FocusedElement)       return 0;
678                 ele = info->FocusedElement;
679
680                 if(gaWM_WidgetTypes[ele->Type]->KeyUp)
681                         gaWM_WidgetTypes[ele->Type]->KeyUp(ele, msg->KeySym);
682                 else
683                 {
684                         // TODO: Pass the buck
685                 }
686                 return 0; }
687
688         // New Widget
689         case MSG_WIDGET_CREATE:
690                 Widget_NewWidget(info, Len, Data);
691                 return 0;
692
693         // Delete a widget
694         case MSG_WIDGET_DELETE:
695                 _SysDebug("TODO: Implement MSG_WIDGET_DELETE");
696                 return 0;
697
698         // Set focused widget
699         case MSG_WIDGET_SETFOCUS: {
700                 tElement        *ele;
701                 const tWidgetMsg_SetFocus       *msg = Data;
702                 if(Len < sizeof(*msg))  return -1;
703                 
704                 ele = Widget_GetElementById(info, msg->WidgetID);
705                 Widget_SetFocus(info, ele);
706                 return 0; }
707
708         // Set Flags
709         case MSG_WIDGET_SETFLAGS:
710                 Widget_SetFlags(info, Len, Data);
711                 return 0;
712         
713         // Set length
714         case MSG_WIDGET_SETSIZE:
715                 Widget_SetSize(info, Len, Data);
716                 return 0;
717         
718         // Set text
719         case MSG_WIDGET_SETTEXT:
720                 Widget_SetText(info, Len, Data);
721                 return 0;
722         case MSG_WIDGET_GETTEXT:
723                 return Widget_GetText(info, Len, Data);
724         
725         // 
726         default:
727                 return 1;       // Unhandled, pass to user
728         }
729 }
730
731 void Widget_Fire(tElement *Element)
732 {
733         tWidgetMsg_Fire msg;
734         msg.WidgetID = Element->ID;
735         WM_SendMessage(Element->Window, Element->Window, MSG_WIDGET_FIRE, sizeof(msg), &msg);
736 }
737

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