2 * Acess2 Window Manager v3
3 * - By John Hodge (thePowersGang)
9 #include <wm_renderer.h>
10 #include <renderer_widget.h>
14 int Renderer_Widget_Init(void);
15 tWindow *Renderer_Widget_Create(int Flags);
16 void Renderer_Widget_Redraw(tWindow *Window);
17 void Widget_RenderWidget(tWindow *Window, tElement *Element);
18 int Renderer_Widget_HandleMessage(tWindow *Target, int Msg, int Len, void *Data);
19 void Widget_UpdateDimensions(tElement *Element);
20 void Widget_UpdatePosition(tElement *Element);
21 tElement *Widget_GetElementById(tWidgetWin *Info, uint32_t ID);
22 void Widget_NewWidget(tWidgetWin *Info, size_t Len, tWidgetMsg_Create *Msg);
25 tWMRenderer gRenderer_Widget = {
27 .CreateWindow = Renderer_Widget_Create,
28 .Redraw = Renderer_Widget_Redraw,
29 .HandleMessage = Renderer_Widget_HandleMessage
33 int Renderer_Widget_Init(void)
35 WM_RegisterRenderer(&gRenderer_Widget);
40 tWindow *Renderer_Widget_Create(int Flags)
44 ret = WM_CreateWindowStruct( sizeof(tWidgetWin) );
45 info = ret->RendererInfo;
47 info->RootElement.BackgroundColour = 0xCCCCCC;
52 void Renderer_Widget_Redraw(tWindow *Window)
54 tWidgetWin *info = Window->RendererInfo;
55 WM_Render_FillRect(Window, 0, 0, 0xFFF, 0xFFF, info->RootElement.BackgroundColour);
57 Widget_UpdateDimensions(&info->RootElement);
58 Widget_UpdatePosition(&info->RootElement);
60 Widget_RenderWidget(Window, &info->RootElement);
63 // --- Render / Resize ---
64 void Widget_RenderWidget(tWindow *Window, tElement *Element)
68 if( Element->Flags & ELEFLAG_NORENDER ) return ;
69 if( Element->Flags & ELEFLAG_INVISIBLE ) return ;
71 Widget_Decorator_RenderWidget(Window, Element);
73 for(child = Element->FirstChild; child; child = child->NextSibling)
75 Widget_RenderWidget(Window, child);
79 void Widget_UpdateDimensions(tElement *Element)
86 int fullCross, dynWith;
89 // - Get the fixed and minimum sizes of the element
90 for( child = Element->FirstChild; child; child = child->NextSibling )
92 // Ignore elements that will not be rendered
93 if( child->Flags & ELEFLAG_NORENDER ) continue ;
95 // Absolutely positioned elements don't affect dimensions
96 if( child->Flags & ELEFLAG_ABSOLUTEPOS ) continue ;
98 // Fixed width elements
99 if( child->FixedWith )
102 fixedSize += child->FixedWith;
105 if( child->FixedCross && maxCross < child->FixedCross )
106 maxCross = child->FixedCross;
107 if( child->MinCross && maxCross < child->MinCross )
108 maxCross = child->MinCross;
112 // Get the dynamic with size from the unused space in the element
113 if( nChildren > nFixed ) {
114 if( Element->Flags & ELEFLAG_VERTICAL )
115 dynWith = Element->CachedH - Element->PaddingT - Element->PaddingB;
117 dynWith = Element->CachedW - Element->PaddingL - Element->PaddingR;
118 dynWith -= fixedSize;
119 if( dynWith < 0 ) return ;
120 dynWith /= nChildren - nFixed;
123 // Get the cross size
124 if( Element->Flags & ELEFLAG_VERTICAL )
125 fullCross = Element->CachedW - Element->PaddingL - Element->PaddingR;
127 fullCross = Element->CachedH - Element->PaddingT - Element->PaddingB;
129 // Pass 2 - Set sizes and recurse
130 for( child = Element->FirstChild; child; child = child->NextSibling )
134 // Ignore elements that will not be rendered
135 if( child->Flags & ELEFLAG_NORENDER ) continue ;
137 // --- Cross Size ---
138 // TODO: Expand to fill?
139 // TODO: Extra flag so options are (Expand, Equal, Wrap)
140 if( child->FixedCross )
141 cross = child->FixedCross;
142 else if( child->Flags & ELEFLAG_NOEXPAND )
143 cross = child->MinCross;
148 if( child->FixedWith)
149 with = child->FixedWith;
150 else if( child->Flags & ELEFLAG_NOSTRETCH )
151 with = child->MinWith;
156 // Update the dimensions if they have changed
157 if( Element->Flags & ELEFLAG_VERTICAL ) {
158 // If no change, don't recurse
159 if( child->CachedW == cross && child->CachedH == with )
161 child->CachedW = cross;
162 child->CachedH = with;
165 // If no change, don't recurse
166 if( child->CachedW == with && child->CachedH == cross )
168 child->CachedW = with;
169 child->CachedH = cross;
172 // Force the positions of child elements to be recalculated
175 // Recurse down so the child elements can be updated
176 Widget_UpdateDimensions(child);
182 * \brief Update the position of child elements
184 void Widget_UpdatePosition(tElement *Element)
189 if( Element->Flags & ELEFLAG_NORENDER ) return ;
192 x = Element->CachedX + Element->PaddingL;
193 y = Element->CachedY + Element->PaddingT;
196 for(child = Element->FirstChild; child; child = child->NextSibling)
199 // Ignore elements that will not be rendered
200 if( child->Flags & ELEFLAG_NORENDER ) continue ;
205 if( Element->Flags & ELEFLAG_ALIGN_CENTER ) {
206 if(Element->Flags & ELEFLAG_VERTICAL)
207 newX += Element->CachedW/2 - child->CachedW/2;
209 newY += Element->CachedH/2 - child->CachedH/2;
211 else if( Element->Flags & ELEFLAG_ALIGN_END ) {
212 if(Element->Flags & ELEFLAG_VERTICAL )
213 newX += Element->CachedW - child->CachedW
214 - Element->PaddingL - Element->PaddingR;
216 newY += Element->CachedH - child->CachedH
217 - Element->PaddingT - Element->PaddingB;
220 // Check for changes, and don't update if there was no change
221 if( newX != child->CachedX || newY != child->CachedY )
223 child->CachedX = newX;
224 child->CachedY = newY;
225 // Update child's children positions
226 Widget_UpdatePosition(child);
230 if(Element->Flags & ELEFLAG_VERTICAL ) {
231 y += child->CachedH + Element->GapSize;
234 x += child->CachedW + Element->GapSize;
241 tElement *Widget_GetElementById(tWidgetWin *Info, uint32_t ID)
246 return &Info->RootElement;
248 if( ID < Info->TableSize ) return Info->ElementTable[ID];
250 ele = Info->ElementTable[ID % Info->TableSize];
251 while(ele && ele->ID != ID) ele = ele->ListNext;
255 // --- Message Handlers ---
256 void Widget_NewWidget(tWidgetWin *Info, size_t Len, tWidgetMsg_Create *Msg)
258 const int max_debugname_len = Len - sizeof(tWidgetMsg_Create);
262 if( Len < sizeof(tWidgetMsg_Create) )
264 if( strnlen(Msg->DebugName, max_debugname_len) == max_debugname_len )
268 parent = Widget_GetElementById(Info, Msg->Parent);
272 int Renderer_Widget_HandleMessage(tWindow *Target, int Msg, int Len, void *Data)
274 tWidgetWin *info = Target->RendererInfo;
277 case WNDMSG_RESIZE: {
278 struct sWndMsg_Resize *msg = Data;
279 if(Len < sizeof(*msg)) return -1;
281 info->RootElement.CachedW = msg->W;
282 info->RootElement.CachedH = msg->H;
286 case MSG_WIDGET_CREATE:
287 Widget_NewWidget(info, Len, Data);
291 return 1; // Unhandled, pass to user