#include <axwin3/widget.h>
#include <axwin3/menu.h>
-#define SIDEBAR_WIDTH 36
+#define SIDEBAR_WIDTH 40
#define RUN_WIDTH 200
#define RUN_HEIGHT 70
OBJ := main.o input.o video.o ipc.o image.o
OBJ += wm.o wm_input.o wm_render.o wm_render_text.o
OBJ += decorator.o
-OBJ += renderer_passthru.o
-OBJ += renderer_background.o
-OBJ += renderer_widget.o renderer_widget_decorator.o
-OBJ += renderer_menu.o
+OBJ += renderers/passthru.o
+OBJ += renderers/background.o
+OBJ += renderers/menu.o
+# TODO: Move to a lower makefile
+OBJ += renderers/widget.o renderers/widget/widget_decorator.o
+OBJ += renderers/widget/button.o
+OBJ += renderers/widget/image.o
+OBJ += renderers/widget/disptext.o
+OBJ += renderers/widget/textinput.o
LDFLAGS += -limage_sif -luri -lnet
#include <common.h>
#include <wm.h>
#include <decorator.h>
+#include <wm_messages.h>
// === PROTOTYPES ===
void Decorator_UpdateBorderSize(tWindow *Window);
void Decorator_Redraw(tWindow *Window);
- int Decorator_HandleMessage(tWindow *Window, int Message, int Length, void *Data);
+ int Decorator_HandleMessage(tWindow *Window, int Message, int Length, const void *Data);
// === CONSTANTS ===
tColour cColourActive_Titlebar = 0xFF8800;
tColour cColourActive_TitleText = 0x000000;
tColour cColourInactive_Titlebar = 0xD0D0D0;
tColour cColourInactive_TitleText= 0x000000;
+tColour cColour_TitleTopBorder = 0xFFFFFF;
tColour cColour_SideBorder = 0xD0D0D0;
tColour cColour_BottomBorder = 0xD0D0D0;
int ciTitlebarHeight = 18;
0, -ciTitlebarHeight, Window->W, ciTitlebarHeight,
(bActive ? cColourActive_Titlebar : cColourInactive_Titlebar)
);
+ WM_Render_FillRect(Window,
+ 0, -ciTitlebarHeight, Window->W, 1,
+ cColour_TitleTopBorder
+ );
+ WM_Render_FillRect(Window,
+ 0, -ciTitlebarHeight, 1, ciTitlebarHeight,
+ cColour_SideBorder
+ );
+ WM_Render_FillRect(Window,
+ Window->W, -ciTitlebarHeight, 1, ciTitlebarHeight,
+ cColour_SideBorder
+ );
WM_Render_GetTextDims(
NULL, // TODO: Select font
);
}
-int Decorator_HandleMessage(tWindow *Window, int Message, int Length, void *Data)
+int Decorator_HandleMessage(tWindow *Window, int Message, int Length, const void *Data)
{
switch(Message)
{
+ case WNDMSG_MOUSEMOVE: {
+ const struct sWndMsg_MouseMove *msg = Data;
+ if(msg->Y >= 0) return 1; // Pass
+
+ // TODO: Handle
+ return 0; }
+ case WNDMSG_MOUSEBTN: {
+ const struct sWndMsg_MouseButton *msg = Data;
+ if(msg->Y >= 0) return 1; // Pass
+
+ // TODO: Handle
+ return 0; }
default: // Anything unhandled is passed on
return 1;
}
extern void Decorator_UpdateBorderSize(tWindow *Window);
extern void Decorator_Redraw(tWindow *Window);
-extern int Decorator_HandleMessage(tWindow *Window, int Message, int Length, void *Data);
+extern int Decorator_HandleMessage(tWindow *Window, int Message, int Length, const void *Data);
#endif
extern void WM_DecorateWindow(tWindow *Window, int bDecorate);
extern int WM_ResizeWindow(tWindow *Window, int W, int H);
extern int WM_MoveWindow(tWindow *Window, int X, int Y);
-extern int WM_SendMessage(tWindow *Source, tWindow *Dest, int MessageID, int Length, void *Data);
+extern int WM_SendMessage(tWindow *Source, tWindow *Dest, int MessageID, int Length, const void *Data);
// --- Rendering
extern void WM_Render_FillRect(tWindow *Window, int X, int Y, int W, int H, tColour Colour);
extern void WM_Render_DrawRect(tWindow *Window, int X, int Y, int W, int H, tColour Colour);
struct sWndMsg_MouseButton
{
- uint16_t X, Y;
+ int16_t X, Y;
uint8_t Button;
uint8_t bPressed;
};
* \param Data Implementation defined data buffer
* \return Boolean failure (0: Handled, 1: Unhandled)
*/
- int (*HandleMessage)(tWindow *Window, int MessageID, int Length, void *Data);
+ int (*HandleMessage)(tWindow *Window, int MessageID, int Length, const void *Data);
};
extern void WM_RegisterRenderer(tWMRenderer *Renderer);
+++ /dev/null
-/*
- * Acess2 Window Manager v3
- * - By John Hodge (thePowersGang)
- *
- * render_widget.c
- * - AxWin2 Background port
- */
-#include <common.h>
-#include <wm_renderer.h>
-
-// === TYPES ===
-
-// === STRUCTURES ===
-struct sBgWin
-{
- uint32_t Colour;
-};
-
-// === PROTOTYPES ===
-tWindow *Renderer_Background_Create(int Flags);
-void Renderer_Background_Redraw(tWindow *Window);
-int Renderer_Background_HandleMessage(tWindow *Target, int Msg, int Len, void *Data);
-
-// === GLOBALS ===
-tWMRenderer gRenderer_Background = {
- .Name = "Background",
- .CreateWindow = Renderer_Background_Create,
- .Redraw = Renderer_Background_Redraw,
- .HandleMessage = Renderer_Background_HandleMessage
-};
-
-// === CODE ===
-int Renderer_Background_Init(void)
-{
- WM_RegisterRenderer(&gRenderer_Background);
-
- return 0;
-}
-
-tWindow *Renderer_Background_Create(int Arg)
-{
- tWindow *ret;
- ret = WM_CreateWindowStruct( sizeof(struct sBgWin) );
-
- ((struct sBgWin*)ret->RendererInfo)->Colour = Arg;
-
- return ret;
-}
-
-void Renderer_Background_Redraw(tWindow *Window)
-{
- struct sBgWin *info = Window->RendererInfo;
-
- WM_Render_FillRect(Window, 0, 0, 0xFFFF, 0xFFFF, info->Colour);
-}
-
-int Renderer_Background_HandleMessage(tWindow *Target, int Msg, int Len, void *Data)
-{
- switch(Msg)
- {
- // TODO: Handle resize
-
- default:
- break;
- }
- return 0;
-}
-
-
-
-
+++ /dev/null
-/*
- * Acess2 Window Manager v3
- * - By John Hodge (thePowersGang)
- *
- * render_classes.c
- * - Simple class based window renderer
- */
-#include <common.h>
-#include <wm_renderer.h>
-#include <renderer_classful.h>
-
-// === TYPES ===
-typedef struct sClassfulInfo
-{
- tColour BGColour;
-} tClassfulInfo;
-
-// === PROTOTYPES ===
-tWindow *Renderer_Class_Create(int Flags);
-void Renderer_Class_Redraw(tWindow *Window);
-int Renderer_Class_HandleMessage(tWindow *Target, int Msg, int Len, void *Data);
-
-// === GLOBALS ===
-tWMRenderer gRenderer_Class = {
- .Name = "Classful",
- .CreateWindow = Renderer_Class_Create,
- .Redraw = Renderer_Class_Redraw,
- .HandleMessage = Renderer_Class_HandleMessage
-};
-
-// === CODE ===
-int Renderer_Class_Init(void)
-{
- WM_RegisterRenderer(&gRenderer_Class);
-
- return 0;
-}
-
-tWindow *Renderer_Class_Create(int Flags)
-{
- return WM_CreateWindowStruct(sizeof(tClassfulInfo));
-}
-
-void Renderer_Class_Redraw(tWindow *Window)
-{
- tClassfulInfo *info = Window->RendererInfo;
- WM_Render_FillRect(Window, 0, 0, Window->W, Window->H, info->BGColour);
-}
-
-int Renderer_Class_HandleMessage(tWindow *Target, int Msg, int Len, void *Data)
-{
- tClassfulInfo *info = Target->RendererInfo;
- switch(Msg)
- {
- case MSG_CLASSFUL_SETBGCOLOUR:
- if( Len != sizeof(uint32_t) ) return -1;
- info->BGColour = *(uint32_t*)Data;
- return 0;
-
- case MSG_CLASSFUL_SETTEXT:
-
- return -1;
-
- // Anything else is unhandled
- default:
- return 1;
- }
-}
-
+++ /dev/null
-/*
- * Acess2 Window Manager v3
- * - By John Hodge (thePowersGang)
- *
- * render_menu.c
- * - Pop-up menu window class/renderer
- */
-#include <common.h>
-#include <wm_renderer.h>
-#include <menu_messages.h>
-#include <wm_messages.h>
-#include <stdlib.h>
-#include <string.h>
-
-// === STRUCTURES ===
-typedef struct sMenuItem
-{
- // Settings
- char *Label;
- char *Shortcut;
- int KeyOffset;
- int Flags;
-
- // Cached values
- int LabelWidth;
- int ShortcutWidth;
- int UnderlineX;
- int UnderlineW;
-
- char Data[];
-} tMenuItem;
-
-typedef struct sMenuWindowInfo
-{
- int MaxLabelWidth;
- int MaxShortcutWidth;
- int CachedW;
-
- int HilightedItem;
-
- int MaxItems;
- int nItems;
- tMenuItem *Items[];
-} tMenuWindowInfo;
-
-// === PROTOTYPES ===
-void Renderer_Menu_Init(void);
-tWindow *Renderer_Menu_Create(int Argument);
-void Renderer_Menu_Redraw(tWindow *Window);
- int Renderer_Menu_HandleMessage(tWindow *Window, int Msg, int Length, void *Data);
-
-// === CONSTANTS ===
-const int ciMenu_Gap = 10; // Gap between label and shortcut
-const int ciMenu_TopPadding = 2;
-const int ciMenu_BottomPadding = 2;
-const int ciMenu_LeftPadding = 2;
-const int ciMenu_RightPadding = 2;
-const int ciMenu_FontHeight = 16;
-const int ciMenu_ItemHeight = 20;
-const int ciMenu_SpacerHeight = 5;
-const tColour cMenu_BackgroundColour = 0xCCCCCC;
-const tColour cMenu_BorderColour = 0x000000;
-const tColour cMenu_SpacerColour = 0x404040;
-const tColour cMenu_LabelColour = 0x000000;
-const tColour cMenu_ShortcutColour = 0x404040;
-const tColour cMenu_HilightColour = 0xE0E0E0;
-
-// === GLOBALS ===
-tWMRenderer gRenderer_Menu = {
- .Name = "Menu",
- .CreateWindow = Renderer_Menu_Create,
- .Redraw = Renderer_Menu_Redraw,
- .HandleMessage = Renderer_Menu_HandleMessage
-};
-tFont *gMenu_Font = NULL; // System monospace
-
-// === CODE ===
-void Renderer_Menu_Init(void)
-{
- WM_RegisterRenderer(&gRenderer_Menu);
-}
-
-tWindow *Renderer_Menu_Create(int Argument)
-{
- tWindow *ret;
- tMenuWindowInfo *info;
-
- if(Argument < 5) Argument = 5;
- if(Argument > 200) Argument = 200;
-
- ret = WM_CreateWindowStruct(sizeof(*info) + Argument*sizeof(info->Items[0]));
- info = ret->RendererInfo;
- info->MaxItems = Argument;
- info->HilightedItem = -1;
-
- ret->Flags |= WINFLAG_NODECORATE;
- ret->H = ciMenu_TopPadding + ciMenu_BottomPadding;
-
-// _SysDebug("Renderer_Menu_Create: ->MaxItems = %i", info->MaxItems);
-
- return ret;
-}
-
-void Renderer_Menu_Redraw(tWindow *Window)
-{
- tMenuWindowInfo *info = Window->RendererInfo;
- int w, h, y, i;
-
- w = info->CachedW;
- #if 0
- h = ciMenu_TopPadding + ciMenu_BottomPadding;
- for( i = 0; i < info->nItems; i ++ )
- {
- if( !info->Items[i] ) continue;
-
- if(info->Items[i]->Label)
- h += ciMenu_ItemHeight;
- else
- h += ciMenu_SpacerHeight;
- }
- #else
- h = Window->H;
- #endif
-
-// _SysDebug("w = %i, h = %i", w, h);
-
- // - Move the window such that it is on screen
- // > Make sure to catch if the menu can't fit fully onscreen
-
- // - Clear
- WM_Render_FillRect(Window, 0, 0, w, h, cMenu_BackgroundColour);
- WM_Render_DrawRect(Window, 0, 0, w, h, cMenu_BorderColour);
-
- // - Render each item
- y = ciMenu_TopPadding;
- for( i = 0; i < info->nItems; i ++ )
- {
- tMenuItem *item = info->Items[i];
-
- // Unused slot
- if(!item) continue;
-
- // Spacer
- if(!item->Label)
- {
- WM_Render_FillRect(Window,
- 1, y + ciMenu_SpacerHeight/2,
- w-2, 1,
- cMenu_SpacerColour
- );
- y += ciMenu_SpacerHeight;
- continue ;
- }
-
- // Hilight
- if( info->HilightedItem == i )
- {
- WM_Render_FillRect(Window,
- 1, y,
- w-2, ciMenu_ItemHeight,
- cMenu_HilightColour
- );
- }
-
- // Text
- WM_Render_DrawText(Window,
- ciMenu_LeftPadding, y,
- w, ciMenu_ItemHeight,
- gMenu_Font,
- cMenu_LabelColour,
- item->Label
- );
- // Underline
- if(item->UnderlineW)
- {
- WM_Render_FillRect(Window,
- ciMenu_LeftPadding + item->UnderlineX, y + ciMenu_FontHeight,
- item->UnderlineW, 1,
- cMenu_LabelColour
- );
- }
-
- // Shortcut key
- if(item->Shortcut)
- {
- WM_Render_DrawText(Window,
- w - item->ShortcutWidth - ciMenu_RightPadding, y,
- w, ciMenu_ItemHeight,
- gMenu_Font,
- cMenu_ShortcutColour,
- item->Shortcut
- );
- }
-
- y += ciMenu_ItemHeight;
- }
-}
-
-int Renderer_Menu_int_AddItem(tWindow *Window, int Length, void *Data)
-{
- tMenuWindowInfo *info = Window->RendererInfo;
- tMenuMsg_AddItem *req = Data;
- tMenuItem *item;
-
- // Sanity checking
- // - Message length
- if(Length < sizeof(*req) + 1 || req->Label[Length-sizeof(*req)-1] != '\0') {
- _SysDebug("Renderer_Menu_int_AddItem: Size checks failed");
- return -1;
- }
- // - ID Number
- if(req->ID >= info->MaxItems) {
- _SysDebug("Renderer_Menu_int_AddItem: ID (%i) >= MaxItems (%i)",
- req->ID, info->MaxItems);
- return -1;
- }
-
- // Don't overwrite
- if(info->Items[req->ID]) {
- _SysDebug("- Caught overwrite of %i", req->ID);
- return 0;
- }
- // Bookkeeping
- if(req->ID >= info->nItems) info->nItems = req->ID + 1;
- // Allocate
- item = malloc(sizeof(tMenuItem)+strlen(req->Label));
- info->Items[req->ID] = item;
-
- if(req->Label[0] == '\0')
- {
- // Spacer
- item->Label = NULL;
- WM_ResizeWindow(Window, info->CachedW, Window->H+ciMenu_SpacerHeight);
-
- return 0;
- }
-
- // Actual item
- char *dest = item->Data;
- char *src = req->Label;
- int ofs = 0;
-
- // - Main label
- item->KeyOffset = -1;
- item->Label = dest;
- for(ofs = 0; *src && *src != '\t'; ofs ++)
- {
- if(*src == '&') {
- *dest = '\0';
- item->KeyOffset = ofs;
- src ++;
- }
- else {
- *dest++ = *src++;
- }
- }
- *dest++ = '\0';
- // - Key combo / Shortcut
- if(*src)
- {
- src ++;
- item->Shortcut = dest;
- strcpy(item->Shortcut, src);
- }
- else
- {
- item->Shortcut = NULL;
- }
-
- // Get dimensions
- // - Underline (hotkey)
- if(item->KeyOffset == -1)
- {
- item->UnderlineX = 0;
- item->UnderlineW = 0;
- }
- else
- {
- char tmp = item->Label[item->KeyOffset];
- // Get width of preceding substring
- item->Label[item->KeyOffset] = '\0';
- WM_Render_GetTextDims(NULL, item->Label, &item->UnderlineX, NULL);
- // Get the width of the underlined character
- // TODO: Fix for high UTF-8 characters
- item->Label[item->KeyOffset] = tmp;
- tmp = item->Label[item->KeyOffset+1];
- item->Label[item->KeyOffset+1] = '\0';
- WM_Render_GetTextDims(
- NULL, item->Label+item->KeyOffset,
- &item->UnderlineW, NULL
- );
- item->Label[item->KeyOffset+1] = tmp;
- }
- // - Labels
- WM_Render_GetTextDims(NULL, item->Label, &item->LabelWidth, NULL);
- if(item->Shortcut)
- WM_Render_GetTextDims(NULL, item->Shortcut, &item->ShortcutWidth, NULL);
- else
- item->ShortcutWidth = 0;
-
- if( item->LabelWidth > info->MaxLabelWidth )
- info->MaxLabelWidth = item->LabelWidth;
- if( item->ShortcutWidth > info->MaxShortcutWidth )
- info->MaxShortcutWidth = item->ShortcutWidth;
-
- if( info->MaxLabelWidth + info->MaxShortcutWidth + ciMenu_Gap > info->CachedW )
- {
- info->CachedW = ciMenu_LeftPadding + info->MaxLabelWidth
- + ciMenu_Gap + info->MaxShortcutWidth
- + ciMenu_RightPadding;
- }
- WM_ResizeWindow(Window, info->CachedW, Window->H+ciMenu_ItemHeight);
-
- return 0;
-}
-
-int Renderer_Menu_int_GetItemByPos(tWindow *Window, tMenuWindowInfo *Info, int X, int Y)
-{
- int i;
-
- if( X < 0 || X >= Window->W )
- return -1;
-
- for( i = 0; i < Info->nItems; i ++ )
- {
- if( !Info->Items[i] ) continue;
-
- if( !Info->Items[i]->Label )
- {
- // Spacer - not selectable
- if(Y < ciMenu_SpacerHeight) {
- return -1;
- }
- Y -= ciMenu_SpacerHeight;
- }
- else
- {
- // Normal item, can be selected/hilighted
- if(Y < ciMenu_ItemHeight) {
- return i;
- }
- Y -= ciMenu_ItemHeight;
- }
- }
- return -1;
-}
-
-int Renderer_Menu_HandleMessage(tWindow *Window, int Msg, int Length, void *Data)
-{
- tMenuWindowInfo *info = Window->RendererInfo;
- switch(Msg)
- {
- case WNDMSG_SHOW: {
- struct sWndMsg_Bool *msg = Data;
- if(Length < sizeof(*msg)) return -1;
- if(msg->Val)
- {
-// _SysDebug(" - Shown, take focus");
- // TODO: This shouldn't really be done, instead focus should be given
- // when the menu is shown.
-// WM_FocusWindow(Window);
- }
- else
- {
- // Hide Children
- _SysDebug("- Hidden, hide the children!");
- }
- return 0; }
- case WNDMSG_FOCUS: {
- struct sWndMsg_Bool *msg = Data;
- if(Length < sizeof(*msg)) return -1;
- if(!msg->Val) {
- // TODO: Catch if focus was given away to a child
- _SysDebug("- Lost focus");
- WM_ShowWindow(Window, 0); // Hide!
- }
- else {
- _SysDebug("- Focus gained, TODO: Show accel keys");
- }
- return 0; }
-
- case WNDMSG_MOUSEBTN: {
- struct sWndMsg_MouseButton *msg = Data;
- int item;
-
- if(Length < sizeof(*msg)) return -1;
-
- if(msg->Button == 0 && msg->bPressed == 0)
- {
- item = Renderer_Menu_int_GetItemByPos(Window, info, msg->X, msg->Y);
- if(item != -1)
- {
- tMenuMsg_Select _msg;
- // TODO: Ignore sub-menus too
- _msg.ID = item;
- WM_SendMessage(Window, Window, MSG_MENU_SELECT, sizeof(_msg), &_msg);
- WM_ShowWindow(Window, 0);
- }
- }
-
-
- return 0; }
-
- case WNDMSG_MOUSEMOVE: {
- struct sWndMsg_MouseMove *msg = Data;
- int new_hilight;
-
- if(Length < sizeof(*msg)) return -1;
-
- new_hilight = Renderer_Menu_int_GetItemByPos(Window, info, msg->X, msg->Y);
-
- if( new_hilight != info->HilightedItem )
- {
- info->HilightedItem = new_hilight;
- // TODO: Change sub-menu
- WM_Invalidate(Window);
- }
-
- return 0; }
-
- // Manipulation messages
- case MSG_MENU_ADDITEM:
-// _SysDebug("MSG_MENU_ADDITEM");
- return Renderer_Menu_int_AddItem(Window, Length, Data);
-
- // Only message to pass to client
- case MSG_MENU_SELECT:
- return 1;
- }
- return 0;
-}
-
+++ /dev/null
-/*
- * Acess2 Window Manager v3
- * - By John Hodge (thePowersGang)
- *
- * renderer_passthru.c
- * - Passthrough window render (framebuffer essentially)
- */
-#include <common.h>
-#include <wm_renderer.h>
-
-// === PROTOTYPES ===
-tWindow *Renderer_Passthru_Create(int Flags);
-void Renderer_Passthru_Redraw(tWindow *Window);
- int Renderer_Passthru_HandleMessage(tWindow *Target, int Msg, int Len, void *Data);
-
-// === GLOBALS ===
-tWMRenderer gRenderer_Passthru = {
- .Name = "Passthru",
- .CreateWindow = Renderer_Passthru_Create,
- .Redraw = Renderer_Passthru_Redraw,
- .HandleMessage = Renderer_Passthru_HandleMessage
-};
-
-// === CODE ===
-int Renderer_Passthru_Init(void)
-{
- return 0;
-}
-
-tWindow *Renderer_Passthru_Create(int Flags)
-{
- return NULL;
-}
-
-void Renderer_Passthru_Redraw(tWindow *Window)
-{
-
-}
-
-int Renderer_Passthru_HandleMessage(tWindow *Target, int Msg, int Len, void *Data)
-{
- return 1;
-}
-
-
+++ /dev/null
-/*
- * Acess2 Window Manager v3
- * - By John Hodge (thePowersGang)
- *
- * render_widget.c
- * - AxWin2 Widget port
- */
-#include <common.h>
-#include <wm_renderer.h>
-#include <renderer_widget.h>
-#include <string.h>
-#include <wm_messages.h>
-#include <stdlib.h>
-#include "include/image.h"
-
-#define DEFAULT_ELETABLE_SIZE 64
-
-// === PROTOTYPES ===
- int Renderer_Widget_Init(void);
-tWindow *Renderer_Widget_Create(int Flags);
-void Renderer_Widget_Redraw(tWindow *Window);
-
-void Widget_RenderWidget(tWindow *Window, tElement *Element);
-void Widget_UpdateDimensions(tElement *Element);
-void Widget_UpdatePosition(tElement *Element);
-// --- Messages
-tElement *Widget_GetElementById(tWidgetWin *Info, uint32_t ID);
-void Widget_NewWidget(tWidgetWin *Info, size_t Len, tWidgetMsg_Create *Msg);
-void Widget_SetFlags(tWidgetWin *Info, int Len, tWidgetMsg_SetFlags *Msg);
-void Widget_SetSize(tWidgetWin *Info, int Len, tWidgetMsg_SetSize *Msg);
-void Widget_SetText(tWidgetWin *Info, int Len, tWidgetMsg_SetText *Msg);
- int Renderer_Widget_HandleMessage(tWindow *Target, int Msg, int Len, void *Data);
-// --- Type helpers
-void Widget_DispText_UpdateText(tElement *Element, const char *Text);
-void Widget_Image_UpdateText(tElement *Element, const char *Text);
- int Widget_Button_MouseButton(tElement *Element, int X, int Y, int Button, int bPress);
-void Widget_TextInput_Init(tElement *Element);
-
-// === GLOBALS ===
-tWMRenderer gRenderer_Widget = {
- .Name = "Widget",
- .CreateWindow = Renderer_Widget_Create,
- .Redraw = Renderer_Widget_Redraw,
- .HandleMessage = Renderer_Widget_HandleMessage
-};
-
-// --- Element callbacks
-struct {
- void (*Init)(tElement *Ele);
- void (*Delete)(tElement *Ele);
-
- void (*UpdateFlags)(tElement *Ele);
- void (*UpdateSize)(tElement *Ele);
- void (*UpdateText)(tElement *Ele, const char *Text); // This should update Ele->Text
-
- /**
- * \name Input handlers
- * \note Returns boolean unhandled
- * \{
- */
- int (*MouseButton)(tElement *Ele, int X, int Y, int Button, int bPressed);
- int (*MouseMove)(tElement *Ele, int X, int Y);
- int (*KeyDown)(tElement *Ele, int KeySym, int Character);
- int (*KeyUp)(tElement *Ele, int KeySym);
- int (*KeyFire)(tElement *Ele, int KeySym, int Character);
- /**
- * \}
- */
-} gaWM_WidgetTypes[NUM_ELETYPES] = {
- {0}, // NULL
- {0}, // Box
- {.UpdateText = Widget_DispText_UpdateText}, // Text
- {.UpdateText = Widget_Image_UpdateText}, // Image
- {.MouseButton = Widget_Button_MouseButton}, // Button
- {0}, // Spacer
- {.Init = Widget_TextInput_Init}, // Text Box (Single Line)
-};
-const int ciWM_NumWidgetTypes = sizeof(gaWM_WidgetTypes)/sizeof(gaWM_WidgetTypes[0]);
-
-// === CODE ===
-int Renderer_Widget_Init(void)
-{
- WM_RegisterRenderer(&gRenderer_Widget);
-
- return 0;
-}
-
-tWindow *Renderer_Widget_Create(int Flags)
-{
- tWindow *ret;
- tWidgetWin *info;
- int eletable_size = DEFAULT_ELETABLE_SIZE;
-
- _SysDebug("Renderer_Widget_Create: (Flags = 0x%x)", Flags);
-
- // TODO: Use `Flags` as default element count?
- // - Actaully, it's taken by the root ele flags
- // - Use the upper bits?
-
- ret = WM_CreateWindowStruct( sizeof(tWidgetWin) + sizeof(tElement*)*eletable_size );
- info = ret->RendererInfo;
-
- info->TableSize = eletable_size;
- info->RootElement.Window = ret;
- info->RootElement.ID = -1;
- info->RootElement.BackgroundColour = 0xCCCCCC;
- info->RootElement.Flags = Flags;
-
- return ret;
-}
-
-void Renderer_Widget_Redraw(tWindow *Window)
-{
- tWidgetWin *info = Window->RendererInfo;
- 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;
- int nChildren = 0;
- int nFixed = 0;
- int maxCross = 0;
- int fixedSize = 0;
- int fullCross, dynWith;
-
- // Pass 1
- // - Get the fixed and minimum sizes of the element
- for( child = Element->FirstChild; child; child = child->NextSibling )
- {
- // Ignore elements that will not be rendered
- if( child->Flags & ELEFLAG_NORENDER ) continue ;
-
- // Absolutely positioned elements don't affect dimensions
- if( child->Flags & ELEFLAG_ABSOLUTEPOS ) continue ;
-
- // Fixed width elements
- if( child->FixedWith )
- {
- nFixed ++;
- fixedSize += child->FixedWith;
- }
- else if( child->Flags & ELEFLAG_NOSTRETCH )
- {
- nFixed ++;
- fixedSize += child->MinWith;
- }
-
- if( child->FixedCross && maxCross < child->FixedCross )
- maxCross = child->FixedCross;
- if( child->MinCross && maxCross < child->MinCross )
- maxCross = child->MinCross;
- nChildren ++;
- }
-
- // Get the dynamic with size from the unused space in the element
- if( nChildren > nFixed ) {
- if( Element->Flags & ELEFLAG_VERTICAL )
- dynWith = Element->CachedH - Element->PaddingT - Element->PaddingB;
- else
- dynWith = Element->CachedW - Element->PaddingL - Element->PaddingR;
- dynWith -= fixedSize;
- if( dynWith < 0 ) return ;
- dynWith /= nChildren - nFixed;
- }
-
-// _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 )
- fullCross = Element->CachedW - Element->PaddingL - Element->PaddingR;
- else
- fullCross = Element->CachedH - Element->PaddingT - Element->PaddingB;
-
- // Pass 2 - Set sizes and recurse
- for( child = Element->FirstChild; child; child = child->NextSibling )
- {
- int cross, with;
-
- // Ignore elements that will not be rendered
- if( child->Flags & ELEFLAG_NORENDER ) 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;
- else
- with = dynWith;
-
-
- if(with < child->MinWith) with = child->MinWith;
- if(cross < child->MinCross) cross = child->MinCross;
-
- // 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;
- }
-
- // Force the positions of child elements to be recalculated
- child->CachedX = -1;
-
- // Recurse down so the child elements can be updated
- Widget_UpdateDimensions(child);
- }
-
-}
-
-/**
- * \brief Update the position of child elements
- */
-void Widget_UpdatePosition(tElement *Element)
-{
- tElement *child;
- int x, y;
-
- if( Element->Flags & ELEFLAG_NORENDER ) return ;
-
-// _SysDebug("Widget_UpdatePosition: (Element=%p(%i Type=%i Flags=0x%x))",
-// Element, Element->ID, Element->Type, Element->Flags);
-
- // Initialise
- x = Element->CachedX + Element->PaddingL;
- y = Element->CachedY + Element->PaddingT;
-
- // Update each child
- for(child = Element->FirstChild; child; child = child->NextSibling)
- {
- int newX, newY;
- // Ignore elements that will not be rendered
- if( child->Flags & ELEFLAG_NORENDER ) continue ;
-
- newX = x; newY = y;
-
- // Handle alignment
- if( Element->Flags & ELEFLAG_ALIGN_CENTER ) {
- if(Element->Flags & ELEFLAG_VERTICAL)
- newX += Element->CachedW/2 - child->CachedW/2;
- else
- newY += Element->CachedH/2 - child->CachedH/2;
- }
- else if( Element->Flags & ELEFLAG_ALIGN_END ) {
- if(Element->Flags & ELEFLAG_VERTICAL )
- newX += Element->CachedW - child->CachedW
- - Element->PaddingL - Element->PaddingR;
- else
- newY += Element->CachedH - child->CachedH
- - Element->PaddingT - Element->PaddingB;
- }
-
-// _SysDebug(" Widget_UpdatePosition[%i]: newX = %i, newY = %i", Element->ID, newX, newY);
-
- // Check for changes, and don't update if there was no change
- if( newX != child->CachedX || newY != child->CachedY )
- {
- child->CachedX = newX;
- child->CachedY = newY;
- // Update child's children positions
- Widget_UpdatePosition(child);
- }
-
- // Increment
- if(Element->Flags & ELEFLAG_VERTICAL ) {
- y += child->CachedH + Element->GapSize;
- }
- else {
- x += child->CachedW + Element->GapSize;
- }
- }
-}
-
-/**
- * \brief Update the minimum dimensions of the element
- * \note Called after a child's minimum dimensions have changed
- */
-void Widget_UpdateMinDims(tElement *Element)
-{
- tElement *child;
-
- if(!Element) return;
-
- Element->MinCross = 0;
- Element->MinWith = 0;
-
- for(child = Element->FirstChild; child; child = child->NextSibling)
- {
- if( Element->Parent &&
- (Element->Flags & ELEFLAG_VERTICAL) == (Element->Parent->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;
- }
- 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;
- }
- }
-
- // Recurse upwards
- Widget_UpdateMinDims(Element->Parent);
-}
-
-tElement *Widget_GetElementByPos(tWidgetWin *Info, int X, int Y)
-{
- tElement *ret, *next, *ele;
-
- next = &Info->RootElement;
- while(next)
- {
- ret = next;
- next = NULL;
- for(ele = ret->FirstChild; ele; ele = ele->NextSibling)
- {
- if(ele->Flags & ELEFLAG_NORENDER) continue;
- if(X < ele->CachedX) continue;
- if(Y < ele->CachedY) continue;
- if(X >= ele->CachedX + ele->CachedW) continue;
- if(Y >= ele->CachedY + ele->CachedH) continue;
- next = ele;
- }
- }
- return ret;
-}
-
-// --- Helpers ---
-tElement *Widget_GetElementById(tWidgetWin *Info, uint32_t ID)
-{
- tElement *ele;
-
- if( ID == -1 ) return &Info->RootElement;
-
- if( ID < Info->TableSize ) return Info->ElementTable[ID];
-
- ele = Info->ElementTable[ID % Info->TableSize];
- while(ele && ele->ID != ID) ele = ele->ListNext;
- return ele;
-}
-
-// --- Message Handlers ---
-void Widget_NewWidget(tWidgetWin *Info, size_t Len, tWidgetMsg_Create *Msg)
-{
- const int max_debugname_len = Len - sizeof(tWidgetMsg_Create);
- tElement *parent, *new;
-
- // Sanity check
- if( Len < sizeof(tWidgetMsg_Create) )
- return ;
- if( strnlen(Msg->DebugName, max_debugname_len) == max_debugname_len )
- return ;
-
- _SysDebug("Widget_NewWidget (%i %i Type %i Flags 0x%x)",
- Msg->Parent, Msg->NewID, Msg->Type, Msg->Flags);
-
- // 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->Window = parent->Window;
- 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;
- new->CachedX = -1;
-
- if( new->Type < ciWM_NumWidgetTypes && gaWM_WidgetTypes[new->Type].Init )
- gaWM_WidgetTypes[new->Type].Init(new);
-
- // Add to parent's list
- if(parent->LastChild)
- parent->LastChild->NextSibling = new;
- else
- parent->FirstChild = new;
- 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;
- }
-
- Widget_UpdateMinDims(parent);
-}
-
-void Widget_SetFlags(tWidgetWin *Info, int Len, tWidgetMsg_SetFlags *Msg)
-{
- tElement *ele;
-
- if( Len < sizeof(tWidgetMsg_SetFlags) )
- return ;
-
- _SysDebug("Widget_SetFlags: (%i 0x%x 0x%x)", Msg->WidgetID, Msg->Value, Msg->Mask);
-
- ele = Widget_GetElementById(Info, Msg->WidgetID);
- if(!ele) return;
-
- Msg->Value &= Msg->Mask;
-
- ele->Flags &= ~Msg->Mask;
- ele->Flags |= Msg->Value;
-}
-
-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)
-{
- tElement *ele;
-
- if( Len < sizeof(tWidgetMsg_SetText) + 1 )
- return ;
- if( Msg->Text[Len - sizeof(tWidgetMsg_SetText) - 1] != '\0' )
- return ;
-
- ele = Widget_GetElementById(Info, Msg->WidgetID);
- if(!ele) return ;
-
-
- if( ele->Type < ciWM_NumWidgetTypes && gaWM_WidgetTypes[ele->Type].UpdateText )
- {
- gaWM_WidgetTypes[ele->Type].UpdateText( ele, Msg->Text );
- }
-// else
-// {
-// if(ele->Text) free(ele->Text);
-// ele->Text = strdup(Msg->Text);
-// }
-}
-
-int Renderer_Widget_HandleMessage(tWindow *Target, int Msg, int Len, void *Data)
-{
- 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;
-
- // TODO: Update dimensions of all child elements?
-
- return 0; }
-
- case WNDMSG_MOUSEMOVE: {
- _SysDebug("TODO: Support widget mouse move events");
- return 0; }
-
- case WNDMSG_MOUSEBTN: {
- struct sWndMsg_MouseButton *msg = Data;
- tWidgetMsg_MouseBtn client_msg;
- tElement *ele;
- int x, y;
- int rv;
-
- if(Len < sizeof(*msg)) return -1;
-
- x = msg->X; y = msg->Y;
- client_msg.Button = msg->Button;
- client_msg.bPressed = msg->bPressed;
-
- ele = Widget_GetElementByPos(info, x, y);
- // Send event to all elements from `ele` upwards
- for( ; ele; ele = ele->Parent )
- {
- if(ele->Type < ciWM_NumWidgetTypes && gaWM_WidgetTypes[ele->Type].MouseButton)
- {
- rv = gaWM_WidgetTypes[ele->Type].MouseButton(
- ele,
- x - ele->CachedX, y - ele->CachedY,
- msg->Button, msg->bPressed
- );
- // Allow a type to trap the input from going any higher
- if(rv == 0) break;
- }
- else
- {
- // Pass to user
- client_msg.X = x - ele->CachedX;
- client_msg.Y = y - ele->CachedY;
- client_msg.WidgetID = ele->ID;
- WM_SendMessage(Target, Target, MSG_WIDGET_MOUSEBTN, sizeof(client_msg), &client_msg);
- }
- }
- return 0; }
-
- // New Widget
- case MSG_WIDGET_CREATE:
- Widget_NewWidget(info, Len, Data);
- return 0;
-
- case MSG_WIDGET_DELETE:
- _SysDebug("TODO: Implement MSG_WIDGET_DELETE");
- return 0;
-
- // Set Flags
- case MSG_WIDGET_SETFLAGS:
- Widget_SetFlags(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
- }
-}
-
-void Widget_Fire(tElement *Element)
-{
- tWidgetMsg_Fire msg;
- msg.WidgetID = Element->ID;
- WM_SendMessage(Element->Window, Element->Window, MSG_WIDGET_FIRE, sizeof(msg), &msg);
-}
-
-// --- Type Helpers
-void Widget_DispText_UpdateText(tElement *Element, const char *Text)
-{
- int w=0, h=0;
-
- if(Element->Text) free(Element->Text);
- Element->Text = strdup(Text);
-
- WM_Render_GetTextDims(NULL, Element->Text, &w, &h);
- if(Element->Parent && (Element->Parent->Flags & ELEFLAG_VERTICAL)) {
- Element->MinCross = w;
- Element->MinWith = h;
- }
- else {
- Element->MinWith = w;
- Element->MinCross = h;
- }
-
- Widget_UpdateMinDims(Element->Parent);
-}
-
-void Widget_Image_UpdateText(tElement *Element, const char *Text)
-{
- if(Element->Data) free(Element->Data);
- Element->Data = Image_Load( Text );
- if(!Element->Data) {
-// Element->Flags &= ~ELEFLAG_FIXEDSIZE;
- return ;
- }
-
- Element->CachedW = ((tImage*)Element->Data)->Width;
- Element->CachedH = ((tImage*)Element->Data)->Height;
-
- if(Element->Parent && (Element->Parent->Flags & ELEFLAG_VERTICAL) ) {
- Element->MinCross = ((tImage*)Element->Data)->Width;
- Element->MinWith = ((tImage*)Element->Data)->Height;
- }
- else {
- Element->MinWith = ((tImage*)Element->Data)->Width;
- Element->MinCross = ((tImage*)Element->Data)->Height;
- }
-
- Widget_UpdateMinDims(Element->Parent);
-
- // NOTE: Doesn't update Element->Text because it's useless
-}
-
-int Widget_Button_MouseButton(tElement *Element, int X, int Y, int Button, int bPress)
-{
- _SysDebug("Ele %i - Button %i %s",
- Element->ID, Button,
- (bPress ? "pressed" : "released")
- );
- if(!bPress) Widget_Fire(Element);
- return 0; // Handled
-}
-
-void Widget_TextInput_Init(tElement *Element)
-{
- int h;
-
- // TODO: Select font correctly
- WM_Render_GetTextDims(NULL, "jJ", NULL, &h);
-
- if( Element->Parent && (Element->Parent->Flags & ELEFLAG_VERTICAL) )
- Element->MinWith = h;
- else
- Element->MinCross = h;
-
- // No need to explicitly update parent min dims, as the AddElement routine does that
-}
-
+++ /dev/null
-/*
- * Acess2 Window Manager v3
- * - By John Hodge (thePowersGang)
- *
- * renderer_widget_decorator.c
- * - Widget Decorator
- */
-#include <common.h>
-#include <wm.h>
-#include <renderer_widget.h>
-
-#define BORDER_EVERYTHING 1
-
-#define BOX_BGCOLOUR 0xC0C0C0
-#define BOX_BORDER 0xA0A0A0
-#define BUTTON_BGCOLOUR 0xD0D0D0
-#define BUTTON_BORDER 0xF0F0F0
-#define TEXT_COLOUR 0x000000
-#define TEXTINPUT_BACKGROUND 0xFFFFFF
-#define TEXTINPUT_BORDER_OUT 0x404040
-
-// === CODE ===
-void Widget_Decorator_RenderWidget(tWindow *Window, tElement *Element)
-{
-// _SysDebug("Widget_Decorator_RenderWidget: (Element={Type:%i,(%i,%i) %ix%i})",
-// Element->Type,
-// Element->CachedX, Element->CachedY,
-// Element->CachedW, Element->CachedH
-// );
-
- #if BORDER_EVERYTHING
- WM_Render_DrawRect(
- Window,
- Element->CachedX, Element->CachedY,
- Element->CachedW, Element->CachedH,
- 0
- );
- #endif
-
- switch(Element->Type)
- {
- case ELETYPE_NONE:
- case ELETYPE_BOX: break; // Box is a meta-element
-
- case ELETYPE_TABBAR: // Tab Bar
- WM_Render_DrawRect(
- Window,
- Element->CachedX, Element->CachedY,
- Element->CachedW, Element->CachedH,
- BOX_BORDER
- );
- WM_Render_FillRect(
- Window,
- Element->CachedX+1, Element->CachedY+1,
- Element->CachedW-2, Element->CachedH-2,
- BOX_BGCOLOUR
- );
- // Enumerate Items.
- break;
- case ELETYPE_TOOLBAR: // Tool Bar
- WM_Render_DrawRect(
- Window,
- Element->CachedX, Element->CachedY,
- Element->CachedW, Element->CachedH,
- BOX_BORDER
- );
- WM_Render_FillRect(
- Window,
- Element->CachedX+1, Element->CachedY+1,
- Element->CachedW-2, Element->CachedH-2,
- BOX_BGCOLOUR
- );
- break;
-
- case ELETYPE_SPACER: // Spacer (subtle line)
- WM_Render_FillRect(
- Window,
- Element->CachedX+3, Element->CachedY+3,
- Element->CachedW-6, Element->CachedH-6,
- BOX_BORDER
- );
- break;
-
- case ELETYPE_BUTTON: // Button
- WM_Render_FillRect(
- Window,
- Element->CachedX+1, Element->CachedY+1,
- Element->CachedW-2, Element->CachedH-2,
- BUTTON_BGCOLOUR
- );
- WM_Render_DrawRect(
- Window,
- Element->CachedX, Element->CachedY,
- Element->CachedW-1, Element->CachedH-1,
- BUTTON_BORDER
- );
- break;
-
- // Text input field / Text Box
- case ELETYPE_TEXTINPUT:
- case ELETYPE_TEXTBOX:
- WM_Render_FillRect(
- Window,
- Element->CachedX, Element->CachedY,
- Element->CachedW, Element->CachedH,
- TEXTINPUT_BACKGROUND
- );
- WM_Render_DrawRect(
- Window,
- Element->CachedX, Element->CachedY,
- Element->CachedW, Element->CachedH,
- TEXTINPUT_BORDER_OUT
- );
-// WM_Render_DrawRect(
-// Window,
-// Element->CachedX+1, Element->CachedY+1,
-// Element->CachedW-2, Element->CachedH-2,
-// TEXTINPUT_BORDER_IN
-// );
- break;
-
- case ELETYPE_TEXT:
- WM_Render_DrawText(
- Window,
- Element->CachedX+1, Element->CachedY+1,
- Element->CachedW-2, Element->CachedH-2,
- NULL,
- TEXT_COLOUR,
- Element->Text
- );
- break;
-
- case ELETYPE_IMAGE:
- WM_Render_DrawImage(
- Window,
- Element->CachedX, Element->CachedY,
- Element->CachedW, Element->CachedH,
- Element->Data
- );
- break;
-
- default:
- _SysDebug(" ERROR: Unknown type %i", Element->Type);
- break;
- }
-}
--- /dev/null
+/*
+ * Acess2 Window Manager v3
+ * - By John Hodge (thePowersGang)
+ *
+ * render_widget.c
+ * - AxWin2 Background port
+ */
+#include <common.h>
+#include <wm_renderer.h>
+
+// === TYPES ===
+
+// === STRUCTURES ===
+struct sBgWin
+{
+ uint32_t Colour;
+};
+
+// === PROTOTYPES ===
+tWindow *Renderer_Background_Create(int Flags);
+void Renderer_Background_Redraw(tWindow *Window);
+int Renderer_Background_HandleMessage(tWindow *Target, int Msg, int Len, const void *Data);
+
+// === GLOBALS ===
+tWMRenderer gRenderer_Background = {
+ .Name = "Background",
+ .CreateWindow = Renderer_Background_Create,
+ .Redraw = Renderer_Background_Redraw,
+ .HandleMessage = Renderer_Background_HandleMessage
+};
+
+// === CODE ===
+int Renderer_Background_Init(void)
+{
+ WM_RegisterRenderer(&gRenderer_Background);
+
+ return 0;
+}
+
+tWindow *Renderer_Background_Create(int Arg)
+{
+ tWindow *ret;
+ ret = WM_CreateWindowStruct( sizeof(struct sBgWin) );
+
+ ((struct sBgWin*)ret->RendererInfo)->Colour = Arg;
+
+ return ret;
+}
+
+void Renderer_Background_Redraw(tWindow *Window)
+{
+ struct sBgWin *info = Window->RendererInfo;
+
+ WM_Render_FillRect(Window, 0, 0, 0xFFFF, 0xFFFF, info->Colour);
+}
+
+int Renderer_Background_HandleMessage(tWindow *Target, int Msg, int Len, const void *Data)
+{
+ switch(Msg)
+ {
+ // TODO: Handle resize
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+
+
+
--- /dev/null
+/*
+ * Acess2 Window Manager v3
+ * - By John Hodge (thePowersGang)
+ *
+ * render_classes.c
+ * - Simple class based window renderer
+ */
+#include <common.h>
+#include <wm_renderer.h>
+#include <renderer_classful.h>
+
+// === TYPES ===
+typedef struct sClassfulInfo
+{
+ tColour BGColour;
+} tClassfulInfo;
+
+// === PROTOTYPES ===
+tWindow *Renderer_Class_Create(int Flags);
+void Renderer_Class_Redraw(tWindow *Window);
+int Renderer_Class_HandleMessage(tWindow *Target, int Msg, int Len, void *Data);
+
+// === GLOBALS ===
+tWMRenderer gRenderer_Class = {
+ .Name = "Classful",
+ .CreateWindow = Renderer_Class_Create,
+ .Redraw = Renderer_Class_Redraw,
+ .HandleMessage = Renderer_Class_HandleMessage
+};
+
+// === CODE ===
+int Renderer_Class_Init(void)
+{
+ WM_RegisterRenderer(&gRenderer_Class);
+
+ return 0;
+}
+
+tWindow *Renderer_Class_Create(int Flags)
+{
+ return WM_CreateWindowStruct(sizeof(tClassfulInfo));
+}
+
+void Renderer_Class_Redraw(tWindow *Window)
+{
+ tClassfulInfo *info = Window->RendererInfo;
+ WM_Render_FillRect(Window, 0, 0, Window->W, Window->H, info->BGColour);
+}
+
+int Renderer_Class_HandleMessage(tWindow *Target, int Msg, int Len, void *Data)
+{
+ tClassfulInfo *info = Target->RendererInfo;
+ switch(Msg)
+ {
+ case MSG_CLASSFUL_SETBGCOLOUR:
+ if( Len != sizeof(uint32_t) ) return -1;
+ info->BGColour = *(uint32_t*)Data;
+ return 0;
+
+ case MSG_CLASSFUL_SETTEXT:
+
+ return -1;
+
+ // Anything else is unhandled
+ default:
+ return 1;
+ }
+}
+
--- /dev/null
+/*
+ * Acess2 Window Manager v3
+ * - By John Hodge (thePowersGang)
+ *
+ * render_menu.c
+ * - Pop-up menu window class/renderer
+ */
+#include <common.h>
+#include <wm_renderer.h>
+#include <menu_messages.h>
+#include <wm_messages.h>
+#include <stdlib.h>
+#include <string.h>
+
+// === STRUCTURES ===
+typedef struct sMenuItem
+{
+ // Settings
+ char *Label;
+ char *Shortcut;
+ int KeyOffset;
+ int Flags;
+
+ // Cached values
+ int LabelWidth;
+ int ShortcutWidth;
+ int UnderlineX;
+ int UnderlineW;
+
+ char Data[];
+} tMenuItem;
+
+typedef struct sMenuWindowInfo
+{
+ int MaxLabelWidth;
+ int MaxShortcutWidth;
+ int CachedW;
+
+ int HilightedItem;
+
+ int MaxItems;
+ int nItems;
+ tMenuItem *Items[];
+} tMenuWindowInfo;
+
+// === PROTOTYPES ===
+void Renderer_Menu_Init(void);
+tWindow *Renderer_Menu_Create(int Argument);
+void Renderer_Menu_Redraw(tWindow *Window);
+ int Renderer_Menu_HandleMessage(tWindow *Window, int Msg, int Length, const void *Data);
+
+// === CONSTANTS ===
+const int ciMenu_Gap = 10; // Gap between label and shortcut
+const int ciMenu_TopPadding = 2;
+const int ciMenu_BottomPadding = 2;
+const int ciMenu_LeftPadding = 2;
+const int ciMenu_RightPadding = 2;
+const int ciMenu_FontHeight = 16;
+const int ciMenu_ItemHeight = 20;
+const int ciMenu_SpacerHeight = 5;
+const tColour cMenu_BackgroundColour = 0xCCCCCC;
+const tColour cMenu_BorderColour = 0x000000;
+const tColour cMenu_SpacerColour = 0x404040;
+const tColour cMenu_LabelColour = 0x000000;
+const tColour cMenu_ShortcutColour = 0x404040;
+const tColour cMenu_HilightColour = 0xE0E0E0;
+
+// === GLOBALS ===
+tWMRenderer gRenderer_Menu = {
+ .Name = "Menu",
+ .CreateWindow = Renderer_Menu_Create,
+ .Redraw = Renderer_Menu_Redraw,
+ .HandleMessage = Renderer_Menu_HandleMessage
+};
+tFont *gMenu_Font = NULL; // System monospace
+
+// === CODE ===
+void Renderer_Menu_Init(void)
+{
+ WM_RegisterRenderer(&gRenderer_Menu);
+}
+
+tWindow *Renderer_Menu_Create(int Argument)
+{
+ tWindow *ret;
+ tMenuWindowInfo *info;
+
+ if(Argument < 5) Argument = 5;
+ if(Argument > 200) Argument = 200;
+
+ ret = WM_CreateWindowStruct(sizeof(*info) + Argument*sizeof(info->Items[0]));
+ info = ret->RendererInfo;
+ info->MaxItems = Argument;
+ info->HilightedItem = -1;
+
+ ret->Flags |= WINFLAG_NODECORATE;
+ ret->H = ciMenu_TopPadding + ciMenu_BottomPadding;
+
+// _SysDebug("Renderer_Menu_Create: ->MaxItems = %i", info->MaxItems);
+
+ return ret;
+}
+
+void Renderer_Menu_Redraw(tWindow *Window)
+{
+ tMenuWindowInfo *info = Window->RendererInfo;
+ int w, h, y, i;
+
+ w = info->CachedW;
+ #if 0
+ h = ciMenu_TopPadding + ciMenu_BottomPadding;
+ for( i = 0; i < info->nItems; i ++ )
+ {
+ if( !info->Items[i] ) continue;
+
+ if(info->Items[i]->Label)
+ h += ciMenu_ItemHeight;
+ else
+ h += ciMenu_SpacerHeight;
+ }
+ #else
+ h = Window->H;
+ #endif
+
+// _SysDebug("w = %i, h = %i", w, h);
+
+ // - Move the window such that it is on screen
+ // > Make sure to catch if the menu can't fit fully onscreen
+
+ // - Clear
+ WM_Render_FillRect(Window, 0, 0, w, h, cMenu_BackgroundColour);
+ WM_Render_DrawRect(Window, 0, 0, w, h, cMenu_BorderColour);
+
+ // - Render each item
+ y = ciMenu_TopPadding;
+ for( i = 0; i < info->nItems; i ++ )
+ {
+ tMenuItem *item = info->Items[i];
+
+ // Unused slot
+ if(!item) continue;
+
+ // Spacer
+ if(!item->Label)
+ {
+ WM_Render_FillRect(Window,
+ 1, y + ciMenu_SpacerHeight/2,
+ w-2, 1,
+ cMenu_SpacerColour
+ );
+ y += ciMenu_SpacerHeight;
+ continue ;
+ }
+
+ // Hilight
+ if( info->HilightedItem == i )
+ {
+ WM_Render_FillRect(Window,
+ 1, y,
+ w-2, ciMenu_ItemHeight,
+ cMenu_HilightColour
+ );
+ }
+
+ // Text
+ WM_Render_DrawText(Window,
+ ciMenu_LeftPadding, y,
+ w, ciMenu_ItemHeight,
+ gMenu_Font,
+ cMenu_LabelColour,
+ item->Label
+ );
+ // Underline
+ if(item->UnderlineW)
+ {
+ WM_Render_FillRect(Window,
+ ciMenu_LeftPadding + item->UnderlineX, y + ciMenu_FontHeight,
+ item->UnderlineW, 1,
+ cMenu_LabelColour
+ );
+ }
+
+ // Shortcut key
+ if(item->Shortcut)
+ {
+ WM_Render_DrawText(Window,
+ w - item->ShortcutWidth - ciMenu_RightPadding, y,
+ w, ciMenu_ItemHeight,
+ gMenu_Font,
+ cMenu_ShortcutColour,
+ item->Shortcut
+ );
+ }
+
+ y += ciMenu_ItemHeight;
+ }
+}
+
+int Renderer_Menu_int_AddItem(tWindow *Window, int Length, const tMenuMsg_AddItem *Msg)
+{
+ tMenuWindowInfo *info = Window->RendererInfo;
+ tMenuItem *item;
+
+ // Sanity checking
+ // - Message length
+ if(Length < sizeof(*Msg) + 1 || Msg->Label[Length-sizeof(*Msg)-1] != '\0') {
+ _SysDebug("Renderer_Menu_int_AddItem: Size checks failed");
+ return -1;
+ }
+ // - ID Number
+ if(Msg->ID >= info->MaxItems) {
+ _SysDebug("Renderer_Menu_int_AddItem: ID (%i) >= MaxItems (%i)",
+ Msg->ID, info->MaxItems);
+ return -1;
+ }
+
+ // Don't overwrite
+ if(info->Items[Msg->ID]) {
+ _SysDebug("- Caught overwrite of %i", Msg->ID);
+ return 0;
+ }
+ // Bookkeeping
+ if(Msg->ID >= info->nItems) info->nItems = Msg->ID + 1;
+ // Allocate
+ item = malloc(sizeof(tMenuItem)+strlen(Msg->Label)+1);
+ info->Items[Msg->ID] = item;
+
+ if(Msg->Label[0] == '\0')
+ {
+ // Spacer
+ item->Label = NULL;
+ WM_ResizeWindow(Window, info->CachedW, Window->H+ciMenu_SpacerHeight);
+
+ return 0;
+ }
+
+ // Actual item
+ char *dest = item->Data;
+ const char *src = Msg->Label;
+ int ofs = 0;
+
+ // - Main label
+ item->KeyOffset = -1;
+ item->Label = dest;
+ for(ofs = 0; *src && *src != '\t'; ofs ++)
+ {
+ if(*src == '&') {
+ *dest = '\0';
+ item->KeyOffset = ofs;
+ src ++;
+ }
+ else {
+ *dest++ = *src++;
+ }
+ }
+ *dest++ = '\0';
+ // - Key combo / Shortcut
+ if(*src)
+ {
+ src ++;
+ item->Shortcut = dest;
+ strcpy(item->Shortcut, src);
+ }
+ else
+ {
+ item->Shortcut = NULL;
+ }
+
+ // Get dimensions
+ // - Underline (hotkey)
+ if(item->KeyOffset == -1)
+ {
+ item->UnderlineX = 0;
+ item->UnderlineW = 0;
+ }
+ else
+ {
+ char tmp = item->Label[item->KeyOffset];
+ // Get width of preceding substring
+ item->Label[item->KeyOffset] = '\0';
+ WM_Render_GetTextDims(NULL, item->Label, &item->UnderlineX, NULL);
+ // Get the width of the underlined character
+ // TODO: Fix for high UTF-8 characters
+ item->Label[item->KeyOffset] = tmp;
+ tmp = item->Label[item->KeyOffset+1];
+ item->Label[item->KeyOffset+1] = '\0';
+ WM_Render_GetTextDims(
+ NULL, item->Label+item->KeyOffset,
+ &item->UnderlineW, NULL
+ );
+ item->Label[item->KeyOffset+1] = tmp;
+ }
+ // - Labels
+ WM_Render_GetTextDims(NULL, item->Label, &item->LabelWidth, NULL);
+ if(item->Shortcut)
+ WM_Render_GetTextDims(NULL, item->Shortcut, &item->ShortcutWidth, NULL);
+ else
+ item->ShortcutWidth = 0;
+
+ if( item->LabelWidth > info->MaxLabelWidth )
+ info->MaxLabelWidth = item->LabelWidth;
+ if( item->ShortcutWidth > info->MaxShortcutWidth )
+ info->MaxShortcutWidth = item->ShortcutWidth;
+
+ if( info->MaxLabelWidth + info->MaxShortcutWidth + ciMenu_Gap > info->CachedW )
+ {
+ info->CachedW = ciMenu_LeftPadding + info->MaxLabelWidth
+ + ciMenu_Gap + info->MaxShortcutWidth
+ + ciMenu_RightPadding;
+ }
+ WM_ResizeWindow(Window, info->CachedW, Window->H+ciMenu_ItemHeight);
+
+ return 0;
+}
+
+int Renderer_Menu_int_GetItemByPos(tWindow *Window, tMenuWindowInfo *Info, int X, int Y)
+{
+ int i;
+
+ if( X < 0 || X >= Window->W )
+ return -1;
+
+ for( i = 0; i < Info->nItems; i ++ )
+ {
+ if( !Info->Items[i] ) continue;
+
+ if( !Info->Items[i]->Label )
+ {
+ // Spacer - not selectable
+ if(Y < ciMenu_SpacerHeight) {
+ return -1;
+ }
+ Y -= ciMenu_SpacerHeight;
+ }
+ else
+ {
+ // Normal item, can be selected/hilighted
+ if(Y < ciMenu_ItemHeight) {
+ return i;
+ }
+ Y -= ciMenu_ItemHeight;
+ }
+ }
+ return -1;
+}
+
+int Renderer_Menu_HandleMessage(tWindow *Window, int Msg, int Length, const void *Data)
+{
+ tMenuWindowInfo *info = Window->RendererInfo;
+ switch(Msg)
+ {
+ case WNDMSG_SHOW: {
+ const struct sWndMsg_Bool *msg = Data;
+ if(Length < sizeof(*msg)) return -1;
+ if(msg->Val)
+ {
+// _SysDebug(" - Shown, take focus");
+ // TODO: This shouldn't really be done, instead focus should be given
+ // when the menu is shown.
+// WM_FocusWindow(Window);
+ }
+ else
+ {
+ // Hide Children
+ _SysDebug("- Hidden, hide the children!");
+ }
+ return 0; }
+ case WNDMSG_FOCUS: {
+ const struct sWndMsg_Bool *msg = Data;
+ if(Length < sizeof(*msg)) return -1;
+ if(!msg->Val) {
+ // TODO: Catch if focus was given away to a child
+ _SysDebug("- Lost focus");
+ WM_ShowWindow(Window, 0); // Hide!
+ }
+ else {
+ _SysDebug("- Focus gained, TODO: Show accel keys");
+ }
+ return 0; }
+
+ case WNDMSG_MOUSEBTN: {
+ const struct sWndMsg_MouseButton *msg = Data;
+ int item;
+
+ if(Length < sizeof(*msg)) return -1;
+
+ if(msg->Button == 0 && msg->bPressed == 0)
+ {
+ item = Renderer_Menu_int_GetItemByPos(Window, info, msg->X, msg->Y);
+ if(item != -1)
+ {
+ tMenuMsg_Select _msg;
+ // TODO: Ignore sub-menus too
+ _msg.ID = item;
+ WM_SendMessage(Window, Window, MSG_MENU_SELECT, sizeof(_msg), &_msg);
+ WM_ShowWindow(Window, 0);
+ }
+ }
+
+
+ return 0; }
+
+ case WNDMSG_MOUSEMOVE: {
+ const struct sWndMsg_MouseMove *msg = Data;
+ int new_hilight;
+
+ if(Length < sizeof(*msg)) return -1;
+
+ new_hilight = Renderer_Menu_int_GetItemByPos(Window, info, msg->X, msg->Y);
+
+ if( new_hilight != info->HilightedItem )
+ {
+ info->HilightedItem = new_hilight;
+ // TODO: Change sub-menu
+ WM_Invalidate(Window);
+ }
+
+ return 0; }
+
+ // Manipulation messages
+ case MSG_MENU_ADDITEM:
+// _SysDebug("MSG_MENU_ADDITEM");
+ return Renderer_Menu_int_AddItem(Window, Length, Data);
+
+ // Only message to pass to client
+ case MSG_MENU_SELECT:
+ return 1;
+ }
+ return 0;
+}
+
--- /dev/null
+/*
+ * Acess2 Window Manager v3
+ * - By John Hodge (thePowersGang)
+ *
+ * renderer_passthru.c
+ * - Passthrough window render (framebuffer essentially)
+ */
+#include <common.h>
+#include <wm_renderer.h>
+
+// === PROTOTYPES ===
+tWindow *Renderer_Passthru_Create(int Flags);
+void Renderer_Passthru_Redraw(tWindow *Window);
+ int Renderer_Passthru_HandleMessage(tWindow *Target, int Msg, int Len, const void *Data);
+
+// === GLOBALS ===
+tWMRenderer gRenderer_Passthru = {
+ .Name = "Passthru",
+ .CreateWindow = Renderer_Passthru_Create,
+ .Redraw = Renderer_Passthru_Redraw,
+ .HandleMessage = Renderer_Passthru_HandleMessage
+};
+
+// === CODE ===
+int Renderer_Passthru_Init(void)
+{
+ return 0;
+}
+
+tWindow *Renderer_Passthru_Create(int Flags)
+{
+ return NULL;
+}
+
+void Renderer_Passthru_Redraw(tWindow *Window)
+{
+
+}
+
+int Renderer_Passthru_HandleMessage(tWindow *Target, int Msg, int Len, const void *Data)
+{
+ return 1;
+}
+
+
--- /dev/null
+/*
+ * Acess2 Window Manager v3
+ * - By John Hodge (thePowersGang)
+ *
+ * render_widget.c
+ * - AxWin2 Widget port
+ */
+#include <common.h>
+#include <wm_renderer.h>
+#include <renderer_widget.h>
+#include <string.h>
+#include <wm_messages.h>
+#include <stdlib.h>
+#include "widget/common.h"
+
+#define DEFAULT_ELETABLE_SIZE 64
+
+// === PROTOTYPES ===
+ int Renderer_Widget_Init(void);
+tWindow *Renderer_Widget_Create(int Flags);
+void Renderer_Widget_Redraw(tWindow *Window);
+
+void Widget_RenderWidget(tWindow *Window, tElement *Element);
+void Widget_UpdateDimensions(tElement *Element);
+void Widget_UpdatePosition(tElement *Element);
+// --- Messages
+tElement *Widget_GetElementById(tWidgetWin *Info, uint32_t ID);
+void Widget_NewWidget(tWidgetWin *Info, size_t Len, const tWidgetMsg_Create *Msg);
+void Widget_SetFlags(tWidgetWin *Info, int Len, const tWidgetMsg_SetFlags *Msg);
+void Widget_SetSize(tWidgetWin *Info, int Len, const tWidgetMsg_SetSize *Msg);
+void Widget_SetText(tWidgetWin *Info, int Len, const tWidgetMsg_SetText *Msg);
+ int Renderer_Widget_HandleMessage(tWindow *Target, int Msg, int Len, const void *Data);
+
+// === GLOBALS ===
+tWMRenderer gRenderer_Widget = {
+ .Name = "Widget",
+ .CreateWindow = Renderer_Widget_Create,
+ .Redraw = Renderer_Widget_Redraw,
+ .HandleMessage = Renderer_Widget_HandleMessage
+};
+
+// --- Element callbacks
+tWidgetDef *gaWM_WidgetTypes[NUM_ELETYPES];
+const int ciWM_NumWidgetTypes = sizeof(gaWM_WidgetTypes)/sizeof(gaWM_WidgetTypes[0]);
+
+// === CODE ===
+int Renderer_Widget_Init(void)
+{
+ WM_RegisterRenderer(&gRenderer_Widget);
+
+ return 0;
+}
+
+void Widget_int_SetTypeDef(int Type, tWidgetDef *Ptr)
+{
+ if( Type < 0 || Type >= ciWM_NumWidgetTypes ) {
+ _SysDebug("ERROR - Widget ID %i out of range (from %p)",
+ Type, __builtin_return_address(0)
+ );
+ return ;
+ }
+
+ if( gaWM_WidgetTypes[Type] ) {
+ _SysDebug("ERROR - Widget ID %i redefined by %p",
+ Type, __builtin_return_address(0)
+ );
+ return ;
+ }
+
+ gaWM_WidgetTypes[Type] = Ptr;
+ _SysDebug("Registered type %i to %p", Type, Ptr);
+}
+
+tWindow *Renderer_Widget_Create(int Flags)
+{
+ tWindow *ret;
+ tWidgetWin *info;
+ int eletable_size = DEFAULT_ELETABLE_SIZE;
+
+ _SysDebug("Renderer_Widget_Create: (Flags = 0x%x)", Flags);
+
+ // TODO: Use `Flags` as default element count?
+ // - Actaully, it's taken by the root ele flags
+ // - Use the upper bits?
+
+ ret = WM_CreateWindowStruct( sizeof(tWidgetWin) + sizeof(tElement*)*eletable_size );
+ info = ret->RendererInfo;
+
+ info->TableSize = eletable_size;
+ info->RootElement.Window = ret;
+ info->RootElement.ID = -1;
+ info->RootElement.BackgroundColour = 0xCCCCCC;
+ info->RootElement.Flags = Flags;
+ info->RootElement.PaddingT = 2;
+ info->RootElement.PaddingB = 2;
+ info->RootElement.PaddingL = 2;
+ info->RootElement.PaddingR = 2;
+
+ return ret;
+}
+
+void Renderer_Widget_Redraw(tWindow *Window)
+{
+ tWidgetWin *info = Window->RendererInfo;
+ 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 ;
+
+ if( Element->Type < ciWM_NumWidgetTypes
+ && gaWM_WidgetTypes[Element->Type]
+ && 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)
+ {
+ Widget_RenderWidget(Window, child);
+ }
+}
+
+void Widget_UpdateDimensions(tElement *Element)
+{
+ tElement *child;
+ int nChildren = 0;
+ int nFixed = 0;
+ int maxCross = 0;
+ int fixedSize = 0;
+ int fullCross, dynWith;
+
+ // Pass 1
+ // - Get the fixed and minimum sizes of the element
+ for( child = Element->FirstChild; child; child = child->NextSibling )
+ {
+ // Ignore elements that will not be rendered
+ if( child->Flags & ELEFLAG_NORENDER ) continue ;
+
+ // Absolutely positioned elements don't affect dimensions
+ if( child->Flags & ELEFLAG_ABSOLUTEPOS ) continue ;
+
+ // Fixed width elements
+ if( child->FixedWith )
+ {
+ nFixed ++;
+ fixedSize += child->FixedWith;
+ }
+ else if( child->Flags & ELEFLAG_NOSTRETCH )
+ {
+ nFixed ++;
+ fixedSize += child->MinWith;
+ }
+
+ if( child->FixedCross && maxCross < child->FixedCross )
+ maxCross = child->FixedCross;
+ if( child->MinCross && maxCross < child->MinCross )
+ maxCross = child->MinCross;
+ nChildren ++;
+ }
+
+ // Get the dynamic with size from the unused space in the element
+ if( nChildren > nFixed ) {
+ if( Element->Flags & ELEFLAG_VERTICAL )
+ dynWith = Element->CachedH - Element->PaddingT - Element->PaddingB;
+ else
+ dynWith = Element->CachedW - Element->PaddingL - Element->PaddingR;
+ dynWith -= fixedSize;
+ if( dynWith < 0 ) return ;
+ dynWith /= nChildren - nFixed;
+ }
+
+// _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 )
+ fullCross = Element->CachedW - Element->PaddingL - Element->PaddingR;
+ else
+ fullCross = Element->CachedH - Element->PaddingT - Element->PaddingB;
+
+ // Pass 2 - Set sizes and recurse
+ for( child = Element->FirstChild; child; child = child->NextSibling )
+ {
+ int cross, with;
+
+ // Ignore elements that will not be rendered
+ if( child->Flags & ELEFLAG_NORENDER ) 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;
+ else
+ with = dynWith;
+
+
+ if(with < child->MinWith) with = child->MinWith;
+ if(cross < child->MinCross) cross = child->MinCross;
+
+ // 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;
+ }
+
+ // Force the positions of child elements to be recalculated
+ child->CachedX = -1;
+
+ // Recurse down so the child elements can be updated
+ Widget_UpdateDimensions(child);
+ }
+
+}
+
+/**
+ * \brief Update the position of child elements
+ */
+void Widget_UpdatePosition(tElement *Element)
+{
+ tElement *child;
+ int x, y;
+
+ if( Element->Flags & ELEFLAG_NORENDER ) return ;
+
+// _SysDebug("Widget_UpdatePosition: (Element=%p(%i Type=%i Flags=0x%x))",
+// Element, Element->ID, Element->Type, Element->Flags);
+
+ // Initialise
+ x = Element->CachedX + Element->PaddingL;
+ y = Element->CachedY + Element->PaddingT;
+
+ // Update each child
+ for(child = Element->FirstChild; child; child = child->NextSibling)
+ {
+ int newX, newY;
+ // Ignore elements that will not be rendered
+ if( child->Flags & ELEFLAG_NORENDER ) continue ;
+
+ newX = x; newY = y;
+
+ // Handle alignment
+ if( Element->Flags & ELEFLAG_ALIGN_CENTER ) {
+ if(Element->Flags & ELEFLAG_VERTICAL)
+ newX += Element->CachedW/2 - child->CachedW/2;
+ else
+ newY += Element->CachedH/2 - child->CachedH/2;
+ }
+ else if( Element->Flags & ELEFLAG_ALIGN_END ) {
+ if(Element->Flags & ELEFLAG_VERTICAL )
+ newX += Element->CachedW - child->CachedW
+ - Element->PaddingL - Element->PaddingR;
+ else
+ newY += Element->CachedH - child->CachedH
+ - Element->PaddingT - Element->PaddingB;
+ }
+
+// _SysDebug(" Widget_UpdatePosition[%i]: newX = %i, newY = %i", Element->ID, newX, newY);
+
+ // Check for changes, and don't update if there was no change
+ if( newX != child->CachedX || newY != child->CachedY )
+ {
+ child->CachedX = newX;
+ child->CachedY = newY;
+ // Update child's children positions
+ Widget_UpdatePosition(child);
+ }
+
+ // Increment
+ if(Element->Flags & ELEFLAG_VERTICAL ) {
+ y += child->CachedH + Element->GapSize;
+ }
+ else {
+ x += child->CachedW + Element->GapSize;
+ }
+ }
+}
+
+/**
+ * \brief Update the minimum dimensions of the element
+ * \note Called after a child's minimum dimensions have changed
+ */
+void Widget_UpdateMinDims(tElement *Element)
+{
+ tElement *child;
+
+ if(!Element) return;
+
+ Element->MinCross = 0;
+ Element->MinWith = 0;
+
+ for(child = Element->FirstChild; child; child = child->NextSibling)
+ {
+ if( Element->Parent &&
+ (Element->Flags & ELEFLAG_VERTICAL) == (Element->Parent->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;
+ }
+ 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;
+ }
+ }
+
+ // Recurse upwards
+ Widget_UpdateMinDims(Element->Parent);
+}
+
+tElement *Widget_GetElementByPos(tWidgetWin *Info, int X, int Y)
+{
+ tElement *ret, *next, *ele;
+
+ next = &Info->RootElement;
+ while(next)
+ {
+ ret = next;
+ next = NULL;
+ for(ele = ret->FirstChild; ele; ele = ele->NextSibling)
+ {
+ if(ele->Flags & ELEFLAG_NORENDER) continue;
+ if(X < ele->CachedX) continue;
+ if(Y < ele->CachedY) continue;
+ if(X >= ele->CachedX + ele->CachedW) continue;
+ if(Y >= ele->CachedY + ele->CachedH) continue;
+ next = ele;
+ }
+ }
+ return ret;
+}
+
+// --- Helpers ---
+tElement *Widget_GetElementById(tWidgetWin *Info, uint32_t ID)
+{
+ tElement *ele;
+
+ if( ID == -1 ) return &Info->RootElement;
+
+ if( ID < Info->TableSize ) return Info->ElementTable[ID];
+
+ ele = Info->ElementTable[ID % Info->TableSize];
+ while(ele && ele->ID != ID) ele = ele->ListNext;
+ return ele;
+}
+
+// --- Message Handlers ---
+void Widget_NewWidget(tWidgetWin *Info, size_t Len, const tWidgetMsg_Create *Msg)
+{
+ const int max_debugname_len = Len - sizeof(tWidgetMsg_Create);
+ tElement *parent, *new;
+
+ // Sanity check
+ if( Len < sizeof(*Msg) )
+ return ;
+ if( strnlen(Msg->DebugName, max_debugname_len) == max_debugname_len )
+ return ;
+
+ _SysDebug("Widget_NewWidget (%i %i Type %i Flags 0x%x)",
+ Msg->Parent, Msg->NewID, Msg->Type, Msg->Flags);
+
+ // 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->Window = parent->Window;
+ 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;
+ new->CachedX = -1;
+
+ if( new->Type < ciWM_NumWidgetTypes && gaWM_WidgetTypes[new->Type] && gaWM_WidgetTypes[new->Type]->Init )
+ gaWM_WidgetTypes[new->Type]->Init(new);
+
+ // Add to parent's list
+ if(parent->LastChild)
+ parent->LastChild->NextSibling = new;
+ else
+ parent->FirstChild = new;
+ 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;
+ }
+
+ Widget_UpdateMinDims(parent);
+}
+
+void Widget_SetFlags(tWidgetWin *Info, int Len, const tWidgetMsg_SetFlags *Msg)
+{
+ tElement *ele;
+
+ if( Len < sizeof(*Msg) )
+ return ;
+
+ _SysDebug("Widget_SetFlags: (%i 0x%x 0x%x)", Msg->WidgetID, Msg->Value, Msg->Mask);
+
+ ele = Widget_GetElementById(Info, Msg->WidgetID);
+ if(!ele) return;
+
+ ele->Flags &= ~Msg->Mask;
+ ele->Flags |= Msg->Value & Msg->Mask;
+}
+
+void Widget_SetSize(tWidgetWin *Info, int Len, const tWidgetMsg_SetSize *Msg)
+{
+ tElement *ele;
+
+ if( Len < sizeof(*Msg) )
+ return ;
+
+ ele = Widget_GetElementById(Info, Msg->WidgetID);
+ if(!ele) return ;
+
+ ele->FixedWith = Msg->Value;
+}
+
+void Widget_SetText(tWidgetWin *Info, int Len, const tWidgetMsg_SetText *Msg)
+{
+ tElement *ele;
+
+ if( Len < sizeof(*Msg) + 1 )
+ return ;
+ if( Msg->Text[Len - sizeof(*Msg) - 1] != '\0' )
+ return ;
+
+ ele = Widget_GetElementById(Info, Msg->WidgetID);
+ if(!ele) return ;
+
+
+ if( ele->Type < ciWM_NumWidgetTypes
+ && gaWM_WidgetTypes[ele->Type]
+ && gaWM_WidgetTypes[ele->Type]->UpdateText )
+ {
+ gaWM_WidgetTypes[ele->Type]->UpdateText( ele, Msg->Text );
+ }
+// else
+// {
+// if(ele->Text) free(ele->Text);
+// ele->Text = strdup(Msg->Text);
+// }
+}
+
+int Renderer_Widget_HandleMessage(tWindow *Target, int Msg, int Len, const void *Data)
+{
+ tWidgetWin *info = Target->RendererInfo;
+ switch(Msg)
+ {
+ case WNDMSG_RESIZE: {
+ const struct sWndMsg_Resize *msg = Data;
+ if(Len < sizeof(*msg)) return -1;
+
+ info->RootElement.CachedW = msg->W;
+ info->RootElement.CachedH = msg->H;
+
+ // TODO: Update dimensions of all child elements?
+
+ return 0; }
+
+ case WNDMSG_MOUSEMOVE: {
+// _SysDebug("TODO: Support widget mouse move events");
+ return 0; }
+
+ case WNDMSG_MOUSEBTN: {
+ const struct sWndMsg_MouseButton *msg = Data;
+ tWidgetMsg_MouseBtn client_msg;
+ tElement *ele;
+ int x, y;
+ int rv;
+
+ if(Len < sizeof(*msg)) return -1;
+
+ x = msg->X; y = msg->Y;
+ client_msg.Button = msg->Button;
+ client_msg.bPressed = msg->bPressed;
+
+ ele = Widget_GetElementByPos(info, x, y);
+ // 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)
+ {
+ rv = gaWM_WidgetTypes[ele->Type]->MouseButton(
+ ele,
+ x - ele->CachedX, y - ele->CachedY,
+ msg->Button, msg->bPressed
+ );
+ // Allow a type to trap the input from going any higher
+ if(rv == 0) break;
+ }
+ else
+ {
+ // Pass to user
+ client_msg.X = x - ele->CachedX;
+ client_msg.Y = y - ele->CachedY;
+ client_msg.WidgetID = ele->ID;
+ WM_SendMessage(Target, Target, MSG_WIDGET_MOUSEBTN, sizeof(client_msg), &client_msg);
+ }
+ }
+ return 0; }
+
+ // New Widget
+ case MSG_WIDGET_CREATE:
+ Widget_NewWidget(info, Len, Data);
+ return 0;
+
+ case MSG_WIDGET_DELETE:
+ _SysDebug("TODO: Implement MSG_WIDGET_DELETE");
+ return 0;
+
+ // Set Flags
+ case MSG_WIDGET_SETFLAGS:
+ Widget_SetFlags(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
+ }
+}
+
+void Widget_Fire(tElement *Element)
+{
+ tWidgetMsg_Fire msg;
+ msg.WidgetID = Element->ID;
+ WM_SendMessage(Element->Window, Element->Window, MSG_WIDGET_FIRE, sizeof(msg), &msg);
+}
+
--- /dev/null
+/*
+ * Acess2 Window Manager v3
+ * - By John Hodge (thePowersGang)
+ *
+ * renderer/widget/button.c
+ * - Button Widget Type
+ */
+#include <common.h>
+#include "./common.h"
+#include "./colours.h"
+
+void Widget_Button_Render(tWindow *Window, tElement *Element)
+{
+ WM_Render_FillRect(
+ Window,
+ Element->CachedX+1, Element->CachedY+1,
+ Element->CachedW-2, Element->CachedH-2,
+ BUTTON_BGCOLOUR
+ );
+ WM_Render_DrawRect(
+ Window,
+ Element->CachedX, Element->CachedY,
+ Element->CachedW-1, Element->CachedH-1,
+ BUTTON_BORDER
+ );
+}
+
+int Widget_Button_MouseButton(tElement *Element, int X, int Y, int Button, int bPress)
+{
+ _SysDebug("Ele %i - Button %i %s",
+ Element->ID, Button,
+ (bPress ? "pressed" : "released")
+ );
+ if(!bPress) Widget_Fire(Element);
+ return 0; // Handled
+}
+
+DEFWIDGETTYPE(ELETYPE_BUTTON,
+ .Render = Widget_Button_Render,
+ .MouseButton = Widget_Button_MouseButton
+ )
+
--- /dev/null
+/**
+ * Acess2 Window Manager v3
+ * - By John Hodge (thePowersGang)
+ *
+ * renderer/widget/colours.h
+ * - Widget style definitions
+ */
+#ifndef _RENDERER_WIDGET_COLOURS_H
+#define _RENDERER_WIDGET_COLOURS_H
+
+#define BOX_BGCOLOUR 0xC0C0C0
+#define BOX_BORDER 0xA0A0A0
+#define BUTTON_BGCOLOUR 0xD0D0D0
+#define BUTTON_BORDER 0xF0F0F0
+#define TEXT_COLOUR 0x000000
+#define TEXTINPUT_BACKGROUND 0xFFFFFF
+#define TEXTINPUT_BORDER_OUT 0x404040
+#define TEXTINPUT_BORDER_IN 0x808080
+
+#endif
+
--- /dev/null
+/**
+ * Acess2 Window Manager v3
+ * - By John Hodge (thePowersGang)
+ *
+ * renderer/widget/common.h
+ * - Widget common definitions
+ */
+#ifndef _RENDERER_WIDGET_COMMON_H
+#define _RENDERER_WIDGET_COMMON_H
+
+#include <renderer_widget.h> // Widget types
+
+typedef struct sWidgetDef tWidgetDef;
+
+struct sWidgetDef
+{
+ void (*Init)(tElement *Ele);
+ void (*Delete)(tElement *Ele);
+
+ void (*Render)(tWindow *Window, tElement *Ele);
+
+ void (*UpdateFlags)(tElement *Ele);
+ void (*UpdateSize)(tElement *Ele);
+ void (*UpdateText)(tElement *Ele, const char *Text); // This should update Ele->Text
+
+ /**
+ * \name Input handlers
+ * \note Returns boolean unhandled
+ * \{
+ */
+ int (*MouseButton)(tElement *Ele, int X, int Y, int Button, int bPressed);
+ int (*MouseMove)(tElement *Ele, int X, int Y);
+ int (*KeyDown)(tElement *Ele, int KeySym, int Character);
+ int (*KeyUp)(tElement *Ele, int KeySym);
+ int (*KeyFire)(tElement *Ele, int KeySym, int Character);
+ /**
+ * \}
+ */
+};
+
+extern void Widget_int_SetTypeDef(int Type, tWidgetDef *Def);
+extern void Widget_UpdateMinDims(tElement *Element);
+extern void Widget_Fire(tElement *Element);
+
+#define DEFWIDGETTYPE(_type, _attribs...) \
+tWidgetDef _widget_typedef_##_type = {_attribs};\
+void _widget_set_##_type(void) __attribute__((constructor));\
+void _widget_set_##_type(void) { Widget_int_SetTypeDef(_type, &_widget_typedef_##_type);}
+
+#endif
+
--- /dev/null
+/*
+ * Acess2 Window Manager v3
+ * - By John Hodge (thePowersGang)
+ *
+ * renderer/widget/button.c
+ * - Button Widget Type
+ */
+#include <common.h>
+#include "./common.h"
+#include "./colours.h"
+#include <string.h>
+
+void Widget_DispText_Render(tWindow *Window, tElement *Element)
+{
+ WM_Render_DrawText(
+ Window,
+ Element->CachedX+1, Element->CachedY+1,
+ Element->CachedW-2, Element->CachedH-2,
+ NULL, TEXT_COLOUR,
+ Element->Text
+ );
+}
+
+void Widget_DispText_UpdateText(tElement *Element, const char *Text)
+{
+ int w=0, h=0;
+
+ if(Element->Text) free(Element->Text);
+ Element->Text = strdup(Text);
+
+ WM_Render_GetTextDims(NULL, Element->Text, &w, &h);
+ if(Element->Parent && (Element->Parent->Flags & ELEFLAG_VERTICAL)) {
+ Element->MinCross = w;
+ Element->MinWith = h;
+ }
+ else {
+ Element->MinWith = w;
+ Element->MinCross = h;
+ }
+
+ Widget_UpdateMinDims(Element->Parent);
+}
+
+DEFWIDGETTYPE(ELETYPE_TEXT,
+ .Render = Widget_DispText_Render,
+ .UpdateText = Widget_DispText_UpdateText
+ );
+
--- /dev/null
+/*
+ * Acess2 Window Manager v3
+ * - By John Hodge (thePowersGang)
+ *
+ * renderer/widget/image.c
+ * - Image Widget Type
+ */
+#include <common.h>
+#include "./common.h"
+#include "./colours.h"
+#include "../../include/image.h"
+
+void Widget_Image_Render(tWindow *Window, tElement *Element)
+{
+ WM_Render_DrawImage(
+ Window,
+ Element->CachedX, Element->CachedY,
+ Element->CachedW, Element->CachedH,
+ Element->Data
+ );
+}
+
+void Widget_Image_UpdateText(tElement *Element, const char *Text)
+{
+ if(Element->Data) free(Element->Data);
+ Element->Data = Image_Load( Text );
+ if(!Element->Data) {
+// Element->Flags &= ~ELEFLAG_FIXEDSIZE;
+ return ;
+ }
+
+ Element->CachedW = ((tImage*)Element->Data)->Width;
+ Element->CachedH = ((tImage*)Element->Data)->Height;
+
+ if(Element->Parent && (Element->Parent->Flags & ELEFLAG_VERTICAL) ) {
+ Element->MinCross = ((tImage*)Element->Data)->Width;
+ Element->MinWith = ((tImage*)Element->Data)->Height;
+ }
+ else {
+ Element->MinWith = ((tImage*)Element->Data)->Width;
+ Element->MinCross = ((tImage*)Element->Data)->Height;
+ }
+
+ Widget_UpdateMinDims(Element->Parent);
+
+ // NOTE: Doesn't update Element->Text because it's useless
+}
+
+DEFWIDGETTYPE(ELETYPE_IMAGE,
+ .Render = Widget_Image_Render,
+ .UpdateText = Widget_Image_UpdateText
+ );
+
--- /dev/null
+/*
+ * Acess2 Window Manager v3
+ * - By John Hodge (thePowersGang)
+ *
+ * renderer/widget/textinput.c
+ * - Single line text box
+ */
+#include <common.h>
+#include "./common.h"
+#include "./colours.h"
+
+void Widget_TextInput_Render(tWindow *Window, tElement *Element)
+{
+ WM_Render_FillRect(
+ Window,
+ Element->CachedX, Element->CachedY,
+ Element->CachedW, Element->CachedH,
+ TEXTINPUT_BACKGROUND
+ );
+ WM_Render_DrawRect(
+ Window,
+ Element->CachedX, Element->CachedY,
+ Element->CachedW, Element->CachedH,
+ TEXTINPUT_BORDER_OUT
+ );
+ WM_Render_DrawRect(
+ Window,
+ Element->CachedX+1, Element->CachedY+1,
+ Element->CachedW-2, Element->CachedH-2,
+ TEXTINPUT_BORDER_IN
+ );
+ // TODO: Cursor?
+}
+
+void Widget_TextInput_Init(tElement *Element)
+{
+ int h;
+
+ // TODO: Select font correctly
+ WM_Render_GetTextDims(NULL, "jJ", NULL, &h);
+
+ if( Element->Parent && (Element->Parent->Flags & ELEFLAG_VERTICAL) )
+ Element->MinWith = h;
+ else
+ Element->MinCross = h;
+
+ // No need to explicitly update parent min dims, as the AddElement routine does that
+}
+
+DEFWIDGETTYPE(ELETYPE_TEXTINPUT,
+ .Render = Widget_TextInput_Render,
+ .Init = Widget_TextInput_Init
+ );
+
+
--- /dev/null
+/*
+ * Acess2 Window Manager v3
+ * - By John Hodge (thePowersGang)
+ *
+ * renderer_widget_decorator.c
+ * - Widget Decorator
+ */
+#include <common.h>
+#include <wm.h>
+#include <renderer_widget.h>
+
+#define BORDER_EVERYTHING 1
+
+#include "./colours.h"
+
+// === CODE ===
+void Widget_Decorator_RenderWidget(tWindow *Window, tElement *Element)
+{
+// _SysDebug("Widget_Decorator_RenderWidget: (Element={Type:%i,(%i,%i) %ix%i})",
+// Element->Type,
+// Element->CachedX, Element->CachedY,
+// Element->CachedW, Element->CachedH
+// );
+
+ #if BORDER_EVERYTHING
+ WM_Render_DrawRect(
+ Window,
+ Element->CachedX, Element->CachedY,
+ Element->CachedW, Element->CachedH,
+ 0
+ );
+ #endif
+
+ switch(Element->Type)
+ {
+ case ELETYPE_NONE:
+ case ELETYPE_BOX: break; // Box is a meta-element
+
+ case ELETYPE_TABBAR: // Tab Bar
+ WM_Render_DrawRect(
+ Window,
+ Element->CachedX, Element->CachedY,
+ Element->CachedW, Element->CachedH,
+ BOX_BORDER
+ );
+ WM_Render_FillRect(
+ Window,
+ Element->CachedX+1, Element->CachedY+1,
+ Element->CachedW-2, Element->CachedH-2,
+ BOX_BGCOLOUR
+ );
+ // Enumerate Items.
+ break;
+ case ELETYPE_TOOLBAR: // Tool Bar
+ WM_Render_DrawRect(
+ Window,
+ Element->CachedX, Element->CachedY,
+ Element->CachedW, Element->CachedH,
+ BOX_BORDER
+ );
+ WM_Render_FillRect(
+ Window,
+ Element->CachedX+1, Element->CachedY+1,
+ Element->CachedW-2, Element->CachedH-2,
+ BOX_BGCOLOUR
+ );
+ break;
+
+ case ELETYPE_SPACER: // Spacer (subtle line)
+ WM_Render_FillRect(
+ Window,
+ Element->CachedX+3, Element->CachedY+3,
+ Element->CachedW-6, Element->CachedH-6,
+ BOX_BORDER
+ );
+ break;
+
+ case ELETYPE_BUTTON: // Button
+ break;
+
+ // Text input field / Text Box
+ case ELETYPE_TEXTINPUT:
+ case ELETYPE_TEXTBOX:
+ break;
+
+ case ELETYPE_TEXT:
+ break;
+
+ case ELETYPE_IMAGE:
+ break;
+
+ default:
+ _SysDebug(" ERROR: Unknown type %i", Element->Type);
+ break;
+ }
+}
#include <decorator.h>
// === IMPORTS ===
-extern void IPC_SendWMMessage(tIPC_Client *Client, uint32_t Src, uint32_t Dst, int Msg, int Len, void *Data);
+extern void IPC_SendWMMessage(tIPC_Client *Client, uint32_t Src, uint32_t Dst, int Msg, int Len, const void *Data);
// === GLOBALS ===
tWMRenderer *gpWM_Renderers;
return 0;
}
-int WM_SendMessage(tWindow *Source, tWindow *Dest, int Message, int Length, void *Data)
+int WM_SendMessage(tWindow *Source, tWindow *Dest, int Message, int Length, const void *Data)
{
if(Dest == NULL) return -2;
if(Length > 0 && Data == NULL) return -1;
+
+ if( Decorator_HandleMessage(Dest, Message, Length, Data) != 1 )
+ {
+ // TODO: Catch errors from ->HandleMessage
+ return 0;
+ }
// ->HandleMessage returns 1 when the message was not handled
if( Dest->Renderer->HandleMessage(Dest, Message, Length, Data) != 1 )
struct sWndMsg_MouseMove msg;
win = WM_int_GetWindowAtPos(OldX, OldY);
- msg.X = NewX - win->X;
- msg.Y = NewY - win->Y;
+ msg.X = NewX - win->X - win->BorderL;
+ msg.Y = NewY - win->Y - win->BorderT;
msg.dX = NewX - OldX;
msg.dY = NewY - OldY;
WM_SendMessage(NULL, win, WNDMSG_MOUSEMOVE, sizeof(msg), &msg);
// TODO: Send mouseup to match mousedown if the cursor moves out of a window?
win = newWin;
- msg.X = NewX - win->X;
- msg.Y = NewY - win->Y;
+ msg.X = NewX - win->X - win->BorderL;
+ msg.Y = NewY - win->Y - win->BorderT;
msg.dX = NewX - OldX;
msg.dY = NewY - OldY;
WM_SendMessage(NULL, win, WNDMSG_MOUSEMOVE, sizeof(msg), &msg);
{
struct sWndMsg_MouseButton msg;
- msg.X = X - Win->X;
- msg.Y = Y - Win->Y;
+ msg.X = X - Win->X - Win->BorderL;
+ msg.Y = Y - Win->Y - Win->BorderT;
msg.Button = Index;
msg.bPressed = !!Pressed;
// Handle press of primary button to change focus
if( ButtonIndex == 0 && Pressed == 1 )
{
- _SysDebug("Gave focus to %p", win);
+// _SysDebug("Gave focus to %p", win);
WM_FocusWindow(win);
WM_RaiseWindow(win);
}