VTerm - Bugfixing mostly
[tpg/acess2.git] / Usermode / Applications / axwin2_src / WM / wm.c
index b91c756..bb8d7f2 100644 (file)
  */
 #include "common.h"
 #include <stdlib.h>
-#include <strings.h>
+#include <string.h>
 #include "wm.h"
+#include <acess/sys.h> // _SysDebug
 
 // === IMPORTS ===
-extern void    Decorator_RenderWidget(tElement *Element);
+extern void    Video_GetTextDims(tFont *Font, const char *Text, int *W, int *H);
 
 // === PROTOTYPES ===
-tElement       *WM_CreateElement(tElement *Parent, int Type, int Flags);
-void   WM_SetFlags(tElement *Element, int Flags);
-void   WM_SetSize(tElement *Element, int Size);
-void   WM_SetText(tElement *Element, char *Text);
-void   WM_UpdateDimensions(tElement *Element, int Pass);
-void   WM_UpdatePosition(tElement *Element);
-void   WM_RenderWidget(tElement *Element);
-void   WM_Update(void);
+tApplication   *AxWin_RegisterClient(tIPC_Type *IPCType, void *Ident, const char *Name);
+void   AxWin_DeregisterClient(tApplication *App);
+tApplication   *AxWin_GetClient(tIPC_Type *Method, void *Ident);
+tElement       *AxWin_CreateElement(tElement *Parent, int Type, int Flags, const char *DebugName);
+void   AxWin_DeleteElement(tElement *Element);
+void   AxWin_SetFlags(tElement *Element, int Flags);
+void   AxWin_SetSize(tElement *Element, int Size);
+void   AxWin_SetText(tElement *Element, const char *Text);
 
 // === GLOBALS ===
-tElement       gWM_RootElement;
+// - TODO: Handle windows by having multiple root elements
+tElement       gWM_RootElement = {
+       .DebugName = "ROOT"
+};
+tWindow        *gWM_WindowFirst;
+tWindow        *gWM_WindowLast;
+tApplication   *gWM_Applications;
+ int   giWM_MaxAreaX = 0;
+ int   giWM_MaxAreaY = 0;
+ int   giWM_MaxAreaW = -1;
+ int   giWM_MaxAreaH = -1;
+
+// --- Element type flags
 struct {
        void    (*Init)(tElement *This);
+       void    (*Delete)(tElement *This);
        void    (*UpdateFlags)(tElement *This);
        void    (*UpdateSize)(tElement *This);
        void    (*UpdateText)(tElement *This);
 }      gaWM_WidgetTypes[MAX_ELETYPES] = {
-       {NULL, NULL, NULL, NULL},       // NULL
-       {NULL, NULL, NULL, NULL}        // Box
+       {NULL, NULL, NULL, NULL, NULL}, // NULL
+       {NULL, NULL, NULL, NULL, NULL}, // Window
+       {NULL, NULL, NULL, NULL, NULL}  // Box
 };
+const int      ciWM_NumWidgetTypes = sizeof(gaWM_WidgetTypes)/sizeof(gaWM_WidgetTypes[0]);
 
 // === CODE ===
-// --- Widget Creation and Control ---
-tElement *WM_CreateElement(tElement *Parent, int Type, int Flags)
+tApplication *AxWin_RegisterClient(tIPC_Type *Method, void *Ident, const char *Name)
+{
+        int    identlen = Method->GetIdentSize(Ident);
+       // Structure, empty string, Name, Ident
+       tApplication    *ret = calloc( 1, sizeof(tApplication) + 1 + strlen(Name) + 1 + identlen );
+       
+       // DebugName is empty
+       
+       // Name/Title
+       ret->Name = &ret->MetaElement.DebugName[1];
+       strcpy(ret->Name, Name);
+       // Ident
+       ret->Ident = ret->Name + strlen(Name) + 1;
+       memcpy(ret->Ident, Ident, identlen);
+       // IPC Type
+       ret->IPCType = Method;
+
+       // Element index
+       ret->MaxElementIndex = DEFAULT_ELEMENTS_PER_APP;
+       ret->EleIndex = calloc( 1, ret->MaxElementIndex * sizeof(*ret->EleIndex) );
+
+       // Add to global list
+       ret->Next = gWM_Applications;
+       gWM_Applications = ret;
+
+       // TODO: Inform listeners of the new application
+
+       return ret;
+}
+
+void AxWin_DeregisterClient(tApplication *App)
+{
+       // TODO: Complete implementing DeregisterClient
+       tElement        *win, *next;
+
+       for( win = App->MetaElement.FirstChild; win; win = next )
+       {
+               next = win->NextSibling;
+               AxWin_DeleteElement(win);
+       }
+
+       // TODO: Inform listeners of deleted application
+       
+       // Remove from list
+       {
+               tApplication    *app, *prev = NULL;
+               for( app = gWM_Applications; app; app = app->Next )
+               {
+                       if( app == App )        break;
+                       prev = app;
+               }
+               
+               if( app )
+               {
+                       if(prev)
+                               prev->Next = App->Next;
+                       else
+                               gWM_Applications = App->Next;
+               }
+       }
+       
+       free(App);
+}
+
+/**
+ * \brief Get an application handle from a client identifier
+ */
+tApplication *AxWin_GetClient(tIPC_Type *Method, void *Ident)
+{
+       // TODO: Faster and smarter technique
+       tApplication    *app;
+       for( app = gWM_Applications; app; app = app->Next )
+       {
+               if( app->IPCType != Method )    continue;
+               if( Method->CompareIdent( app->Ident, Ident ) != 0 ) continue;
+               return app;
+       }
+       return NULL;
+}
+
+tElement *AxWin_CreateAppWindow(tApplication *App, const char *Name)
 {
        tElement        *ret;
+       tWindow *win;
+       
+       win = calloc(1, sizeof(tWindow) + 1);
+       if(!win)        return NULL;
        
-       if(Type < 0 || Type > NUM_ELETYPES)     return NULL;
+       ret = &win->Element;
+       ret->Type = ELETYPE_WINDOW;
+       ret->Data = win;
+       ret->Parent = &App->MetaElement;
+       
+       // Add to parent list
+       if(ret->Parent->LastChild)
+               ret->Parent->LastChild->NextSibling = ret;
+       ret->Parent->LastChild = ret;
+       if(!ret->Parent->FirstChild)
+               ret->Parent->FirstChild = ret;
+       
+       ret->Text = strdup(Name);
+       
+       return ret;
+}
+
+// --- Widget Creation and Control ---
+tAxWin_Element *AxWin_CreateElement(tElement *Parent, int Type, int Flags, const char *DebugName)
+{
+       tElement        *ret;
+       const char      *dbgName = DebugName ? DebugName : "";
        
-       ret = calloc(sizeof(tElement), 1);
+       ret = calloc(sizeof(tElement)+strlen(dbgName)+1, 1);
        if(!ret)        return NULL;
        
        // Prepare
        ret->Type = Type;
+       strcpy(ret->DebugName, dbgName);
        if(Parent == NULL)      Parent = &gWM_RootElement;
        ret->Parent = Parent;
+       ret->Flags = Flags;
        
        // Append to parent's list
-       ret->NextSibling = Parent->LastChild;
+       if(Parent->LastChild)
+               Parent->LastChild->NextSibling = ret;
        Parent->LastChild = ret;
        if(!Parent->FirstChild) Parent->FirstChild = ret;
        
@@ -60,10 +183,46 @@ tElement *WM_CreateElement(tElement *Parent, int Type, int Flags)
        ret->PaddingT = 2;
        ret->PaddingB = 2;
        
+       if( Type < ciWM_NumWidgetTypes && gaWM_WidgetTypes[Type].Init )
+               gaWM_WidgetTypes[Type].Init(ret);
+       
+       WM_UpdateMinDims(ret->Parent);
+       
        return ret;
 }
 
-void WM_SetFlags(tElement *Element, int Flags)
+/**
+ * \brief Delete an element
+ */
+void AxWin_DeleteElement(tElement *Element)
+{
+       tElement        *child, *next;
+       
+       for(child = Element->FirstChild; child; child = next)
+       {
+               next = child->NextSibling;
+               AxWin_DeleteElement(child);
+       }
+
+       // TODO: Implement AxWin_DeleteElement
+       // TODO: Clean up related data.
+       if( Element->Type < ciWM_NumWidgetTypes && gaWM_WidgetTypes[Element->Type].Delete )
+               gaWM_WidgetTypes[Element->Type].Delete(Element);
+
+       if(Element->Owner)
+               Element->Owner->EleIndex[ Element->ApplicationID ] = NULL;
+
+       Element->Type = 0;
+       Element->Owner = 0;
+       Element->Flags = 0;
+
+       free(Element);
+}
+
+/**
+ * \brief Alter an element's flags 
+ */
+void AxWin_SetFlags(tElement *Element, int Flags)
 {
        // Permissions are handled in the message handler
        if(!Element) {
@@ -75,14 +234,21 @@ void WM_SetFlags(tElement *Element, int Flags)
        return ;
 }
 
-void WM_SetSize(tElement *Element, int Size)
+/**
+ * \brief Set the fixed lenghthways size of an element
+ */
+void AxWin_SetSize(tElement *Element, int Size)
 {
        if(!Element)    return ;
-       Element->Size = Size;
+       Element->FixedWith = Size;
        return ;
 }
 
-void WM_SetText(tElement *Element, char *Text)
+/**
+ * \brief Set the text field of an element
+ * \note Used for the image path on ELETYPE_IMAGE
+ */
+void AxWin_SetText(tElement *Element, const char *Text)
 {
        if(!Element)    return ;
        if(Element->Text)       free(Element->Text);
@@ -92,397 +258,43 @@ void WM_SetText(tElement *Element, char *Text)
        {
        case ELETYPE_IMAGE:
                if(Element->Data)       free(Element->Data);
-               Element->Data = LoadImage( Element->Text );
+               Element->Data = Image_Load( Element->Text );
                if(!Element->Data) {
                        Element->Flags &= ~ELEFLAG_FIXEDSIZE;
                        return ;
                }
                
-               Element->Flags |= ELEFLAG_FIXEDSIZE;
+               //Element->Flags |= ELEFLAG_FIXEDSIZE;
                Element->CachedW = ((tImage*)Element->Data)->Width;
                Element->CachedH = ((tImage*)Element->Data)->Height;
                
-               if(Element->Parent && Element->Parent->Flags & ELEFLAG_VERTICAL)
-                       Element->Size = Element->CachedH;
-               else
-                       Element->Size = Element->CachedW;
-               break;
-       }
-       
-       return ;
-}
-
-// --- Pre-Rendering ---
-#if 0
-void WM_UpdateDimensions(tElement *Element, int Pass)
-{
-       // Pass zero intialises
-       if( Pass == 0 )
-       {
-               // If not a fixed size element, initialise the sizes
-               if( !(Element->Flags & ELEFLAG_FIXEDSIZE) )
-               {
-                       Element->CachedH = 0;
-                       Element->CachedW = 0;
-                       if( Element->Size )
-                       {
-                               if( Element->Parent->Flags & ELEFLAG_VERTICAL )
-                                       Element->CachedH = Element->Size;
-                               else
-                                       Element->CachedW = Element->Size;
-                       }
-               }
-       }
-
-        int    fixedSize = 0, maxCross = 0;
-        int    nFixed = 0, nChildren = 0;
-       for( child = Element->FirstChild; child; child = child->NextSibling )
-       {
-               WM_UpdateDimensions( child, 0 );
-               
-               if( Element->Flags & ELEFLAG_VERTICAL )
-               {
-                       if( child->CachedH ) {
-                               fixedSize += child->CachedH;
-                               nFixed ++;
-                       }
-                       if( maxCross < child->CachedW )
-                               maxCross = child->CachedW;
-               }
-               else
-               {
-                       if( child->CachedW ) {
-                               fixedSize += child->CachedW;
-                               nFixed ++;
-                       }
-                       if( maxCross < child->CachedH )
-                               maxCross = child->CachedH;
-               }
-               nChildren ++;
-       }
-
-
-       // If we don't have our dimensions, get the child dimensions
-       if( Element->CachedW == 0 || Element->CachedH == 0 )
-       {       
-               if( Element->Flags & ELEFLAG_VERTICAL )
-               {
-                       if( Element->CachedW == 0 && maxCross )
-                               Element->CachedW = Element->PaddingL
-                                       + Element->PaddingR + maxCross;
-                       
-                       if( Element->CachedH == 0 && nFixed == nChildren )
-                               Element->CachedH = Element->PaddingT
-                                       + Element->PaddingB + fixedSize
-                                       + nChildren * Element->GapSize;
-               }
-               else
-               {
-                       if( maxCross )
-                               Element->CachedH = Element->PaddingT
-                                       + Element->PaddingB + maxCross;
-                       
-                       if( Element->CachedW == 0 && nFixed == nChildren )
-                               Element->CachedW = Element->PaddingL
-                                       + Element->PaddingR + fixedSize
-                                       + nChildren * Element->GapSize;
-               }
-       }
-       
-       // Now, if we have the "length" of the widget, we can size the children
-       if( (Element->Flags & ELEFLAG_VERTICAL && Element->CachedH > 0)
-        || (!(Element->Flags & ELEFLAG_VERTICAL) && Element->CachedW > 0) )
-       {
-                int    dynSize;
-               
-               // Calculate the size of dynamically sized elements
-               if( Element->Flags & ELEFLAG_VERTICAL )
-                       dynSize = Element->CachedH - Element->PaddingT
-                                - Element->PaddingB - fixedSize;
-               else
-                       dynSize = Element->CachedW - Element->PaddingL
-                                - Element->PaddingR - fixedSize;
-               dynSize /= nChildren - nFixed;
-               
-               // Itterate children again
-               for( child = Element->FirstChild; child; child = child->NextSibling )
-               {
-                        int    tmp;
-                       
-                       // Get the size of them
-                       if(child->Size)
-                               tmp = child->Size;
-                       else if(dynSize < Element->MinSize)
-                               tmp = child->MinSize;
-                       else
-                               tmp = dynSize;
-                       
-                       if( Element->Flags & ELEFLAG_VERTICAL )
-                               child->CachedH = tmp;
-                       else
-                               child->CachedW = tmp;
-                       
-                       WM_UpdateDimensions(child, 1);
-               }
-       }
-}
-
-#endif
-
-/**
- * \brief Updates the dimensions of an element
- * 
- * The dimensions of an element are calculated from the parent's
- * cross dimension (the side at right angles to the alignment) sans some
- * padding.
- */
-void WM_UpdateDimensions(tElement *Element, int Pass)
-{
-       tElement        *child;
-        int    fixedChildSize = 0;
-        int    dynamicSize;
-        int    nChildren = 0;
-        int    nFixed = 0;
-       
-       _SysDebug("WM_UpdateDimensions: (Element=%p{Flags:0x%x}, Pass=%i)",
-               Element, Element->Flags,
-               Pass);
-       
-       if( Pass == 0 )
-       {
-               if( Element->Flags & ELEFLAG_NORENDER ) return ;
-               
-               if( !(Element->Flags & ELEFLAG_ABSOLUTEPOS) ) {
-                       Element->CachedX = 0;
-                       Element->CachedY = 0;
-               }
-               if( !(Element->Flags & ELEFLAG_FIXEDSIZE) ) {
-                       Element->CachedW = 0;
-                       Element->CachedH = 0;
-               }
-       }
-       
-       if( !(Element->Flags & ELEFLAG_FIXEDSIZE) ) {
-               // If the element is sized, fix its dimension(s)
-               if(Element->Size)
-               {
-                       if(Element->Flags & ELEFLAG_NOEXPAND)
-                       {
-                               Element->CachedW = Element->Size;
-                               Element->CachedH = Element->Size;
-                       }
-                       else {
-                               if( Element->Parent->Flags & ELEFLAG_VERTICAL ) {
-                                       Element->CachedH = Element->Size;
-                                       Element->CachedW = Element->Parent->CachedW;
-                                       if(Element->CachedW)
-                                               Element->CachedW -= (Element->Parent->PaddingL + Element->Parent->PaddingR);
-                               }
-                               else {
-                                       Element->CachedW = Element->Size;
-                                       Element->CachedH = Element->Parent->CachedH;
-                                       if(Element->CachedH)
-                                               Element->CachedH -= (Element->Parent->PaddingT + Element->Parent->PaddingB);
-                               }
-                       }
+               if(Element->Parent && Element->Parent->Flags & ELEFLAG_VERTICAL) {
+                       Element->MinCross = ((tImage*)Element->Data)->Width;
+                       Element->MinWith = ((tImage*)Element->Data)->Height;
                }
                else {
-                       // Ok, so now we need to calculate the size of all child elements
-                       // However, if ELEFLAG_NOEXPAND is not set, we can still set one
-                       // dimension
-                       if( !(Element->Flags & ELEFLAG_NOEXPAND) ) {
-                               if( Element->Parent->Flags & ELEFLAG_VERTICAL ) {
-                                       Element->CachedW = Element->Parent->CachedW;
-                                       if(Element->CachedW)
-                                               Element->CachedW -= (Element->Parent->PaddingL + Element->Parent->PaddingR);
-                               }
-                               else {
-                                       Element->CachedH = Element->Parent->CachedH;
-                                       if(Element->CachedH)
-                                               Element->CachedH -= (Element->Parent->PaddingT + Element->Parent->PaddingB);
-                               }
-                       }
+                       Element->MinWith = ((tImage*)Element->Data)->Width;
+                       Element->MinCross = ((tImage*)Element->Data)->Height;
                }
-       }
+               break;
        
-       // Process Children (first pass)
-       for( child = Element->FirstChild; child; child = child->NextSibling )
-       {
-               if( child->Flags & ELEFLAG_NORENDER )   continue;
-               WM_UpdateDimensions(child, 0);
-               
-               // Children that don't inherit positions are ignored
-               if( child->Flags & ELEFLAG_ABSOLUTEPOS )        continue;
-               
-               fixedChildSize += child->Size;
-               if(child->Size > 0)
-                       nFixed ++;
-               nChildren ++;
-               
-               // If we are wrapping the children, get the largest cross size
-               if( !(Element->Flags & ELEFLAG_FIXEDSIZE)
-                && Element->Flags & ELEFLAG_NOEXPAND
-                && Element->Size == 0 )
+       case ELETYPE_TEXT:
                {
-                       if( Element->Flags & ELEFLAG_VERTICAL ) {
-                               if( Element->CachedW < child->CachedW )
-                                       Element->CachedW = child->CachedW;
-                       }
-                       else {
-                               if( Element->CachedH < child->CachedH )
-                                       Element->CachedH = child->CachedH;
-                       }
-               }
-       }
-       
-       // Let's avoid a #DIV0 shall we?
-       if( nChildren > 0 )
-       {
-               // Calculate the size of dynamically sized children
-               if( Element->Flags & ELEFLAG_VERTICAL ) {
-                       if( Element->CachedH == 0 ) {
-                               if( nFixed == nChildren )
-                                       Element->CachedH = fixedChildSize;
-                               else
-                                       return ;
-                       }
-                       dynamicSize = (Element->CachedH - (Element->PaddingT + Element->PaddingB)  - fixedChildSize) / nChildren;
+                int    w=0, h=0;
+               Video_GetTextDims(NULL, Element->Text, &w, &h);
+               if(Element->Parent && Element->Parent->Flags & ELEFLAG_VERTICAL) {
+                       Element->MinCross = w;
+                       Element->MinWith = h;
                }
                else {
-                       if( Element->CachedW == 0 ) {
-                               if( nFixed == nChildren )
-                                       Element->CachedW = fixedChildSize;
-                               else
-                                       return ;
-                       }
-                       dynamicSize = (Element->CachedW - (Element->PaddingL + Element->PaddingR) - fixedChildSize) / nChildren;
+                       Element->MinWith = w;
+                       Element->MinCross = h;
                }
-               
-               // Process Children (second pass)
-               for( child = Element->FirstChild; child; child = child->NextSibling )
-               {
-                       if( child->Flags & ELEFLAG_NORENDER )   continue;
-                       // Children that don't inherit positions are ignored
-                       if( child->Flags & ELEFLAG_ABSOLUTEPOS )        continue;
-                       
-                       if(!child->Size) {
-                               if(child->Flags & ELEFLAG_VERTICAL)
-                                       child->CachedH = dynamicSize;
-                               else
-                                       child->CachedW = dynamicSize;
-                       }
-                       
-                       WM_UpdateDimensions(child, 1);
-                       
-                       // If we are wrapping the children, get the largest cross size
-                       if( Element->Flags & ELEFLAG_NOEXPAND ) {
-                               if( Element->Flags & ELEFLAG_VERTICAL ) {
-                                       if( Element->CachedW < child->CachedW )
-                                               Element->CachedW = child->CachedW;
-                               }
-                               else {
-                                       if( Element->CachedH < child->CachedH )
-                                               Element->CachedH = child->CachedH;
-                               }
-                       }
-               }
-       }
-       
-       // Add the padding
-       //Element->CachedW += Element->PaddingL + Element->PaddingR;
-       //Element->CachedH += Element->PaddingT + Element->PaddingB;
-       
-       _SysDebug("Pass %i, Element %p %ix%i",
-               Pass, Element, Element->CachedW, Element->CachedH
-               );
-       
-       // We should be done
-       // Next function will do the coordinates
-}
-
-
-/**
- * \brief Updates the position of an element
- * 
- * The parent element sets the positions of its children
- */
-void WM_UpdatePosition(tElement *Element)
-{
-       tElement        *child;
-        int    x, y;
-       
-       if( Element->Flags & ELEFLAG_NORENDER ) return ;
-       
-       _SysDebug("Element=%p{PaddingL:%i, PaddingT:%i}",
-               Element, Element->PaddingL, Element->PaddingT);
-       
-       // Initialise
-       x = Element->CachedX + Element->PaddingL;
-       y = Element->CachedY + Element->PaddingT;
-       
-       // Update each child
-       for(child = Element->FirstChild; child; child = child->NextSibling)
-       {
-               child->CachedX = x;
-               child->CachedY = y;
-               
-               // Set Alignment
-               if( Element->Flags & ELEFLAG_ALIGN_CENTER ) {
-                       if(Element->Flags & ELEFLAG_VERTICAL )
-                               child->CachedX += Element->CachedW/2 - child->CachedW/2;
-                       else
-                               child->CachedY += Element->CachedH/2 - child->CachedH/2;
-               }
-               else if( Element->Flags & ELEFLAG_ALIGN_END ) {
-                       if(Element->Flags & ELEFLAG_VERTICAL )
-                               child->CachedX += Element->CachedW - child->CachedW;
-                       else
-                               child->CachedY += Element->CachedH - child->CachedH;
-               }
-               
-               // Update child's children positions
-               WM_UpdatePosition(child);
-               
-               // Increment
-               if(Element->Flags & ELEFLAG_VERTICAL ) {
-                       y += child->CachedH + Element->GapSize;
-               }
-               else {
-                       x += child->CachedW + Element->GapSize;
                }
+               break;
+       default:        // Any other, no special case
+               break ; 
        }
        
-       _SysDebug("Element %p (%i,%i)",
-                Element, Element->CachedX, Element->CachedY
-               );
-}
-
-// --- Render ---
-void WM_RenderWidget(tElement *Element)
-{
-       tElement        *child;
-       
-       if( Element->Flags & ELEFLAG_NORENDER ) return ;
-       if( Element->Flags & ELEFLAG_INVISIBLE )        return ;
-       
-       Decorator_RenderWidget(Element);
-       
-       for(child = Element->FirstChild; child; child = child->NextSibling)
-       {
-               WM_RenderWidget(child);
-       }
-}
-
-void WM_Update(void)
-{
-       gWM_RootElement.CachedX = 0;    gWM_RootElement.CachedY = 0;
-       gWM_RootElement.CachedW = giScreenWidth;
-       gWM_RootElement.CachedH = giScreenHeight;
-       gWM_RootElement.Flags |= ELEFLAG_NOEXPAND|ELEFLAG_ABSOLUTEPOS|ELEFLAG_FIXEDSIZE;
-       
-       WM_UpdateDimensions( &gWM_RootElement, 0 );
-       WM_UpdatePosition( &gWM_RootElement );
-       WM_RenderWidget( &gWM_RootElement );
-       
-       Video_Update();
+       return ;
 }

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