diff --git a/client/client.pro b/client/client.pro
index 22a794c..b34173e 100644
--- a/client/client.pro
+++ b/client/client.pro
@@ -16,6 +16,9 @@
# along with this program. If not, see .
#
+# NOTE: You'll occasionally find a file with a capital "C" extension.
+# These are C files that we want ignored by the DOS compiler.
+
TEMPLATE = app
CONFIG -= qt
@@ -47,14 +50,16 @@ INCLUDEPATH += \
HEADERS = \
$$LINUX_HEADERS \
+ src/settings.h \
src/system/color.h \
+ src/system/memory.h \
src/system/surface.h \
src/system/taglist.h \
+ src/test.h \
src/thirdparty/stb_ds.h \
src/thirdparty/stb_image.h \
src/thirdparty/memwatch/memwatch.h \
src/thirdparty/minicoro/minicoro.h \
- src/system/memory.h \
src/system/keyboard.h \
src/system/task.h \
src/system/timer.h \
@@ -80,14 +85,17 @@ HEADERS = \
src/gui/widget.h \
src/gui/window.h \
src/gui/image.h \
- src/stddclmr.h
+ src/stddclmr.h \
+ src/welcome.h
SOURCES = \
$$LINUX_SOURCES \
+ src/system/memory.c \
+ src/thirdparty/memwatch/memwatch.c \
+ src/settings.c \
src/system/surface.c \
src/system/taglist.c \
- src/thirdparty/memwatch/memwatch.c \
- src/system/memory.c \
+ src/test.c \
src/system/array.c \
src/system/log.c \
src/system/timer.c \
@@ -108,7 +116,8 @@ SOURCES = \
src/gui/button.c \
src/gui/checkbox.c \
src/gui/label.c \
- src/main.c
+ src/main.c \
+ src/welcome.c
LIBS = \
-lSDL2 \
diff --git a/client/data/dconnect.png b/client/data/dconnect.png
new file mode 100644
index 0000000..31330eb
--- /dev/null
+++ b/client/data/dconnect.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:c7746b1b9f31d50cde41a84a371ead61a0f65fcbaf4a9a48f552d54dc4fcdbe5
+size 656
diff --git a/client/data/ddialing.png b/client/data/ddialing.png
new file mode 100644
index 0000000..d42a95b
--- /dev/null
+++ b/client/data/ddialing.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:7b3d3e7c4b135a0afb65636dbd016bb34263114c3c4b0523ca16f06d635dd0d9
+size 660
diff --git a/client/data/dinit.png b/client/data/dinit.png
new file mode 100644
index 0000000..6996c6b
--- /dev/null
+++ b/client/data/dinit.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:807dd015d2dee994756070fc2e65557a61b24b74e2798885d6c0075713fa8b5b
+size 576
diff --git a/client/data/logo.png b/client/data/logo.png
new file mode 100644
index 0000000..a23cd7f
--- /dev/null
+++ b/client/data/logo.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:a930ea0207e47bef4d95472fded1324b918fbcd29d41bc732d2b8cf964f27f62
+size 985
diff --git a/client/src/gui/button.c b/client/src/gui/button.c
index d28054a..20deb45 100644
--- a/client/src/gui/button.c
+++ b/client/src/gui/button.c
@@ -34,11 +34,7 @@ void buttonClickHandlerSet(ButtonT *button, widgetCallback callback) {
static void buttonDel(WidgetT **widget) {
ButtonT *b = (ButtonT *)*widget;
- arrfree(b->base.children);
if (b->title) free(b->title);
- free(b);
- b = NULL;
- *widget = W(b);
}
diff --git a/client/src/gui/checkbox.c b/client/src/gui/checkbox.c
index 43b436b..05886af 100644
--- a/client/src/gui/checkbox.c
+++ b/client/src/gui/checkbox.c
@@ -34,11 +34,7 @@ void checkboxClickHandlerSet(CheckboxT *checkbox, widgetCallback callback) {
static void checkboxDel(WidgetT **widget) {
CheckboxT *c = (CheckboxT *)*widget;
- arrfree(c->base.children);
if (c->title) free(c->title);
- free(c);
- c = NULL;
- *widget = W(c);
}
diff --git a/client/src/gui/desktop.c b/client/src/gui/desktop.c
index 4eaa990..fb5bd15 100644
--- a/client/src/gui/desktop.c
+++ b/client/src/gui/desktop.c
@@ -22,26 +22,13 @@
#include "window.h"
-static void desktopDel(WidgetT **widget);
static void desktopPaint(WidgetT *desktop, RectT pos);
-static void desktopDel(WidgetT **widget) {
- DesktopT *d = (DesktopT *)*widget;
-
- arrfree(d->base.children);
- surfaceDestroy(&d->base.surface);
- free(d);
- d = NULL;
- *widget = W(d);
-}
-
-
WidgetT *desktopInit(WidgetT *desktop) {
DesktopT *d = (DesktopT *)desktop;
d->base.magic = MAGIC_DESKTOP;
- d->base.delMethod = desktopDel;
d->base.paintMethod = desktopPaint;
GUI_SET_FLAG(desktop, WIDGET_FLAG_OWNS_SURFACE);
diff --git a/client/src/gui/frame.c b/client/src/gui/frame.c
index c63aa7d..16e8199 100644
--- a/client/src/gui/frame.c
+++ b/client/src/gui/frame.c
@@ -28,11 +28,7 @@ static void framePaint(WidgetT *widget, RectT pos);
static void frameDel(WidgetT **widget) {
FrameT *f = (FrameT *)*widget;
- arrfree(f->base.children);
if (f->title) free(f->title);
- free(f);
- f = NULL;
- *widget = W(f);
}
diff --git a/client/src/gui/gui.c b/client/src/gui/gui.c
index 5fd2d80..f370ce9 100644
--- a/client/src/gui/gui.c
+++ b/client/src/gui/gui.c
@@ -39,10 +39,12 @@ uint16_t _guiDragOffsetY = 0;
WindowT *_guiActiveWindow = NULL;
-static DesktopT *_guiDesktop = NULL;
-static WidgetT *_guiLastWidgetLeft = NULL;
-static uint8_t _guiLastWidgetLeftEvent = MOUSE_EVENT_NONE;
-static WidgetT *_guiFocused = NULL;
+static DesktopT *_guiDesktop = NULL;
+static WidgetT *_guiLastWidgetLeft = NULL;
+static uint8_t _guiLastWidgetLeftEvent = MOUSE_EVENT_NONE;
+static WidgetT *_guiFocused = NULL;
+static uint8_t _guiHasStopped = 0;
+static WidgetT ***_guiDeleteList = NULL;
// Widget Magic Debug Info
@@ -63,6 +65,8 @@ static char *_magicDebugNames[MAGIC_COUNT] = {
};
+static void guiDeleteList(void);
+static void guiDeleteListItem(WidgetT **widget);
static void guiPaintBoundsGet(WidgetT *widget, RectT *pos);
static void guiKeyboardChildrenProcess(WidgetT *widget, uint8_t ascii, uint8_t extended, uint8_t scancode, uint8_t shift, uint8_t control, uint8_t alt);
static uint8_t guiMouseChildrenProcess(WidgetT *widget, MouseT *mouse);
@@ -120,7 +124,7 @@ void guiAttach(WidgetT *parent, WidgetT *child) {
void guiComposite() {
WidgetT *widget = (WidgetT *)_guiDesktop;
- size_t len = arrlenu(widget->children);
+ size_t len;
size_t x;
// Repaint anyone who needs it.
@@ -133,9 +137,8 @@ void guiComposite() {
surfaceBlit(widget->surface, widget->pos.x, widget->pos.y);
}
- //***TODO*** This is wrong. Should be recursive.
-
// Now render all surface-containing children to the VBE buffer.
+ len = arrlenu(widget->children);
if (len > 0) {
for (x=0; xchildren[x], WIDGET_FLAG_OWNS_SURFACE)) {
@@ -146,20 +149,113 @@ void guiComposite() {
}
+void guiDebugAreaShow(WidgetT *widget) {
+ RectT r;
+
+ guiWidgetBoundsDrawableOnScreenGet(widget, &r);
+ logWrite("%s: %dx%d\n", _magicDebugNames[widget->magic], r.w, r.h);
+}
+
+
+void guiDebugWidgetTreeDump(WidgetT *widget, uint16_t depth) {
+ size_t len = arrlenu(widget->children);
+ size_t x;
+ char line[256];
+
+ for (x=0; xmagic],
+ widget->pos.x, widget->pos.y, widget->pos.w, widget->pos.h,
+ widget->margin.x, widget->margin.y, widget->margin.w, widget->margin.h,
+ widget->clip.x, widget->clip.y, widget->clip.w, widget->clip.h,
+ widget->flags);
+
+ // Mark all children.
+ if (len > 0) {
+ for (x=0; xchildren[x], depth + 1);
+ }
+ }
+}
+
+
void guiDelete(WidgetT **widget) {
- WidgetT *w = *widget;
- size_t len = arrlenu(w->children);
- size_t x = 0;
+ // Since deleting happens in widget events, it's not safe to do it
+ // immediately. Instead, we make a list of what to delete and
+ // then process it before painting.
+ arrput(_guiDeleteList, widget);
+}
+
+
+static void guiDeleteList(void) {
+ WidgetT **w = NULL;
+
+ while (arrlen(_guiDeleteList) > 0) {
+ w = arrpop(_guiDeleteList);
+ guiDeleteListItem(w);
+ }
+
+ arrfree(_guiDeleteList);
+ _guiDeleteList = NULL;
+}
+
+
+static void guiDeleteListItem(WidgetT **widget) {
+ WidgetT *w = *widget;
+ size_t len = arrlenu(w->children);
+ size_t plen = arrlen(w->parent != NULL ? w->parent->children : 0);
+ size_t x = 0;
+ uint8_t nuke = 1;
+ static uint16_t depth = 0;
// Delete children.
if (len > 0) {
for (x=0; xchildren[x]);
+ depth++;
+ guiDeleteListItem(&w->children[x]);
+ depth--;
}
}
+ // Remove us from parent children list.
+ if (depth == 0) {
+ if (plen > 0) {
+ for (x=0; xparent->children[x]) {
+ arrdel(w->parent->children, x);
+ break;
+ }
+ }
+ // Was this the last child in the list?
+ if (plen == 1) {
+ // Erase the list.
+ arrfree(w->parent->children);
+ w->parent->children = NULL;
+ }
+ }
+ }
+
+ // If we were involved in a mouse event, get out of it.
+ if (w == _guiLastWidgetLeft) _guiLastWidgetLeft = NULL;
+ if (w == _guiFocused) _guiFocused = NULL;
+
// Delete us.
- w->delMethod(&w);
+ //logWrite("Deleting %s %p\n", _magicDebugNames[w->magic], w);
+ if (w->delMethod != NULL) w->delMethod(&w);
+ arrfree(w->children);
+ if (w->surface != NULL) {
+ // Only free the surface if we own it. If it's our parent's, ignore.
+ if (w->parent != NULL) {
+ if (w->surface == w->parent->surface) nuke = 0;
+ }
+ if (nuke) surfaceDestroy(&w->surface);
+ }
+ free(w);
+ w = NULL;
+ *widget = w;
// Make sure we're not drawing into oblivion.
surfaceSet(NULL);
@@ -195,6 +291,11 @@ void guiFocusSet(WidgetT *widget) {
}
+uint8_t guiHasStopped(void) {
+ return _guiHasStopped;
+}
+
+
static void guiKeyboardChildrenProcess(WidgetT *widget, uint8_t ascii, uint8_t extended, uint8_t scancode, uint8_t shift, uint8_t control, uint8_t alt) {
size_t len;
size_t x;
@@ -246,21 +347,13 @@ static uint8_t guiMouseChildrenProcess(WidgetT *widget, MouseT *mouse) {
uint8_t event = MOUSE_EVENT_NONE;
static WidgetT *focusDown = NULL;
- // Search children backwards for active widget before checking this widget.
- len = arrlenu(widget->children);
- for (x=len-1; x>=0; --x) {
- if (guiMouseChildrenProcess(widget->children[x], mouse)) {
- return 1;
- }
- }
-
// Get widget and screen coordinates of pointer.
guiWidgetPositionOnScreenGet(widget, &r);
sx = r.x;
sy = r.y;
guiMousePositionOnWidgetGet(widget, mouse, &mx, &my);
- //logWrite("Mouse %dx%d Widget %s %dx%d\n", mouse->x, mouse->y, MagicDebugNames[widget->magic], sx, sy);
+ //logWrite("Mouse %dx%d Widget %s %dx%d Screen %dx%d\n", mouse->x, mouse->y, _magicDebugNames[widget->magic], mx, my, sx, sy);
// Serious hack to make window dragging work better.
// This is because it's possible to move the mouse faster than METRIC_WINDOW_TITLE_GRAB_HEIGHT pixels
@@ -270,6 +363,14 @@ static uint8_t guiMouseChildrenProcess(WidgetT *widget, MouseT *mouse) {
return 1;
}
+ // Search children backwards for active widget before checking this widget.
+ len = arrlenu(widget->children);
+ for (x=len-1; x>=0; --x) {
+ if (guiMouseChildrenProcess(widget->children[x], mouse)) {
+ return 1;
+ }
+ }
+
// Is the mouse inside this widget?
if (mouse->x >= sx && mouse->y >= sy && mouse->x < sx + widget->pos.w && mouse->y < sy + widget->pos.h) {
@@ -277,7 +378,9 @@ static uint8_t guiMouseChildrenProcess(WidgetT *widget, MouseT *mouse) {
if (_guiLastWidgetLeft != widget) {
// Tell previous widget we're moving out.
- if (_guiLastWidgetLeft->mouseEventMethod) _guiLastWidgetLeft->mouseEventMethod(_guiLastWidgetLeft, mouse, mx, my, MOUSE_EVENT_OUT);
+ if (_guiLastWidgetLeft) {
+ if (_guiLastWidgetLeft->mouseEventMethod) _guiLastWidgetLeft->mouseEventMethod(_guiLastWidgetLeft, mouse, mx, my, MOUSE_EVENT_OUT);
+ }
// Tell new widget we've moved in.
event = MOUSE_EVENT_IN;
@@ -329,10 +432,13 @@ void guiMouseProcess(MouseT *mouse) {
void guiPaint(WidgetT *widget) {
- size_t len = arrlenu(widget->children);
+ size_t len;
size_t x;
RectT pos;
+ // Process any pending widget deletions.
+ guiDeleteList();
+
// Paint us. Widget handles dirty flag so they can animate if needed.
if (widget->paintMethod) {
surfaceSet(widget->surface);
@@ -341,6 +447,7 @@ void guiPaint(WidgetT *widget) {
}
// Paint all children.
+ len = arrlenu(widget->children);
if (len > 0) {
for (x=0; xchildren[x]);
@@ -368,6 +475,19 @@ WidgetT *guiRootGet(void) {
}
+void guiShutdown(void) {
+ // Unload fonts.
+ fontUnload(&_guiFont16);
+ fontUnload(&_guiFont14);
+ fontUnload(&_guiFont8);
+ _guiFont = NULL;
+
+ // Delete all widgets in GUI tree.
+ guiDelete((WidgetT **)&_guiDesktop);
+ guiDeleteList();
+}
+
+
DesktopT *guiStartup(void) {
_guiMetric[METRIC_BUTTON_BEZEL_SIZE] = 2;
@@ -457,15 +577,8 @@ DesktopT *guiStartup(void) {
}
-void guiShutdown(void) {
- // Unload fonts.
- fontUnload(&_guiFont16);
- fontUnload(&_guiFont14);
- fontUnload(&_guiFont8);
- _guiFont = NULL;
-
- // Delete all widgets in GUI tree.
- guiDelete((WidgetT **)&_guiDesktop);
+void guiStop(void) {
+ _guiHasStopped = 1;
}
@@ -525,28 +638,3 @@ void guiWidgetPositionOnScreenGet(WidgetT *widget, RectT *pos) {
}
}
-
-
-void guiWidgetTreeDump(WidgetT *widget, uint16_t depth) {
- size_t len = arrlenu(widget->children);
- size_t x;
- char line[256];
-
- for (x=0; xmagic],
- widget->pos.x, widget->pos.y, widget->pos.w, widget->pos.h,
- widget->margin.x, widget->margin.y, widget->margin.w, widget->margin.h,
- widget->clip.x, widget->clip.y, widget->clip.w, widget->clip.h,
- widget->flags);
-
- // Mark all children.
- if (len > 0) {
- for (x=0; xchildren[x], depth + 1);
- }
- }
-}
diff --git a/client/src/gui/gui.h b/client/src/gui/gui.h
index 848b548..96062f2 100644
--- a/client/src/gui/gui.h
+++ b/client/src/gui/gui.h
@@ -36,6 +36,7 @@
#define GUI_CLEAR_FLAG(w,f) ((w)->flags &= (~(1 << (f))))
#define W(w) ((WidgetT *)w)
+#define D(w) ((WidgetT **)&w)
// Widget Magics
@@ -161,22 +162,25 @@ extern WindowT *_guiActiveWindow;
void guiAttach(WidgetT *parent, WidgetT *child);
void guiComposite(void);
+void guiDebugAreaShow(WidgetT *widget);
+void guiDebugWidgetTreeDump(WidgetT *widget, uint16_t depth);
void guiDelete(WidgetT **widget);
WidgetT *guiFocusGet(void);
void guiFocusSet(WidgetT *widget);
+uint8_t guiHasStopped(void);
void guiKeyboardProcess(uint8_t ascii, uint8_t extended, uint8_t scancode, uint8_t shift, uint8_t control, uint8_t alt);
void guiMousePositionOnWidgetGet(WidgetT *widget, MouseT *mouse, uint16_t *x, uint16_t *y);
void guiMouseProcess(MouseT *mouse);
void guiPaint(WidgetT *widget);
WidgetT *guiRootGet(void);
-DesktopT *guiStartup(void);
void guiShutdown(void);
+DesktopT *guiStartup(void);
+void guiStop(void);
void *guiUserDataGet(WidgetT *widget);
void guiUserDataSet(WidgetT *widget, void *userData);
void guiWidgetAndChildrenDirtySet(WidgetT *widget);
void guiWidgetBoundsDrawableOnScreenGet(WidgetT *widget, RectT *bounds);
void guiWidgetPositionOnScreenGet(WidgetT *widget, RectT *pos);
-void guiWidgetTreeDump(WidgetT *widget, uint16_t depth);
#endif // GUI_H
diff --git a/client/src/gui/label.c b/client/src/gui/label.c
index 766e022..19c28d8 100644
--- a/client/src/gui/label.c
+++ b/client/src/gui/label.c
@@ -52,11 +52,7 @@ void labelColorForegroundSet(LabelT *label, ColorT color) {
static void labelDel(WidgetT **widget) {
LabelT *l = (LabelT *)*widget;
- arrfree(l->base.children);
if (l->title) free(l->title);
- free(l);
- l = NULL;
- *widget = W(l);
}
diff --git a/client/src/gui/listbox.c b/client/src/gui/listbox.c
index b881ef4..9a6a6c4 100644
--- a/client/src/gui/listbox.c
+++ b/client/src/gui/listbox.c
@@ -52,12 +52,6 @@ static void listboxDel(WidgetT **widget) {
}
}
arrfree(l->values);
-
- arrfree(l->base.children);
- if (l->title) free(l->title);
- free(l);
- l = NULL;
- *widget = W(l);
}
diff --git a/client/src/gui/picture.c b/client/src/gui/picture.c
index ec80735..19f0718 100644
--- a/client/src/gui/picture.c
+++ b/client/src/gui/picture.c
@@ -34,12 +34,8 @@ void pictureClickHandlerSet(PictureT *picture, widgetCallback callback) {
static void pictureDel(WidgetT **widget) {
PictureT *p = (PictureT *)*widget;
- arrfree(p->base.children);
if (p->image) imageUnload(&p->image);
if (p->filename) free(p->filename);
- free(p);
- p = NULL;
- *widget = W(p);
}
diff --git a/client/src/gui/radio.c b/client/src/gui/radio.c
index 21860be..638540b 100644
--- a/client/src/gui/radio.c
+++ b/client/src/gui/radio.c
@@ -36,11 +36,7 @@ void radioClickHandlerSet(RadioT *radio, widgetCallback callback) {
static void radioDel(WidgetT **widget) {
RadioT *r = (RadioT *)*widget;
- arrfree(r->base.children);
if (r->title) free(r->title);
- free(r);
- r = NULL;
- *widget = W(r);
}
diff --git a/client/src/gui/terminal.c b/client/src/gui/terminal.c
index d8c6aef..9133dd7 100644
--- a/client/src/gui/terminal.c
+++ b/client/src/gui/terminal.c
@@ -502,11 +502,6 @@ static void terminalDel(WidgetT **widget) {
free(t->cells[x]);
}
free(t->cells);
-
- arrfree(t->base.children);
- free(t);
- t = NULL;
- *widget = W(t);
}
diff --git a/client/src/gui/textbox.c b/client/src/gui/textbox.c
index 1adbd46..66f7f78 100644
--- a/client/src/gui/textbox.c
+++ b/client/src/gui/textbox.c
@@ -32,12 +32,8 @@ static void textboxPaint(WidgetT *widget, RectT pos);
static void textboxDel(WidgetT **widget) {
TextboxT *t = (TextboxT *)*widget;
- arrfree(t->base.children);
if (t->title) free(t->title);
if (t->value) free(t->value);
- free(t);
- t = NULL;
- *widget = W(t);
}
diff --git a/client/src/gui/updown.c b/client/src/gui/updown.c
index 735ee73..a53b982 100644
--- a/client/src/gui/updown.c
+++ b/client/src/gui/updown.c
@@ -47,11 +47,7 @@ static void updownVisibleSet(UpdownT *updown);
static void updownDel(WidgetT **widget) {
UpdownT *u = (UpdownT *)*widget;
- arrfree(u->base.children);
if (u->title) free(u->title);
- free(u);
- u = NULL;
- *widget = W(u);
}
diff --git a/client/src/gui/widget.c b/client/src/gui/widget.c
index 4ef7412..b403321 100644
--- a/client/src/gui/widget.c
+++ b/client/src/gui/widget.c
@@ -22,19 +22,6 @@
#include "window.h"
-static void widgetDel(WidgetT **widget);
-
-
-static void widgetDel(WidgetT **widget) {
- WidgetT *w = (WidgetT *)*widget;
-
- arrfree(w->children);
- free(w);
- w = NULL;
- *widget = w;
-}
-
-
uint16_t widgetHeightGet(WidgetT *widget) {
return widget->pos.h;
}
@@ -59,7 +46,7 @@ WidgetT *widgetInit(WidgetT *widget, uint8_t magic, uint16_t x, uint16_t y, uint
widget->children = NULL;
widget->parent = NULL;
widget->window = NULL;
- widget->delMethod = widgetDel;
+ widget->delMethod = NULL;
widget->focusMethod = NULL;
widget->keyboardEventMethod = NULL;
widget->paintMethod = NULL;
diff --git a/client/src/gui/window.c b/client/src/gui/window.c
index 1bb3952..bee67ed 100644
--- a/client/src/gui/window.c
+++ b/client/src/gui/window.c
@@ -79,12 +79,7 @@ static void windowAllDeactivate(WidgetT *widget) {
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);
}
diff --git a/client/src/linux/linux.c b/client/src/linux/linux.c
index 542bb6d..50bac14 100644
--- a/client/src/linux/linux.c
+++ b/client/src/linux/linux.c
@@ -37,6 +37,7 @@ static MouseT _mouse;
static SDL_Window *_window = NULL;
static SDL_Renderer *_renderer = NULL;
static SDL_Surface *_surface = NULL;
+static SDL_Texture *_texture = NULL;
static uint16_t _width = 0;
static uint16_t _height = 0;
static uint8_t _windowScale = 1;
@@ -253,40 +254,28 @@ uint16_t vbeDisplayWidthGet(void) {
ColorT vbeColorMake(uint8_t red, uint8_t green, uint8_t blue) {
+ // Pixels are 8:8:8:8 RGBA - SDL_PIXELFORMAT_RGBA8888
return
(red << 24) |
(green << 16) |
- (blue << 8);
+ (blue << 8) |
+ 255;
}
void vbePresent(void) {
- uint16_t x;
- uint16_t y;
- SurfaceT *s = surfaceOffScreenGet();
- uint32_t p;
- uint8_t r;
- uint8_t g;
- uint8_t b;
-
- SDL_SetRenderTarget(_renderer, NULL);
-
- //***TODO*** This is stupid inefficient.
- for (y=0; yheight; y++) {
- for (x=0; xwidth; x++) {
- p = s->buffer.bits32[y * s->width + x];
- r = (p & 0xFF000000) >> 24;
- g = (p & 0x00FF0000) >> 16;
- b = (p & 0x0000FF00) >> 8;
- SDL_SetRenderDrawColor(_renderer, r, g, b, 255);
- SDL_RenderDrawPoint(_renderer, x, y);
- }
- }
+ void *pixels;
+ int pitch;
+ SurfaceT *s = surfaceOffScreenGet();
+ SDL_LockTexture(_texture, NULL, &pixels, &pitch);
+ memcpy(pixels, s->buffer.bits8, s->bytes);
+ SDL_UnlockTexture(_texture);
+ SDL_RenderCopy(_renderer, _texture, NULL, NULL);
SDL_RenderPresent(_renderer);
// Throttle this to some sane frame rate.
- //SDL_Delay(32);
+ SDL_Delay(32);
}
@@ -297,6 +286,11 @@ int16_t vbeInfoShow(void) {
int16_t vbeShutdown(void) {
+ if (_texture) {
+ SDL_DestroyTexture(_texture);
+ _texture = NULL;
+ }
+
if (_renderer) {
SDL_DestroyRenderer(_renderer);
_renderer = NULL;
@@ -327,6 +321,7 @@ uint8_t vbeStartup(uint16_t xRes, uint16_t yRes, uint8_t bpp) {
_window = SDL_CreateWindow("GUI Test", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, xRes, yRes, SDL_WINDOW_ALLOW_HIGHDPI);
_surface = SDL_GetWindowSurface(_window);
_renderer = SDL_CreateRenderer(_window, -1, SDL_RENDERER_ACCELERATED);
+ _texture = SDL_CreateTexture(_renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, xRes, yRes);
SDL_RenderSetLogicalSize(_renderer, xRes, yRes);
SDL_SetWindowSize(_window, xRes * _windowScale, yRes * _windowScale);
diff --git a/client/src/main.c b/client/src/main.c
index 577e287..12ef389 100644
--- a/client/src/main.c
+++ b/client/src/main.c
@@ -18,6 +18,9 @@
*/
+//#define TESTING
+
+
/*
* To Do:
*
@@ -29,7 +32,6 @@
* - 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
*/
@@ -45,48 +47,25 @@
#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"
+#include "welcome.h"
+
+#ifdef TESTING
+#include "test.h"
+#endif
-static TerminalT *t1 = NULL;
-static uint8_t lastKey = 0;
+static void taskGuiEventLoop(void *data);
-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) {
+static void taskGuiEventLoop(void *data) {
MouseT *mouse = NULL;
ImageT *pointer = NULL;
ColorT alpha;
- int8_t key = 0;
+#ifdef TESTING
int8_t debugState = 0;
+#endif
(void)data;
@@ -97,17 +76,17 @@ static void mainLoop(void *data) {
timerUpdate();
mouse = mouseRead();
if (keyHit()) {
- key = keyASCIIGet();
- lastKey = key; //***DEBUG***
+#ifdef TESTING
+ lastKey = keyASCIIGet(); //***DEBUG***
+#endif
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;
+ //logWrite("Key '%d' Extended '%d' Scancode '%d' Shift '%d' Control '%d' Alt '%d'\n", keyASCIIGet(), keyExtended(), keyScanCode(), keyShift(), keyControl(), keyAlt());
}
guiMouseProcess(mouse);
guiComposite();
imageRenderWithAlpha(pointer, mouse->x, mouse->y, alpha);
+#ifdef TESTING
if (key == '=') guiWidgetTreeDump(guiRootGet(), 0);
if (key == '+') {
debugState++;
@@ -115,308 +94,30 @@ static void mainLoop(void *data) {
}
if (debugState > 0) widgetDebugDraw(guiRootGet(), debugState - 1);
//if (timerHalfSecondOn) guiDrawRectangle(0, 0, vbeSurfaceWidthGet() - 1, vbeSurfaceHeightGet() - 1, vbeMakeColor(255, 255, 255));
+#endif
vbeVBlankWait();
vbePresent();
taskYield();
+#ifdef TESTING
} while (key != 27); // Exit on ESC.
+#else
+ } while (!guiHasStopped());
+#endif
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();
+ memoryStartup(argv[0]);
+ logOpenByHandle(memoryLogHandleGet());
// 0 1 2 3 4 5 6 7 8
// 12345678901234567890123456789012345678901234567890123456789012345678901234567890
@@ -424,21 +125,6 @@ int main(int argc, char *argv[]) {
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();
@@ -463,8 +149,13 @@ int main(int argc, char *argv[]) {
guiStartup();
taskStartup();
- taskCreate(testTagList, "testTagList");
- taskCreate(mainLoop, "mainLoop");
+#ifdef TESTING
+ taskCreate(taskTestTagList, NULL);
+#else
+ taskCreate(taskWelcome, NULL);
+#endif
+
+ taskCreate(taskGuiEventLoop, NULL);
taskRun();
taskShutdown();
@@ -475,7 +166,6 @@ int main(int argc, char *argv[]) {
vbeShutdown();
logClose();
-
memoryShutdown();
return 0;
diff --git a/client/src/settings.c b/client/src/settings.c
new file mode 100644
index 0000000..002e320
--- /dev/null
+++ b/client/src/settings.c
@@ -0,0 +1,69 @@
+/*
+ * 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 "settings.h"
+#include "welcome.h"
+
+#include "taglist.h"
+#include "task.h"
+
+#include "window.h"
+#include "button.h"
+#include "frame.h"
+#include "radio.h"
+
+
+static WindowT *winSettings;
+static FrameT *frmComPorts;
+static ButtonT *btnOkay;
+
+
+static void btnOkayClick(WidgetT *widget);
+
+
+static void btnOkayClick(WidgetT *widget) {
+ (void)widget;
+ taskCreate(taskWelcome, NULL);
+ guiDelete(D(winSettings));
+}
+
+
+void taskSettings(void *data) {
+
+ (void)data;
+
+ TagItemT ui[] = {
+ T_START,
+ T_WINDOW, O(winSettings),
+ T_TITLE, P("Settings"),
+ T_WIDTH, 200, T_HEIGHT, 200,
+ T_BUTTON, O(btnOkay),
+ T_TITLE, P("Okay"),
+ T_CLICK, P(btnOkayClick),
+ T_BUTTON, T_DONE,
+ T_WINDOW, T_DONE,
+ T_END
+ };
+
+ tagListRun(ui);
+
+ guiDebugAreaShow(W(winSettings));
+ guiDebugAreaShow(W(btnOkay));
+}
diff --git a/client/src/settings.h b/client/src/settings.h
new file mode 100644
index 0000000..0c61e57
--- /dev/null
+++ b/client/src/settings.h
@@ -0,0 +1,31 @@
+/*
+ * 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 .
+ *
+ */
+
+
+#ifndef SETTINGS_H
+#define SETTINGS_H
+
+
+#include "os.h"
+
+
+void taskSettings(void *data);
+
+
+#endif // SETTINGS_H
diff --git a/client/src/system/log.c b/client/src/system/log.c
index 58e415f..9937b30 100644
--- a/client/src/system/log.c
+++ b/client/src/system/log.c
@@ -21,19 +21,29 @@
#include "log.h"
-FILE *_log = NULL;
+static FILE *_log = NULL;
+static uint8_t _ourHandle = 0;
uint8_t logOpen(char *filename, uint8_t append) {
_log = fopen(filename, append ? "a" : "w");
- if (_log) return 1;
+ if (_log) {
+ return 1;
+ _ourHandle = 1;
+ }
return 0;
}
+void logOpenByHandle(FILE *handle) {
+ _log = handle;
+}
+
+
void logClose(void) {
- if (_log) {
+ if (_log && _ourHandle) {
fclose(_log);
+ _ourHandle = 0;
}
}
@@ -44,8 +54,8 @@ void logWrite(char *format, ...) {
va_start(args, format);
#ifdef __linux__
+ // Also output to stdout on Linux.
va_list args2;
-
va_copy(args2, args);
vfprintf(stdout, format, args2);
fflush(stdout);
diff --git a/client/src/system/log.h b/client/src/system/log.h
index fd75f3f..080162b 100644
--- a/client/src/system/log.h
+++ b/client/src/system/log.h
@@ -26,6 +26,7 @@
uint8_t logOpen(char *filename, uint8_t append);
+void logOpenByHandle(FILE *handle);
void logClose(void);
void logWrite(char *format, ...);
diff --git a/client/src/system/memory.c b/client/src/system/memory.c
index 6009db9..3191e0f 100644
--- a/client/src/system/memory.c
+++ b/client/src/system/memory.c
@@ -21,20 +21,60 @@
#include "memory.h"
-#ifdef MEMWATCH_STDIO
+FILE *_memoryLog = NULL;
+
+
+#ifdef MEMORY_CHECK_ENABLED
+void mwLogW(FILE *p);
+#endif
+
+
+FILE *memoryLogHandleGet(void) {
+ return _memoryLog;
+}
+
+
+#ifdef MEMORY_CHECK_ENABLED
void memoryOutput(int c) {
- logWrite("%c", c);
+ fputc(c, _memoryLog);
+ fflush(_memoryLog);
+
+ fputc(c, stdout);
+ fflush(stdout);
}
#endif
void memoryShutdown(void) {
- // Nada.
-}
-
-
-void memoryStartup(void) {
-#ifdef MEMWATCH_STDIO
- mwSetOutFunc(memoryOutput);
+#ifdef MEMORY_CHECK_ENABLED
+ mwTerm();
+#endif
+}
+
+
+void memoryStartup(char *appName) {
+ char logName[32] = { "log.log" };
+ char *c = NULL;
+ int16_t x = strlen(appName);
+
+ // Find last portion of filename.
+ while (x > 0) {
+ if (appName[x] == '/' || appName[x] == '\\') break;
+ x--;
+ }
+ if (strlen(appName) - x < 32) {
+ // Replace any extension with ".log"
+ strncpy(logName, &appName[x + 1], 31);
+ c = strstr(logName, ".");
+ if (c) *c = 0;
+ strncat(logName, ".log", 31);
+ }
+
+ _memoryLog = fopen(logName, "w");
+
+#ifdef MEMORY_CHECK_ENABLED
+ mwLogW(_memoryLog);
+ mwSetOutFunc(memoryOutput);
+ mwInit();
#endif
}
diff --git a/client/src/system/memory.h b/client/src/system/memory.h
index a9aa1b7..91c0cfd 100644
--- a/client/src/system/memory.h
+++ b/client/src/system/memory.h
@@ -24,16 +24,15 @@
#include "os.h"
-
#ifdef MEMORY_CHECK_ENABLED
#define MEMWATCH
-#define MEMWATCH_STDIO
+#include "memwatch/memwatch.h"
#endif
-#include "memwatch/memwatch.h"
-void memoryShutdown(void);
-void memoryStartup(void);
+FILE *memoryLogHandleGet(void);
+void memoryShutdown(void);
+void memoryStartup(char *appName);
#endif // MEMORY_H
diff --git a/client/src/system/taglist.c b/client/src/system/taglist.c
index 19e3585..0cb096f 100644
--- a/client/src/system/taglist.c
+++ b/client/src/system/taglist.c
@@ -247,6 +247,12 @@ static void tagListWidgetAttributeHandle(void) {
parent = *w->parent;
}
+ // Auto-center windows if position not specified.
+ if (pos.x == 0 && pos.y == 0 && w->type == T_WINDOW) {
+ pos.x = vbeDisplayWidthGet() / 2 - pos.w / 2;
+ pos.y = vbeDisplayHeightGet() / 2 - pos.h / 2;
+ }
+
// Create the widget.
switch (w->type) {
@@ -316,7 +322,7 @@ static void tagListWidgetAttributeHandle(void) {
break;
}
- guiUserDataSet(widget, userdata);
+ if (userdata != NULL) guiUserDataSet(widget, userdata);
// Store everything we did.
*w->widget = widget;
diff --git a/client/src/test.c b/client/src/test.c
new file mode 100644
index 0000000..e8e68e5
--- /dev/null
+++ b/client/src/test.c
@@ -0,0 +1,336 @@
+/*
+ * 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 "test.h"
+
+#include "task.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"
+
+
+uint8_t lastKey = 0;
+
+static TerminalT *t1 = NULL;
+
+
+static void buttonClick(WidgetT *widget);
+//static void test(void *data);
+static void testTerminal(void *data);
+
+
+static void buttonClick(WidgetT *widget) {
+ logWrite("'%s' was clicked.\n", ((ButtonT *)widget)->title);
+}
+
+
+/*
+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");
+}
+*/
+
+
+void taskTestTagList(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, NULL);
+}
+
+
+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);
+}
+
+
+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);
+ }
+ }
+}
+
diff --git a/client/src/test.h b/client/src/test.h
new file mode 100644
index 0000000..105fc93
--- /dev/null
+++ b/client/src/test.h
@@ -0,0 +1,36 @@
+/*
+ * 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 .
+ *
+ */
+
+
+#ifndef TEST_H
+#define TEST_H
+
+
+#include "os.h"
+#include "terminal.h"
+
+
+extern uint8_t lastKey;
+
+
+void taskTestTagList(void *data);
+void widgetDebugDraw(WidgetT *widget, uint8_t debugToggle);
+
+
+#endif // TEST_H
diff --git a/client/src/thirdparty/memwatch/memwatch.c b/client/src/thirdparty/memwatch/memwatch.c
index 9d712d7..ae0f6ab 100644
--- a/client/src/thirdparty/memwatch/memwatch.c
+++ b/client/src/thirdparty/memwatch/memwatch.c
@@ -307,7 +307,7 @@ typedef pthread_mutex_t mwMutex;
***********************************************************************/
static int mwInited = 0;
-static int mwInfoWritten = 0;
+static int mwInfoWritten = 1;
static int mwUseAtexit = 0;
static FILE* mwLog = NULL;
static int mwFlushing = 0;
@@ -370,7 +370,7 @@ static mwMutex mwGlobalMutex;
static void mwAutoInit( void );
static FILE* mwLogR( void );
-static void mwLogW( FILE* );
+/* static */ void mwLogW( FILE* );
static int mwFlushR( void );
static void mwFlushW( int );
static void mwFlush( void );
@@ -1531,7 +1531,7 @@ static FILE *mwLogR() {
return mwSTDERR;
}
-static void mwLogW( FILE *p ) {
+/* static */ void mwLogW( FILE *p ) {
mwLog = mwLogB1 = mwLogB2 = p;
}
diff --git a/client/src/welcome.c b/client/src/welcome.c
new file mode 100644
index 0000000..2ef5209
--- /dev/null
+++ b/client/src/welcome.c
@@ -0,0 +1,97 @@
+/*
+ * 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 "welcome.h"
+#include "settings.h"
+
+#include "taglist.h"
+#include "task.h"
+
+#include "window.h"
+#include "picture.h"
+#include "button.h"
+
+
+static WindowT *winWelcome = NULL;
+static PictureT *picLogo = NULL;
+static ButtonT *btnQuit = NULL;
+static ButtonT *btnSettings = NULL;
+static ButtonT *btnConnect = NULL;
+
+
+static void btnConnectClick(WidgetT *widget);
+static void btnQuitClick(WidgetT *widget);
+static void btnSettingsClick(WidgetT *widget);
+
+
+static void btnConnectClick(WidgetT *widget) {
+ (void)widget;
+}
+
+
+static void btnQuitClick(WidgetT *widget) {
+ (void)widget;
+ guiStop();
+}
+
+
+static void btnSettingsClick(WidgetT *widget) {
+ (void)widget;
+ taskCreate(taskSettings, NULL);
+ guiDelete(D(winWelcome));
+}
+
+
+void taskWelcome(void *data) {
+
+ (void)data;
+
+ // 450x128 logo
+
+ TagItemT ui[] = {
+ T_START,
+ T_WINDOW, O(winWelcome),
+ T_TITLE, P("Welcome to KangaWorld!"),
+ T_WIDTH, 500, T_HEIGHT, 225,
+ T_PICTURE, O(picLogo),
+ T_FILENAME, P("logo.png"),
+ T_X, 18, T_Y, 18,
+ T_PICTURE, T_DONE,
+ T_BUTTON, O(btnQuit),
+ T_TITLE, P("Quit"),
+ T_X, 30, T_Y, 157,
+ T_CLICK, P(btnQuitClick),
+ T_BUTTON, T_DONE,
+ T_BUTTON, O(btnSettings),
+ T_TITLE, P("Settings"),
+ T_X, 201, T_Y, 157,
+ T_CLICK, P(btnSettingsClick),
+ T_BUTTON, T_DONE,
+ T_BUTTON, O(btnConnect),
+ T_TITLE, P("Connect"),
+ T_X, 379, T_Y, 157,
+ T_CLICK, P(btnConnectClick),
+ T_BUTTON, T_DONE,
+ T_WINDOW, T_DONE,
+ T_END
+ };
+
+ tagListRun(ui);
+}
diff --git a/client/src/welcome.h b/client/src/welcome.h
new file mode 100644
index 0000000..ba98f3e
--- /dev/null
+++ b/client/src/welcome.h
@@ -0,0 +1,31 @@
+/*
+ * 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 .
+ *
+ */
+
+
+#ifndef WELCOME_H
+#define WELCOME_H
+
+
+#include "os.h"
+
+
+void taskWelcome(void *data);
+
+
+#endif // WELCOME_H