/* * 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 . * */ /* * To Do: * * - Replace any direct data manipulation from outside a class with methods to handle it * - More widget states: Ghosted, hidden * - Methods that can change the width of a widget (such as setTitle) need to repaint the parent window as well * - Metrics, colors, etc. should be defined in each widget and not in GUI * - Widgets should support a "changed" callback that can cancel the change * - Use LabelT in all widgets that have a label * - Find a light grey to replace white widget data areas * - No thumb in listbox scrollbar * - Window dragging is being screwball * * - Random crash on exit - looks memwatch / task related - hasn't happened on DOS yet */ #include "stddclmr.h" #include "os.h" #include "vesa.h" #include "surface.h" #include "mouse.h" #include "keyboard.h" #include "task.h" #include "image.h" #include "font.h" #include "timer.h" #include "gui.h" #include "widget.h" #include "desktop.h" #include "window.h" #include "button.h" #include "label.h" #include "checkbox.h" #include "radio.h" #include "picture.h" #include "frame.h" #include "textbox.h" #include "updown.h" #include "listbox.h" #include "terminal.h" #include "taglist.h" static TerminalT *t1 = NULL; static uint8_t lastKey = 0; static void buttonClick(WidgetT *widget); static void mainLoop(void *data); //static void test(void *data); static void testTagList(void *data); static void testTerminal(void *data); static void widgetDebugDraw(WidgetT *widget, uint8_t debugToggle); static void buttonClick(WidgetT *widget) { logWrite("'%s' was clicked.\n", ((ButtonT *)widget)->title); } static void mainLoop(void *data) { MouseT *mouse = NULL; ImageT *pointer = NULL; ColorT alpha; int8_t key = 0; int8_t debugState = 0; (void)data; pointer = imageLoad("mouse.png"); alpha = imagePixelGet(pointer, 5, 0); do { timerUpdate(); mouse = mouseRead(); if (keyHit()) { key = keyASCIIGet(); lastKey = key; //***DEBUG*** guiKeyboardProcess(keyASCIIGet(), keyExtendedGet(), keyScanCodeGet(), keyShiftGet(), keyControlGet(), keyAltGet()); //logWrite("Key '%d' Extended '%d' Scancode '%d' Shift '%d' Control '%d' Alt '%d'\n", key, keyExtended(), keyScanCode(), keyShift(), keyControl(), keyAlt()); } else { key = 0; } guiMouseProcess(mouse); guiComposite(); imageRenderWithAlpha(pointer, mouse->x, mouse->y, alpha); if (key == '=') guiWidgetTreeDump(guiRootGet(), 0); if (key == '+') { debugState++; if (debugState > 2) debugState = 0; } if (debugState > 0) widgetDebugDraw(guiRootGet(), debugState - 1); //if (timerHalfSecondOn) guiDrawRectangle(0, 0, vbeSurfaceWidthGet() - 1, vbeSurfaceHeightGet() - 1, vbeMakeColor(255, 255, 255)); vbeVBlankWait(); vbePresent(); taskYield(); } while (key != 27); // Exit on ESC. imageUnload(&pointer); } /* static void test(void *data) { DesktopT *desktop = (DesktopT *)guiRootGet(); WindowT *w1 = NULL; WindowT *w2 = NULL; WindowT *w3 = NULL; WindowT *w4 = NULL; ButtonT *b1 = NULL; LabelT *l1 = NULL; CheckboxT *c1 = NULL; RadioT *r1a = NULL; RadioT *r2a = NULL; RadioT *r3a = NULL; RadioT *r1b = NULL; RadioT *r2b = NULL; RadioT *r3b = NULL; PictureT *p1 = NULL; FrameT *f1 = NULL; TextboxT *tb1 = NULL; TextboxT *tb2 = NULL; UpdownT *u1 = NULL; ListboxT *lb1 = NULL; (void)data; // Windows w1 = windowNew(300, 25, 300, 200, "Window 1"); guiAttach(W(desktop), W(w1)); w2 = windowNew(150, 150, 300, 200, "Window 2"); guiAttach(W(desktop), W(w2)); w3 = windowNew(300, 300, 300, 200, "Window 3"); guiAttach(W(desktop), W(w3)); w4 = windowNew(10, 10, 7 + 8 + (80 * 8), 26 + 8 + (24 * 14), "Terminal"); guiAttach(W(desktop), W(w4)); // Window 1 p1 = pictureNew(0, 0, "kanga.png"); guiAttach(W(w1), W(p1)); lb1 = listboxNew(155, 10, 120, 140, "List Box"); listboxItemAdd(lb1, "One"); listboxItemAdd(lb1, "Two"); listboxItemAdd(lb1, "Three"); listboxItemAdd(lb1, "Four"); listboxItemAdd(lb1, "Five"); listboxItemAdd(lb1, "Six"); listboxItemAdd(lb1, "Seven"); listboxItemAdd(lb1, "Eight"); listboxItemAdd(lb1, "Nine"); listboxItemAdd(lb1, "Ten"); listboxStepSet(lb1, 3); guiAttach(W(w1), W(lb1)); // Window 2 r1a = radioNew(10, 10, "Radio 1a", 1); guiAttach(W(w2), W(r1a)); r2a = radioNew(20 + widgetWidthGet(W(r1a)), 10, "Radio 2a", 1); guiAttach(W(w2), W(r2a)); r3a = radioNew(30 + widgetWidthGet(W(r1a)) + widgetWidthGet(W(r2a)), 10, "Radio 3a", 1); guiAttach(W(w2), W(r3a)); r1b = radioNew(10, 35, "Radio 1b", 2); guiAttach(W(w2), W(r1b)); r2b = radioNew(20 + widgetWidthGet(W(r1b)), 35, "Radio 2b", 2); guiAttach(W(w2), W(r2b)); r3b = radioNew(30 + widgetWidthGet(W(r1b)) + widgetWidthGet(W(r2b)), 35, "Radio 3b", 2); guiAttach(W(w2), W(r3b)); radioSelectedSet(r1a); radioSelectedSet(r2b); tb1 = textboxNew(10, 60, 265, "Test Textbox"); textboxValueSet(tb1, "Really long text string to edit!"); guiAttach(W(w2), W(tb1)); tb2 = textboxNew(10, 85, 265, "Test Textbox"); textboxValueSet(tb2, "Short string."); guiAttach(W(w2), W(tb2)); u1 = updownNew(10, 110, 0, 1024, 5, "UpDown"); guiAttach(W(w2), W(u1)); // Window 3 f1 = frameNew(10, 5, 175, 125, "Test Frame"); guiAttach(W(w3), W(f1)); b1 = buttonNew(0, 0, "Test Button", buttonClick); guiAttach(W(f1), W(b1)); l1 = labelNew(10, 40, "Test Label"); guiAttach(W(f1), W(l1)); c1 = checkboxNew(10, 65, "Test Checkbox"); guiAttach(W(f1), W(c1)); // Window 4 - Terminal t1 = terminalNew(0, 0, 80, 24); guiAttach(W(w4), W(t1)); taskCreate(testTerminal, "terminalTest"); } */ static void testTagList(void *data) { WindowT *w1 = NULL; WindowT *w2 = NULL; WindowT *w3 = NULL; WindowT *w4 = NULL; ButtonT *b1 = NULL; LabelT *l1 = NULL; CheckboxT *c1 = NULL; RadioT *r1a = NULL; RadioT *r2a = NULL; RadioT *r3a = NULL; RadioT *r1b = NULL; RadioT *r2b = NULL; RadioT *r3b = NULL; PictureT *p1 = NULL; FrameT *f1 = NULL; TextboxT *tb1 = NULL; TextboxT *tb2 = NULL; UpdownT *u1 = NULL; ListboxT *lb1 = NULL; (void)data; TagItemT ui[] = { T_START, T_WINDOW, O(w1), T_TITLE, P("Window 1"), T_X, 300, T_Y, 25, T_WIDTH, 300, T_HEIGHT, 200, T_PICTURE, O(p1), T_X, 0, T_Y, 0, T_FILENAME, P("kanga.png"), T_PICTURE, T_DONE, T_LISTBOX, O(lb1), T_TITLE, P("Listbox"), T_X, 155, T_Y, 10, T_WIDTH, 120, T_HEIGHT, 140, T_ITEM, P("One"), T_ITEM, P("Two"), T_ITEM, P("Three"), T_ITEM, P("Four"), T_ITEM, P("Five"), T_ITEM, P("Six"), T_ITEM, P("Seven"), T_ITEM, P("Eight"), T_ITEM, P("Nine"), T_ITEM, P("Ten"), T_STEP, 3, T_LISTBOX, T_DONE, T_WINDOW, T_DONE, T_WINDOW, O(w2), T_TITLE, P("Window 2"), T_X, 150, T_Y, 150, T_WIDTH, 300, T_HEIGHT, 200, T_RADIOBUTTON, O(r1a), T_TITLE, P("Radio 1a"), T_X, 10, T_Y, 10, T_GROUP, 1, T_SELECTED, 1, T_RADIOBUTTON, T_DONE, T_RADIOBUTTON, O(r2a), T_TITLE, P("Radio 2a"), T_X, 20 + 80, T_Y, 10, T_GROUP, 1, T_RADIOBUTTON, T_DONE, T_RADIOBUTTON, O(r3a), T_TITLE, P("Radio 3a"), T_X, 30 + 80 * 2, T_Y, 10, T_GROUP, 1, T_RADIOBUTTON, T_DONE, T_RADIOBUTTON, O(r1b), T_TITLE, P("Radio 1b"), T_X, 10, T_Y, 35, T_GROUP, 2, T_RADIOBUTTON, T_DONE, T_RADIOBUTTON, O(r2b), T_TITLE, P("Radio 2b"), T_X, 20 + 80, T_Y, 35, T_GROUP, 2, T_SELECTED, 1, T_RADIOBUTTON, T_DONE, T_RADIOBUTTON, O(r3b), T_TITLE, P("Radio 3b"), T_X, 30 + 80 * 2, T_Y, 35, T_GROUP, 2, T_RADIOBUTTON, T_DONE, T_TEXTBOX, O(tb1), T_TITLE, P("Test Textbox"), T_X, 10, T_Y, 60, T_WIDTH, 265, T_VALUE, P("Really long text string to edit!"), T_TEXTBOX, T_DONE, T_TEXTBOX, O(tb2), T_TITLE, P("Test Textbox"), T_X, 10, T_Y, 85, T_WIDTH, 265, T_VALUE, P("Short String."), T_TEXTBOX, T_DONE, T_UPDOWN, O(u1), T_TITLE, P("UpDown"), T_X, 10, T_Y, 120, T_MINIMUM, 0, T_MAXIMUM, 1024, T_STEP, 5, T_UPDOWN, T_DONE, T_WINDOW, T_DONE, T_WINDOW, O(w3), T_TITLE, P("Window 3"), T_X, 300, T_Y, 300, T_WIDTH, 300, T_HEIGHT, 200, T_FRAME, O(f1), T_TITLE, P("Test Frame"), T_X, 10, T_Y, 5, T_WIDTH, 175, T_HEIGHT, 125, T_BUTTON, O(b1), T_TITLE, P("Test Button"), T_X, 0, T_Y, 0, T_CLICK, P(buttonClick), T_BUTTON, T_DONE, T_LABEL, O(l1), T_TITLE, P("Test Label"), T_X, 10, T_Y, 40, T_LABEL, T_DONE, T_CHECKBOX, O(c1), T_TITLE, P("Test Checkbox"), T_X, 10, T_Y, 65, T_CHECKBOX, T_DONE, T_FRAME, T_DONE, T_WINDOW, T_DONE, T_WINDOW, O(w4), T_TITLE, P("Terminal"), T_X, 10, T_Y, 10, T_WIDTH, 7 + 8 + (80 * 8), T_HEIGHT, 26 + 8 + (24 * 14), T_TERMINAL, O(t1), T_X, 0, T_Y, 0, T_WIDTH, 80, T_HEIGHT, 24, T_TERMINAL, T_DONE, T_WINDOW, T_DONE, T_END }; tagListRun(ui); taskCreate(testTerminal, "terminalTest"); } static void testTerminal(void *data) { FILE *in = NULL; char *buffer = NULL; uint16_t length = 0; (void)data; // Load ANSI file for terminal test. in = fopen("kanga.ans", "rt"); fseek(in, 0, SEEK_END); length = ftell(in); fseek(in, 0, SEEK_SET); buffer = (char *)malloc(length + 1); fread(buffer, 1, length, in); fclose(in); buffer[length] = 0; terminalStringPrint(t1, buffer); free(buffer); } static void widgetDebugDraw(WidgetT *widget, uint8_t debugToggle) { size_t len = arrlenu(widget->children); size_t i; RectT r; if (debugToggle) { // Clipping region (blue) guiWidgetBoundsDrawableOnScreenGet(widget, &r); surfaceRectangleDraw(r.x, r.y, r.x + r.w, r.y + r.h, vbeColorMake(0, 0, 255)); } else { // Widget border (red) guiWidgetPositionOnScreenGet(widget, &r); surfaceRectangleDraw(r.x, r.y, r.x + widget->pos.w, r.y + widget->pos.h, vbeColorMake(255, 0, 0)); } if (len > 0) { for (i=0; ichildren[i], debugToggle); } } } int main(int argc, char *argv[]) { uint16_t xResolution = 0; uint16_t yResolution = 0; uint16_t colorDepth = 0; char logName[32] = { "log.log" }; char *c = NULL; int16_t x = strlen(argv[0]); memoryStartup(); // 0 1 2 3 4 5 6 7 8 // 12345678901234567890123456789012345678901234567890123456789012345678901234567890 printf("Kangaroo Punch MultiPlayer DOS Game Client Mark II\n"); printf("Copyright (C) 2020-2021 Scott Duensing scott@kangaroopunch.com\n\n"); fflush(stdout); // Find last portion of filename. while (x > 0) { if (argv[0][x] == '/' || argv[0][x] == '\\') break; x--; } if (strlen(argv[0]) - x < 32) { // Replace any extension with ".log" strncpy(logName, &argv[0][x + 1], 31); c = strstr(logName, "."); if (c) *c = 0; strncat(logName, ".log", 31); } logOpen(logName, 0); // Command line needs to have the desired resolution and color depth on it. if (argc != 4) { vbeInfoShow(); fflush(stdout); memoryShutdown(); return 0; } xResolution = atoi(argv[1]); yResolution = atoi(argv[2]); colorDepth = atoi(argv[3]); // Do we have the video mode they asked for? if (vbeStartup(xResolution, yResolution, colorDepth)) { fflush(stdout); memoryShutdown(); return 1; } surfaceStartup(); mouseStartup(); timerStartup(); guiStartup(); taskStartup(); taskCreate(testTagList, "testTagList"); taskCreate(mainLoop, "mainLoop"); taskRun(); taskShutdown(); guiShutdown(); timerShutdown(); mouseShutdown(); surfaceShutdown(); vbeShutdown(); logClose(); memoryShutdown(); return 0; }