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 if(Type < 0 || Type > NUM_ELETYPES) return NULL;
45 ret = calloc(sizeof(tElement), 1);
50 if(Parent == NULL) Parent = &gWM_RootElement;
53 // Append to parent's list
54 ret->NextSibling = Parent->LastChild;
55 Parent->LastChild = ret;
56 if(!Parent->FirstChild) Parent->FirstChild = ret;
66 void WM_SetFlags(tElement *Element, int Flags)
68 // Permissions are handled in the message handler
70 gWM_RootElement.Flags = Flags;
74 Element->Flags = Flags;
78 void WM_SetSize(tElement *Element, int Size)
85 void WM_SetText(tElement *Element, char *Text)
88 if(Element->Text) free(Element->Text);
89 Element->Text = strdup(Text);
94 if(Element->Data) free(Element->Data);
95 Element->Data = LoadImage( Element->Text );
97 Element->Flags &= ~ELEFLAG_FIXEDSIZE;
101 Element->Flags |= ELEFLAG_FIXEDSIZE;
102 Element->CachedW = ((tImage*)Element->Data)->Width;
103 Element->CachedH = ((tImage*)Element->Data)->Height;
105 if(Element->Parent && Element->Parent->Flags & ELEFLAG_VERTICAL)
106 Element->Size = Element->CachedH;
108 Element->Size = Element->CachedW;
115 // --- Pre-Rendering ---
117 void WM_UpdateDimensions(tElement *Element, int Pass)
119 // Pass zero intialises
122 // If not a fixed size element, initialise the sizes
123 if( !(Element->Flags & ELEFLAG_FIXEDSIZE) )
125 Element->CachedH = 0;
126 Element->CachedW = 0;
129 if( Element->Parent->Flags & ELEFLAG_VERTICAL )
130 Element->CachedH = Element->Size;
132 Element->CachedW = Element->Size;
137 int fixedSize = 0, maxCross = 0;
138 int nFixed = 0, nChildren = 0;
139 for( child = Element->FirstChild; child; child = child->NextSibling )
141 WM_UpdateDimensions( child, 0 );
143 if( Element->Flags & ELEFLAG_VERTICAL )
145 if( child->CachedH ) {
146 fixedSize += child->CachedH;
149 if( maxCross < child->CachedW )
150 maxCross = child->CachedW;
154 if( child->CachedW ) {
155 fixedSize += child->CachedW;
158 if( maxCross < child->CachedH )
159 maxCross = child->CachedH;
165 // If we don't have our dimensions, get the child dimensions
166 if( Element->CachedW == 0 || Element->CachedH == 0 )
168 if( Element->Flags & ELEFLAG_VERTICAL )
170 if( Element->CachedW == 0 && maxCross )
171 Element->CachedW = Element->PaddingL
172 + Element->PaddingR + maxCross;
174 if( Element->CachedH == 0 && nFixed == nChildren )
175 Element->CachedH = Element->PaddingT
176 + Element->PaddingB + fixedSize
177 + nChildren * Element->GapSize;
182 Element->CachedH = Element->PaddingT
183 + Element->PaddingB + maxCross;
185 if( Element->CachedW == 0 && nFixed == nChildren )
186 Element->CachedW = Element->PaddingL
187 + Element->PaddingR + fixedSize
188 + nChildren * Element->GapSize;
192 // Now, if we have the "length" of the widget, we can size the children
193 if( (Element->Flags & ELEFLAG_VERTICAL && Element->CachedH > 0)
194 || (!(Element->Flags & ELEFLAG_VERTICAL) && Element->CachedW > 0) )
198 // Calculate the size of dynamically sized elements
199 if( Element->Flags & ELEFLAG_VERTICAL )
200 dynSize = Element->CachedH - Element->PaddingT
201 - Element->PaddingB - fixedSize;
203 dynSize = Element->CachedW - Element->PaddingL
204 - Element->PaddingR - fixedSize;
205 dynSize /= nChildren - nFixed;
207 // Itterate children again
208 for( child = Element->FirstChild; child; child = child->NextSibling )
212 // Get the size of them
215 else if(dynSize < Element->MinSize)
216 tmp = child->MinSize;
220 if( Element->Flags & ELEFLAG_VERTICAL )
221 child->CachedH = tmp;
223 child->CachedW = tmp;
225 WM_UpdateDimensions(child, 1);
233 * \brief Updates the dimensions of an element
235 * The dimensions of an element are calculated from the parent's
236 * cross dimension (the side at right angles to the alignment) sans some
239 void WM_UpdateDimensions(tElement *Element, int Pass)
242 int fixedChildSize = 0;
247 _SysDebug("WM_UpdateDimensions: (Element=%p{Flags:0x%x}, Pass=%i)",
248 Element, Element->Flags,
253 if( Element->Flags & ELEFLAG_NORENDER ) return ;
255 if( !(Element->Flags & ELEFLAG_ABSOLUTEPOS) ) {
256 Element->CachedX = 0;
257 Element->CachedY = 0;
259 if( !(Element->Flags & ELEFLAG_FIXEDSIZE) ) {
260 Element->CachedW = 0;
261 Element->CachedH = 0;
265 if( !(Element->Flags & ELEFLAG_FIXEDSIZE) ) {
266 // If the element is sized, fix its dimension(s)
269 if(Element->Flags & ELEFLAG_NOEXPAND)
271 Element->CachedW = Element->Size;
272 Element->CachedH = Element->Size;
275 if( Element->Parent->Flags & ELEFLAG_VERTICAL ) {
276 Element->CachedH = Element->Size;
277 Element->CachedW = Element->Parent->CachedW;
279 Element->CachedW -= (Element->Parent->PaddingL + Element->Parent->PaddingR);
282 Element->CachedW = Element->Size;
283 Element->CachedH = Element->Parent->CachedH;
285 Element->CachedH -= (Element->Parent->PaddingT + Element->Parent->PaddingB);
290 // Ok, so now we need to calculate the size of all child elements
291 // However, if ELEFLAG_NOEXPAND is not set, we can still set one
293 if( !(Element->Flags & ELEFLAG_NOEXPAND) ) {
294 if( Element->Parent->Flags & ELEFLAG_VERTICAL ) {
295 Element->CachedW = Element->Parent->CachedW;
297 Element->CachedW -= (Element->Parent->PaddingL + Element->Parent->PaddingR);
300 Element->CachedH = Element->Parent->CachedH;
302 Element->CachedH -= (Element->Parent->PaddingT + Element->Parent->PaddingB);
308 // Process Children (first pass)
309 for( child = Element->FirstChild; child; child = child->NextSibling )
311 if( child->Flags & ELEFLAG_NORENDER ) continue;
312 WM_UpdateDimensions(child, 0);
314 // Children that don't inherit positions are ignored
315 if( child->Flags & ELEFLAG_ABSOLUTEPOS ) continue;
317 fixedChildSize += child->Size;
322 // If we are wrapping the children, get the largest cross size
323 if( !(Element->Flags & ELEFLAG_FIXEDSIZE)
324 && Element->Flags & ELEFLAG_NOEXPAND
325 && Element->Size == 0 )
327 if( Element->Flags & ELEFLAG_VERTICAL ) {
328 if( Element->CachedW < child->CachedW )
329 Element->CachedW = child->CachedW;
332 if( Element->CachedH < child->CachedH )
333 Element->CachedH = child->CachedH;
338 // Let's avoid a #DIV0 shall we?
341 // Calculate the size of dynamically sized children
342 if( Element->Flags & ELEFLAG_VERTICAL ) {
343 if( Element->CachedH == 0 ) {
344 if( nFixed == nChildren )
345 Element->CachedH = fixedChildSize;
349 dynamicSize = (Element->CachedH - (Element->PaddingT + Element->PaddingB) - fixedChildSize) / nChildren;
352 if( Element->CachedW == 0 ) {
353 if( nFixed == nChildren )
354 Element->CachedW = fixedChildSize;
358 dynamicSize = (Element->CachedW - (Element->PaddingL + Element->PaddingR) - fixedChildSize) / nChildren;
361 // Process Children (second pass)
362 for( child = Element->FirstChild; child; child = child->NextSibling )
364 if( child->Flags & ELEFLAG_NORENDER ) continue;
365 // Children that don't inherit positions are ignored
366 if( child->Flags & ELEFLAG_ABSOLUTEPOS ) continue;
369 if(child->Flags & ELEFLAG_VERTICAL)
370 child->CachedH = dynamicSize;
372 child->CachedW = dynamicSize;
375 WM_UpdateDimensions(child, 1);
377 // If we are wrapping the children, get the largest cross size
378 if( Element->Flags & ELEFLAG_NOEXPAND ) {
379 if( Element->Flags & ELEFLAG_VERTICAL ) {
380 if( Element->CachedW < child->CachedW )
381 Element->CachedW = child->CachedW;
384 if( Element->CachedH < child->CachedH )
385 Element->CachedH = child->CachedH;
392 //Element->CachedW += Element->PaddingL + Element->PaddingR;
393 //Element->CachedH += Element->PaddingT + Element->PaddingB;
395 _SysDebug("Pass %i, Element %p %ix%i",
396 Pass, Element, Element->CachedW, Element->CachedH
400 // Next function will do the coordinates
405 * \brief Updates the position of an element
407 * The parent element sets the positions of its children
409 void WM_UpdatePosition(tElement *Element)
414 if( Element->Flags & ELEFLAG_NORENDER ) return ;
416 _SysDebug("Element=%p{PaddingL:%i, PaddingT:%i}",
417 Element, Element->PaddingL, Element->PaddingT);
420 x = Element->CachedX + Element->PaddingL;
421 y = Element->CachedY + Element->PaddingT;
424 for(child = Element->FirstChild; child; child = child->NextSibling)
430 if( Element->Flags & ELEFLAG_ALIGN_CENTER ) {
431 if(Element->Flags & ELEFLAG_VERTICAL )
432 child->CachedX += Element->CachedW/2 - child->CachedW/2;
434 child->CachedY += Element->CachedH/2 - child->CachedH/2;
436 else if( Element->Flags & ELEFLAG_ALIGN_END ) {
437 if(Element->Flags & ELEFLAG_VERTICAL )
438 child->CachedX += Element->CachedW - child->CachedW;
440 child->CachedY += Element->CachedH - child->CachedH;
443 // Update child's children positions
444 WM_UpdatePosition(child);
447 if(Element->Flags & ELEFLAG_VERTICAL ) {
448 y += child->CachedH + Element->GapSize;
451 x += child->CachedW + Element->GapSize;
455 _SysDebug("Element %p (%i,%i)",
456 Element, Element->CachedX, Element->CachedY
461 void WM_RenderWidget(tElement *Element)
465 if( Element->Flags & ELEFLAG_NORENDER ) return ;
466 if( Element->Flags & ELEFLAG_INVISIBLE ) return ;
468 Decorator_RenderWidget(Element);
470 for(child = Element->FirstChild; child; child = child->NextSibling)
472 WM_RenderWidget(child);
478 gWM_RootElement.CachedX = 0; gWM_RootElement.CachedY = 0;
479 gWM_RootElement.CachedW = giScreenWidth;
480 gWM_RootElement.CachedH = giScreenHeight;
481 gWM_RootElement.Flags |= ELEFLAG_NOEXPAND|ELEFLAG_ABSOLUTEPOS|ELEFLAG_FIXEDSIZE;
483 WM_UpdateDimensions( &gWM_RootElement, 0 );
484 WM_UpdatePosition( &gWM_RootElement );
485 WM_RenderWidget( &gWM_RootElement );