2 * Acess GUI (AxWin) Version 2
3 * By John Hodge (thePowersGang)
5 * Window Manager and Widget Control
13 extern void Decorator_RenderWidget(tElement *Element);
16 tElement *WM_CreateElement(tElement *Parent, int Type, int Flags);
17 void WM_SetFlags(tElement *Element, int Flags);
18 void WM_SetSize(tElement *Element, int Size);
19 void WM_SetText(tElement *Element, char *Text);
20 void WM_UpdateDimensions(tElement *Element, int Pass);
21 void WM_UpdatePosition(tElement *Element);
22 void WM_RenderWidget(tElement *Element);
26 tElement gWM_RootElement;
28 void (*Init)(tElement *This);
29 void (*UpdateFlags)(tElement *This);
30 void (*UpdateSize)(tElement *This);
31 void (*UpdateText)(tElement *This);
32 } gaWM_WidgetTypes[MAX_ELETYPES] = {
33 {NULL, NULL, NULL, NULL}, // NULL
34 {NULL, NULL, NULL, NULL} // Box
38 // --- Widget Creation and Control ---
39 tElement *WM_CreateElement(tElement *Parent, int Type, int Flags)
43 ret = calloc(sizeof(tElement), 1);
48 if(Parent == NULL) Parent = &gWM_RootElement;
51 // Append to parent's list
52 ret->NextSibling = Parent->LastChild;
53 Parent->LastChild = ret;
54 if(!Parent->FirstChild) Parent->FirstChild = ret;
64 void WM_SetFlags(tElement *Element, int Flags)
66 // Permissions are handled in the message handler
68 gWM_RootElement.Flags = Flags;
72 Element->Flags = Flags;
76 void WM_SetSize(tElement *Element, int Size)
83 void WM_SetText(tElement *Element, char *Text)
86 if(Element->Text) free(Element->Text);
87 Element->Text = strdup(Text);
92 if(Element->Data) free(Element->Data);
93 Element->Data = Image_Load( Element->Text );
95 Element->Flags &= ~ELEFLAG_FIXEDSIZE;
99 Element->Flags |= ELEFLAG_FIXEDSIZE;
100 Element->CachedW = ((tImage*)Element->Data)->Width;
101 Element->CachedH = ((tImage*)Element->Data)->Height;
103 if(Element->Parent && Element->Parent->Flags & ELEFLAG_VERTICAL)
104 Element->Size = Element->CachedH;
106 Element->Size = Element->CachedW;
113 // --- Pre-Rendering ---
115 void WM_UpdateDimensions(tElement *Element, int Pass)
117 int fixedSize = 0, maxCross = 0;
118 int nFixed = 0, nChildren = 0;
122 // Pass zero intialises
125 // If not a fixed size element, initialise the sizes
126 if( !(Element->Flags & ELEFLAG_FIXEDSIZE) )
128 Element->CachedH = 0;
129 Element->CachedW = 0;
132 if( Element->Parent->Flags & ELEFLAG_VERTICAL )
133 Element->CachedH = Element->Size;
135 Element->CachedW = Element->Size;
138 if( !(Element->Flags & ELEFLAG_NOEXPAND) )
140 if( Element->Parent->Flags & ELEFLAG_VERTICAL )
141 Element->CachedW = Element->Parent->CachedW;
143 Element->CachedH = Element->Parent->CachedH;
148 for( child = Element->FirstChild; child; child = child->NextSibling )
150 WM_UpdateDimensions( child, 0 );
152 if( Element->Flags & ELEFLAG_VERTICAL )
154 if( child->CachedH ) {
155 fixedSize += child->CachedH;
156 minSize += child->CachedH;
160 minSize += child->MinHeight;
162 if( maxCross < child->CachedW )
163 maxCross = child->CachedW;;
167 if( child->CachedW ) {
168 fixedSize += child->CachedW;
169 minSize += child->CachedW;
173 minSize += child->MinWidth;
175 if( maxCross < child->CachedH )
176 maxCross = child->CachedH;
180 _SysDebug("WM_UpdateDimensions: nFixed=%i, fixedSize=%i, minSize=%i, maxCross=%i",
181 nFixed, fixedSize, minSize, maxCross
185 // If we don't have our dimensions, get the child dimensions
186 if( Element->CachedW == 0 || Element->CachedH == 0 )
188 if( Element->Flags & ELEFLAG_VERTICAL )
190 if( Element->CachedW == 0 && maxCross )
191 Element->CachedW = Element->PaddingL
192 + Element->PaddingR + maxCross;
194 if( Element->CachedH == 0 && nFixed == nChildren )
195 Element->CachedH = Element->PaddingT
196 + Element->PaddingB + fixedSize
197 + nChildren * Element->GapSize;
202 Element->CachedH = Element->PaddingT
203 + Element->PaddingB + maxCross;
205 if( Element->CachedW == 0 && nFixed == nChildren )
206 Element->CachedW = Element->PaddingL
207 + Element->PaddingR + fixedSize
208 + nChildren * Element->GapSize;
212 // Now, if we have the "length" of the widget, we can size the children
213 if( (Element->Flags & ELEFLAG_VERTICAL && Element->CachedH > 0)
214 || (!(Element->Flags & ELEFLAG_VERTICAL) && Element->CachedW > 0) )
218 // Calculate the size of dynamically sized elements
219 if( Element->Flags & ELEFLAG_VERTICAL )
220 dynSize = Element->CachedH - Element->PaddingT
221 - Element->PaddingB - fixedSize;
223 dynSize = Element->CachedW - Element->PaddingL
224 - Element->PaddingR - fixedSize;
225 dynSize /= nChildren - nFixed;
227 // Itterate children again
228 for( child = Element->FirstChild; child; child = child->NextSibling )
232 // Get the size of them
238 if( Element->Flags & ELEFLAG_VERTICAL ) {
239 if( tmp < child->MinHeight )
240 tmp = child->MinHeight;
241 child->CachedH = tmp;
244 if( tmp < child->MinWidth )
245 tmp = child->MinWidth;
246 child->CachedW = tmp;
249 WM_UpdateDimensions(child, 1);
257 * \brief Updates the dimensions of an element
259 * The dimensions of an element are calculated from the parent's
260 * cross dimension (the side at right angles to the alignment) sans some
263 void WM_UpdateDimensions(tElement *Element, int Pass)
266 int fixedChildSize = 0;
271 _SysDebug("WM_UpdateDimensions: (Element=%p{Flags:0x%x}, Pass=%i)",
272 Element, Element->Flags,
277 if( Element->Flags & ELEFLAG_NORENDER ) return ;
279 if( !(Element->Flags & ELEFLAG_ABSOLUTEPOS) ) {
280 Element->CachedX = 0;
281 Element->CachedY = 0;
283 if( !(Element->Flags & ELEFLAG_FIXEDSIZE) ) {
284 Element->CachedW = 0;
285 Element->CachedH = 0;
289 if( !(Element->Flags & ELEFLAG_FIXEDSIZE) ) {
290 // If the element is sized, fix its dimension(s)
293 if(Element->Flags & ELEFLAG_NOEXPAND)
295 Element->CachedW = Element->Size;
296 Element->CachedH = Element->Size;
299 if( Element->Parent->Flags & ELEFLAG_VERTICAL ) {
300 Element->CachedH = Element->Size;
301 Element->CachedW = Element->Parent->CachedW;
303 Element->CachedW -= (Element->Parent->PaddingL + Element->Parent->PaddingR);
306 Element->CachedW = Element->Size;
307 Element->CachedH = Element->Parent->CachedH;
309 Element->CachedH -= (Element->Parent->PaddingT + Element->Parent->PaddingB);
314 // Ok, so now we need to calculate the size of all child elements
315 // However, if ELEFLAG_NOEXPAND is not set, we can still set one
317 if( !(Element->Flags & ELEFLAG_NOEXPAND) ) {
318 if( Element->Parent->Flags & ELEFLAG_VERTICAL ) {
319 Element->CachedW = Element->Parent->CachedW;
321 Element->CachedW -= (Element->Parent->PaddingL + Element->Parent->PaddingR);
324 Element->CachedH = Element->Parent->CachedH;
326 Element->CachedH -= (Element->Parent->PaddingT + Element->Parent->PaddingB);
332 // Process Children (first pass)
333 for( child = Element->FirstChild; child; child = child->NextSibling )
335 if( child->Flags & ELEFLAG_NORENDER ) continue;
336 WM_UpdateDimensions(child, 0);
338 // Children that don't inherit positions are ignored
339 if( child->Flags & ELEFLAG_ABSOLUTEPOS ) continue;
341 fixedChildSize += child->Size;
346 // If we are wrapping the children, get the largest cross size
347 if( !(Element->Flags & ELEFLAG_FIXEDSIZE)
348 && Element->Flags & ELEFLAG_NOEXPAND
349 && Element->Size == 0 )
351 if( Element->Flags & ELEFLAG_VERTICAL ) {
352 if( Element->CachedW < child->CachedW )
353 Element->CachedW = child->CachedW;
356 if( Element->CachedH < child->CachedH )
357 Element->CachedH = child->CachedH;
362 // Let's avoid a #DIV0 shall we?
365 // Calculate the size of dynamically sized children
366 if( Element->Flags & ELEFLAG_VERTICAL ) {
367 if( Element->CachedH == 0 ) {
368 if( nFixed == nChildren )
369 Element->CachedH = fixedChildSize;
373 dynamicSize = (Element->CachedH - (Element->PaddingT + Element->PaddingB) - fixedChildSize) / nChildren;
376 if( Element->CachedW == 0 ) {
377 if( nFixed == nChildren )
378 Element->CachedW = fixedChildSize;
382 dynamicSize = (Element->CachedW - (Element->PaddingL + Element->PaddingR) - fixedChildSize) / nChildren;
385 // Process Children (second pass)
386 for( child = Element->FirstChild; child; child = child->NextSibling )
388 if( child->Flags & ELEFLAG_NORENDER ) continue;
389 // Children that don't inherit positions are ignored
390 if( child->Flags & ELEFLAG_ABSOLUTEPOS ) continue;
393 if(child->Flags & ELEFLAG_VERTICAL)
394 child->CachedH = dynamicSize;
396 child->CachedW = dynamicSize;
399 WM_UpdateDimensions(child, 1);
401 // If we are wrapping the children, get the largest cross size
402 if( Element->Flags & ELEFLAG_NOEXPAND ) {
403 if( Element->Flags & ELEFLAG_VERTICAL ) {
404 if( Element->CachedW < child->CachedW )
405 Element->CachedW = child->CachedW;
408 if( Element->CachedH < child->CachedH )
409 Element->CachedH = child->CachedH;
416 //Element->CachedW += Element->PaddingL + Element->PaddingR;
417 //Element->CachedH += Element->PaddingT + Element->PaddingB;
419 _SysDebug("Pass %i, Element %p %ix%i",
420 Pass, Element, Element->CachedW, Element->CachedH
424 // Next function will do the coordinates
430 * \brief Updates the position of an element
432 * The parent element sets the positions of its children
434 void WM_UpdatePosition(tElement *Element)
439 if( Element->Flags & ELEFLAG_NORENDER ) return ;
441 _SysDebug("Element=%p{PaddingL:%i, PaddingT:%i}",
442 Element, Element->PaddingL, Element->PaddingT);
445 x = Element->CachedX + Element->PaddingL;
446 y = Element->CachedY + Element->PaddingT;
449 for(child = Element->FirstChild; child; child = child->NextSibling)
455 if( Element->Flags & ELEFLAG_ALIGN_CENTER ) {
456 if(Element->Flags & ELEFLAG_VERTICAL )
457 child->CachedX += Element->CachedW/2 - child->CachedW/2;
459 child->CachedY += Element->CachedH/2 - child->CachedH/2;
461 else if( Element->Flags & ELEFLAG_ALIGN_END ) {
462 if(Element->Flags & ELEFLAG_VERTICAL )
463 child->CachedX += Element->CachedW - child->CachedW;
465 child->CachedY += Element->CachedH - child->CachedH;
468 // Update child's children positions
469 WM_UpdatePosition(child);
472 if(Element->Flags & ELEFLAG_VERTICAL ) {
473 y += child->CachedH + Element->GapSize;
476 x += child->CachedW + Element->GapSize;
480 _SysDebug("Element %p (%i,%i)",
481 Element, Element->CachedX, Element->CachedY
486 void WM_RenderWidget(tElement *Element)
490 if( Element->Flags & ELEFLAG_NORENDER ) return ;
491 if( Element->Flags & ELEFLAG_INVISIBLE ) return ;
493 Decorator_RenderWidget(Element);
495 for(child = Element->FirstChild; child; child = child->NextSibling)
497 WM_RenderWidget(child);
503 gWM_RootElement.CachedX = 0; gWM_RootElement.CachedY = 0;
504 gWM_RootElement.CachedW = giScreenWidth;
505 gWM_RootElement.CachedH = giScreenHeight;
506 gWM_RootElement.Flags |= ELEFLAG_NOEXPAND|ELEFLAG_ABSOLUTEPOS|ELEFLAG_FIXEDSIZE;
508 WM_UpdateDimensions( &gWM_RootElement, 0 );
509 WM_UpdatePosition( &gWM_RootElement );
510 WM_RenderWidget( &gWM_RootElement );