32d1a97f100e0f22e5bf0e70fe00efe3651d8de1
[tpg/acess2.git] / Usermode / Applications / axwin3_src / WM / renderer_widget.c
1 /*
2  * Acess2 Window Manager v3
3  * - By John Hodge (thePowersGang)
4  *
5  * render_widget.c
6  * - AxWin2 Widget port
7  */
8 #include <common.h>
9 #include <wm_renderer.h>
10 #include <renderer_widget.h>
11 #include <string.h>
12
13 // === TYPES ===
14 typedef struct sWidgetWin       tWidgetWin;
15 typedef struct sAxWin_Element   tElement;
16
17 // === STRUCTURES ===
18 struct sAxWin_Element
19 {
20         enum eElementTypes      Type;
21
22         uint32_t        ID;     //!< Application provided ID number
23         tElement        *ListNext;      //!< Next element in bucket
24         
25         // Element Tree
26         tElement        *Parent;
27         tElement        *FirstChild;
28         tElement        *LastChild;
29         tElement        *NextSibling;
30         
31         // User modifiable attributes   
32         short   PaddingL, PaddingR;
33         short   PaddingT, PaddingB;
34         short   GapSize;
35         
36         uint32_t        Flags;
37         
38         short   FixedWith;      //!< Fixed lengthways Size attribute (height)
39         short   FixedCross;     //!< Fixed Cross Size attribute (width)
40         
41         char    *Text;
42         
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
48         
49         // -- Render Cache
50         short   CachedX, CachedY;
51         short   CachedW, CachedH;
52         
53         char    DebugName[];
54 };
55 struct sWidgetWin
56 {
57         tElement        RootElement;
58         
59          int    TableSize;      //!< Number of entries, anything over will wrap
60         tElement        *ElementTable[];        //!< Hash table essentially
61 };
62
63 // === PROTOTYPES ===
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);
67
68 // === GLOBALS ===
69 tWMRenderer     gRenderer_Widget = {
70         .Name = "Classful",
71         .CreateWindow = Renderer_Widget_Create,
72         .Redraw = Renderer_Widget_Redraw,
73         .HandleMessage = Renderer_Widget_HandleMessage
74 };
75
76 // === CODE ===
77 int Renderer_Widget_Init(void)
78 {
79         WM_RegisterRenderer(&gRenderer_Widget); 
80
81         return 0;
82 }
83
84 tWindow *Renderer_Widget_Create(int Width, int Height, int Flags)
85 {
86         // TODO: Add info
87         return WM_CreateWindowStruct( sizeof(tWidgetWin) );
88 }
89
90 void Renderer_Widget_Redraw(tWindow *Window)
91 {
92 }
93
94 // --- Render / Resize ---
95 void Widget_UpdateDimensions(tElement *Element)
96 {
97         tElement        *child;
98          int    nChildren = 0;
99          int    nFixed = 0;
100          int    maxCross = 0;
101          int    fixedSize = 0;
102          int    fullCross, dynWith;
103         
104         // Pass 1
105         // - Get the fixed and minimum sizes of the element
106         for( child = Element->FirstChild; child; child = child->NextSibling )
107         {
108                 // Ignore elements that will not be rendered
109                 if( child->Flags & ELEFLAG_NORENDER )   continue ;
110                 
111                 // Absolutely positioned elements don't affect dimensions
112                 if( child->Flags & ELEFLAG_ABSOLUTEPOS )        continue ;
113         
114                 // Fixed width elements 
115                 if( child->FixedWith )
116                 {
117                         nFixed ++;
118                         fixedSize += child->FixedWith;
119                 }
120                 
121                 if( child->FixedCross && maxCross < child->FixedCross )
122                         maxCross = child->FixedCross;
123                 if( child->MinCross && maxCross < child->MinCross )
124                         maxCross = child->MinCross;
125                 nChildren ++;
126         }
127         
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;
132                 else
133                         dynWith = Element->CachedW - Element->PaddingL - Element->PaddingR;
134                 dynWith -= fixedSize;
135                 if( dynWith < 0 )       return ;
136                 dynWith /= nChildren - nFixed;
137         }
138         
139         // Get the cross size
140         if( Element->Flags & ELEFLAG_VERTICAL )
141                 fullCross = Element->CachedW - Element->PaddingL - Element->PaddingR;
142         else
143                 fullCross = Element->CachedH - Element->PaddingT - Element->PaddingB;
144         
145         // Pass 2 - Set sizes and recurse
146         for( child = Element->FirstChild; child; child = child->NextSibling )
147         {
148                  int    cross, with;
149
150                 // Ignore elements that will not be rendered
151                 if( child->Flags & ELEFLAG_NORENDER )   continue ;
152                 
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;
160                 else
161                         cross = fullCross;
162                 
163                 // --- With Size ---
164                 if( child->FixedWith)
165                         with = child->FixedWith;
166                 else if( child->Flags & ELEFLAG_NOSTRETCH )
167                         with = child->MinWith;
168                 else
169                         with = dynWith;
170                 
171                 
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 )
176                                 continue ;
177                         child->CachedW = cross;
178                         child->CachedH = with;
179                 }
180                 else {
181                         // If no change, don't recurse
182                         if( child->CachedW == with && child->CachedH == cross )
183                                 continue ;
184                         child->CachedW = with;
185                         child->CachedH = cross;
186                 }
187                 
188                 // Force the positions of child elements to be recalculated
189                 child->CachedX = -1;
190         
191                 // Recurse down so the child elements can be updated    
192                 Widget_UpdateDimensions(child);
193         }
194         
195 }
196
197 /**
198  * \brief Update the position of child elements
199  */
200 void Widget_UpdatePosition(tElement *Element)
201 {
202         tElement        *child;
203          int    x, y;
204         
205         if( Element->Flags & ELEFLAG_NORENDER ) return ;
206         
207         // Initialise
208         x = Element->CachedX + Element->PaddingL;
209         y = Element->CachedY + Element->PaddingT;
210         
211         // Update each child
212         for(child = Element->FirstChild; child; child = child->NextSibling)
213         {
214                  int    newX, newY;
215                 // Ignore elements that will not be rendered
216                 if( child->Flags & ELEFLAG_NORENDER )   continue ;
217
218                 newX = x; newY = y;
219                 
220                 // Handle alignment
221                 if( Element->Flags & ELEFLAG_ALIGN_CENTER ) {
222                         if(Element->Flags & ELEFLAG_VERTICAL)
223                                 newX += Element->CachedW/2 - child->CachedW/2;
224                         else
225                                 newY += Element->CachedH/2 - child->CachedH/2;
226                 }
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;
231                         else
232                                 newY += Element->CachedH - child->CachedH
233                                         - Element->PaddingT - Element->PaddingB;
234                 }
235
236                 // Check for changes, and don't update if there was no change
237                 if( newX != child->CachedX || newY != child->CachedY )
238                 {
239                         child->CachedX = newX;
240                         child->CachedY = newY;
241                         // Update child's children positions
242                         Widget_UpdatePosition(child);
243                 }
244                 
245                 // Increment
246                 if(Element->Flags & ELEFLAG_VERTICAL ) {
247                         y += child->CachedH + Element->GapSize;
248                 }
249                 else {
250                         x += child->CachedW + Element->GapSize;
251                 }
252         }
253 }
254
255
256 // --- Helpers ---
257 tElement *Widget_GetElementById(tWidgetWin *Info, uint32_t ID)
258 {
259         tElement        *ele;
260         
261         if( ID < Info->TableSize )      return Info->ElementTable[ID];
262
263         ele = Info->ElementTable[ID % Info->TableSize];
264         while(ele && ele->ID != ID)     ele = ele->ListNext;
265         return ele;
266 }
267
268 // --- Message Handlers ---
269 void Widget_NewWidget(tWidgetWin *Info, size_t Len, tWidgetMsg_Create *Msg)
270 {
271         const int       max_debugname_len = Len - sizeof(tWidgetMsg_Create);
272         tElement        *parent;        
273
274         // Sanity check
275         if( Len < sizeof(tWidgetMsg_Create) )
276                 return ;
277         if( strnlen(Msg->DebugName, max_debugname_len) == max_debugname_len )
278                 return ;
279         
280         // Create
281         parent = Widget_GetElementById(Info, Msg->Parent);
282         
283 }
284
285 int Renderer_Widget_HandleMessage(tWindow *Target, int Msg, int Len, void *Data)
286 {
287         tWidgetWin      *info = Target->RendererInfo;
288         switch(Msg)
289         {
290         // New Widget
291         case MSG_WIDGET_CREATE:
292                 Widget_NewWidget(info, Len, Data);
293                 return 0;
294         // 
295         default:
296                 return 1;       // Unhandled, pass to user
297         }
298 }
299
300
301
302

UCC git Repository :: git.ucc.asn.au