X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Usermode%2FApplications%2Faxwin2_src%2FWM%2Fwm.c;h=dc1de6a22fd1a35b2eaef949f5a3dffb7664cf0c;hb=b43ed8d15c86ff9b7f5abc9f47e1385503dcdf35;hp=163e8104ee0557780916ce98e7760ca857847ce7;hpb=a98b0e6ff33593616a21337492bb2fd48e9e5845;p=tpg%2Facess2.git diff --git a/Usermode/Applications/axwin2_src/WM/wm.c b/Usermode/Applications/axwin2_src/WM/wm.c index 163e8104..dc1de6a2 100644 --- a/Usermode/Applications/axwin2_src/WM/wm.c +++ b/Usermode/Applications/axwin2_src/WM/wm.c @@ -6,50 +6,155 @@ */ #include "common.h" #include -#include +#include #include "wm.h" +#include // _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" +}; +tApplication *gWM_Applications; + +// --- 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 === +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_CreateWindow(tApplication *App, const char *Name) +{ + tElement *ret; + + // TODO: Implement _CreateTab + + ret = AxWin_CreateElement(&App->MetaElement, ELETYPE_WINDOW, 0, NULL); + ret->Text = strdup(Name); + return ret; +} + // --- Widget Creation and Control --- -tElement *WM_CreateElement(tElement *Parent, int Type, int Flags) +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; @@ -58,10 +163,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) { @@ -73,14 +214,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); @@ -96,418 +244,37 @@ void WM_SetText(tElement *Element, char *Text) 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 1 -void WM_UpdateDimensions(tElement *Element, int Pass) -{ - int fixedSize = 0, maxCross = 0; - int nFixed = 0, nChildren = 0; - int minSize = 0; - tElement *child; - - // 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; - } - - if( !(Element->Flags & ELEFLAG_NOEXPAND) ) - { - if( Element->Parent->Flags & ELEFLAG_VERTICAL ) - Element->CachedW = Element->Parent->CachedW; - else - Element->CachedH = Element->Parent->CachedH; - } - } - } - - for( child = Element->FirstChild; child; child = child->NextSibling ) - { - WM_UpdateDimensions( child, 0 ); - - if( Element->Flags & ELEFLAG_VERTICAL ) - { - if( child->CachedH ) { - fixedSize += child->CachedH; - minSize += child->CachedH; - nFixed ++; - } - else - minSize += child->MinHeight; - - if( maxCross < child->CachedW ) - maxCross = child->CachedW;; - } - else - { - if( child->CachedW ) { - fixedSize += child->CachedW; - minSize += child->CachedW; - nFixed ++; - } - else - minSize += child->MinWidth; - - if( maxCross < child->CachedH ) - maxCross = child->CachedH; - } - nChildren ++; - } - _SysDebug("WM_UpdateDimensions: nFixed=%i, fixedSize=%i, minSize=%i, maxCross=%i", - nFixed, fixedSize, minSize, maxCross - ); - - - // 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 - tmp = dynSize; - - if( Element->Flags & ELEFLAG_VERTICAL ) { - if( tmp < child->MinHeight ) - tmp = child->MinHeight; - child->CachedH = tmp; - } - else { - if( tmp < child->MinWidth ) - tmp = child->MinWidth; - child->CachedW = tmp; - } - - WM_UpdateDimensions(child, 1); - } - } -} - -#else - -/** - * \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; - } - - // 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 -} -#endif - - -/** - * \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; + Element->MinWith = w; + Element->MinCross = h; } - 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 ; }