/* * 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 "radio.h" static void radioClearSelectedInGroup(WidgetT *widget, uint32_t group); static RadioT *radioFindSelectedInGroup(WidgetT *widget, uint32_t group); static void radioMouseEvent(WidgetT *widget, MouseT *mouse, uint16_t x, uint16_t y, uint8_t event); static void radioPaint(WidgetT *widget, RectT pos); static void radioClearSelectedInGroup(WidgetT *widget, uint32_t group) { size_t len = arrlenu(widget->children); size_t x; // Is this a Radio Button? if (widget->magic == MAGIC_RADIOBUTTON) { // Is this in our group and active? if (((RadioT *)widget)->group == group && GUI_GET_FLAG(widget, WIDGET_FLAG_ACTIVE)) { // Deactivate it, mark it dirty, and stop searching. GUI_CLEAR_FLAG(widget, WIDGET_FLAG_ACTIVE); GUI_SET_FLAG(widget, WIDGET_FLAG_DIRTY); return; } } // Process any children. if (len > 0) { for (x=0; xchildren[x], group); } } } void radioDel(WidgetT **widget) { RadioT *r = (RadioT *)*widget; if (r->title) free(r->title); free(r); r = NULL; } static RadioT *radioFindSelectedInGroup(WidgetT *widget, uint32_t group) { size_t len = arrlenu(widget->children); size_t x; RadioT *result = NULL; // Is this a Radio Button? if (widget->magic == MAGIC_RADIOBUTTON) { // Is this in our group and active? if (((RadioT *)widget)->group == group && GUI_GET_FLAG(widget, WIDGET_FLAG_ACTIVE)) { // Found! Stop searching. return (RadioT *)widget; } } // Process any children. if (len > 0) { for (x=0; xchildren[x], group); if (result) break; } } return result; } RadioT *radioGetSelected(RadioT *radio) { return radioFindSelectedInGroup(guiRootGet(), radio->group); } WidgetT *radioInit(WidgetT *widget, char *title, uint16_t group) { RadioT *r = (RadioT *)widget; r->base.delMethod = radioDel; r->base.paintMethod = radioPaint; r->base.mouseEventMethod = radioMouseEvent; r->title = NULL; r->clicked = NULL; r->group = group; radioSetTitle(r, title); // Width is set in radioSetTitle r->base.pos.h = fontHeightGet(_guiFont); return widget; } static void radioMouseEvent(WidgetT *widget, MouseT *mouse, uint16_t x, uint16_t y, uint8_t event) { RadioT *r = (RadioT *)widget; (void)x; (void)y; (void)mouse; if (event == MOUSE_EVENT_LEFT_UP) { // Select us. radioSetSelected(r); // Fire callback on mouse up. if (r->clicked) r->clicked(widget); } } RadioT *radioNew(uint16_t x, uint16_t y, char *title, uint16_t group) { RadioT *radio = (RadioT *)malloc(sizeof(RadioT)); WidgetT *widget = NULL; if (!radio) return NULL; // We set the widget width and height in Init. widget = widgetInit(W(radio), MAGIC_RADIOBUTTON, x, y, 0, 0, 0, 0, 0, 0); if (!widget) { free(radio); return NULL; } radio = (RadioT *)radioInit((WidgetT *)radio, title, group); return radio; } static void radioPaint(WidgetT *widget, RectT pos) { RadioT *r = (RadioT *)widget; int16_t i; int16_t o; uint8_t active; ColorT highlight; ColorT shadow; ColorT fill; if (GUI_GET_FLAG(widget, WIDGET_FLAG_DIRTY)) { active = (radioGetSelected(r) == r); highlight = active ? _guiColor[COLOR_RADIOBUTTON_SHADOW] : _guiColor[COLOR_RADIOBUTTON_HIGHLIGHT]; shadow = active ? _guiColor[COLOR_RADIOBUTTON_HIGHLIGHT] : _guiColor[COLOR_RADIOBUTTON_SHADOW]; fill = active ? _guiColor[COLOR_RADIOBUTTON_ACTIVE] : _guiColor[COLOR_RADIOBUTTON_INACTIVE]; // Radio button is 10x10 pixels. Find offset based on font height. o = (_guiFont->height - 10) * 0.5; // Draw outline of radio button. guiDrawLine(pos.x, pos.y + o + 5, pos.x + 5, pos.y + o, highlight); guiDrawLine(pos.x + 5, pos.y + o, pos.x + 10, pos.y + o + 5, highlight); guiDrawLine(pos.x, pos.y + o + 5, pos.x + 5, pos.y + o + 10, shadow); guiDrawLine(pos.x + 5, pos.y + o + 10, pos.x + 10, pos.y + o + 5, shadow); // Fill radio button. for (i=0; i<4; i++) { guiDrawLine(pos.x + 5 - i, pos.y + o + i + 1, pos.x + 5 + i, pos.y + o + i + 1, fill); guiDrawLine(pos.x + 5 - i, pos.y + o - i + 8, pos.x + 5 + i, pos.y + o - i + 8, fill); } // Draw title. fontRender(_guiFont, r->title, _guiColor[COLOR_RADIOBUTTON_TEXT], _guiColor[COLOR_WINDOW_BACKGROUND], pos.x + 10 + _guiMetric[METRIC_RADIOBUTTON_PADDING], pos.y); GUI_CLEAR_FLAG(widget, WIDGET_FLAG_DIRTY); } } void radioSetClickHandler(RadioT *radio, widgetCallback callback) { radio->clicked = callback; } void radioSetSelected(RadioT *radio) { // Are we already selected? if (!GUI_GET_FLAG((WidgetT *)radio, WIDGET_FLAG_ACTIVE)) { // Clear whoever is selected. radioClearSelectedInGroup(guiRootGet(), radio->group); // Select us. GUI_SET_FLAG((WidgetT *)radio, WIDGET_FLAG_ACTIVE); GUI_SET_FLAG((WidgetT *)radio, WIDGET_FLAG_DIRTY); } } void radioSetTitle(RadioT *radio, char *title) { if (radio->title) free(radio->title); radio->title = strdup(title); radio->base.pos.w = (strlen(title) * fontWidthGet(_guiFont)) + 10 + _guiMetric[METRIC_RADIOBUTTON_PADDING]; GUI_SET_FLAG((WidgetT *)radio, WIDGET_FLAG_DIRTY); }