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 *AxWin_CreateElement(tElement *Parent, int Type, int Flags, const char *DebugName);
18 void AxWin_DeleteElement(tElement *Element);
19 void AxWin_SetFlags(tElement *Element, int Flags);
20 void AxWin_SetSize(tElement *Element, int Size);
21 void AxWin_SetText(tElement *Element, const char *Text);
22 void WM_UpdateMinDims(tElement *Element);
23 void WM_UpdateDimensions(tElement *Element, int Pass);
24 void WM_UpdatePosition(tElement *Element);
25 void WM_RenderWidget(tElement *Element);
29 tElement gWM_RootElement = {
33 void (*Init)(tElement *This);
34 void (*UpdateFlags)(tElement *This);
35 void (*UpdateSize)(tElement *This);
36 void (*UpdateText)(tElement *This);
37 } gaWM_WidgetTypes[MAX_ELETYPES] = {
38 {NULL, NULL, NULL, NULL}, // NULL
39 {NULL, NULL, NULL, NULL} // Box
43 // --- Widget Creation and Control ---
44 tAxWin_Element *AxWin_CreateElement(tElement *Parent, int Type, int Flags, const char *DebugName)
47 const char *dbgName = DebugName ? DebugName : "";
49 ret = calloc(sizeof(tElement)+strlen(dbgName)+1, 1);
54 strcpy(ret->DebugName, dbgName);
55 if(Parent == NULL) Parent = &gWM_RootElement;
59 // Append to parent's list
61 Parent->LastChild->NextSibling = ret;
62 Parent->LastChild = ret;
63 if(!Parent->FirstChild) Parent->FirstChild = ret;
70 if( gaWM_WidgetTypes[Type].Init )
71 gaWM_WidgetTypes[Type].Init(ret);
73 WM_UpdateMinDims(ret->Parent);
81 void AxWin_DeleteElement(tElement *Element)
83 // TODO: Implement AxWin_DeleteElement
87 * \brief Alter an element's flags
89 void AxWin_SetFlags(tElement *Element, int Flags)
91 // Permissions are handled in the message handler
93 gWM_RootElement.Flags = Flags;
97 Element->Flags = Flags;
101 void AxWin_SetSize(tElement *Element, int Size)
103 if(!Element) return ;
104 Element->FixedWith = Size;
109 * \brief Set the text field of an element
110 * \note Used for the image path on ELETYPE_IMAGE
112 void AxWin_SetText(tElement *Element, const char *Text)
114 if(!Element) return ;
115 if(Element->Text) free(Element->Text);
116 Element->Text = strdup(Text);
118 switch(Element->Type)
121 if(Element->Data) free(Element->Data);
122 Element->Data = Image_Load( Element->Text );
124 Element->Flags &= ~ELEFLAG_FIXEDSIZE;
128 //Element->Flags |= ELEFLAG_FIXEDSIZE;
129 Element->CachedW = ((tImage*)Element->Data)->Width;
130 Element->CachedH = ((tImage*)Element->Data)->Height;
132 if(Element->Parent && Element->Parent->Flags & ELEFLAG_VERTICAL) {
133 Element->MinCross = ((tImage*)Element->Data)->Width;
134 Element->MinWith = ((tImage*)Element->Data)->Height;
137 Element->MinWith = ((tImage*)Element->Data)->Width;
138 Element->MinCross = ((tImage*)Element->Data)->Height;
145 Video_GetTextDims(NULL, Element->Text, &w, &h);
146 if(Element->Parent && Element->Parent->Flags & ELEFLAG_VERTICAL) {
147 Element->MinCross = w;
148 Element->MinWith = h;
151 Element->MinWith = w;
152 Element->MinCross = h;
161 // --- Pre-Rendering ---
163 * \name Pre-Rendering
164 * \brief Updates the element positions and sizes
168 * \brief Updates the dimensions of an element
170 * The dimensions of an element are calculated from the parent's
171 * cross dimension (the side at right angles to the alignment) sans some
174 void WM_UpdateDimensions(tElement *Element, int Pass)
181 int fullCross, dynWith;
183 _SysDebug("WM_UpdateDimensions %p'%s'", Element, Element->DebugName);
184 _SysDebug(" -> Flags = 0x%x", Element->Flags);
185 _SysDebug(" ->CachedH = %i, ->PaddingT = %i, ->PaddingB = %i",
186 Element->CachedH, Element->PaddingT, Element->PaddingB
188 _SysDebug(" ->CachedW = %i, ->PaddingL = %i, ->PaddingR = %i",
189 Element->CachedW, Element->PaddingL, Element->PaddingR
193 for( child = Element->FirstChild; child; child = child->NextSibling )
195 if( child->Flags & ELEFLAG_ABSOLUTEPOS )
198 _SysDebug(" > %p'%s' ->FixedWith = %i", child, child->DebugName, child->FixedWith);
199 if( child->FixedWith )
202 fixedSize += child->FixedWith;
205 if( child->FixedCross && maxCross < child->FixedCross )
206 maxCross = child->FixedCross;
207 if( child->MinCross && maxCross < child->MinCross )
208 maxCross = child->MinCross;
212 _SysDebug(" - nChildren = %i, nFixed = %i", Element, nChildren, nFixed);
213 if( nChildren > nFixed ) {
214 if( Element->Flags & ELEFLAG_VERTICAL )
215 dynWith = Element->CachedH - Element->PaddingT
218 dynWith = Element->CachedW - Element->PaddingL
220 dynWith -= fixedSize;
221 if( dynWith < 0 ) return ;
222 dynWith /= nChildren - nFixed;
223 _SysDebug(" - dynWith = %i", dynWith);
226 if( Element->Flags & ELEFLAG_VERTICAL )
227 fullCross = Element->CachedW - Element->PaddingL - Element->PaddingR;
229 fullCross = Element->CachedH - Element->PaddingT - Element->PaddingB;
231 _SysDebug(" - fullCross = %i", Element, fullCross);
233 // Pass 2 - Set sizes and recurse
234 for( child = Element->FirstChild; child; child = child->NextSibling )
238 _SysDebug(" > %p'%s' ->MinCross = %i", child, child->DebugName, child->MinCross);
241 // --- Cross Size ---
242 if( child->FixedCross )
243 cross = child->FixedCross;
245 // TODO: Extra flag so options are (Expand, Equal, Wrap)
246 else if( child->Flags & ELEFLAG_NOEXPAND )
247 cross = child->MinCross;
250 _SysDebug(" > %p'%s' - cross = %i", child, child->DebugName, cross);
251 if( Element->Flags & ELEFLAG_VERTICAL )
252 child->CachedW = cross;
254 child->CachedH = cross;
257 if( child->FixedWith)
258 with = child->FixedWith;
259 else if( child->Flags & ELEFLAG_NOSTRETCH )
260 with = child->MinWith;
263 _SysDebug(" > %p'%s' - with = %i", child, child->DebugName, with);
264 if( Element->Flags & ELEFLAG_VERTICAL )
265 child->CachedH = with;
267 child->CachedW = with;
269 WM_UpdateDimensions(child, 0);
272 _SysDebug("%p'%s' Done", Element, Element->DebugName);
276 * \brief Updates the position of an element
278 * The parent element sets the positions of its children
280 void WM_UpdatePosition(tElement *Element)
284 static int depth = 0;
285 char indent[depth+1];
287 if( Element->Flags & ELEFLAG_NORENDER ) return ;
289 memset(indent, ' ', depth);
290 indent[depth] = '\0';
293 _SysDebug("%sWM_UpdatePosition %p'%s'{PaddingL:%i, PaddingT:%i}",
294 indent, Element, Element->DebugName, Element->PaddingL, Element->PaddingT);
297 x = Element->CachedX + Element->PaddingL;
298 y = Element->CachedY + Element->PaddingT;
300 _SysDebug("%s- Alignment = %s", indent,
301 (Element->Flags & ELEFLAG_VERTICAL) ? "vertical" : "horizontal");
304 for(child = Element->FirstChild; child; child = child->NextSibling)
306 _SysDebug("%s- x = %i, y = %i", indent, x, y);
311 if( Element->Flags & ELEFLAG_ALIGN_CENTER ) {
312 _SysDebug("%sChild being aligned to center", indent);
313 if(Element->Flags & ELEFLAG_VERTICAL)
314 child->CachedX += Element->CachedW/2 - child->CachedW/2;
316 child->CachedY += Element->CachedH/2 - child->CachedH/2;
318 else if( Element->Flags & ELEFLAG_ALIGN_END) {
319 _SysDebug("%sChild being aligned to end", indent);
320 if(Element->Flags & ELEFLAG_VERTICAL )
321 child->CachedX += Element->CachedW
322 - Element->PaddingL - Element->PaddingR
325 child->CachedY += Element->CachedH
331 _SysDebug("%s> %p'%s' at (%i,%i)", indent, child, child->DebugName,
332 child->CachedX, child->CachedY);
334 // Update child's children positions
335 WM_UpdatePosition(child);
338 if(Element->Flags & ELEFLAG_VERTICAL ) {
339 y += child->CachedH + Element->GapSize;
342 x += child->CachedW + Element->GapSize;
346 _SysDebug("%sElement %p'%s' (%i,%i)",
347 indent, Element, Element->DebugName, Element->CachedX, Element->CachedY
353 * \brief Update the minimum dimensions of the element
354 * \note Called after a child's minimum dimensions have changed
356 void WM_UpdateMinDims(tElement *Element)
362 Element->MinCross = 0;
363 Element->MinWith = 0;
365 for(child = Element->FirstChild; child; child = child->NextSibling)
367 if( Element->Parent &&
368 (Element->Flags & ELEFLAG_VERTICAL) == (Element->Parent->Flags & ELEFLAG_VERTICAL)
371 if(child->FixedCross)
372 Element->MinCross += child->FixedCross;
374 Element->MinCross += child->MinCross;
376 Element->MinWith += child->FixedWith;
378 Element->MinWith += child->MinWith;
382 if(child->FixedCross)
383 Element->MinWith += child->FixedCross;
385 Element->MinWith += child->MinCross;
387 Element->MinCross += child->FixedWith;
389 Element->MinCross += child->MinWith;
394 WM_UpdateMinDims(Element->Parent);
401 void WM_RenderWidget(tElement *Element)
405 if( Element->Flags & ELEFLAG_NORENDER ) return ;
406 if( Element->Flags & ELEFLAG_INVISIBLE ) return ;
408 Decorator_RenderWidget(Element);
410 for(child = Element->FirstChild; child; child = child->NextSibling)
412 WM_RenderWidget(child);
418 gWM_RootElement.CachedX = 0; gWM_RootElement.CachedY = 0;
419 gWM_RootElement.CachedW = giScreenWidth;
420 gWM_RootElement.CachedH = giScreenHeight;
421 gWM_RootElement.Flags |= ELEFLAG_NOEXPAND|ELEFLAG_ABSOLUTEPOS|ELEFLAG_FIXEDSIZE;
423 WM_UpdateDimensions( &gWM_RootElement, 0 );
424 WM_UpdatePosition( &gWM_RootElement );
425 WM_RenderWidget( &gWM_RootElement );