/* * 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 . * */ #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; xchildren[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); }