2 * Acess2 Window Manager v3
3 * - By John Hodge (thePowersGang)
9 #include <wm_renderer.h>
10 #include <renderer_widget.h>
14 typedef struct sWidgetWin tWidgetWin;
15 typedef struct sAxWin_Element tElement;
20 enum eElementTypes Type;
22 uint32_t ID; //!< Application provided ID number
23 tElement *ListNext; //!< Next element in bucket
29 tElement *NextSibling;
31 // User modifiable attributes
32 short PaddingL, PaddingR;
33 short PaddingT, PaddingB;
38 short FixedWith; //!< Fixed lengthways Size attribute (height)
39 short FixedCross; //!< Fixed Cross Size attribute (width)
43 // -- Attributes maitained by the element code
44 // Not touched by the user
45 short MinWith; //!< Minimum long size
46 short MinCross; //!< Minimum cross size
47 void *Data; //!< Per-type data
50 short CachedX, CachedY;
51 short CachedW, CachedH;
59 int TableSize; //!< Number of entries, anything over will wrap
60 tElement *ElementTable[]; //!< Hash table essentially
64 tWindow *Renderer_Widget_Create(int Width, int Height, int Flags);
65 void Renderer_Widget_Redraw(tWindow *Window);
66 int Renderer_Widget_HandleMessage(tWindow *Target, int Msg, int Len, void *Data);
69 tWMRenderer gRenderer_Widget = {
71 .CreateWindow = Renderer_Widget_Create,
72 .Redraw = Renderer_Widget_Redraw,
73 .HandleMessage = Renderer_Widget_HandleMessage
77 int Renderer_Widget_Init(void)
79 WM_RegisterRenderer(&gRenderer_Widget);
84 tWindow *Renderer_Widget_Create(int Width, int Height, int Flags)
87 return WM_CreateWindowStruct( sizeof(tWidgetWin) );
90 void Renderer_Widget_Redraw(tWindow *Window)
94 // --- Render / Resize ---
95 void Widget_UpdateDimensions(tElement *Element)
102 int fullCross, dynWith;
105 // - Get the fixed and minimum sizes of the element
106 for( child = Element->FirstChild; child; child = child->NextSibling )
108 // Ignore elements that will not be rendered
109 if( child->Flags & ELEFLAG_NORENDER ) continue ;
111 // Absolutely positioned elements don't affect dimensions
112 if( child->Flags & ELEFLAG_ABSOLUTEPOS ) continue ;
114 // Fixed width elements
115 if( child->FixedWith )
118 fixedSize += child->FixedWith;
121 if( child->FixedCross && maxCross < child->FixedCross )
122 maxCross = child->FixedCross;
123 if( child->MinCross && maxCross < child->MinCross )
124 maxCross = child->MinCross;
128 // Get the dynamic with size from the unused space in the element
129 if( nChildren > nFixed ) {
130 if( Element->Flags & ELEFLAG_VERTICAL )
131 dynWith = Element->CachedH - Element->PaddingT - Element->PaddingB;
133 dynWith = Element->CachedW - Element->PaddingL - Element->PaddingR;
134 dynWith -= fixedSize;
135 if( dynWith < 0 ) return ;
136 dynWith /= nChildren - nFixed;
139 // Get the cross size
140 if( Element->Flags & ELEFLAG_VERTICAL )
141 fullCross = Element->CachedW - Element->PaddingL - Element->PaddingR;
143 fullCross = Element->CachedH - Element->PaddingT - Element->PaddingB;
145 // Pass 2 - Set sizes and recurse
146 for( child = Element->FirstChild; child; child = child->NextSibling )
150 // Ignore elements that will not be rendered
151 if( child->Flags & ELEFLAG_NORENDER ) continue ;
153 // --- Cross Size ---
154 // TODO: Expand to fill?
155 // TODO: Extra flag so options are (Expand, Equal, Wrap)
156 if( child->FixedCross )
157 cross = child->FixedCross;
158 else if( child->Flags & ELEFLAG_NOEXPAND )
159 cross = child->MinCross;
164 if( child->FixedWith)
165 with = child->FixedWith;
166 else if( child->Flags & ELEFLAG_NOSTRETCH )
167 with = child->MinWith;
172 // Update the dimensions if they have changed
173 if( Element->Flags & ELEFLAG_VERTICAL ) {
174 // If no change, don't recurse
175 if( child->CachedW == cross && child->CachedH == with )
177 child->CachedW = cross;
178 child->CachedH = with;
181 // If no change, don't recurse
182 if( child->CachedW == with && child->CachedH == cross )
184 child->CachedW = with;
185 child->CachedH = cross;
188 // Force the positions of child elements to be recalculated
191 // Recurse down so the child elements can be updated
192 Widget_UpdateDimensions(child);
198 * \brief Update the position of child elements
200 void Widget_UpdatePosition(tElement *Element)
205 if( Element->Flags & ELEFLAG_NORENDER ) return ;
208 x = Element->CachedX + Element->PaddingL;
209 y = Element->CachedY + Element->PaddingT;
212 for(child = Element->FirstChild; child; child = child->NextSibling)
215 // Ignore elements that will not be rendered
216 if( child->Flags & ELEFLAG_NORENDER ) continue ;
221 if( Element->Flags & ELEFLAG_ALIGN_CENTER ) {
222 if(Element->Flags & ELEFLAG_VERTICAL)
223 newX += Element->CachedW/2 - child->CachedW/2;
225 newY += Element->CachedH/2 - child->CachedH/2;
227 else if( Element->Flags & ELEFLAG_ALIGN_END ) {
228 if(Element->Flags & ELEFLAG_VERTICAL )
229 newX += Element->CachedW - child->CachedW
230 - Element->PaddingL - Element->PaddingR;
232 newY += Element->CachedH - child->CachedH
233 - Element->PaddingT - Element->PaddingB;
236 // Check for changes, and don't update if there was no change
237 if( newX != child->CachedX || newY != child->CachedY )
239 child->CachedX = newX;
240 child->CachedY = newY;
241 // Update child's children positions
242 Widget_UpdatePosition(child);
246 if(Element->Flags & ELEFLAG_VERTICAL ) {
247 y += child->CachedH + Element->GapSize;
250 x += child->CachedW + Element->GapSize;
257 tElement *Widget_GetElementById(tWidgetWin *Info, uint32_t ID)
261 if( ID < Info->TableSize ) return Info->ElementTable[ID];
263 ele = Info->ElementTable[ID % Info->TableSize];
264 while(ele && ele->ID != ID) ele = ele->ListNext;
268 // --- Message Handlers ---
269 void Widget_NewWidget(tWidgetWin *Info, size_t Len, tWidgetMsg_Create *Msg)
271 const int max_debugname_len = Len - sizeof(tWidgetMsg_Create);
275 if( Len < sizeof(tWidgetMsg_Create) )
277 if( strnlen(Msg->DebugName, max_debugname_len) == max_debugname_len )
281 parent = Widget_GetElementById(Info, Msg->Parent);
285 int Renderer_Widget_HandleMessage(tWindow *Target, int Msg, int Len, void *Data)
287 tWidgetWin *info = Target->RendererInfo;
291 case MSG_WIDGET_CREATE:
292 Widget_NewWidget(info, Len, Data);
296 return 1; // Unhandled, pass to user