2 * Acess GUI (AxWin) Version 2
3 * By John Hodge (thePowersGang)
5 * Window Manager and Widget Control
13 extern void Decorator_RenderWidget(tElement *Element);
14 extern void Video_GetTextDims(tFont *Font, const char *Text, int *W, int *H);
17 tElement *WM_CreateElement(tElement *Parent, int Type, int Flags, const char *DebugName);
18 void WM_UpdateMinDims(tElement *Element);
19 void WM_SetFlags(tElement *Element, int Flags);
20 void WM_SetSize(tElement *Element, int Size);
21 void WM_SetText(tElement *Element, const char *Text);
22 void WM_UpdateDimensions(tElement *Element, int Pass);
23 void WM_UpdatePosition(tElement *Element);
24 void WM_RenderWidget(tElement *Element);
28 tElement gWM_RootElement = {
32 void (*Init)(tElement *This);
33 void (*UpdateFlags)(tElement *This);
34 void (*UpdateSize)(tElement *This);
35 void (*UpdateText)(tElement *This);
36 } gaWM_WidgetTypes[MAX_ELETYPES] = {
37 {NULL, NULL, NULL, NULL}, // NULL
38 {NULL, NULL, NULL, NULL} // Box
42 // --- Widget Creation and Control ---
43 tElement *WM_CreateElement(tElement *Parent, int Type, int Flags, const char *DebugName)
46 const char *dbgName = DebugName ? DebugName : "";
48 ret = calloc(sizeof(tElement)+strlen(dbgName)+1, 1);
53 strcpy(ret->DebugName, dbgName);
54 if(Parent == NULL) Parent = &gWM_RootElement;
58 // Append to parent's list
60 Parent->LastChild->NextSibling = ret;
61 Parent->LastChild = ret;
62 if(!Parent->FirstChild) Parent->FirstChild = ret;
69 if( gaWM_WidgetTypes[Type].Init )
70 gaWM_WidgetTypes[Type].Init(ret);
72 WM_UpdateMinDims(ret->Parent);
78 * \brief Alter an element's flags
80 void WM_SetFlags(tElement *Element, int Flags)
82 // Permissions are handled in the message handler
84 gWM_RootElement.Flags = Flags;
88 Element->Flags = Flags;
92 void WM_SetSize(tElement *Element, int Size)
95 Element->FixedWith = Size;
100 * \brief Set the text field of an element
101 * \note Used for the image path on ELETYPE_IMAGE
103 void WM_SetText(tElement *Element, const char *Text)
105 if(!Element) return ;
106 if(Element->Text) free(Element->Text);
107 Element->Text = strdup(Text);
109 switch(Element->Type)
112 if(Element->Data) free(Element->Data);
113 Element->Data = Image_Load( Element->Text );
115 Element->Flags &= ~ELEFLAG_FIXEDSIZE;
119 //Element->Flags |= ELEFLAG_FIXEDSIZE;
120 Element->CachedW = ((tImage*)Element->Data)->Width;
121 Element->CachedH = ((tImage*)Element->Data)->Height;
123 if(Element->Parent && Element->Parent->Flags & ELEFLAG_VERTICAL) {
124 Element->MinCross = ((tImage*)Element->Data)->Width;
125 Element->MinWith = ((tImage*)Element->Data)->Height;
128 Element->MinWith = ((tImage*)Element->Data)->Width;
129 Element->MinCross = ((tImage*)Element->Data)->Height;
136 Video_GetTextDims(NULL, Element->Text, &w, &h);
137 if(Element->Parent && Element->Parent->Flags & ELEFLAG_VERTICAL) {
138 Element->MinCross = w;
139 Element->MinWith = h;
142 Element->MinWith = w;
143 Element->MinCross = h;
152 // --- Pre-Rendering ---
154 * \name Pre-Rendering
155 * \brief Updates the element positions and sizes
159 * \brief Updates the dimensions of an element
161 * The dimensions of an element are calculated from the parent's
162 * cross dimension (the side at right angles to the alignment) sans some
165 void WM_UpdateDimensions(tElement *Element, int Pass)
172 int fullCross, dynWith;
174 _SysDebug("WM_UpdateDimensions %p'%s'", Element, Element->DebugName);
175 _SysDebug(" -> Flags = 0x%x", Element->Flags);
176 _SysDebug(" ->CachedH = %i, ->PaddingT = %i, ->PaddingB = %i",
177 Element->CachedH, Element->PaddingT, Element->PaddingB
179 _SysDebug(" ->CachedW = %i, ->PaddingL = %i, ->PaddingR = %i",
180 Element->CachedW, Element->PaddingL, Element->PaddingR
184 for( child = Element->FirstChild; child; child = child->NextSibling )
186 if( child->Flags & ELEFLAG_ABSOLUTEPOS )
189 _SysDebug(" > %p'%s' ->FixedWith = %i", child, child->DebugName, child->FixedWith);
190 if( child->FixedWith )
193 fixedSize += child->FixedWith;
196 if( child->FixedCross && maxCross < child->FixedCross )
197 maxCross = child->FixedCross;
198 if( child->MinCross && maxCross < child->MinCross )
199 maxCross = child->MinCross;
203 _SysDebug(" - nChildren = %i, nFixed = %i", Element, nChildren, nFixed);
204 if( nChildren > nFixed ) {
205 if( Element->Flags & ELEFLAG_VERTICAL )
206 dynWith = Element->CachedH - Element->PaddingT
209 dynWith = Element->CachedW - Element->PaddingL
211 dynWith -= fixedSize;
212 if( dynWith < 0 ) return ;
213 dynWith /= nChildren - nFixed;
214 _SysDebug(" - dynWith = %i", dynWith);
217 if( Element->Flags & ELEFLAG_VERTICAL )
218 fullCross = Element->CachedW - Element->PaddingL - Element->PaddingR;
220 fullCross = Element->CachedH - Element->PaddingT - Element->PaddingB;
222 _SysDebug(" - fullCross = %i", Element, fullCross);
224 // Pass 2 - Set sizes and recurse
225 for( child = Element->FirstChild; child; child = child->NextSibling )
229 _SysDebug(" > %p'%s' ->MinCross = %i", child, child->DebugName, child->MinCross);
232 // --- Cross Size ---
233 if( child->FixedCross )
234 cross = child->FixedCross;
236 // TODO: Extra flag so options are (Expand, Equal, Wrap)
237 else if( child->Flags & ELEFLAG_NOEXPAND )
238 cross = child->MinCross;
241 _SysDebug(" > %p'%s' - cross = %i", child, child->DebugName, cross);
242 if( Element->Flags & ELEFLAG_VERTICAL )
243 child->CachedW = cross;
245 child->CachedH = cross;
248 if( child->FixedWith)
249 with = child->FixedWith;
250 else if( child->Flags & ELEFLAG_NOSTRETCH )
251 with = child->MinWith;
254 _SysDebug(" > %p'%s' - with = %i", child, child->DebugName, with);
255 if( Element->Flags & ELEFLAG_VERTICAL )
256 child->CachedH = with;
258 child->CachedW = with;
260 WM_UpdateDimensions(child, 0);
263 _SysDebug("%p'%s' Done", Element, Element->DebugName);
267 * \brief Updates the position of an element
269 * The parent element sets the positions of its children
271 void WM_UpdatePosition(tElement *Element)
275 static int depth = 0;
276 char indent[depth+1];
278 if( Element->Flags & ELEFLAG_NORENDER ) return ;
280 memset(indent, ' ', depth);
281 indent[depth] = '\0';
284 _SysDebug("%sWM_UpdatePosition %p'%s'{PaddingL:%i, PaddingT:%i}",
285 indent, Element, Element->DebugName, Element->PaddingL, Element->PaddingT);
288 x = Element->CachedX + Element->PaddingL;
289 y = Element->CachedY + Element->PaddingT;
291 _SysDebug("%s- Alignment = %s", indent,
292 (Element->Flags & ELEFLAG_VERTICAL) ? "vertical" : "horizontal");
295 for(child = Element->FirstChild; child; child = child->NextSibling)
297 _SysDebug("%s- x = %i, y = %i", indent, x, y);
302 if( Element->Flags & ELEFLAG_ALIGN_CENTER ) {
303 _SysDebug("%sChild being aligned to center", indent);
304 if(Element->Flags & ELEFLAG_VERTICAL)
305 child->CachedX += Element->CachedW/2 - child->CachedW/2;
307 child->CachedY += Element->CachedH/2 - child->CachedH/2;
309 else if( Element->Flags & ELEFLAG_ALIGN_END) {
310 _SysDebug("%sChild being aligned to end", indent);
311 if(Element->Flags & ELEFLAG_VERTICAL )
312 child->CachedX += Element->CachedW
313 - Element->PaddingL - Element->PaddingR
316 child->CachedY += Element->CachedH
322 _SysDebug("%s> %p'%s' at (%i,%i)", indent, child, child->DebugName,
323 child->CachedX, child->CachedY);
325 // Update child's children positions
326 WM_UpdatePosition(child);
329 if(Element->Flags & ELEFLAG_VERTICAL ) {
330 y += child->CachedH + Element->GapSize;
333 x += child->CachedW + Element->GapSize;
337 _SysDebug("%sElement %p'%s' (%i,%i)",
338 indent, Element, Element->DebugName, Element->CachedX, Element->CachedY
344 * \brief Update the minimum dimensions of the element
345 * \note Called after a child's minimum dimensions have changed
347 void WM_UpdateMinDims(tElement *Element)
353 Element->MinCross = 0;
354 Element->MinWith = 0;
356 for(child = Element->FirstChild; child; child = child->NextSibling)
358 if( Element->Parent &&
359 (Element->Flags & ELEFLAG_VERTICAL) == (Element->Parent->Flags & ELEFLAG_VERTICAL)
362 if(child->FixedCross)
363 Element->MinCross += child->FixedCross;
365 Element->MinCross += child->MinCross;
367 Element->MinWith += child->FixedWith;
369 Element->MinWith += child->MinWith;
373 if(child->FixedCross)
374 Element->MinWith += child->FixedCross;
376 Element->MinWith += child->MinCross;
378 Element->MinCross += child->FixedWith;
380 Element->MinCross += child->MinWith;
385 WM_UpdateMinDims(Element->Parent);
392 void WM_RenderWidget(tElement *Element)
396 if( Element->Flags & ELEFLAG_NORENDER ) return ;
397 if( Element->Flags & ELEFLAG_INVISIBLE ) return ;
399 Decorator_RenderWidget(Element);
401 for(child = Element->FirstChild; child; child = child->NextSibling)
403 WM_RenderWidget(child);
409 gWM_RootElement.CachedX = 0; gWM_RootElement.CachedY = 0;
410 gWM_RootElement.CachedW = giScreenWidth;
411 gWM_RootElement.CachedH = giScreenHeight;
412 gWM_RootElement.Flags |= ELEFLAG_NOEXPAND|ELEFLAG_ABSOLUTEPOS|ELEFLAG_FIXEDSIZE;
414 WM_UpdateDimensions( &gWM_RootElement, 0 );
415 WM_UpdatePosition( &gWM_RootElement );
416 WM_RenderWidget( &gWM_RootElement );