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)
41 tColour BackgroundColour;
45 // -- Attributes maitained by the element code
46 // Not touched by the user
47 short MinWith; //!< Minimum long size
48 short MinCross; //!< Minimum cross size
49 void *Data; //!< Per-type data
52 short CachedX, CachedY;
53 short CachedW, CachedH;
61 int TableSize; //!< Number of entries, anything over will wrap
62 tElement *ElementTable[]; //!< Hash table essentially
66 tWindow *Renderer_Widget_Create(int Flags);
67 void Renderer_Widget_Redraw(tWindow *Window);
68 int Renderer_Widget_HandleMessage(tWindow *Target, int Msg, int Len, void *Data);
71 tWMRenderer gRenderer_Widget = {
73 .CreateWindow = Renderer_Widget_Create,
74 .Redraw = Renderer_Widget_Redraw,
75 .HandleMessage = Renderer_Widget_HandleMessage
79 int Renderer_Widget_Init(void)
81 WM_RegisterRenderer(&gRenderer_Widget);
86 tWindow *Renderer_Widget_Create(int Flags)
90 ret = WM_CreateWindowStruct( sizeof(tWidgetWin) );
91 info = ret->RendererInfo;
93 info->RootElement.BackgroundColour = 0xCCCCCC;
98 void Renderer_Widget_Redraw(tWindow *Window)
100 tWidgetWin *info = Window->RendererInfo;
101 WM_Render_FilledRect(Window, info->RootElement.BackgroundColour, 0, 0, 0xFFF, 0xFFF);
104 // --- Render / Resize ---
105 void Widget_UpdateDimensions(tElement *Element)
112 int fullCross, dynWith;
115 // - Get the fixed and minimum sizes of the element
116 for( child = Element->FirstChild; child; child = child->NextSibling )
118 // Ignore elements that will not be rendered
119 if( child->Flags & ELEFLAG_NORENDER ) continue ;
121 // Absolutely positioned elements don't affect dimensions
122 if( child->Flags & ELEFLAG_ABSOLUTEPOS ) continue ;
124 // Fixed width elements
125 if( child->FixedWith )
128 fixedSize += child->FixedWith;
131 if( child->FixedCross && maxCross < child->FixedCross )
132 maxCross = child->FixedCross;
133 if( child->MinCross && maxCross < child->MinCross )
134 maxCross = child->MinCross;
138 // Get the dynamic with size from the unused space in the element
139 if( nChildren > nFixed ) {
140 if( Element->Flags & ELEFLAG_VERTICAL )
141 dynWith = Element->CachedH - Element->PaddingT - Element->PaddingB;
143 dynWith = Element->CachedW - Element->PaddingL - Element->PaddingR;
144 dynWith -= fixedSize;
145 if( dynWith < 0 ) return ;
146 dynWith /= nChildren - nFixed;
149 // Get the cross size
150 if( Element->Flags & ELEFLAG_VERTICAL )
151 fullCross = Element->CachedW - Element->PaddingL - Element->PaddingR;
153 fullCross = Element->CachedH - Element->PaddingT - Element->PaddingB;
155 // Pass 2 - Set sizes and recurse
156 for( child = Element->FirstChild; child; child = child->NextSibling )
160 // Ignore elements that will not be rendered
161 if( child->Flags & ELEFLAG_NORENDER ) continue ;
163 // --- Cross Size ---
164 // TODO: Expand to fill?
165 // TODO: Extra flag so options are (Expand, Equal, Wrap)
166 if( child->FixedCross )
167 cross = child->FixedCross;
168 else if( child->Flags & ELEFLAG_NOEXPAND )
169 cross = child->MinCross;
174 if( child->FixedWith)
175 with = child->FixedWith;
176 else if( child->Flags & ELEFLAG_NOSTRETCH )
177 with = child->MinWith;
182 // Update the dimensions if they have changed
183 if( Element->Flags & ELEFLAG_VERTICAL ) {
184 // If no change, don't recurse
185 if( child->CachedW == cross && child->CachedH == with )
187 child->CachedW = cross;
188 child->CachedH = with;
191 // If no change, don't recurse
192 if( child->CachedW == with && child->CachedH == cross )
194 child->CachedW = with;
195 child->CachedH = cross;
198 // Force the positions of child elements to be recalculated
201 // Recurse down so the child elements can be updated
202 Widget_UpdateDimensions(child);
208 * \brief Update the position of child elements
210 void Widget_UpdatePosition(tElement *Element)
215 if( Element->Flags & ELEFLAG_NORENDER ) return ;
218 x = Element->CachedX + Element->PaddingL;
219 y = Element->CachedY + Element->PaddingT;
222 for(child = Element->FirstChild; child; child = child->NextSibling)
225 // Ignore elements that will not be rendered
226 if( child->Flags & ELEFLAG_NORENDER ) continue ;
231 if( Element->Flags & ELEFLAG_ALIGN_CENTER ) {
232 if(Element->Flags & ELEFLAG_VERTICAL)
233 newX += Element->CachedW/2 - child->CachedW/2;
235 newY += Element->CachedH/2 - child->CachedH/2;
237 else if( Element->Flags & ELEFLAG_ALIGN_END ) {
238 if(Element->Flags & ELEFLAG_VERTICAL )
239 newX += Element->CachedW - child->CachedW
240 - Element->PaddingL - Element->PaddingR;
242 newY += Element->CachedH - child->CachedH
243 - Element->PaddingT - Element->PaddingB;
246 // Check for changes, and don't update if there was no change
247 if( newX != child->CachedX || newY != child->CachedY )
249 child->CachedX = newX;
250 child->CachedY = newY;
251 // Update child's children positions
252 Widget_UpdatePosition(child);
256 if(Element->Flags & ELEFLAG_VERTICAL ) {
257 y += child->CachedH + Element->GapSize;
260 x += child->CachedW + Element->GapSize;
267 tElement *Widget_GetElementById(tWidgetWin *Info, uint32_t ID)
271 if( ID < Info->TableSize ) return Info->ElementTable[ID];
273 ele = Info->ElementTable[ID % Info->TableSize];
274 while(ele && ele->ID != ID) ele = ele->ListNext;
278 // --- Message Handlers ---
279 void Widget_NewWidget(tWidgetWin *Info, size_t Len, tWidgetMsg_Create *Msg)
281 const int max_debugname_len = Len - sizeof(tWidgetMsg_Create);
285 if( Len < sizeof(tWidgetMsg_Create) )
287 if( strnlen(Msg->DebugName, max_debugname_len) == max_debugname_len )
291 parent = Widget_GetElementById(Info, Msg->Parent);
295 int Renderer_Widget_HandleMessage(tWindow *Target, int Msg, int Len, void *Data)
297 tWidgetWin *info = Target->RendererInfo;
301 case MSG_WIDGET_CREATE:
302 Widget_NewWidget(info, Len, Data);
306 return 1; // Unhandled, pass to user