2 * Acess2 Window Manager v3
3 * - By John Hodge (thePowersGang)
9 #include <wm_renderer.h>
10 #include <renderer_widget.h>
12 #include <wm_messages.h>
15 int Renderer_Widget_Init(void);
16 tWindow *Renderer_Widget_Create(int Flags);
17 void Renderer_Widget_Redraw(tWindow *Window);
18 void Widget_RenderWidget(tWindow *Window, tElement *Element);
19 int Renderer_Widget_HandleMessage(tWindow *Target, int Msg, int Len, void *Data);
20 void Widget_UpdateDimensions(tElement *Element);
21 void Widget_UpdatePosition(tElement *Element);
22 tElement *Widget_GetElementById(tWidgetWin *Info, uint32_t ID);
23 void Widget_NewWidget(tWidgetWin *Info, size_t Len, tWidgetMsg_Create *Msg);
26 tWMRenderer gRenderer_Widget = {
28 .CreateWindow = Renderer_Widget_Create,
29 .Redraw = Renderer_Widget_Redraw,
30 .HandleMessage = Renderer_Widget_HandleMessage
34 int Renderer_Widget_Init(void)
36 WM_RegisterRenderer(&gRenderer_Widget);
41 tWindow *Renderer_Widget_Create(int Flags)
45 ret = WM_CreateWindowStruct( sizeof(tWidgetWin) );
46 info = ret->RendererInfo;
48 info->RootElement.BackgroundColour = 0xCCCCCC;
53 void Renderer_Widget_Redraw(tWindow *Window)
55 tWidgetWin *info = Window->RendererInfo;
56 WM_Render_FillRect(Window, 0, 0, 0xFFF, 0xFFF, info->RootElement.BackgroundColour);
58 Widget_UpdateDimensions(&info->RootElement);
59 Widget_UpdatePosition(&info->RootElement);
61 Widget_RenderWidget(Window, &info->RootElement);
64 // --- Render / Resize ---
65 void Widget_RenderWidget(tWindow *Window, tElement *Element)
69 if( Element->Flags & ELEFLAG_NORENDER ) return ;
70 if( Element->Flags & ELEFLAG_INVISIBLE ) return ;
72 Widget_Decorator_RenderWidget(Window, Element);
74 for(child = Element->FirstChild; child; child = child->NextSibling)
76 Widget_RenderWidget(Window, child);
80 void Widget_UpdateDimensions(tElement *Element)
87 int fullCross, dynWith;
90 // - Get the fixed and minimum sizes of the element
91 for( child = Element->FirstChild; child; child = child->NextSibling )
93 // Ignore elements that will not be rendered
94 if( child->Flags & ELEFLAG_NORENDER ) continue ;
96 // Absolutely positioned elements don't affect dimensions
97 if( child->Flags & ELEFLAG_ABSOLUTEPOS ) continue ;
99 // Fixed width elements
100 if( child->FixedWith )
103 fixedSize += child->FixedWith;
106 if( child->FixedCross && maxCross < child->FixedCross )
107 maxCross = child->FixedCross;
108 if( child->MinCross && maxCross < child->MinCross )
109 maxCross = child->MinCross;
113 // Get the dynamic with size from the unused space in the element
114 if( nChildren > nFixed ) {
115 if( Element->Flags & ELEFLAG_VERTICAL )
116 dynWith = Element->CachedH - Element->PaddingT - Element->PaddingB;
118 dynWith = Element->CachedW - Element->PaddingL - Element->PaddingR;
119 dynWith -= fixedSize;
120 if( dynWith < 0 ) return ;
121 dynWith /= nChildren - nFixed;
124 // Get the cross size
125 if( Element->Flags & ELEFLAG_VERTICAL )
126 fullCross = Element->CachedW - Element->PaddingL - Element->PaddingR;
128 fullCross = Element->CachedH - Element->PaddingT - Element->PaddingB;
130 // Pass 2 - Set sizes and recurse
131 for( child = Element->FirstChild; child; child = child->NextSibling )
135 // Ignore elements that will not be rendered
136 if( child->Flags & ELEFLAG_NORENDER ) continue ;
138 // --- Cross Size ---
139 // TODO: Expand to fill?
140 // TODO: Extra flag so options are (Expand, Equal, Wrap)
141 if( child->FixedCross )
142 cross = child->FixedCross;
143 else if( child->Flags & ELEFLAG_NOEXPAND )
144 cross = child->MinCross;
149 if( child->FixedWith)
150 with = child->FixedWith;
151 else if( child->Flags & ELEFLAG_NOSTRETCH )
152 with = child->MinWith;
157 // Update the dimensions if they have changed
158 if( Element->Flags & ELEFLAG_VERTICAL ) {
159 // If no change, don't recurse
160 if( child->CachedW == cross && child->CachedH == with )
162 child->CachedW = cross;
163 child->CachedH = with;
166 // If no change, don't recurse
167 if( child->CachedW == with && child->CachedH == cross )
169 child->CachedW = with;
170 child->CachedH = cross;
173 // Force the positions of child elements to be recalculated
176 // Recurse down so the child elements can be updated
177 Widget_UpdateDimensions(child);
183 * \brief Update the position of child elements
185 void Widget_UpdatePosition(tElement *Element)
190 if( Element->Flags & ELEFLAG_NORENDER ) return ;
193 x = Element->CachedX + Element->PaddingL;
194 y = Element->CachedY + Element->PaddingT;
197 for(child = Element->FirstChild; child; child = child->NextSibling)
200 // Ignore elements that will not be rendered
201 if( child->Flags & ELEFLAG_NORENDER ) continue ;
206 if( Element->Flags & ELEFLAG_ALIGN_CENTER ) {
207 if(Element->Flags & ELEFLAG_VERTICAL)
208 newX += Element->CachedW/2 - child->CachedW/2;
210 newY += Element->CachedH/2 - child->CachedH/2;
212 else if( Element->Flags & ELEFLAG_ALIGN_END ) {
213 if(Element->Flags & ELEFLAG_VERTICAL )
214 newX += Element->CachedW - child->CachedW
215 - Element->PaddingL - Element->PaddingR;
217 newY += Element->CachedH - child->CachedH
218 - Element->PaddingT - Element->PaddingB;
221 // Check for changes, and don't update if there was no change
222 if( newX != child->CachedX || newY != child->CachedY )
224 child->CachedX = newX;
225 child->CachedY = newY;
226 // Update child's children positions
227 Widget_UpdatePosition(child);
231 if(Element->Flags & ELEFLAG_VERTICAL ) {
232 y += child->CachedH + Element->GapSize;
235 x += child->CachedW + Element->GapSize;
242 tElement *Widget_GetElementById(tWidgetWin *Info, uint32_t ID)
247 return &Info->RootElement;
249 if( ID < Info->TableSize ) return Info->ElementTable[ID];
251 ele = Info->ElementTable[ID % Info->TableSize];
252 while(ele && ele->ID != ID) ele = ele->ListNext;
256 // --- Message Handlers ---
257 void Widget_NewWidget(tWidgetWin *Info, size_t Len, tWidgetMsg_Create *Msg)
259 const int max_debugname_len = Len - sizeof(tWidgetMsg_Create);
263 if( Len < sizeof(tWidgetMsg_Create) )
265 if( strnlen(Msg->DebugName, max_debugname_len) == max_debugname_len )
269 parent = Widget_GetElementById(Info, Msg->Parent);
273 int Renderer_Widget_HandleMessage(tWindow *Target, int Msg, int Len, void *Data)
275 tWidgetWin *info = Target->RendererInfo;
278 case WNDMSG_RESIZE: {
279 struct sWndMsg_Resize *msg = Data;
280 if(Len < sizeof(*msg)) return -1;
282 info->RootElement.CachedW = msg->W;
283 info->RootElement.CachedH = msg->H;
287 case MSG_WIDGET_CREATE:
288 Widget_NewWidget(info, Len, Data);
292 return 1; // Unhandled, pass to user