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

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