270 lines
7.2 KiB
C
270 lines
7.2 KiB
C
#include "wmwindow.h"
|
|
#include "array.h"
|
|
|
|
|
|
uint8_t __MAGIC_WINDOW = 0;
|
|
|
|
static WindowT **_windowList = NULL;
|
|
static GrContext *_backBuffer = NULL;
|
|
static GrContext *_screenBuffer = 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;
|
|
|
|
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.
|
|
w->close.x = 0;
|
|
w->close.y = 0;
|
|
w->close.x2 = 0;
|
|
w->close.y2 = 0;
|
|
// 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;
|
|
} else {
|
|
// No maximize box.
|
|
w->maximize.x = 0;
|
|
w->maximize.y = 0;
|
|
w->maximize.x2 = 0;
|
|
w->maximize.y2 = 0;
|
|
}
|
|
|
|
// 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;
|
|
} else {
|
|
// No minimize box.
|
|
w->minimize.x = 0;
|
|
w->minimize.y = 0;
|
|
w->minimize.x2 = 0;
|
|
w->minimize.y2 = 0;
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
|
|
|
|
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 ®
|
|
}
|
|
|
|
|
|
void wmPaint(void) {
|
|
uint16_t i;
|
|
WidgetT *widget;
|
|
|
|
// Paint desktop.
|
|
GrSetContext(_backBuffer);
|
|
GrClearContext(GUI_CYAN);
|
|
|
|
// Paint all windows.
|
|
for (i=0; i<arrlen(_windowList); i++) {
|
|
GrSetContext(_backBuffer);
|
|
widget = (WidgetT *)_windowList[i];
|
|
widget->reg->paint(widget);
|
|
}
|
|
|
|
// Copy to screen.
|
|
GrBitBltNC(_screenBuffer, 0, 0, _backBuffer, 0, 0, GrMaxX(), GrMaxY(), GrWRITE);
|
|
}
|
|
|
|
|
|
void wmShutdown(void) {
|
|
while (arrlen(_windowList) > 0) {
|
|
windowDestroy((WidgetT *)_windowList[0]);
|
|
}
|
|
arrfree(_windowList);
|
|
|
|
GrDestroyContext(_backBuffer);
|
|
}
|
|
|
|
|
|
void wmStartup(void) {
|
|
_screenBuffer = GrScreenContext();
|
|
_backBuffer = GrCreateContext(GrScreenX(), GrScreenY(), NULL, NULL);
|
|
}
|