X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Usermode%2FApplications%2Faxwin3_src%2FWM%2Frenderers%2Fwidget.c;h=7668cbd65d6c6f73afc2740b335c2b7ac00eeda8;hb=f4e3c3d24ca880fe72396b2b0fc1ca3ce506b6ff;hp=1bd437dabc249daea5dd4bdeec03b56bf394e375;hpb=2f16fec349eabb42f5e23ea2b821f149fa6b767e;p=tpg%2Facess2.git diff --git a/Usermode/Applications/axwin3_src/WM/renderers/widget.c b/Usermode/Applications/axwin3_src/WM/renderers/widget.c index 1bd437da..7668cbd6 100644 --- a/Usermode/Applications/axwin3_src/WM/renderers/widget.c +++ b/Usermode/Applications/axwin3_src/WM/renderers/widget.c @@ -14,6 +14,7 @@ #include "widget/common.h" #define DEFAULT_ELETABLE_SIZE 64 +#define BORDER_EVERYTHING 0 // === PROTOTYPES === int Renderer_Widget_Init(void); @@ -42,12 +43,21 @@ tWMRenderer gRenderer_Widget = { // --- Element callbacks tWidgetDef *gaWM_WidgetTypes[NUM_ELETYPES]; const int ciWM_NumWidgetTypes = sizeof(gaWM_WidgetTypes)/sizeof(gaWM_WidgetTypes[0]); +tWidgetDef gWidget_NullWidgetDef; // === CODE === int Renderer_Widget_Init(void) { + int i; WM_RegisterRenderer(&gRenderer_Widget); + for(i = 0; i < ciWM_NumWidgetTypes; i ++) + { + if(gaWM_WidgetTypes[i] != NULL) continue; + + gaWM_WidgetTypes[i] = &gWidget_NullWidgetDef; + } + return 0; } @@ -60,7 +70,8 @@ void Widget_int_SetTypeDef(int Type, tWidgetDef *Ptr) return ; } - if( gaWM_WidgetTypes[Type] ) { + if( gaWM_WidgetTypes[Type] && gaWM_WidgetTypes[Type] != &gWidget_NullWidgetDef ) + { _SysDebug("ERROR - Widget ID %i redefined by %p", Type, __builtin_return_address(0) ); @@ -68,7 +79,6 @@ void Widget_int_SetTypeDef(int Type, tWidgetDef *Ptr) } gaWM_WidgetTypes[Type] = Ptr; - _SysDebug("Registered type %i to %p", Type, Ptr); } tWindow *Renderer_Widget_Create(int Flags) @@ -87,6 +97,7 @@ tWindow *Renderer_Widget_Create(int Flags) info = ret->RendererInfo; info->TableSize = eletable_size; + info->FocusedElement = &info->RootElement; info->RootElement.Window = ret; info->RootElement.ID = -1; info->RootElement.BackgroundColour = 0xCCCCCC; @@ -102,7 +113,7 @@ tWindow *Renderer_Widget_Create(int Flags) void Renderer_Widget_Redraw(tWindow *Window) { tWidgetWin *info = Window->RendererInfo; - WM_Render_FillRect(Window, 0, 0, 0xFFF, 0xFFF, info->RootElement.BackgroundColour); + WM_Render_FillRect(Window, 0, 0, Window->W, Window->H, info->RootElement.BackgroundColour); Widget_UpdateDimensions(&info->RootElement); Widget_UpdatePosition(&info->RootElement); @@ -118,17 +129,19 @@ void Widget_RenderWidget(tWindow *Window, tElement *Element) if( Element->Flags & ELEFLAG_NORENDER ) return ; if( Element->Flags & ELEFLAG_INVISIBLE ) return ; - if( Element->Type < ciWM_NumWidgetTypes - && gaWM_WidgetTypes[Element->Type] - && gaWM_WidgetTypes[Element->Type]->Render - ) + #if BORDER_EVERYTHING + WM_Render_DrawRect( + Window, + Element->CachedX, Element->CachedY, + Element->CachedW, Element->CachedH, + 0 + ); + #endif + + if(gaWM_WidgetTypes[Element->Type]->Render) { gaWM_WidgetTypes[Element->Type]->Render(Window, Element); } - else - { - Widget_Decorator_RenderWidget(Window, Element); - } for(child = Element->FirstChild; child; child = child->NextSibling) { @@ -143,12 +156,20 @@ void Widget_UpdateDimensions(tElement *Element) int nFixed = 0; int maxCross = 0; int fixedSize = 0; - int fullCross, dynWith; + int fullCross, dynWith = 0; + int bVertical = Element->Flags & ELEFLAG_VERTICAL; + + // Check if this element can have children + if( (gaWM_WidgetTypes[Element->Type]->Flags & WIDGETTYPE_FLAG_NOCHILDREN) ) + return ; // Pass 1 // - Get the fixed and minimum sizes of the element for( child = Element->FirstChild; child; child = child->NextSibling ) { + int minWith = bVertical ? child->MinH : child->MinW; + int minCross = bVertical ? child->MinW : child->MinH; + // Ignore elements that will not be rendered if( child->Flags & ELEFLAG_NORENDER ) continue ; @@ -164,81 +185,80 @@ void Widget_UpdateDimensions(tElement *Element) else if( child->Flags & ELEFLAG_NOSTRETCH ) { nFixed ++; - fixedSize += child->MinWith; + fixedSize += minWith; } - if( child->FixedCross && maxCross < child->FixedCross ) - maxCross = child->FixedCross; - if( child->MinCross && maxCross < child->MinCross ) - maxCross = child->MinCross; + if( maxCross < child->FixedCross ) maxCross = child->FixedCross; + if( maxCross < minCross ) maxCross = minCross; nChildren ++; } // Get the dynamic with size from the unused space in the element if( nChildren > nFixed ) { - if( Element->Flags & ELEFLAG_VERTICAL ) + if( bVertical ) dynWith = Element->CachedH - Element->PaddingT - Element->PaddingB; else dynWith = Element->CachedW - Element->PaddingL - Element->PaddingR; dynWith -= fixedSize; + dynWith -= Element->GapSize * (nChildren-1); if( dynWith < 0 ) return ; dynWith /= nChildren - nFixed; } + else { + dynWith = 0; + } -// _SysDebug("%i - nChildren = %i, nFixed = %i, dynWith = %i, fixedSize = %i", -// Element->ID, nChildren, nFixed, dynWith, fixedSize); - // Get the cross size - if( Element->Flags & ELEFLAG_VERTICAL ) + if( bVertical ) fullCross = Element->CachedW - Element->PaddingL - Element->PaddingR; else fullCross = Element->CachedH - Element->PaddingT - Element->PaddingB; + + _SysDebug("%i (p=%i) - WxH=%ix%i", + Element->ID, (Element->Parent ? Element->Parent->ID : -1), + Element->CachedW, Element->CachedH + ); + _SysDebug(" %s dynWith = %i, fullCross = %i", + (Element->Flags & ELEFLAG_VERTICAL ? "Vert" : "Horiz"), + dynWith, fullCross + ); // Pass 2 - Set sizes and recurse for( child = Element->FirstChild; child; child = child->NextSibling ) { - int cross, with; + int w, h; // Ignore elements that will not be rendered if( child->Flags & ELEFLAG_NORENDER ) continue ; + // Don't resize floating elements + if( child->Flags & ELEFLAG_ABSOLUTEPOS ) continue ; - // --- Cross Size --- - // TODO: Expand to fill? - // TODO: Extra flag so options are (Expand, Equal, Wrap) - if( child->FixedCross ) - cross = child->FixedCross; - else if( child->Flags & ELEFLAG_NOEXPAND ) - cross = child->MinCross; - else - cross = fullCross; - - // --- With Size --- - if( child->FixedWith ) - with = child->FixedWith; - else if( child->Flags & ELEFLAG_NOSTRETCH ) - with = child->MinWith; + // --- Width --- + if( child->Flags & ELEFLAG_NOEXPAND ) + w = child->MinW; + else if( bVertical ) + w = child->FixedCross ? child->FixedCross : fullCross; else - with = dynWith; + w = child->FixedWith ? child->FixedWith : dynWith; + // --- Height --- + if( child->Flags & ELEFLAG_NOSTRETCH ) + h = child->MinH; + else if( bVertical ) + h = child->FixedWith ? child->FixedWith : dynWith; + else + h = child->FixedCross ? child->FixedCross : fullCross; - if(with < child->MinWith) with = child->MinWith; - if(cross < child->MinCross) cross = child->MinCross; - + if(w < child->MinW) w = child->MinW; + if(h < child->MinH) h = child->MinH; + +// _SysDebug("Child %ix%i (min %ix%i)", w, h, child->MinW, child->MinH); + // Update the dimensions if they have changed - if( Element->Flags & ELEFLAG_VERTICAL ) { - // If no change, don't recurse - if( child->CachedW == cross && child->CachedH == with ) - continue ; - child->CachedW = cross; - child->CachedH = with; - } - else { - // If no change, don't recurse - if( child->CachedW == with && child->CachedH == cross ) - continue ; - child->CachedW = with; - child->CachedH = cross; - } + if( child->CachedW == w && child->CachedH == h ) + continue ; + child->CachedW = w; + child->CachedH = h; // Force the positions of child elements to be recalculated child->CachedX = -1; @@ -259,6 +279,10 @@ void Widget_UpdatePosition(tElement *Element) if( Element->Flags & ELEFLAG_NORENDER ) return ; + // Check if this element can have children + if( (gaWM_WidgetTypes[Element->Type]->Flags & WIDGETTYPE_FLAG_NOCHILDREN) ) + return ; + // _SysDebug("Widget_UpdatePosition: (Element=%p(%i Type=%i Flags=0x%x))", // Element, Element->ID, Element->Type, Element->Flags); @@ -275,7 +299,7 @@ void Widget_UpdatePosition(tElement *Element) newX = x; newY = y; - // Handle alignment + // Handle alignment (across parent) if( Element->Flags & ELEFLAG_ALIGN_CENTER ) { if(Element->Flags & ELEFLAG_VERTICAL) newX += Element->CachedW/2 - child->CachedW/2; @@ -319,40 +343,46 @@ void Widget_UpdatePosition(tElement *Element) void Widget_UpdateMinDims(tElement *Element) { tElement *child; + int minW, minH; + int nChildren; if(!Element) return; - Element->MinCross = 0; - Element->MinWith = 0; + minW = 0; + minH = 0; + nChildren = 0; for(child = Element->FirstChild; child; child = child->NextSibling) { - if( Element->Parent && - (Element->Flags & ELEFLAG_VERTICAL) == (Element->Parent->Flags & ELEFLAG_VERTICAL) - ) + int cross; + + if(Element->Flags & ELEFLAG_NORENDER) continue ; + + if( (Element->Flags & ELEFLAG_VERTICAL) ) { - if(child->FixedCross) - Element->MinCross += child->FixedCross; - else - Element->MinCross += child->MinCross; - if(child->FixedWith) - Element->MinWith += child->FixedWith; - else - Element->MinWith += child->MinWith; + cross = child->FixedCross ? child->FixedCross : child->MinW; + if(minW < cross) minW = cross; + minH += child->FixedWith ? child->FixedWith : child->MinH; } else { - if(child->FixedCross) - Element->MinWith += child->FixedCross; - else - Element->MinWith += child->MinCross; - if(child->FixedWith) - Element->MinCross += child->FixedWith; - else - Element->MinCross += child->MinWith; + cross = child->FixedCross ? child->FixedCross : child->MinH; + minW += child->FixedWith ? child->FixedWith : child->MinW; + if(minH < cross) minH = cross; } +// _SysDebug("%i/%i cross = %i", Element->ID, child->ID, cross); + + nChildren ++; } + if( Element->Flags & ELEFLAG_VERTICAL ) + minH += (nChildren - 1) * Element->GapSize; + else + minW += (nChildren - 1) * Element->GapSize; + + Element->MinW = Element->PaddingL + minW + Element->PaddingR; + Element->MinH = Element->PaddingT + minH + Element->PaddingB; + // Recurse upwards Widget_UpdateMinDims(Element->Parent); } @@ -362,7 +392,7 @@ tElement *Widget_GetElementByPos(tWidgetWin *Info, int X, int Y) tElement *ret, *next, *ele; next = &Info->RootElement; - while(next) + do { ret = next; next = NULL; @@ -375,7 +405,7 @@ tElement *Widget_GetElementByPos(tWidgetWin *Info, int X, int Y) if(Y >= ele->CachedY + ele->CachedH) continue; next = ele; } - } + } while(next); return ret; } @@ -408,6 +438,12 @@ void Widget_NewWidget(tWidgetWin *Info, size_t Len, const tWidgetMsg_Create *Msg _SysDebug("Widget_NewWidget (%i %i Type %i Flags 0x%x)", Msg->Parent, Msg->NewID, Msg->Type, Msg->Flags); + if(Msg->Type >= ciWM_NumWidgetTypes) + { + _SysDebug("Widget_NewWidget - Bad widget type %i", Msg->Type); + return ; + } + // Create parent = Widget_GetElementById(Info, Msg->Parent); if(!parent) @@ -433,7 +469,7 @@ void Widget_NewWidget(tWidgetWin *Info, size_t Len, const tWidgetMsg_Create *Msg new->PaddingR = 2; new->CachedX = -1; - if( new->Type < ciWM_NumWidgetTypes && gaWM_WidgetTypes[new->Type] && gaWM_WidgetTypes[new->Type]->Init ) + if( gaWM_WidgetTypes[new->Type]->Init ) gaWM_WidgetTypes[new->Type]->Init(new); // Add to parent's list @@ -456,6 +492,13 @@ void Widget_NewWidget(tWidgetWin *Info, size_t Len, const tWidgetMsg_Create *Msg Widget_UpdateMinDims(parent); } +void Widget_SetFocus(tWidgetWin *Info, tElement *Ele) +{ + // TODO: Callbacks + + Info->FocusedElement = Ele; +} + void Widget_SetFlags(tWidgetWin *Info, int Len, const tWidgetMsg_SetFlags *Msg) { tElement *ele; @@ -498,9 +541,7 @@ void Widget_SetText(tWidgetWin *Info, int Len, const tWidgetMsg_SetText *Msg) if(!ele) return ; - if( ele->Type < ciWM_NumWidgetTypes - && gaWM_WidgetTypes[ele->Type] - && gaWM_WidgetTypes[ele->Type]->UpdateText ) + if( gaWM_WidgetTypes[ele->Type]->UpdateText ) { gaWM_WidgetTypes[ele->Type]->UpdateText( ele, Msg->Text ); } @@ -514,6 +555,7 @@ void Widget_SetText(tWidgetWin *Info, int Len, const tWidgetMsg_SetText *Msg) int Renderer_Widget_HandleMessage(tWindow *Target, int Msg, int Len, const void *Data) { tWidgetWin *info = Target->RendererInfo; + tElement *ele; switch(Msg) { case WNDMSG_RESIZE: { @@ -534,7 +576,6 @@ int Renderer_Widget_HandleMessage(tWindow *Target, int Msg, int Len, const void case WNDMSG_MOUSEBTN: { const struct sWndMsg_MouseButton *msg = Data; tWidgetMsg_MouseBtn client_msg; - tElement *ele; int x, y; int rv; @@ -545,12 +586,11 @@ int Renderer_Widget_HandleMessage(tWindow *Target, int Msg, int Len, const void client_msg.bPressed = msg->bPressed; ele = Widget_GetElementByPos(info, x, y); + Widget_SetFocus(info, ele); // Send event to all elements from `ele` upwards for( ; ele; ele = ele->Parent ) { - if(ele->Type < ciWM_NumWidgetTypes - && gaWM_WidgetTypes[ele->Type] - && gaWM_WidgetTypes[ele->Type]->MouseButton) + if(gaWM_WidgetTypes[ele->Type]->MouseButton) { rv = gaWM_WidgetTypes[ele->Type]->MouseButton( ele, @@ -571,15 +611,72 @@ int Renderer_Widget_HandleMessage(tWindow *Target, int Msg, int Len, const void } return 0; } + case WNDMSG_KEYDOWN: { + const struct sWndMsg_KeyAction *msg = Data; + if(Len < sizeof(*msg)) return -1; + + if(!info->FocusedElement) return 0; + ele = info->FocusedElement; + + if(gaWM_WidgetTypes[ele->Type]->KeyDown) + gaWM_WidgetTypes[ele->Type]->KeyDown(ele, msg->KeySym, msg->UCS32); + else + { + // TODO: Pass to user + } + + return 0; } + + case WNDMSG_KEYFIRE: { + const struct sWndMsg_KeyAction *msg = Data; + if(Len < sizeof(*msg)) return -1; + + if(!info->FocusedElement) return 0; + ele = info->FocusedElement; + + if(gaWM_WidgetTypes[ele->Type]->KeyFire) + gaWM_WidgetTypes[ele->Type]->KeyFire(ele, msg->KeySym, msg->UCS32); + else + { + // TODO: Pass the buck + } + return 0; } + + case WNDMSG_KEYUP: { + const struct sWndMsg_KeyAction *msg = Data; + if(Len < sizeof(*msg)) return -1; + + if(!info->FocusedElement) return 0; + ele = info->FocusedElement; + + if(gaWM_WidgetTypes[ele->Type]->KeyUp) + gaWM_WidgetTypes[ele->Type]->KeyUp(ele, msg->KeySym); + else + { + // TODO: Pass the buck + } + return 0; } + // New Widget case MSG_WIDGET_CREATE: Widget_NewWidget(info, Len, Data); return 0; + // Delete a widget case MSG_WIDGET_DELETE: _SysDebug("TODO: Implement MSG_WIDGET_DELETE"); return 0; + // Set focused widget + case MSG_WIDGET_SETFOCUS: { + tElement *ele; + const tWidgetMsg_SetFocus *msg = Data; + if(Len < sizeof(*msg)) return -1; + + ele = Widget_GetElementById(info, msg->WidgetID); + Widget_SetFocus(info, ele); + return 0; } + // Set Flags case MSG_WIDGET_SETFLAGS: Widget_SetFlags(info, Len, Data);