209 lines
6.9 KiB
C
209 lines
6.9 KiB
C
/*
|
|
* Kangaroo Punch Multi Player Game Server Mark II
|
|
* Copyright (C) 2020-2021 Scott Duensing
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
|
|
#include "window.h"
|
|
|
|
|
|
static void windowDeactivateAll(WidgetT *widget);
|
|
static void windowMouseEvent(WidgetT *widget, MouseT *mouse, uint16_t x, uint16_t y, uint8_t event);
|
|
static void windowPaint(WidgetT *widget);
|
|
|
|
|
|
static void windowDeactivateAll(WidgetT *widget) {
|
|
size_t len = arrlenu(widget->children);
|
|
size_t x;
|
|
|
|
// Is this a Window?
|
|
if (widget->magic == MAGIC_WINDOW) {
|
|
// Deactivate it.
|
|
GUI_CLEAR_FLAG(widget, WIDGET_FLAG_ACTIVE);
|
|
guiSetWidgetAndChildrenDirty(widget);
|
|
}
|
|
|
|
// Process any children.
|
|
if (len > 0) {
|
|
for (x=0; x<len; x++) {
|
|
windowDeactivateAll(widget->children[x]);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void windowDel(WidgetT **widget) {
|
|
WindowT *w = (WindowT *)*widget;
|
|
|
|
vbeSurfaceDestroy(&w->base.surface);
|
|
if (w->title) free(w->title);
|
|
free(w);
|
|
w = NULL;
|
|
}
|
|
|
|
|
|
WidgetT *windowInit(WidgetT *window, uint16_t x, uint16_t y, uint16_t w, uint16_t h, char *title) {
|
|
WindowT *win = (WindowT *)window;
|
|
|
|
win->base.magic = MAGIC_WINDOW;
|
|
win->base.x = x;
|
|
win->base.y = y;
|
|
win->base.w = w;
|
|
win->base.h = h;
|
|
win->base.delMethod = windowDel;
|
|
win->base.paintMethod = windowPaint;
|
|
win->base.mouseEventMethod = windowMouseEvent;
|
|
win->flags = 0;
|
|
win->title = NULL;
|
|
|
|
win->base.marginX += _guiMetric[METRIC_WINDOW_BORDER_WIDTH] + 2;
|
|
win->base.marginY += _guiMetric[METRIC_WINDOW_TITLE_GRAB_HEIGHT];
|
|
|
|
windowSetTitle(win, title);
|
|
|
|
GUI_SET_FLAG(window, WIDGET_FLAG_OWNS_SURFACE);
|
|
win->base.surface = vbeSurfaceCreate(win->base.w, win->base.h);
|
|
if (!win->base.surface) {
|
|
free(win->title);
|
|
free(win);
|
|
return NULL;
|
|
}
|
|
|
|
return window;
|
|
}
|
|
|
|
|
|
static void windowMouseEvent(WidgetT *widget, MouseT *mouse, uint16_t x, uint16_t y, uint8_t event) {
|
|
|
|
WindowT *window = (WindowT *)widget;
|
|
|
|
(void)x;
|
|
|
|
// Raise window?
|
|
if (event == MOUSE_EVENT_LEFT_UP && !GUI_GET_FLAG(widget, WIDGET_FLAG_ACTIVE)) windowSetActive(window);
|
|
|
|
// Start dragging?
|
|
if (event == MOUSE_EVENT_LEFT_DOWN && GUI_GET_FLAG(widget, WIDGET_FLAG_ACTIVE)) {
|
|
// Are we on the draggable area of the titlebar / borders?
|
|
if (y < _guiMetric[METRIC_WINDOW_TITLE_GRAB_HEIGHT]) {
|
|
// Start dragging.
|
|
_guiDragWidget = widget;
|
|
_guiDragOffsetX = mouse->x - window->base.x;
|
|
_guiDragOffsetY = mouse->y - window->base.y;
|
|
}
|
|
}
|
|
|
|
// Still dragging? We use raw mouse data here because it's possible to drag too quickly and trigger "OUT" events.
|
|
if (_guiDragWidget == widget && mouse->buttonLeft && GUI_GET_FLAG(widget, WIDGET_FLAG_ACTIVE)) {
|
|
// Move window.
|
|
window->base.x = mouse->x - _guiDragOffsetX;
|
|
window->base.y = mouse->y - _guiDragOffsetY;
|
|
// Keep it on the screen.
|
|
if (window->base.x < 0) window->base.x = 0;
|
|
if (window->base.x + window->base.w > vbeDisplayWidthGet()) window->base.x = vbeDisplayWidthGet() - window->base.w;
|
|
if (window->base.y < 0) window->base.y = 0;
|
|
if (window->base.y + window->base.h > vbeDisplayHeightGet()) window->base.y = vbeDisplayHeightGet() - window->base.h;
|
|
}
|
|
|
|
// Be sure we stop dragging on mouse up or move out.
|
|
if (_guiDragWidget == widget && event == MOUSE_EVENT_LEFT_UP) {
|
|
_guiDragWidget = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
WindowT *windowNew(uint16_t x, uint16_t y, uint16_t w, uint16_t h, char *title) {
|
|
WindowT *window = (WindowT *)malloc(sizeof(WindowT));
|
|
WidgetT *widget = NULL;
|
|
|
|
if (!window) return NULL;
|
|
|
|
widget = widgetInit((WidgetT *)window);
|
|
if (!widget) {
|
|
free(window);
|
|
return NULL;
|
|
}
|
|
|
|
window = (WindowT *)windowInit((WidgetT *)window, x, y, w, h, title);
|
|
|
|
return window;
|
|
}
|
|
|
|
|
|
static void windowPaint(WidgetT *widget) {
|
|
WindowT *w = (WindowT *)widget;
|
|
uint16_t x2 = w->base.w - 1;
|
|
uint16_t y2 = w->base.h - 1;
|
|
PixelT background = GUI_GET_FLAG(widget, WIDGET_FLAG_ACTIVE) ? _guiColor[COLOR_WINDOW_TITLE_ACTIVE] : _guiColor[COLOR_WINDOW_TITLE_INACTIVE];
|
|
PixelT text = GUI_GET_FLAG(widget, WIDGET_FLAG_ACTIVE) ? _guiColor[COLOR_WINDOW_TITLE_TEXT_ACTIVE] : _guiColor[COLOR_WINDOW_TITLE_TEXT_INACTIVE];
|
|
|
|
if (GUI_GET_FLAG(widget, WIDGET_FLAG_DIRTY)) {
|
|
vbeSurfaceSet(w->base.surface);
|
|
|
|
// Background.
|
|
vbeSurfaceClear(_guiColor[COLOR_WINDOW_BACKGROUND]);
|
|
|
|
// Outer edge.
|
|
guiDrawHighlightFrame(0, 0, x2, y2, _guiColor[COLOR_WINDOW_HIGHLIGHT], _guiColor[COLOR_WINDOW_SHADOW]);
|
|
|
|
// Inner edge - skip METRIC_WINDOW_BORDER_WIDTH pixels. Be sure shadow and highlight are not included in the width.
|
|
guiDrawHighlightFrame(_guiMetric[METRIC_WINDOW_BORDER_WIDTH] + 2, _guiMetric[METRIC_WINDOW_BORDER_WIDTH] + 2, x2 - _guiMetric[METRIC_WINDOW_BORDER_WIDTH] - 2, y2 - _guiMetric[METRIC_WINDOW_BORDER_WIDTH] - 2, _guiColor[COLOR_WINDOW_SHADOW], _guiColor[COLOR_WINDOW_HIGHLIGHT]);
|
|
|
|
// Title bar - METRIC_WINDOW_TITLE_HEIGHT pixels high. Be sure shadow and highlight are not included in the width.
|
|
guiDrawHighlightFrame(_guiMetric[METRIC_WINDOW_BORDER_WIDTH] + 3, _guiMetric[METRIC_WINDOW_BORDER_WIDTH] + 3, x2 - _guiMetric[METRIC_WINDOW_BORDER_WIDTH] - 3, _guiMetric[METRIC_WINDOW_BORDER_WIDTH] + _guiMetric[METRIC_WINDOW_TITLE_HEIGHT] + 4, _guiColor[COLOR_WINDOW_HIGHLIGHT], _guiColor[COLOR_WINDOW_SHADOW]);
|
|
guiDrawFilledRectangle(_guiMetric[METRIC_WINDOW_BORDER_WIDTH] + 4, _guiMetric[METRIC_WINDOW_BORDER_WIDTH] + 4, x2 - _guiMetric[METRIC_WINDOW_BORDER_WIDTH] - 4, _guiMetric[METRIC_WINDOW_BORDER_WIDTH] + _guiMetric[METRIC_WINDOW_TITLE_HEIGHT] + 2, background);
|
|
|
|
fontRender(_guiFont, w->title, text, background, _guiMetric[METRIC_WINDOW_BORDER_WIDTH] + 16, _guiMetric[METRIC_WINDOW_BORDER_WIDTH] + 5);
|
|
|
|
GUI_CLEAR_FLAG(widget, WIDGET_FLAG_DIRTY);
|
|
}
|
|
}
|
|
|
|
|
|
void windowSetActive(WindowT *window) {
|
|
size_t len;
|
|
int16_t i;
|
|
WidgetT *parent = W(window)->parent;
|
|
WidgetT *child;
|
|
|
|
// Deactivate all windows.
|
|
windowDeactivateAll(guiRootGet());
|
|
|
|
// Activate us.
|
|
GUI_SET_FLAG(W(window), WIDGET_FLAG_ACTIVE);
|
|
|
|
// Find our window in the widget list.
|
|
len = arrlenu(parent->children);
|
|
for (i=len-1; i>=0; i--) {
|
|
child = parent->children[i];
|
|
if (child == W(window)) {
|
|
// Move to the top of the widget list.
|
|
arrdel(parent->children, i);
|
|
arrput(parent->children, child);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Tell the GUI.
|
|
_guiActiveWindow = window;
|
|
}
|
|
|
|
|
|
void windowSetTitle(WindowT *window, char *title) {
|
|
if (window->title) free(window->title);
|
|
window->title = strdup(title);
|
|
}
|