#include <wm_renderer.h>
#include <renderer_widget.h>
#include <string.h>
+#include <wm_messages.h>
+#include <stdlib.h>
-// === TYPES ===
-typedef struct sWidgetWin tWidgetWin;
-typedef struct sAxWin_Element tElement;
-
-// === STRUCTURES ===
-struct sAxWin_Element
-{
- enum eElementTypes Type;
-
- uint32_t ID; //!< Application provided ID number
- tElement *ListNext; //!< Next element in bucket
-
- // Element Tree
- tElement *Parent;
- tElement *FirstChild;
- tElement *LastChild;
- tElement *NextSibling;
-
- // User modifiable attributes
- short PaddingL, PaddingR;
- short PaddingT, PaddingB;
- short GapSize;
-
- uint32_t Flags;
-
- short FixedWith; //!< Fixed lengthways Size attribute (height)
- short FixedCross; //!< Fixed Cross Size attribute (width)
-
- tColour BackgroundColour;
-
- char *Text;
-
- // -- Attributes maitained by the element code
- // Not touched by the user
- short MinWith; //!< Minimum long size
- short MinCross; //!< Minimum cross size
- void *Data; //!< Per-type data
-
- // -- Render Cache
- short CachedX, CachedY;
- short CachedW, CachedH;
-
- char DebugName[];
-};
-struct sWidgetWin
-{
- tElement RootElement;
-
- int TableSize; //!< Number of entries, anything over will wrap
- tElement *ElementTable[]; //!< Hash table essentially
-};
+#define DEFAULT_ELETABLE_SIZE 64
// === PROTOTYPES ===
+ int Renderer_Widget_Init(void);
tWindow *Renderer_Widget_Create(int Flags);
void Renderer_Widget_Redraw(tWindow *Window);
-int Renderer_Widget_HandleMessage(tWindow *Target, int Msg, int Len, void *Data);
+void Widget_RenderWidget(tWindow *Window, tElement *Element);
+ int Renderer_Widget_HandleMessage(tWindow *Target, int Msg, int Len, void *Data);
+void Widget_UpdateDimensions(tElement *Element);
+void Widget_UpdatePosition(tElement *Element);
+tElement *Widget_GetElementById(tWidgetWin *Info, uint32_t ID);
+void Widget_NewWidget(tWidgetWin *Info, size_t Len, tWidgetMsg_Create *Msg);
// === GLOBALS ===
tWMRenderer gRenderer_Widget = {
{
tWindow *ret;
tWidgetWin *info;
- ret = WM_CreateWindowStruct( sizeof(tWidgetWin) );
+ int eletable_size = DEFAULT_ELETABLE_SIZE;
+
+ // TODO: Use `Flags` as default element count?
+
+ ret = WM_CreateWindowStruct( sizeof(tWidgetWin) + sizeof(tElement*)*eletable_size );
info = ret->RendererInfo;
+ info->TableSize = eletable_size;
info->RootElement.BackgroundColour = 0xCCCCCC;
return ret;
void Renderer_Widget_Redraw(tWindow *Window)
{
tWidgetWin *info = Window->RendererInfo;
- WM_Render_FilledRect(Window, info->RootElement.BackgroundColour, 0, 0, 0xFFF, 0xFFF);
+ WM_Render_FillRect(Window, 0, 0, 0xFFF, 0xFFF, info->RootElement.BackgroundColour);
+
+ Widget_UpdateDimensions(&info->RootElement);
+ Widget_UpdatePosition(&info->RootElement);
+
+ Widget_RenderWidget(Window, &info->RootElement);
}
// --- Render / Resize ---
+void Widget_RenderWidget(tWindow *Window, tElement *Element)
+{
+ tElement *child;
+
+ if( Element->Flags & ELEFLAG_NORENDER ) return ;
+ if( Element->Flags & ELEFLAG_INVISIBLE ) return ;
+
+ Widget_Decorator_RenderWidget(Window, Element);
+
+ for(child = Element->FirstChild; child; child = child->NextSibling)
+ {
+ Widget_RenderWidget(Window, child);
+ }
+}
+
void Widget_UpdateDimensions(tElement *Element)
{
tElement *child;
tElement *Widget_GetElementById(tWidgetWin *Info, uint32_t ID)
{
tElement *ele;
+
+ if(ID == -1)
+ return &Info->RootElement;
if( ID < Info->TableSize ) return Info->ElementTable[ID];
void Widget_NewWidget(tWidgetWin *Info, size_t Len, tWidgetMsg_Create *Msg)
{
const int max_debugname_len = Len - sizeof(tWidgetMsg_Create);
- tElement *parent;
+ tElement *parent, *new;
// Sanity check
if( Len < sizeof(tWidgetMsg_Create) )
// Create
parent = Widget_GetElementById(Info, Msg->Parent);
+ if(!parent)
+ {
+ _SysDebug("Widget_NewWidget - Bad parent ID %i", Msg->Parent);
+ return ;
+ }
+
+ // Check if the ID is already in use
+ if( Widget_GetElementById(Info, Msg->NewID) )
+ return ;
+
+ // Create new element
+ new = calloc(sizeof(tElement), 1);
+ new->ID = Msg->NewID;
+ new->Type = Msg->Type;
+ new->Parent = parent;
+ new->Flags = Msg->Flags;
+ new->PaddingT = 2;
+ new->PaddingB = 2;
+ new->PaddingL = 2;
+ new->PaddingR = 2;
+
+ // Add to parent's list
+ if(parent->LastChild)
+ parent->LastChild->NextSibling = new;
+ else
+ parent->FirstChild = new;
+ new->NextSibling = parent->LastChild;
+ parent->LastChild = new;
+
+ // Add to info
+ {
+ tElement *ele, *prev = NULL;
+ for(ele = Info->ElementTable[new->ID % Info->TableSize]; ele; prev = ele, ele = ele->ListNext);
+ if(prev)
+ prev->ListNext = new;
+ else
+ Info->ElementTable[new->ID % Info->TableSize] = new;
+ }
+}
+
+void Widget_SetSize(tWidgetWin *Info, int Len, tWidgetMsg_SetSize *Msg)
+{
+ tElement *ele;
+
+ if( Len < sizeof(tWidgetMsg_SetSize) )
+ return ;
+
+ ele = Widget_GetElementById(Info, Msg->WidgetID);
+ if(!ele) return ;
+
+ ele->FixedWith = Msg->Value;
+}
+
+void Widget_SetText(tWidgetWin *Info, int Len, tWidgetMsg_SetText *Msg)
+{
}
tWidgetWin *info = Target->RendererInfo;
switch(Msg)
{
+ case WNDMSG_RESIZE: {
+ struct sWndMsg_Resize *msg = Data;
+ if(Len < sizeof(*msg)) return -1;
+
+ info->RootElement.CachedW = msg->W;
+ info->RootElement.CachedH = msg->H;
+ return 0; }
+
// New Widget
case MSG_WIDGET_CREATE:
Widget_NewWidget(info, Len, Data);
return 0;
+
+ // Set length
+ case MSG_WIDGET_SETSIZE:
+ Widget_SetSize(info, Len, Data);
+ return 0;
+ // Set text
+ case MSG_WIDGET_SETTEXT:
+ Widget_SetText(info, Len, Data);
+ return 0;
+
//
default:
return 1; // Unhandled, pass to user