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

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