roo_e/client/src/gui/wmwindow.c
2022-05-22 18:46:16 -05:00

348 lines
10 KiB
C

#include "wmwindow.h"
#include "array.h"
uint8_t __MAGIC_WINDOW = 0;
static WindowT **_windowList = NULL;
static GrTextOption _textOption;
WindowT *windowCreate(uint16_t x, uint16_t y, uint16_t w, uint16_t h, char *title, uint8_t flags, ...) {
WindowT *win = NULL;
NEW(WindowT, win);
guiWidgetBaseSet((WidgetT *)win, __MAGIC_WINDOW, x, y, w, h);
win->title = strdup(title);
win->flags = flags;
win->close.x = win->close.y = win->close.x2 = win->close.y2 = 0;
win->titlebar.x = win->titlebar.y = win->titlebar.x2 = win->titlebar.y2 = 0;
win->minimize.x = win->minimize.y = win->minimize.x2 = win->minimize.y2 = 0;
win->maximize.x = win->maximize.y = win->maximize.x2 = win->maximize.y2 = 0;
win->bounds.x = win->bounds.y = win->bounds.x2 = win->bounds.y2 = 0;
arrput(_windowList, win);
return win;
}
void windowDestroy(struct WidgetS *widget, ...) {
uint16_t i;
WindowT *window = (WindowT *)widget;
for (i=0; i<arrlen(_windowList); i++) {
if (window == _windowList[i]) {
if (_windowList[i]->title) DEL(_windowList[i]->title);
DEL(_windowList[i]);
arrdel(_windowList, i);
break;
}
}
}
void windowPaint(struct WidgetS *widget, ...) {
WindowT *w = (WindowT *)widget;
uint16_t x1 = w->base.r.x;
uint16_t y1 = w->base.r.y;
uint16_t x2 = w->base.r.x + w->base.r.w - 1;
uint16_t y2 = w->base.r.y + w->base.r.h - 1;
uint16_t tx1;
uint16_t ty1;
uint16_t tx2;
uint16_t ty2;
uint16_t minimizeOffset = 0;
GrColor titleBackgroundColor = GUI_DARKGRAY;
// Fake Window contents.
GrFilledBox(x1, y1, x2, y2, GUI_BLACK);
// If we need a titlebar, it's 18px.
if (w->title || w->flags & WIN_CLOSE || w->flags & WIN_MAXIMIZE || w->flags & WIN_MINIMIZE) {
// Draw title bar background.
y1 -= 18;
GrFilledBox(x1, y1, x2, y1 + 17, titleBackgroundColor);
// Close box?
if (w->flags & WIN_CLOSE) {
// 26px wide, 18 tall including highlight and shadow.
w->close.x = x1 + 1;
w->close.y = y1 + 1;
w->close.x2 = w->close.x + 24;
w->close.y2 = w->close.y + 15;
GrFilledBox(w->close.x + 1, w->close.y + 1, w->close.x2 - 1, w->close.y2 - 1, GUI_LIGHTGRAY);
GrHLine(w->close.x, w->close.x2, w->close.y, GUI_WHITE);
GrVLine(w->close.x, w->close.y, w->close.y2, GUI_WHITE);
// Button is 8px down, 3px tall, and 4px in on both sides.
tx1 = w->close.x + 4;
ty1 = w->close.y + 7;
tx2 = w->close.x2 - 4;
ty2 = w->close.y + 9;
GrHLine(tx1, tx2, ty1, GUI_WHITE);
GrPlot(tx1, ty1 + 1, GUI_WHITE);
GrHLine(tx1, tx2, ty2, GUI_BLACK);
GrVLine(tx2, ty1, ty2, GUI_BLACK);
// Set titlebar area.
w->titlebar.x = w->close.x2 + 2;
} else {
// No close box - set titlebar area.
w->titlebar.x = x1;
}
w->titlebar.y = y1;
w->titlebar.x2 = x2;
w->titlebar.y2 = y1 + 17;
// Maximize box?
if (w->flags & WIN_MAXIMIZE) {
// 26px wide, 18 tall including highlight and shadow.
w->maximize.y = y1 + 1;
w->maximize.x2 = x2 - 1;
w->maximize.x = w->maximize.x2 - 24;
w->maximize.y2 = w->maximize.y + 15;
GrFilledBox(w->maximize.x + 1, w->maximize.y + 1, w->maximize.x2 - 1, w->maximize.y2 - 1, GUI_LIGHTGRAY);
GrHLine(w->maximize.x, w->maximize.x2, w->maximize.y, GUI_WHITE);
GrVLine(w->maximize.x, w->maximize.y, w->maximize.y2, GUI_WHITE);
// Button is 3px down, and 4px in on both sides.
tx1 = w->maximize.x + 4;
ty1 = w->maximize.y + 4;
tx2 = w->maximize.x2 - 3;
ty2 = w->maximize.y + 12;
GrHLine(tx1, tx2, ty1, GUI_WHITE);
GrVLine(tx1, ty1, ty2, GUI_WHITE);
GrHLine(tx1, tx2, ty2, GUI_BLACK);
GrVLine(tx2, ty1, ty2, GUI_BLACK);
// Move minimize button over.
minimizeOffset = 26;
// Set titlebar area.
w->titlebar.x2 -= 26;
}
// Minimize box?
if (w->flags & WIN_MINIMIZE) {
// 26px wide, 18 tall including highlight and shadow.
w->minimize.y = y1 + 1;
w->minimize.x2 = x2 - 1 - minimizeOffset;
w->minimize.x = w->minimize.x2 - 24;
w->minimize.y2 = w->minimize.y + 15;
GrFilledBox(w->minimize.x + 1, w->minimize.y + 1, w->minimize.x2 - 1, w->minimize.y2 - 1, GUI_LIGHTGRAY);
GrHLine(w->minimize.x, w->minimize.x2, w->minimize.y, GUI_WHITE);
GrVLine(w->minimize.x, w->minimize.y, w->minimize.y2, GUI_WHITE);
tx1 = w->minimize.x + 10;
ty1 = w->minimize.y + 6;
tx2 = w->minimize.x2 - 8;
ty2 = w->minimize.y + 9;
GrHLine(tx1, tx2, ty1, GUI_WHITE);
GrVLine(tx1, ty1, ty2, GUI_WHITE);
GrHLine(tx1, tx2, ty2, GUI_BLACK);
GrVLine(tx2, ty1, ty2, GUI_BLACK);
// Set titlebar area.
w->titlebar.x2 -= 26;
}
// Title font area is 12px high.
GrHLine(w->titlebar.x, w->titlebar.x2 - 1, w->titlebar.y, GUI_WHITE);
GrVLine(w->titlebar.x, w->titlebar.y, w->titlebar.y2 - 1, GUI_WHITE);
if (w->title) {
//***TODO*** Look into GrTextRegion
_textOption.txo_bgcolor.v = titleBackgroundColor;
ty1 = w->titlebar.y + 2;
tx1 = w->titlebar.x + 2 + (w->titlebar.x2 - w->titlebar.x - 4) * 0.5 - (GrStringWidth(w->title, strlen(w->title), &_textOption) * 0.5);
//***TODO*** Does not handle text being clipped.
GrDrawString(w->title, strlen(w->title), tx1, ty1, &_textOption);
}
}
// Innermost shadow frame. 1px wide.
x1--;
y1--;
x2++;
y2++;
GrHLine(x1, x2, y2, GUI_WHITE);
GrVLine(x2, y1, y2, GUI_WHITE);
GrHLine(x1, x2, y1, GUI_DARKGRAY);
GrVLine(x1, y1, y2, GUI_DARKGRAY);
// Frame Border. 4px wide.
x1 -= 4;
y1 -= 4;
x2 += 4;
y2 += 4;
GrFilledBox(x1, y1, x1 + 3, y2, GUI_LIGHTGRAY);
GrFilledBox(x2, y1, x2 - 3, y2, GUI_LIGHTGRAY);
GrFilledBox(x1, y1, x2, y1 + 3, GUI_LIGHTGRAY);
GrFilledBox(x1, y2, x2, y2 - 3, GUI_LIGHTGRAY);
// Resize handle.
if (w->flags & WIN_RESIZE) {
ty1 = y2 - 15 - 3;
tx1 = x2 - 15 - 3;
GrHLine(x2, x2 - 3, ty1, GUI_DARKGRAY);
GrHLine(x2, x2 - 3, ty1 + 1, GUI_WHITE);
GrVLine(tx1, y2, y2 - 3, GUI_DARKGRAY);
GrVLine(tx1 + 1, y2, y2 - 3, GUI_WHITE);
}
// Outermost shadow frame. 1px wide.
x1--;
y1--;
x2++;
y2++;
GrHLine(x1, x2, y1, GUI_WHITE);
GrVLine(x1, y1, y2, GUI_WHITE);
GrHLine(x1, x2, y2, GUI_DARKGRAY);
GrVLine(x2, y1, y2, GUI_DARKGRAY);
w->bounds.x = x1;
w->bounds.x2 = x2;
w->bounds.y = y1;
w->bounds.y2 = y2;
}
RegisterT *windowRegister(uint8_t magic) {
static RegisterT reg = {
"Window",
windowPaint,
windowDestroy,
NULL
};
// One-time widget startup code.
__MAGIC_WINDOW = magic;
_textOption.txo_bgcolor.v = GUI_DARKGRAY;
_textOption.txo_fgcolor.v = GUI_WHITE;
_textOption.txo_chrtype = GR_BYTE_TEXT;
_textOption.txo_direct = GR_TEXT_RIGHT;
_textOption.txo_font = &GrFont_PC8x14;
_textOption.txo_xalign = GR_ALIGN_DEFAULT;
_textOption.txo_yalign = GR_ALIGN_DEFAULT;
return &reg;
}
void wmPaint(GrMouseEvent *event) {
uint16_t i;
WidgetT *widget;
WindowT *win;
static uint8_t dragging = 0;
static PointT dragOffset = { 0 };
// Do we have windows?
if (arrlen(_windowList) > 0) {
// Paint all windows.
for (i=0; i<arrlen(_windowList); i++) {
GrSetContext(__guiBackBuffer);
widget = (WidgetT *)_windowList[i];
widget->reg->paint(widget);
}
// Get top window.
win = _windowList[arrlen(_windowList) - 1];
// Wrap left button processing with a 'for' so we can 'break' out of it.
for (;;) {
// Is the left mouse button down?
if (event->buttons & GR_M_LEFT) {
// DEBUG - draw active regions. ***TODO*** No resize grabber here.
GrBox(win->bounds.x, win->bounds.y, win->bounds.x2, win->bounds.y2, GUI_YELLOW);
GrBox(win->base.r.x, win->base.r.y, win->base.r.x + win->base.r.w - 1, win->base.r.y + win->base.r.h - 1, GUI_YELLOW);
GrBox(win->close.x, win->close.y, win->close.x2, win->close.y2, GUI_RED);
GrBox(win->titlebar.x, win->titlebar.y, win->titlebar.x2, win->titlebar.y2, GUI_RED);
GrBox(win->minimize.x, win->minimize.y, win->minimize.x2, win->minimize.y2, GUI_RED);
GrBox(win->maximize.x, win->maximize.y, win->maximize.x2, win->maximize.y2, GUI_RED);
// Are we currently dragging?
if (dragging) {
// Move window to new mouse location.
win->base.r.x = event->x - dragOffset.x;
win->base.r.y = event->y - dragOffset.y;
break;
} else { // Dragging.
// Did the button just go down?
if (event->flags & GR_M_LEFT_DOWN) {
// Are we on the topmost window?
if (event->x <= win->bounds.x2 && event->x >= win->bounds.x && event->y <= win->bounds.y2 && event->y >= win->bounds.y) {
//***TODO*** Are we inside the window content? Most likely, check first.
if (event->x <= (win->base.r.x + win->base.r.w - 1) && event->x >= win->base.r.x &&
event->y <= (win->base.r.y + win->base.r.h - 1) && event->y >= win->base.r.y) {
//***TODO*** Send to window for processing.
}
//***TODO*** Are we inside the close button?
// Are we inside the title bar to begin dragging?
if (event->x <= win->titlebar.x2 && event->x >= win->titlebar.x && event->y <= win->titlebar.y2 && event->y >= win->titlebar.y) {
dragging = 1;
dragOffset.x = event->x - win->base.r.x;
dragOffset.y = event->y - win->base.r.y;
break;
}
//***TODO*** Are we inside the minimize button?
//***TODO*** Are we inside the maximize button?
} else { // On topmost window.
// Not over topmost window. Search backwards to find first window we're inside.
i = arrlen(_windowList) - 2;
if (i >= 0) {
for (; i>=0; i--) {
win = _windowList[i];
if (event->x <= win->bounds.x2 && event->x >= win->bounds.x && event->y <= win->bounds.y2 && event->y >= win->bounds.y) {
// Bring this window forward.
arrdel(_windowList, i);
arrput(_windowList, win);
// If we happened to be in the title bar, go ahead and start dragging.
if (event->x <= win->titlebar.x2 && event->x >= win->titlebar.x && event->y <= win->titlebar.y2 && event->y >= win->titlebar.y) {
dragging = 1;
dragOffset.x = event->x - win->base.r.x;
dragOffset.y = event->y - win->base.r.y;
}
break;
}
}
}
} // On topmost window.
} // Button just went down.
} // Dragging.
} else { // Left mouse button.
// Left mouse not down.
// Can no longer be dragging.
dragging = 0;
}
break;
} // Left button processing.
} // Do we have windows?
}
void wmShutdown(void) {
while (arrlen(_windowList) > 0) {
windowDestroy((WidgetT *)_windowList[0]);
}
arrfree(_windowList);
}
void wmStartup(void) {
}