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

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