b07322359dc71cdb441c6bfe093d32ebcd46d14c
[tpg/acess2.git] / Usermode / Applications / axwin2_src / WM / wm.c
1 /*
2  * Acess GUI (AxWin) Version 2
3  * By John Hodge (thePowersGang)
4  * 
5  * Window Manager and Widget Control
6  */
7 #include "common.h"
8 #include <stdlib.h>
9 #include <string.h>
10 #include "wm.h"
11 #include <acess/sys.h>  // _SysDebug
12
13 // === IMPORTS ===
14 extern void     Video_GetTextDims(tFont *Font, const char *Text, int *W, int *H);
15
16 // === PROTOTYPES ===
17 tApplication    *AxWin_RegisterClient(tIPC_Type *IPCType, void *Ident, const char *Name);
18 void    AxWin_DeregisterClient(tApplication *App);
19 tApplication    *AxWin_GetClient(tIPC_Type *Method, void *Ident);
20 tElement        *AxWin_CreateElement(tElement *Parent, int Type, int Flags, const char *DebugName);
21 void    AxWin_DeleteElement(tElement *Element);
22 void    AxWin_SetFlags(tElement *Element, int Flags);
23 void    AxWin_SetSize(tElement *Element, int Size);
24 void    AxWin_SetText(tElement *Element, const char *Text);
25
26 // === GLOBALS ===
27 // - TODO: Handle windows by having multiple root elements
28 tElement        gWM_RootElement = {
29         .DebugName = "ROOT"
30 };
31 tWindow *gWM_WindowFirst;
32 tWindow *gWM_WindowLast;
33 tApplication    *gWM_Applications;
34  int    giWM_MaxAreaX = 0;
35  int    giWM_MaxAreaY = 0;
36  int    giWM_MaxAreaW = -1;
37  int    giWM_MaxAreaH = -1;
38
39 // --- Element type flags
40 struct {
41         void    (*Init)(tElement *This);
42         void    (*Delete)(tElement *This);
43         void    (*UpdateFlags)(tElement *This);
44         void    (*UpdateSize)(tElement *This);
45         void    (*UpdateText)(tElement *This);
46 }       gaWM_WidgetTypes[MAX_ELETYPES] = {
47         {NULL, NULL, NULL, NULL, NULL}, // NULL
48         {NULL, NULL, NULL, NULL, NULL}, // Window
49         {NULL, NULL, NULL, NULL, NULL}  // Box
50 };
51 const int       ciWM_NumWidgetTypes = sizeof(gaWM_WidgetTypes)/sizeof(gaWM_WidgetTypes[0]);
52
53 // === CODE ===
54 tApplication *AxWin_RegisterClient(tIPC_Type *Method, void *Ident, const char *Name)
55 {
56          int    identlen = Method->GetIdentSize(Ident);
57         // Structure, empty string, Name, Ident
58         tApplication    *ret = calloc( 1, sizeof(tApplication) + 1 + strlen(Name) + 1 + identlen );
59         
60         // DebugName is empty
61         
62         // Name/Title
63         ret->Name = &ret->MetaElement.DebugName[1];
64         strcpy(ret->Name, Name);
65         // Ident
66         ret->Ident = ret->Name + strlen(Name) + 1;
67         memcpy(ret->Ident, Ident, identlen);
68         // IPC Type
69         ret->IPCType = Method;
70
71         // Element index
72         ret->MaxElementIndex = DEFAULT_ELEMENTS_PER_APP;
73         ret->EleIndex = calloc( 1, ret->MaxElementIndex * sizeof(*ret->EleIndex) );
74
75         // Add to global list
76         ret->Next = gWM_Applications;
77         gWM_Applications = ret;
78
79         // TODO: Inform listeners of the new application
80
81         return ret;
82 }
83
84 void AxWin_DeregisterClient(tApplication *App)
85 {
86         // TODO: Complete implementing DeregisterClient
87         tElement        *win, *next;
88
89         for( win = App->MetaElement.FirstChild; win; win = next )
90         {
91                 next = win->NextSibling;
92                 AxWin_DeleteElement(win);
93         }
94
95         // TODO: Inform listeners of deleted application
96         
97         // Remove from list
98         {
99                 tApplication    *app, *prev = NULL;
100                 for( app = gWM_Applications; app; app = app->Next )
101                 {
102                         if( app == App )        break;
103                         prev = app;
104                 }
105                 
106                 if( app )
107                 {
108                         if(prev)
109                                 prev->Next = App->Next;
110                         else
111                                 gWM_Applications = App->Next;
112                 }
113         }
114         
115         free(App);
116 }
117
118 /**
119  * \brief Get an application handle from a client identifier
120  */
121 tApplication *AxWin_GetClient(tIPC_Type *Method, void *Ident)
122 {
123         // TODO: Faster and smarter technique
124         tApplication    *app;
125         for( app = gWM_Applications; app; app = app->Next )
126         {
127                 if( app->IPCType != Method )    continue;
128                 if( Method->CompareIdent( app->Ident, Ident ) != 0 ) continue;
129                 return app;
130         }
131         return NULL;
132 }
133
134 tElement *AxWin_CreateAppWindow(tApplication *App, const char *Name)
135 {
136         tElement        *ret;
137         tWindow *win;
138         
139         win = calloc(1, sizeof(tWindow) + 1);
140         if(!win)        return NULL;
141         
142         ret = &win->RootElement;
143         ret->Type = ELETYPE_WINDOW;
144         ret->Data = win;
145         ret->Parent = &App->MetaElement;
146         
147         // Add to parent list
148         if(ret->Parent->LastChild)
149                 ret->Parent->LastChild->NextSibling = ret;
150         ret->Parent->LastChild = ret;
151         if(!ret->Parent->FirstChild)
152                 ret->Parent->FirstChild = ret;
153         
154         ret->Text = strdup(Name);
155         
156         return ret;
157 }
158
159 // --- Widget Creation and Control ---
160 tAxWin_Element *AxWin_CreateElement(tElement *Parent, int Type, int Flags, const char *DebugName)
161 {
162         tElement        *ret;
163         const char      *dbgName = DebugName ? DebugName : "";
164         
165         ret = calloc(sizeof(tElement)+strlen(dbgName)+1, 1);
166         if(!ret)        return NULL;
167         
168         // Prepare
169         ret->Type = Type;
170         strcpy(ret->DebugName, dbgName);
171         if(Parent == NULL)      Parent = &gWM_RootElement;
172         ret->Parent = Parent;
173         ret->Flags = Flags;
174         
175         // Append to parent's list
176         if(Parent->LastChild)
177                 Parent->LastChild->NextSibling = ret;
178         Parent->LastChild = ret;
179         if(!Parent->FirstChild) Parent->FirstChild = ret;
180         
181         ret->PaddingL = 2;
182         ret->PaddingR = 2;
183         ret->PaddingT = 2;
184         ret->PaddingB = 2;
185         
186         if( Type < ciWM_NumWidgetTypes && gaWM_WidgetTypes[Type].Init )
187                 gaWM_WidgetTypes[Type].Init(ret);
188         
189         WM_UpdateMinDims(ret->Parent);
190         
191         return ret;
192 }
193
194 /**
195  * \brief Delete an element
196  */
197 void AxWin_DeleteElement(tElement *Element)
198 {
199         tElement        *child, *next;
200         
201         for(child = Element->FirstChild; child; child = next)
202         {
203                 next = child->NextSibling;
204                 AxWin_DeleteElement(child);
205         }
206
207         // TODO: Implement AxWin_DeleteElement
208         // TODO: Clean up related data.
209         if( Element->Type < ciWM_NumWidgetTypes && gaWM_WidgetTypes[Element->Type].Delete )
210                 gaWM_WidgetTypes[Element->Type].Delete(Element);
211
212         if(Element->Owner)
213                 Element->Owner->EleIndex[ Element->ApplicationID ] = NULL;
214
215         Element->Type = 0;
216         Element->Owner = 0;
217         Element->Flags = 0;
218
219         free(Element);
220 }
221
222 /**
223  * \brief Alter an element's flags 
224  */
225 void AxWin_SetFlags(tElement *Element, int Flags)
226 {
227         // Permissions are handled in the message handler
228         if(!Element) {
229                 gWM_RootElement.Flags = Flags;
230                 return ;
231         }
232         
233         Element->Flags = Flags;
234         return ;
235 }
236
237 /**
238  * \brief Set the fixed lenghthways size of an element
239  */
240 void AxWin_SetSize(tElement *Element, int Size)
241 {
242         if(!Element)    return ;
243         Element->FixedWith = Size;
244         return ;
245 }
246
247 /**
248  * \brief Set the text field of an element
249  * \note Used for the image path on ELETYPE_IMAGE
250  */
251 void AxWin_SetText(tElement *Element, const char *Text)
252 {
253         if(!Element)    return ;
254         if(Element->Text)       free(Element->Text);
255         Element->Text = strdup(Text);
256         
257         switch(Element->Type)
258         {
259         case ELETYPE_IMAGE:
260                 if(Element->Data)       free(Element->Data);
261                 Element->Data = Image_Load( Element->Text );
262                 if(!Element->Data) {
263                         Element->Flags &= ~ELEFLAG_FIXEDSIZE;
264                         return ;
265                 }
266                 
267                 //Element->Flags |= ELEFLAG_FIXEDSIZE;
268                 Element->CachedW = ((tImage*)Element->Data)->Width;
269                 Element->CachedH = ((tImage*)Element->Data)->Height;
270                 
271                 if(Element->Parent && Element->Parent->Flags & ELEFLAG_VERTICAL) {
272                         Element->MinCross = ((tImage*)Element->Data)->Width;
273                         Element->MinWith = ((tImage*)Element->Data)->Height;
274                 }
275                 else {
276                         Element->MinWith = ((tImage*)Element->Data)->Width;
277                         Element->MinCross = ((tImage*)Element->Data)->Height;
278                 }
279                 break;
280         
281         case ELETYPE_TEXT:
282                 {
283                  int    w=0, h=0;
284                 Video_GetTextDims(NULL, Element->Text, &w, &h);
285                 if(Element->Parent && Element->Parent->Flags & ELEFLAG_VERTICAL) {
286                         Element->MinCross = w;
287                         Element->MinWith = h;
288                 }
289                 else {
290                         Element->MinWith = w;
291                         Element->MinCross = h;
292                 }
293                 }
294                 break;
295         default:        // Any other, no special case
296                 break ; 
297         }
298         
299         return ;
300 }

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