Usermode/AxWin3 - Porting over the AxWin2 widget code
[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 _UpdateDimensions(tElement *Ele)
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                 _UpdateDimensions(child);
193         }
194         
195 }
196
197 void _UpdatePosition(tElement *Element)
198 {
199         tElement        *child;
200          int    x, y;
201         
202         if( Element->Flags & ELEFLAG_NORENDER ) return ;
203         
204         // Initialise
205         x = Element->CachedX + Element->PaddingL;
206         y = Element->CachedY + Element->PaddingT;
207         
208         // Update each child
209         for(child = Element->FirstChild; child; child = child->NextSibling)
210         {
211                  int    newX, newY;
212                 // Ignore elements that will not be rendered
213                 if( child->Flags & ELEFLAG_NORENDER )   continue ;
214
215                 newX = x; newY = y;
216                 
217                 // Handle alignment
218                 if( Element->Flags & ELEFLAG_ALIGN_CENTER ) {
219                         if(Element->Flags & ELEFLAG_VERTICAL)
220                                 newX += Element->CachedW/2 - child->CachedW/2;
221                         else
222                                 newY += Element->CachedH/2 - child->CachedH/2;
223                 }
224                 else if( Element->Flags & ELEFLAG_ALIGN_END ) {
225                         if(Element->Flags & ELEFLAG_VERTICAL )
226                                 newX += Element->CachedW - child->CachedW
227                                         - Element->PaddingL - Element->PaddingR;
228                         else
229                                 newY += Element->CachedH - child->CachedH
230                                         - Element->PaddingT - Element->PaddingB;
231                 }
232
233                 // Check for changes, and don't update if there was no change
234                 if( newX != child->CachedX || newY != child->CachedY )
235                 {
236                         child->CachedX = newX;
237                         child->CachedY = newY;
238                         // Update child's children positions
239                         WM_UpdatePosition(child);
240                 }
241                 
242                 // Increment
243                 if(Element->Flags & ELEFLAG_VERTICAL ) {
244                         y += child->CachedH + Element->GapSize;
245                 }
246                 else {
247                         x += child->CachedW + Element->GapSize;
248                 }
249         }
250 }
251
252
253 // --- Helpers ---
254 tElement *_GetElementById(tWidgetWin *Info, uint32_t ID)
255 {
256         tElement        *ele;
257          int    num;
258         
259         if( ID < Info->TableSize )      return Info->ElementTable[ID];
260
261         while( ID >= Info->TableSize ) {
262                 num ++;
263                 ID -= Info->TableSize;
264         }
265
266         ele = Info->ElementTable[num];
267         while(num-- && ele)     ele = ele->ListNext;
268         return ele;
269 }
270
271 // --- Message Handlers ---
272 void _NewWidget(tWidgetWin *Info, size_t Len, tWidgetMsg_Create *Msg)
273 {
274         const int       max_debugname_len = Len - sizeof(tWidgetMsg_Create);
275         tElement        *parent;        
276
277         // Sanity check
278         if( Len < sizeof(tWidgetMsg_Create) )
279                 return ;
280         if( strnlen(Msg->DebugName, max_debugname_len) == max_debugname_len )
281                 return ;
282         
283         // Create
284         parent = _GetElementById(Info, Msg->Parent);
285         
286 }
287
288 int Renderer_Widget_HandleMessage(tWindow *Target, int Msg, int Len, void *Data)
289 {
290         tWidgetWin      *info = Target->RendererInfo;
291         switch(Msg)
292         {
293         case MSG_WIDGET_CREATE:
294                 _NewWidget(info, Len, Data);
295                 return 0;
296         default:
297                 return 1;       // Unhandled
298         }
299 }
300
301
302
303

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