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