Dynamic screenshot display working in browser.
This commit is contained in:
parent
377e40f28f
commit
f477ee15d0
23 changed files with 460 additions and 176 deletions
|
@ -131,6 +131,7 @@ SOURCES = \
|
|||
$$SHARED/thirdparty/tiny-AES128-C/pkcs7_padding.c \
|
||||
$$SHARED/thirdparty/SHA256/sha256.c \
|
||||
$$SHARED/memory.c \
|
||||
../shared/game.c \
|
||||
src/browser.c \
|
||||
src/file.c \
|
||||
src/gui/msgbox.c \
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
#include "db.h"
|
||||
#include "network.h"
|
||||
#include "util.h"
|
||||
#include "game.h"
|
||||
#include "file.h"
|
||||
|
||||
|
||||
static WindowT *_winBrowser = NULL;
|
||||
|
@ -50,17 +52,11 @@ static ListboxT *_lstDescription = NULL;
|
|||
|
||||
static ButtonT *_btnScreensTab = NULL;
|
||||
static FrameT *_fraScreens = NULL;
|
||||
static PictureT *_picThumb1 = NULL;
|
||||
static PictureT *_picThumb2 = NULL;
|
||||
static PictureT *_picThumb3 = NULL;
|
||||
static PictureT *_picThumb4 = NULL;
|
||||
static PictureT *_picThumb5 = NULL;
|
||||
static PictureT *_picThumb6 = NULL;
|
||||
static PictureT *_picThumb[6];
|
||||
|
||||
static ButtonT *_btnBoxTab = NULL;
|
||||
static FrameT *_fraBox = NULL;
|
||||
static PictureT *_picBox1 = NULL;
|
||||
static PictureT *_picBox2 = NULL;
|
||||
static PictureT *_picBox[2];
|
||||
|
||||
static ButtonT *_btnInfoTab = NULL;
|
||||
static FrameT *_fraInfo = NULL;
|
||||
|
@ -69,14 +65,22 @@ static ListboxT *_lstInfo = NULL;
|
|||
static uint8_t _channel = 0;
|
||||
static char *_lastSearchText = NULL;
|
||||
|
||||
static GameT _selectedGame = { 0 };
|
||||
|
||||
|
||||
static void browserHide(void);
|
||||
static void btnTabClick(WidgetT *widget);
|
||||
static void fraBoxShow(void);
|
||||
static void fraDescriptionShow(void);
|
||||
static void fraInfoShow(void);
|
||||
static void fraScreensShow(void);
|
||||
static void fraScreensReady(char *file);
|
||||
static void packetHandler(PacketDecodeDataT *packet);
|
||||
static void tabsBusySet(uint8_t busy);
|
||||
static void timSearchUpdate(WidgetT *widget);
|
||||
static void updateSelectedGame(void);
|
||||
|
||||
|
||||
static void browserHide(void) {
|
||||
void browserHide(void) {
|
||||
timerStop(_timSearchUpdate);
|
||||
DEL(_lastSearchText);
|
||||
netChannelRelease(_channel);
|
||||
|
@ -106,7 +110,7 @@ void browserShow(void) {
|
|||
T_TITLE, P("Search"),
|
||||
|
||||
T_TEXTBOX, O(_txtSearch),
|
||||
T_TITLE, P("Game, Publisher, or Developer:"),
|
||||
T_TITLE, P("Filter:"),
|
||||
T_X, 5, T_Y, 3,
|
||||
T_WIDTH, 490,
|
||||
T_LENGTH, 255,
|
||||
|
@ -155,38 +159,33 @@ void browserShow(void) {
|
|||
T_TITLE, P("Screenshots"),
|
||||
T_VISIBLE, T_FALSE,
|
||||
|
||||
T_PICTURE, O(_picThumb1), // Thumbs are 160x100
|
||||
T_PICTURE, O(_picThumb[0]), // Thumbs are 160x100
|
||||
T_X, 1, T_Y, 5,
|
||||
T_CACHENAME, P("browser:no-screen.png"),
|
||||
T_PICTURE, T_DONE,
|
||||
T_PICTURE, O(_picThumb2),
|
||||
T_PICTURE, O(_picThumb[1]),
|
||||
T_X, 167, T_Y, 5,
|
||||
T_CACHENAME, P("browser:no-screen.png"),
|
||||
T_VISIBLE, T_FALSE,
|
||||
T_PICTURE, T_DONE,
|
||||
T_PICTURE, O(_picThumb3),
|
||||
T_PICTURE, O(_picThumb[2]),
|
||||
T_X, 333, T_Y, 5,
|
||||
T_CACHENAME, P("browser:no-screen.png"),
|
||||
T_VISIBLE, T_FALSE,
|
||||
T_PICTURE, T_DONE,
|
||||
|
||||
T_PICTURE, O(_picThumb4),
|
||||
T_PICTURE, O(_picThumb[3]),
|
||||
T_X, 1, T_Y, 116,
|
||||
T_CACHENAME, P("browser:no-screen.png"),
|
||||
T_VISIBLE, T_FALSE,
|
||||
T_PICTURE, T_DONE,
|
||||
T_PICTURE, O(_picThumb5),
|
||||
T_PICTURE, O(_picThumb[4]),
|
||||
T_X, 167, T_Y, 116,
|
||||
T_CACHENAME, P("browser:no-screen.png"),
|
||||
T_VISIBLE, T_FALSE,
|
||||
T_PICTURE, T_DONE,
|
||||
T_PICTURE, O(_picThumb6),
|
||||
T_PICTURE, O(_picThumb[5]),
|
||||
T_X, 333, T_Y, 116,
|
||||
T_CACHENAME, P("browser:no-screen.png"),
|
||||
T_VISIBLE, T_FALSE,
|
||||
T_PICTURE, T_DONE,
|
||||
|
||||
T_FRAME, T_DONE,
|
||||
T_FRAME, T_DONE,
|
||||
|
||||
// BOX
|
||||
T_BUTTON, O(_btnBoxTab),
|
||||
|
@ -201,17 +200,16 @@ void browserShow(void) {
|
|||
T_TITLE, P("Packaging"),
|
||||
T_VISIBLE, T_FALSE,
|
||||
|
||||
T_PICTURE, O(_picBox1), // Thumbs are 240x210
|
||||
T_PICTURE, O(_picBox[0]), // Thumbs are 240x210
|
||||
T_X, 1, T_Y, 5,
|
||||
T_CACHENAME, P("browser:no-box.png"),
|
||||
T_PICTURE, T_DONE,
|
||||
T_PICTURE, O(_picBox2),
|
||||
T_PICTURE, O(_picBox[1]),
|
||||
T_X, 250, T_Y, 5,
|
||||
T_CACHENAME, P("browser:no-box.png"),
|
||||
T_VISIBLE, T_FALSE,
|
||||
T_PICTURE, T_DONE,
|
||||
|
||||
T_FRAME, T_DONE,
|
||||
T_FRAME, T_DONE,
|
||||
|
||||
// INFO
|
||||
T_BUTTON, O(_btnInfoTab),
|
||||
|
@ -247,7 +245,7 @@ void browserShow(void) {
|
|||
guiFocusSet(W(_txtSearch));
|
||||
_channel = netChannelGet(packetHandler);
|
||||
|
||||
_lastSearchText = strdup("");
|
||||
_lastSearchText = strdup("x");
|
||||
|
||||
/*
|
||||
guiDebugAreaShow(W(_fraSearch));
|
||||
|
@ -288,17 +286,101 @@ void browserShow(void) {
|
|||
|
||||
static void btnTabClick(WidgetT *widget) {
|
||||
|
||||
tabsBusySet(1);
|
||||
|
||||
// Hide everything.
|
||||
widgetVisibleSet(W(_fraBox), 0);
|
||||
widgetVisibleSet(W(_fraDescription), 0);
|
||||
widgetVisibleSet(W(_fraInfo), 0);
|
||||
widgetVisibleSet(W(_fraScreens), 0);
|
||||
widgetVisibleSet(W(_fraSearch), 0);
|
||||
|
||||
if (widget == W(_btnBoxTab)) widgetVisibleSet(W(_fraBox), 1);
|
||||
if (widget == W(_btnDescriptionTab)) widgetVisibleSet(W(_fraDescription), 1);
|
||||
if (widget == W(_btnInfoTab)) widgetVisibleSet(W(_fraInfo), 1);
|
||||
if (widget == W(_btnScreensTab)) widgetVisibleSet(W(_fraScreens), 1);
|
||||
if (widget == W(_btnSearchTab)) widgetVisibleSet(W(_fraSearch), 1);
|
||||
updateSelectedGame();
|
||||
|
||||
// Show selected frame.
|
||||
if (widget == W(_btnBoxTab)) fraBoxShow();
|
||||
if (widget == W(_btnDescriptionTab)) fraDescriptionShow();
|
||||
if (widget == W(_btnInfoTab)) fraInfoShow();
|
||||
if (widget == W(_btnScreensTab)) fraScreensShow();
|
||||
if (widget == W(_btnSearchTab)) {
|
||||
widgetVisibleSet(W(_fraSearch), 1);
|
||||
tabsBusySet(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void fraBoxShow(void) {
|
||||
widgetVisibleSet(W(_fraBox), 1);
|
||||
tabsBusySet(0);
|
||||
}
|
||||
|
||||
|
||||
static void fraDescriptionShow(void) {
|
||||
widgetVisibleSet(W(_fraDescription), 1);
|
||||
tabsBusySet(0);
|
||||
}
|
||||
|
||||
|
||||
static void fraInfoShow(void) {
|
||||
widgetVisibleSet(W(_fraInfo), 1);
|
||||
tabsBusySet(0);
|
||||
}
|
||||
|
||||
|
||||
static void fraScreensShow(void) {
|
||||
char **fileList = NULL;
|
||||
char *temp;
|
||||
uint8_t i;
|
||||
|
||||
// Build list of screen filenames needed.
|
||||
for (i=0; i<_selectedGame.screens; i++) {
|
||||
temp = utilCreateString("games:%c:%s:screen%d.png", _selectedGame.shortName[0], _selectedGame.shortName, i + 1);
|
||||
utilStringToLower(temp);
|
||||
arrput(fileList, temp);
|
||||
temp = utilCreateString("games:%c:%s:screen%d-thumb.png", _selectedGame.shortName[0], _selectedGame.shortName, i + 1);
|
||||
utilStringToLower(temp);
|
||||
arrput(fileList, temp);
|
||||
}
|
||||
|
||||
if (fileList) {
|
||||
fileCacheCheckArr(fraScreensReady, fileList);
|
||||
} else {
|
||||
fraScreensReady(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void fraScreensReady(char *file) {
|
||||
|
||||
uint8_t i;
|
||||
|
||||
// Is this a file update notice? If so, exit.
|
||||
if (file) return;
|
||||
|
||||
// Are there screenshots?
|
||||
if (_selectedGame.screens == 0) {
|
||||
// Nope.
|
||||
pictureReplace(_picThumb[0], "browser:no-screen.png");
|
||||
for (i=1; i<6; i++) {
|
||||
widgetVisibleSet(W(_picThumb[i]), 0);
|
||||
}
|
||||
} else {
|
||||
for (i=0; i<6; i++) {
|
||||
if (i < _selectedGame.screens) {
|
||||
snprintf(_scratch, SCRATCH_SIZE, "games:%c:%s:screen%d-thumb.png", _selectedGame.shortName[0], _selectedGame.shortName, i + 1);
|
||||
utilStringToLower(_scratch);
|
||||
logWrite("Loading screen: %s\n", _scratch);
|
||||
pictureReplace(_picThumb[i], _scratch);
|
||||
widgetVisibleSet(W(_picThumb[i]), 1);
|
||||
} else {
|
||||
widgetVisibleSet(W(_picThumb[i]), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Display us.
|
||||
widgetVisibleSet(W(_fraScreens), 1);
|
||||
tabsBusySet(0);
|
||||
}
|
||||
|
||||
|
||||
|
@ -307,39 +389,113 @@ static void packetHandler(PacketDecodeDataT *packet) {
|
|||
}
|
||||
|
||||
|
||||
static void tabsBusySet(uint8_t busy) {
|
||||
uint8_t enabled = busy ? 0 : 1;
|
||||
|
||||
if (busy) {
|
||||
guiMouseBusyPush();
|
||||
} else {
|
||||
guiMouseBusyPop();
|
||||
}
|
||||
|
||||
widgetEnableSet(W(_btnSearchTab), enabled);
|
||||
widgetEnableSet(W(_btnDescriptionTab), enabled);
|
||||
widgetEnableSet(W(_btnScreensTab), enabled);
|
||||
widgetEnableSet(W(_btnBoxTab), enabled);
|
||||
widgetEnableSet(W(_btnInfoTab), enabled);
|
||||
}
|
||||
|
||||
|
||||
static void timSearchUpdate(WidgetT *widget) {
|
||||
char ***records = NULL;
|
||||
char **fields = NULL;
|
||||
uint16_t count = 0;
|
||||
char query[258]; // 255 search characters, two %'s, and the terminating null.
|
||||
|
||||
(void)widget;
|
||||
|
||||
// Are there more than two characters in the search field?
|
||||
if (textboxValueGet(_txtSearch) && strlen(textboxValueGet(_txtSearch)) > 2) {
|
||||
// Did the search contents change?
|
||||
if (strcmp(_lastSearchText, textboxValueGet(_txtSearch))) {
|
||||
// Remember what was in the search box.
|
||||
DEL(_lastSearchText);
|
||||
_lastSearchText = strdup(textboxValueGet(_txtSearch));
|
||||
// Clear current search results.
|
||||
listboxItemsClear(_lstResults);
|
||||
// Execute search.
|
||||
snprintf(query, 258, "%%%s%%", _lastSearchText);
|
||||
// Did the search contents change?
|
||||
if (strcmp(_lastSearchText, textboxValueGet(_txtSearch))) {
|
||||
// Remember what was in the search box.
|
||||
DEL(_lastSearchText);
|
||||
_lastSearchText = strdup(textboxValueGet(_txtSearch));
|
||||
// Clear current search results.
|
||||
listboxItemsClear(_lstResults);
|
||||
// Is there something in the search field?
|
||||
if (textboxValueGet(_txtSearch) && strlen(textboxValueGet(_txtSearch)) > 0) {
|
||||
// Yes. Filter based on what is in the search field.
|
||||
snprintf(_scratch, SCRATCH_SIZE, "%%%s%%", _lastSearchText);
|
||||
dbQueryMultiple(&records,
|
||||
"SELECT title FROM games WHERE "
|
||||
"title LIKE ? OR developer LIKE ? OR publisher LIKE ? "
|
||||
"SELECT ROWID, title FROM games WHERE "
|
||||
"title LIKE ? "
|
||||
"ORDER BY title",
|
||||
"vvv",
|
||||
query,
|
||||
query,
|
||||
query);
|
||||
// Did we get anything?
|
||||
"v",
|
||||
_scratch);
|
||||
} else {
|
||||
// No. Display ALL games.
|
||||
dbQueryMultiple(&records,
|
||||
"SELECT ROWID, title FROM games "
|
||||
"ORDER BY title",
|
||||
NULL);
|
||||
}
|
||||
// Did we get anything?
|
||||
if (records) {
|
||||
for (count = 0; count < arrlen(records); count++) {
|
||||
fields = records[count];
|
||||
listboxItemAddWithData(_lstResults, fields[1], atol(fields[0]));
|
||||
}
|
||||
dbResultRelease(&records);
|
||||
}
|
||||
// Ghost or enable tab buttons depending on if the listbox has an item highlighted or not.
|
||||
count = listboxItemsCountGet(_lstResults) > 0; // Reusing count.
|
||||
widgetEnableSet(W(_btnDescriptionTab), count);
|
||||
widgetEnableSet(W(_btnScreensTab), count);
|
||||
widgetEnableSet(W(_btnBoxTab), count);
|
||||
widgetEnableSet(W(_btnInfoTab), count);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void updateSelectedGame(void) {
|
||||
char ***records = NULL;
|
||||
char **fields = NULL;
|
||||
|
||||
// If a game is selected...
|
||||
if (listboxItemsCountGet(_lstResults) > 0) {
|
||||
// Is it a different game?
|
||||
if (listboxDataGet(_lstResults) != _selectedGame.ROWID) {
|
||||
// Clear last loadead game.
|
||||
gameClear(&_selectedGame);
|
||||
|
||||
logWrite("Loading game details: %d = '%s'\n", listboxDataGet(_lstResults), listboxValueGet(_lstResults));
|
||||
|
||||
// Load the details from the SQL database.
|
||||
dbQueryMultiple(&records,
|
||||
"SELECT title, publisher, developer, description, "
|
||||
"releaseDate, rating, series, origin, shortName, "
|
||||
"worksWith, type, maxPlayers, joinable, screens, "
|
||||
"boxes, ROWID "
|
||||
"FROM games WHERE "
|
||||
"ROWID=?",
|
||||
"i",
|
||||
listboxDataGet(_lstResults));
|
||||
if (records) {
|
||||
for (count = 0; count < arrlen(records); count++) {
|
||||
fields = records[count];
|
||||
listboxItemAdd(_lstResults, fields[0]);
|
||||
}
|
||||
fields = records[0];
|
||||
_selectedGame.title = strdup(fields[0]);
|
||||
_selectedGame.publisher = strdup(fields[1]);
|
||||
_selectedGame.developer = strdup(fields[2]);
|
||||
_selectedGame.description = strdup(fields[3]);
|
||||
_selectedGame.releaseDate = strdup(fields[4]);
|
||||
_selectedGame.rating = strdup(fields[5]);
|
||||
_selectedGame.series = strdup(fields[6]);
|
||||
_selectedGame.origin = strdup(fields[7]);
|
||||
_selectedGame.shortName = strdup(fields[8]);
|
||||
_selectedGame.worksWith = strdup(fields[9]);
|
||||
_selectedGame.type = atoi(fields[10]);
|
||||
_selectedGame.maxPlayers = atoi(fields[11]);
|
||||
_selectedGame.joinable = atoi(fields[12]);
|
||||
_selectedGame.screens = atoi(fields[13]);
|
||||
_selectedGame.boxes = atoi(fields[14]);
|
||||
_selectedGame.ROWID = atol(fields[15]);
|
||||
dbResultRelease(&records);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "os.h"
|
||||
|
||||
|
||||
void browserHide(void);
|
||||
void browserShow(void);
|
||||
|
||||
|
||||
|
|
|
@ -70,20 +70,46 @@ static void btnMsgBoxOkay(MsgBoxButtonT button) {
|
|||
}
|
||||
|
||||
|
||||
// List of character array.
|
||||
void fileCacheCheck(fileCallback callback, char *vpaths[]) {
|
||||
uint16_t i = 0;
|
||||
char **files = NULL;
|
||||
|
||||
// Used during development & debugging.
|
||||
if (!netPacketHandlerIsRunning()) {
|
||||
callback(NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
BEGIN
|
||||
|
||||
while (vpaths[i] != NULL) {
|
||||
arrput(files, strdup(vpaths[i]));
|
||||
i++;
|
||||
}
|
||||
|
||||
fileCacheCheckArr(callback, files);
|
||||
|
||||
END
|
||||
}
|
||||
|
||||
|
||||
// List of dynamic array.
|
||||
void fileCacheCheckArr(fileCallback callback, char **vpathArr) {
|
||||
FileListT *newList = NULL;
|
||||
uint16_t i = 0;
|
||||
|
||||
// Used during development & debugging.
|
||||
if (!netPacketHandlerIsRunning()) {
|
||||
callback(NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
BEGIN
|
||||
|
||||
// Add new entries to anything already in the queue.
|
||||
NEW(FileListT, newList);
|
||||
newList->callback = callback;
|
||||
newList->files = NULL;
|
||||
while (vpaths[i] != NULL) {
|
||||
arrput(newList->files, strdup(vpaths[i]));
|
||||
i++;
|
||||
}
|
||||
newList->files = vpathArr;
|
||||
arrput(_fileList, newList);
|
||||
|
||||
// New queue?
|
||||
|
|
|
@ -29,6 +29,7 @@ typedef void (*fileCallback)(char *updatedFile);
|
|||
|
||||
|
||||
void fileCacheCheck(fileCallback callback, char *vpaths[]);
|
||||
void fileCacheCheckArr(fileCallback callback, char **vpathArr);
|
||||
|
||||
|
||||
#endif // FILE_H
|
||||
|
|
|
@ -218,6 +218,7 @@ void guiDelayedFree(void **pointer) {
|
|||
// Delayed Free allows freeing of data that may be in use by the
|
||||
// GUI system at a safe time. (After compositing.)
|
||||
arrput(_guiPendingFrees, *pointer);
|
||||
*pointer = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
@ -230,6 +231,7 @@ void guiDelete(WidgetT **widget) {
|
|||
// that is also handled in the paint event.
|
||||
|
||||
arrput(_guiDeleteList, widget);
|
||||
*widget = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -42,6 +42,11 @@ static void listboxScrollUp(ListboxT *listbox);
|
|||
static void listboxSizesRecalculate(ListboxT *listbox);
|
||||
|
||||
|
||||
uint32_t listboxDataGet(ListboxT *listbox) {
|
||||
return listbox->values[listbox->selected]->data;
|
||||
}
|
||||
|
||||
|
||||
static void listboxDel(WidgetT **widget) {
|
||||
ListboxT *l = (ListboxT *)*widget;
|
||||
|
||||
|
@ -83,7 +88,19 @@ WidgetT *listboxInit(WidgetT *widget, char *title) {
|
|||
|
||||
|
||||
void listboxItemAdd(ListboxT *listbox, char *item) {
|
||||
arrput(listbox->values, strdup(item));
|
||||
listboxItemAddWithData(listbox, item, 0);
|
||||
}
|
||||
|
||||
|
||||
void listboxItemAddWithData(ListboxT *listbox, char *item, uint32_t data) {
|
||||
ListboxItemT *i;
|
||||
|
||||
NEW(ListboxItemT, i);
|
||||
|
||||
i->text = strdup(item);
|
||||
i->data = data;
|
||||
arrput(listbox->values, i);
|
||||
|
||||
GUI_SET_FLAG((WidgetT *)listbox, WIDGET_FLAG_DIRTY);
|
||||
}
|
||||
|
||||
|
@ -94,7 +111,8 @@ void listboxItemRemove(ListboxT *listbox, char *item) {
|
|||
|
||||
if (len > 0) {
|
||||
for (x=0; x<len; x++) {
|
||||
if (strcmp(item, listbox->values[x]) == 0) {
|
||||
if (strcmp(item, listbox->values[x]->text) == 0) {
|
||||
DEL(listbox->values[x]->text);
|
||||
DEL(listbox->values[x]);
|
||||
arrdel(listbox->values, x);
|
||||
if (listbox->selected > len || listbox->selected > 0) listbox->selected--;
|
||||
|
@ -108,12 +126,20 @@ void listboxItemRemove(ListboxT *listbox, char *item) {
|
|||
|
||||
void listboxItemsClear(ListboxT *listbox) {
|
||||
while (arrlen(listbox->values) > 0) {
|
||||
DEL(listbox->values[0]->text);
|
||||
DEL(listbox->values[0]);
|
||||
arrdel(listbox->values, 0);
|
||||
}
|
||||
arrfree(listbox->values);
|
||||
|
||||
listbox->selected = 0;
|
||||
|
||||
GUI_SET_FLAG((WidgetT *)listbox, WIDGET_FLAG_DIRTY);
|
||||
}
|
||||
|
||||
|
||||
uint16_t listboxItemsCountGet(ListboxT *listbox) {
|
||||
return arrlen(listbox->values);
|
||||
}
|
||||
|
||||
|
||||
|
@ -278,9 +304,9 @@ static void listboxPaint(WidgetT *widget, uint8_t enabled, RectT pos) {
|
|||
for (i=0; i<items; i++) {
|
||||
if (i == l->selected) {
|
||||
surfaceRectangleFilledDraw(pos.x + __guiMetric[METRIC_LISTBOX_HORIZONTAL_PADDING], o, pos.x + _valueWidth - __guiMetric[METRIC_LISTBOX_HORIZONTAL_PADDING], o + fontHeightGet(__guiFont) - 1, __guiColor[COLOR_LISTBOX_SELECTED_BACKGROUND]);
|
||||
fontRender(__guiFont, l->values[l->offset + i], __guiColor[COLOR_LISTBOX_SELECTED_TEXT], __guiColor[COLOR_LISTBOX_SELECTED_BACKGROUND], pos.x + 1 + __guiMetric[METRIC_LISTBOX_HORIZONTAL_PADDING], o);
|
||||
fontRender(__guiFont, l->values[l->offset + i]->text, __guiColor[COLOR_LISTBOX_SELECTED_TEXT], __guiColor[COLOR_LISTBOX_SELECTED_BACKGROUND], pos.x + 1 + __guiMetric[METRIC_LISTBOX_HORIZONTAL_PADDING], o);
|
||||
} else {
|
||||
fontRender(__guiFont, l->values[l->offset + i], __guiColor[COLOR_LISTBOX_TEXT], __guiColor[COLOR_LISTBOX_BACKGROUND], pos.x + 1 + __guiMetric[METRIC_LISTBOX_HORIZONTAL_PADDING], o);
|
||||
fontRender(__guiFont, l->values[l->offset + i]->text, __guiColor[COLOR_LISTBOX_TEXT], __guiColor[COLOR_LISTBOX_BACKGROUND], pos.x + 1 + __guiMetric[METRIC_LISTBOX_HORIZONTAL_PADDING], o);
|
||||
}
|
||||
o += fontHeightGet(__guiFont);
|
||||
}
|
||||
|
@ -389,7 +415,7 @@ void listboxTitleSet(ListboxT *listbox, char *title) {
|
|||
|
||||
|
||||
char *listboxValueGet(ListboxT *listbox) {
|
||||
return listbox->values[listbox->selected];
|
||||
return listbox->values[listbox->selected]->text;
|
||||
}
|
||||
|
||||
|
||||
|
@ -399,7 +425,7 @@ void listboxValueSet(ListboxT *listbox, char *value) {
|
|||
|
||||
if (len > 0) {
|
||||
for (x=0; x<len; x++) {
|
||||
if (strcmp(value, listbox->values[x]) == 0) {
|
||||
if (strcmp(value, listbox->values[x]->text) == 0) {
|
||||
listbox->selected = x;
|
||||
GUI_SET_FLAG((WidgetT *)listbox, WIDGET_FLAG_DIRTY);
|
||||
break;
|
||||
|
|
|
@ -26,22 +26,30 @@
|
|||
#include "widget.h"
|
||||
|
||||
|
||||
typedef struct ListboxItemS {
|
||||
char *text;
|
||||
uint32_t data;
|
||||
} ListboxItemT;
|
||||
|
||||
typedef struct ListboxS {
|
||||
WidgetT base; // Must be first in every widget
|
||||
char *title;
|
||||
char **values;
|
||||
ListboxItemT **values;
|
||||
uint16_t selected; // values[offset + selected]
|
||||
int32_t step;
|
||||
int32_t offset;
|
||||
} ListboxT;
|
||||
|
||||
|
||||
uint32_t listboxDataGet(ListboxT *listbox);
|
||||
uint16_t listboxIndexGet(ListboxT *listbox);
|
||||
void listboxIndexSet(ListboxT *listbox, uint16_t index);
|
||||
WidgetT *listboxInit(WidgetT *widget, char *title);
|
||||
void listboxItemAdd(ListboxT *listbox, char *item);
|
||||
void listboxItemAddWithData(ListboxT *listbox, char *item, uint32_t data);
|
||||
void listboxItemRemove(ListboxT *listbox, char *item);
|
||||
void listboxItemsClear(ListboxT *listbox);
|
||||
uint16_t listboxItemsCountGet(ListboxT *listbox);
|
||||
ListboxT *listboxNew(uint16_t x, uint16_t y, uint16_t w, uint16_t h, char *title);
|
||||
void listboxStepSet(ListboxT *listbox, int32_t step);
|
||||
void listboxTitleSet(ListboxT *listbox, char *title);
|
||||
|
|
|
@ -117,6 +117,21 @@ static void picturePaint(WidgetT *widget, uint8_t enabled, RectT pos) {
|
|||
}
|
||||
|
||||
|
||||
void pictureReplace(PictureT *picture, char *filename) {
|
||||
ImageT *newImage = NULL;
|
||||
|
||||
newImage = imageLoadCache(filename);
|
||||
if (newImage) {
|
||||
DEL(picture->filename);
|
||||
picture->filename = strdup(filename);
|
||||
imageUnload(&picture->image);
|
||||
picture->image = newImage;
|
||||
GUI_SET_FLAG(W(picture), WIDGET_FLAG_DIRTY);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void pictureZoomSet(PictureT *picture, PictureZoomT zoom) {
|
||||
picture->zoom = zoom;
|
||||
GUI_SET_FLAG(W(picture), WIDGET_FLAG_DIRTY);
|
||||
|
|
|
@ -45,6 +45,7 @@ typedef struct PictureS {
|
|||
void pictureClickHandlerSet(PictureT *picture, widgetCallback callback);
|
||||
WidgetT *pictureInit(WidgetT *widget, char *filename);
|
||||
PictureT *pictureNew(uint16_t x, uint16_t y, char *filename);
|
||||
void pictureReplace(PictureT *picture, char *filename);
|
||||
void pictureZoomSet(PictureT *picture, PictureZoomT zoom);
|
||||
|
||||
|
||||
|
|
|
@ -145,6 +145,16 @@ static void menuFilesReady(char *updatedFile) {
|
|||
}
|
||||
|
||||
|
||||
void menuHide(void) {
|
||||
guiDelete(D(_picChat));
|
||||
guiDelete(D(_picEmail));
|
||||
guiDelete(D(_picForums));
|
||||
guiDelete(D(_picGames));
|
||||
guiDelete(D(_picLogoff));
|
||||
guiDelete(D(_picProfile));
|
||||
}
|
||||
|
||||
|
||||
void menuShow(void) {
|
||||
char *fileList[] = {
|
||||
"menu:48chat.png",
|
||||
|
@ -154,6 +164,9 @@ void menuShow(void) {
|
|||
"menu:48logoff.png",
|
||||
"menu:48profile.png",
|
||||
"generated:games.dat",
|
||||
"browser:no-box.png",
|
||||
"browser:no-screen.png",
|
||||
// "browser:no-banner.png",
|
||||
|
||||
// LOAD THE WORLD! This is for debugging the browser.
|
||||
"games:d:descent:banner.png",
|
||||
|
@ -295,8 +308,6 @@ void menuShow(void) {
|
|||
"games:s:sre:screen1.png",
|
||||
"games:s:sre:screen1-thumb.png",
|
||||
"games:s:sre:banner.png",
|
||||
"browser:no-box.png",
|
||||
"browser:no-screen.png",
|
||||
|
||||
NULL
|
||||
};
|
||||
|
@ -357,44 +368,6 @@ static void picProfileClick(WidgetT *widget) {
|
|||
}
|
||||
|
||||
|
||||
uint8_t utilFromFileReadByte(FILE *f, uint8_t *result) {
|
||||
unsigned char c;
|
||||
|
||||
// Get next byte.
|
||||
c = fgetc(f);
|
||||
// End of file?
|
||||
if (feof(f)) return FAIL;
|
||||
// Add to result.
|
||||
*result = c;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
uint8_t utilFromFileReadString(FILE *f, char **result) {
|
||||
unsigned char c;
|
||||
char buffer[GAME_MAX_DESCRIPTION];
|
||||
uint16_t x = 0;
|
||||
|
||||
// Something already in 'result'?
|
||||
DEL(*result);
|
||||
|
||||
while (1) {
|
||||
// Get next byte.
|
||||
c = fgetc(f);
|
||||
// End of file?
|
||||
if (feof(f)) return FAIL;
|
||||
// Add to result.
|
||||
buffer[x++] = c;
|
||||
buffer[x] = 0;
|
||||
// End of string?
|
||||
if (c == 0) {
|
||||
*result = strdup(buffer);
|
||||
return SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* static */ void updateGameDatabase(void) {
|
||||
FILE *f = NULL;
|
||||
uint8_t result;
|
||||
|
@ -491,16 +464,7 @@ uint8_t utilFromFileReadString(FILE *f, char **result) {
|
|||
dbExecute("DELETE FROM games WHERE touched=0", NULL);
|
||||
|
||||
// Free 'game'.
|
||||
DEL(game.title);
|
||||
DEL(game.publisher);
|
||||
DEL(game.developer);
|
||||
DEL(game.description);
|
||||
DEL(game.releaseDate);
|
||||
DEL(game.rating);
|
||||
DEL(game.series);
|
||||
DEL(game.origin);
|
||||
DEL(game.shortName);
|
||||
DEL(game.worksWith);
|
||||
gameClear(&game);
|
||||
|
||||
//***TODO*** Did we have problems updating the game database?
|
||||
if (result == FAIL) {
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "os.h"
|
||||
|
||||
|
||||
void menuHide(void);
|
||||
void menuShow(void);
|
||||
|
||||
|
||||
|
|
|
@ -55,50 +55,37 @@ void runtimeDataLoad(void) {
|
|||
|
||||
void runtimeDataUpdate(void) {
|
||||
FILE *f;
|
||||
uint8_t c;
|
||||
char name[33];
|
||||
char data[1025];
|
||||
uint8_t which = 0; // 0 = Reading name, 1 = Reading data.
|
||||
uint16_t x = 0;
|
||||
char *name = NULL;
|
||||
char *data = NULL;
|
||||
uint8_t result = FAIL;
|
||||
|
||||
f = cacheFOpen("generated:client.dat", "rb");
|
||||
if (f) {
|
||||
while (1) {
|
||||
// Get next byte.
|
||||
c = fgetc(f);
|
||||
// End of file?
|
||||
if (feof(f)) break;
|
||||
// End of string?
|
||||
if (c == 0) {
|
||||
if (which == 0) {
|
||||
// Got the name, move on to data.
|
||||
which++;
|
||||
name[x] = 0;
|
||||
x = 0;
|
||||
} else {
|
||||
// Got data. Write both to database and start over.
|
||||
which = 0;
|
||||
data[x] = 0;
|
||||
x = 0;
|
||||
dbExecute(
|
||||
"REPLACE INTO data (name, data) VALUES (?, ?)",
|
||||
"vv",
|
||||
name, data
|
||||
);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// Got byte.
|
||||
if (which == 0) {
|
||||
name[x++] = c;
|
||||
} else {
|
||||
data[x++] = c;
|
||||
// If this first read fails, we're out of data. Any other read fails, we have problems.
|
||||
if (!utilFromFileReadString(f, &name)) {
|
||||
result = SUCCESS;
|
||||
break;
|
||||
}
|
||||
if (!utilFromFileReadString(f, &data)) break;
|
||||
// Write this to the database.
|
||||
dbExecute(
|
||||
"REPLACE INTO data (name, data) VALUES (?, ?)",
|
||||
"vv",
|
||||
name, data
|
||||
);
|
||||
DEL(name);
|
||||
DEL(data);
|
||||
}
|
||||
cacheFClose(f);
|
||||
}
|
||||
|
||||
runtimeDataLoad();
|
||||
//***TODO*** Did we have problems updating the runtime data?
|
||||
if (result == FAIL) {
|
||||
// Do something here.
|
||||
} else {
|
||||
runtimeDataLoad();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -206,7 +206,6 @@ static void settingsComShow(void) {
|
|||
|
||||
|
||||
static void timSettingsProgress(WidgetT *widget) {
|
||||
char buffer[1024];
|
||||
int32_t rc;
|
||||
uint32_t len;
|
||||
|
||||
|
@ -224,8 +223,8 @@ static void timSettingsProgress(WidgetT *widget) {
|
|||
case S_OPEN_COM:
|
||||
rc = comOpen(com, 57600L, 8, 'n', 1, SER_HANDSHAKING_RTSCTS);
|
||||
if (rc == SER_SUCCESS) {
|
||||
snprintf(buffer, 1023, "%s%c", "AT+SOCK1", 13);
|
||||
comWrite(com, buffer, strlen(buffer));
|
||||
snprintf(_scratch, SCRATCH_SIZE, "%s%c", "AT+SOCK1", 13);
|
||||
comWrite(com, _scratch, strlen(_scratch));
|
||||
timerQuarterSecondsSet((TimerT *)widget, 4);
|
||||
_state = S_WAIT_FOR_INIT;
|
||||
} else {
|
||||
|
@ -243,16 +242,16 @@ static void timSettingsProgress(WidgetT *widget) {
|
|||
break;
|
||||
|
||||
case S_WAIT_FOR_INIT:
|
||||
len = comRead(com, buffer, 1023);
|
||||
buffer[len] = 0;
|
||||
if (strstr(buffer, "OK")) {
|
||||
len = comRead(com, _scratch, SCRATCH_SIZE);
|
||||
_scratch[len] = 0;
|
||||
if (strstr(_scratch, "OK")) {
|
||||
snprintf(_port[com].title, TITLE_LEN - 1, "COM%d - Modem Found!", com + 1);
|
||||
_port[com].status = PORT_GOOD_MODEM;
|
||||
_port[com].selected = selected;
|
||||
_port[com].enabled = 1;
|
||||
selected = 0;
|
||||
} else {
|
||||
if (strstr(buffer, "ERROR")) {
|
||||
if (strstr(_scratch, "ERROR")) {
|
||||
snprintf(_port[com].title, TITLE_LEN - 1, "COM%d - Incompatable Modem", com + 1);
|
||||
_port[com].status = PORT_BAD_MODEM;
|
||||
_port[com].selected = 0;
|
||||
|
|
|
@ -82,6 +82,11 @@ void netChannelSystemRelease(netPacketHandler handler) {
|
|||
}
|
||||
|
||||
|
||||
uint8_t netPacketHandlerIsRunning(void) {
|
||||
return _netRunning;
|
||||
}
|
||||
|
||||
|
||||
void netPacketHandlerStart(void) {
|
||||
_netRunning = 1;
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ uint8_t netChannelGet(netPacketHandler handler);
|
|||
void netChannelRelease(uint8_t channel);
|
||||
void netChannelSystemGet(netPacketHandler handler);
|
||||
void netChannelSystemRelease(netPacketHandler handler);
|
||||
uint8_t netPacketHandlerIsRunning(void);
|
||||
void netPacketHandlerStart(void);
|
||||
void netPacketHandlerStop(void);
|
||||
void netProcess(void);
|
||||
|
|
|
@ -21,6 +21,9 @@
|
|||
#include "os.h"
|
||||
|
||||
|
||||
char _scratch[SCRATCH_SIZE];
|
||||
|
||||
|
||||
uint8_t osFileExists(char *filename) {
|
||||
FILE *f = fopen(filename, "rb");
|
||||
if (f) {
|
||||
|
|
|
@ -42,7 +42,8 @@
|
|||
#define TICKS_PER_SECOND 18.2
|
||||
#define TICKS_PER_DAY (SECONDS_IN_DAY * TICKS_PER_SECOND)
|
||||
|
||||
#define OS_PATH_MAX 256
|
||||
#define OS_PATH_MAX 256
|
||||
#define SCRATCH_SIZE 4096
|
||||
|
||||
|
||||
#ifdef __linux__
|
||||
|
@ -79,11 +80,14 @@ void linuxOsStartup(void);
|
|||
#include "packet.h"
|
||||
#include "cache.h"
|
||||
|
||||
|
||||
#ifndef PacketThreadDataT
|
||||
typedef struct PacketThreadDataS PacketThreadDataT;
|
||||
#endif
|
||||
|
||||
|
||||
extern PacketThreadDataT *__packetThreadData; // Declared in main.c
|
||||
extern char _scratch[SCRATCH_SIZE]; // Declared in os.c
|
||||
|
||||
|
||||
uint8_t osFileExists(char *filename);
|
||||
|
|
|
@ -249,7 +249,6 @@ static void timWelcomeProgress(WidgetT *widget) {
|
|||
TimerT *t = (TimerT *)widget;
|
||||
int32_t r = 0;
|
||||
uint32_t len = 0;
|
||||
static char buffer[1024] = { 0 };
|
||||
static uint16_t offset = 0;
|
||||
|
||||
BEGIN
|
||||
|
@ -279,25 +278,25 @@ static void timWelcomeProgress(WidgetT *widget) {
|
|||
break;
|
||||
}
|
||||
// Send a CR to clear anything in the modem.
|
||||
snprintf(buffer, 1023, "%c", 13);
|
||||
comWrite(__configData.serialCom - 1, buffer, strlen(buffer));
|
||||
snprintf(_scratch, SCRATCH_SIZE, "%c", 13);
|
||||
comWrite(__configData.serialCom - 1, _scratch, strlen(_scratch));
|
||||
timerQuarterSecondsSet(t, 4);
|
||||
_state = S_INIT_MODEM;
|
||||
break;
|
||||
|
||||
case S_INIT_MODEM:
|
||||
// Just read anything to clear the buffer.
|
||||
comRead(__configData.serialCom - 1, buffer, 1023);
|
||||
comRead(__configData.serialCom - 1, _scratch, SCRATCH_SIZE);
|
||||
// Send actual init
|
||||
snprintf(buffer, 1023, "%s%c", "AT+SOCK1", 13);
|
||||
comWrite(__configData.serialCom - 1, buffer, strlen(buffer));
|
||||
snprintf(_scratch, SCRATCH_SIZE, "%s%c", "AT+SOCK1", 13);
|
||||
comWrite(__configData.serialCom - 1, _scratch, strlen(_scratch));
|
||||
_state = S_INIT_RESULT;
|
||||
break;
|
||||
|
||||
case S_INIT_RESULT:
|
||||
len = comRead(__configData.serialCom - 1, buffer, 1023);
|
||||
buffer[len] = 0;
|
||||
if (strstr(buffer, "OK") == NULL) {
|
||||
len = comRead(__configData.serialCom - 1, _scratch, SCRATCH_SIZE);
|
||||
_scratch[len] = 0;
|
||||
if (strstr(_scratch, "OK") == NULL) {
|
||||
comClose(__configData.serialCom - 1);
|
||||
timerStop(t);
|
||||
// Restore mouse.
|
||||
|
@ -312,8 +311,8 @@ static void timWelcomeProgress(WidgetT *widget) {
|
|||
break;
|
||||
|
||||
case S_DIAL:
|
||||
snprintf(buffer, 1023, "ATDT%s:%d%c", __configData.serverHost, __configData.serverPort, 13);
|
||||
comWrite(__configData.serialCom - 1, buffer, strlen(buffer));
|
||||
snprintf(_scratch, SCRATCH_SIZE, "ATDT%s:%d%c", __configData.serverHost, __configData.serverPort, 13);
|
||||
comWrite(__configData.serialCom - 1, _scratch, strlen(_scratch));
|
||||
timerQuarterSecondsSet(t, 0); // Run as fast as we can so we don't miss any data.
|
||||
offset = 0;
|
||||
_timeoutCounter = 7 * 4; // Seven seconds.
|
||||
|
@ -322,11 +321,11 @@ static void timWelcomeProgress(WidgetT *widget) {
|
|||
|
||||
case S_WAIT_FOR_BANNER:
|
||||
// Process incoming bytes one at a time so we don't accidentally eat the first packet after the banner.
|
||||
len = comRead(__configData.serialCom - 1, &buffer[offset], 1);
|
||||
len = comRead(__configData.serialCom - 1, &_scratch[offset], 1);
|
||||
offset += len;
|
||||
buffer[offset] = 0;
|
||||
_scratch[offset] = 0;
|
||||
// ***TODO*** Should probably cleanly handle a full server here with some kind of SERVER_FULL packet.
|
||||
if (strstr(buffer, "KPMPGSMKII\rOKAY\r") != NULL) {
|
||||
if (strstr(_scratch, "KPMPGSMKII\rOKAY\r") != NULL) {
|
||||
// Connect! Start packet handler and negotiate encryption.
|
||||
netPacketHandlerStart();
|
||||
packetEncryptionSetup(__packetThreadData);
|
||||
|
|
41
shared/game.c
Normal file
41
shared/game.c
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "game.h"
|
||||
|
||||
|
||||
void gameClear(GameT *game) {
|
||||
DEL(game->title);
|
||||
DEL(game->publisher);
|
||||
DEL(game->developer);
|
||||
DEL(game->description);
|
||||
DEL(game->releaseDate);
|
||||
DEL(game->rating);
|
||||
DEL(game->series);
|
||||
DEL(game->origin);
|
||||
DEL(game->shortName);
|
||||
DEL(game->worksWith);
|
||||
game->type = GAME_TYPE_UNKNOWN;
|
||||
game->maxPlayers = 0;
|
||||
game->joinable = 0;
|
||||
game->screens = 0;
|
||||
game->boxes = 0;
|
||||
game->ROWID = 0;
|
||||
}
|
|
@ -53,7 +53,11 @@ typedef struct GameS { // Data type in DAT file sent to client.
|
|||
uint8_t joinable; // 1
|
||||
uint8_t screens; // 1
|
||||
uint8_t boxes; // 1
|
||||
uint64_t ROWID; // Provided by SQLite.
|
||||
} GameT;
|
||||
|
||||
|
||||
void gameClear(GameT *game);
|
||||
|
||||
|
||||
#endif // GAME_H
|
||||
|
|
|
@ -119,6 +119,43 @@ uint8_t utilFileExists(char *filename) {
|
|||
}
|
||||
|
||||
|
||||
uint8_t utilFromFileReadByte(FILE *f, uint8_t *result) {
|
||||
unsigned char c;
|
||||
|
||||
// Get next byte.
|
||||
c = fgetc(f);
|
||||
// End of file?
|
||||
if (feof(f)) return FAIL;
|
||||
// Add to result.
|
||||
*result = c;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
uint8_t utilFromFileReadString(FILE *f, char **result) {
|
||||
unsigned char c;
|
||||
uint16_t x = 0;
|
||||
|
||||
// Something already in 'result'?
|
||||
DEL(*result);
|
||||
|
||||
while (1) {
|
||||
// Get next byte.
|
||||
c = fgetc(f);
|
||||
// End of file?
|
||||
if (feof(f)) return FAIL;
|
||||
// Add to result.
|
||||
_scratch[x++] = c;
|
||||
_scratch[x] = 0;
|
||||
// End of string?
|
||||
if (c == 0) {
|
||||
*result = strdup(_scratch);
|
||||
return SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void utilStringToLower(char *string) {
|
||||
uint16_t i;
|
||||
|
||||
|
|
|
@ -31,6 +31,8 @@ char *utilCreateString(char *format, ...);
|
|||
char *utilCreateStringVArgs(char *format, va_list args);
|
||||
void utilDie(const char *why, ...);
|
||||
uint8_t utilFileExists(char *filename);
|
||||
uint8_t utilFromFileReadByte(FILE *f, uint8_t *result);
|
||||
uint8_t utilFromFileReadString(FILE *f, char **result);
|
||||
void utilStringToLower(char *string);
|
||||
char **utilWrapText(char *text, uint16_t width);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue