211 lines
6.9 KiB
C
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);
|
|
}
|