/*
* 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;
}