kpmpgsmkii/client/src/gui/window.c
2021-11-09 19:51:03 -06:00

211 lines
6.9 KiB
C

/*
* Kangaroo Punch MultiPlayer 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 windowAllDeactivate(WidgetT *widget);
static void windowDel(WidgetT **widget);
static void windowMouseEvent(WidgetT *widget, MouseT *mouse, uint16_t x, uint16_t y, uint8_t event);
static void windowPaint(WidgetT *widget, RectT pos);
void windowActiveSet(WindowT *window) {
size_t len;
int16_t i;
WidgetT *parent = W(window)->parent;
WidgetT *child;
// Deactivate all windows.
windowAllDeactivate(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;
}
static void windowAllDeactivate(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);
guiWidgetAndChildrenDirtySet(widget);
}
// Process any children.
if (len > 0) {
for (x=0; x<len; x++) {
windowAllDeactivate(widget->children[x]);
}
}
}
static void windowDel(WidgetT **widget) {
WindowT *w = (WindowT *)*widget;
surfaceDestroy(&w->base.surface);
arrfree(w->base.children);
if (w->title) free(w->title);
free(w);
w = NULL;
*widget = W(w);
}
WidgetT *windowInit(WidgetT *window, char *title) {
WindowT *win = (WindowT *)window;
win->base.delMethod = windowDel;
win->base.paintMethod = windowPaint;
win->base.mouseEventMethod = windowMouseEvent;
win->flags = 0;
win->title = NULL;
windowTitleSet(win, title);
GUI_SET_FLAG(window, WIDGET_FLAG_OWNS_SURFACE);
win->base.surface = surfaceCreate(win->base.pos.w, win->base.pos.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)) windowActiveSet(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.pos.x;
_guiDragOffsetY = mouse->y - window->base.pos.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.pos.x = mouse->x - _guiDragOffsetX;
window->base.pos.y = mouse->y - _guiDragOffsetY;
// Keep it on the screen.
if (window->base.pos.x < 0) window->base.pos.x = 0;
if (window->base.pos.x + window->base.pos.w > vbeDisplayWidthGet()) window->base.pos.x = vbeDisplayWidthGet() - window->base.pos.w;
if (window->base.pos.y < 0) window->base.pos.y = 0;
if (window->base.pos.y + window->base.pos.h > vbeDisplayHeightGet()) window->base.pos.y = vbeDisplayHeightGet() - window->base.pos.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(W(window), MAGIC_WINDOW, x, y, w, h,
_guiMetric[METRIC_WINDOW_BORDER_WIDTH] + 3,
_guiMetric[METRIC_WINDOW_TITLE_GRAB_HEIGHT],
_guiMetric[METRIC_WINDOW_BORDER_WIDTH] + 4,
_guiMetric[METRIC_WINDOW_BORDER_WIDTH] + 4);
if (!widget) {
free(window);
return NULL;
}
window = (WindowT *)windowInit((WidgetT *)window, title);
return window;
}
static void windowPaint(WidgetT *widget, RectT pos) {
WindowT *w = (WindowT *)widget;
uint16_t x2;
uint16_t y2;
ColorT background;
ColorT text;
if (GUI_GET_FLAG(widget, WIDGET_FLAG_DIRTY)) {
x2 = pos.w - 1;
y2 = pos.h - 1;
background = GUI_GET_FLAG(widget, WIDGET_FLAG_ACTIVE) ? _guiColor[COLOR_WINDOW_TITLE_ACTIVE] : _guiColor[COLOR_WINDOW_TITLE_INACTIVE];
text = GUI_GET_FLAG(widget, WIDGET_FLAG_ACTIVE) ? _guiColor[COLOR_WINDOW_TITLE_TEXT_ACTIVE] : _guiColor[COLOR_WINDOW_TITLE_TEXT_INACTIVE];
// Background.
surfaceClear(_guiColor[COLOR_WINDOW_BACKGROUND]);
// Outer edge.
surfaceHighlightFrameDraw(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.
surfaceHighlightFrameDraw(_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.
surfaceHighlightFrameDraw(_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]);
surfaceRectangleFilledDraw(_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 windowTitleSet(WindowT *window, char *title) {
if (window->title) free(window->title);
window->title = strdup(title);
}