Some label fixes
This commit is contained in:
+3
-4
@@ -14,10 +14,9 @@ cmake_policy(SET CMP0079 NEW)
|
||||
|
||||
option(DUSK_BUILD_TESTS "Enable tests" OFF)
|
||||
|
||||
# Game identity — override these per-project
|
||||
set(DUSK_GAME_NAME "Dusk" CACHE STRING "Game display name")
|
||||
set(DUSK_GAME_AUTHOR "YouWish" CACHE STRING "Game author / coder")
|
||||
set(DUSK_GAME_SHORT_DESCRIPTION "Dusk game" CACHE STRING "One-line description")
|
||||
set(DUSK_GAME_NAME "Dusk" CACHE STRING "Game display name")
|
||||
set(DUSK_GAME_AUTHOR "YourWishes" CACHE STRING "Game author / coder")
|
||||
set(DUSK_GAME_SHORT_DESCRIPTION "Dusk game" CACHE STRING "One-line description")
|
||||
set(DUSK_GAME_LONG_DESCRIPTION "No description yet." CACHE STRING "Full description")
|
||||
|
||||
# Prep cache
|
||||
|
||||
@@ -45,7 +45,7 @@ endif()
|
||||
|
||||
# Link libraries.
|
||||
# zip/z/lzma use target_link_options (raw flags) to bypass cmake target
|
||||
# resolution — pkg-config-generated targets for these carry ZLIB::ZLIB in
|
||||
# resolution - pkg-config-generated targets for these carry ZLIB::ZLIB in
|
||||
# INTERFACE_LINK_LIBRARIES which breaks the PPC link step.
|
||||
target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PRIVATE
|
||||
cglm
|
||||
|
||||
@@ -18,7 +18,7 @@ void uiSettingsSelected(
|
||||
const uint8_t index,
|
||||
const uimenuitem_t *item
|
||||
) {
|
||||
if(item->type == UIMENU_WIDGET_TYPE_CHECKBOX) {
|
||||
if(item->type == UI_MENU_WIDGET_TYPE_CHECKBOX) {
|
||||
uiCheckboxToggle(&UI_SETTINGS.items[index].checkbox);
|
||||
}
|
||||
}
|
||||
@@ -30,27 +30,42 @@ void uiSettingsClosed(const uimenu_t *menu) {
|
||||
errorret_t uiSettingsInit(void) {
|
||||
memoryZero(&UI_SETTINGS, sizeof(uisettings_t));
|
||||
|
||||
UI_SETTINGS.items[0] = (uimenuitem_t){
|
||||
.type = UIMENU_WIDGET_TYPE_LABEL,
|
||||
uint8_t i = 0;
|
||||
|
||||
UI_SETTINGS.items[i] = (uimenuitem_t){
|
||||
.type = UI_MENU_WIDGET_TYPE_LABEL,
|
||||
.label = "Settings"
|
||||
};
|
||||
UI_SETTINGS.items[1] = (uimenuitem_t){
|
||||
.type = UIMENU_WIDGET_TYPE_LABEL,
|
||||
.label = "Settings two"
|
||||
++i;
|
||||
|
||||
UI_SETTINGS.items[i].type = UI_MENU_WIDGET_TYPE_BUTTON;
|
||||
uiButtonInit(&UI_SETTINGS.items[i].button, "Do thing");
|
||||
++i;
|
||||
|
||||
UI_SETTINGS.items[i].type = UI_MENU_WIDGET_TYPE_BUTTON;
|
||||
uiButtonInit(&UI_SETTINGS.items[i].button, "Do other thing");
|
||||
++i;
|
||||
|
||||
UI_SETTINGS.items[i].type = UI_MENU_WIDGET_TYPE_SPACER;
|
||||
++i;
|
||||
|
||||
UI_SETTINGS.items[i] = (uimenuitem_t){
|
||||
.type = UI_MENU_WIDGET_TYPE_LABEL,
|
||||
.label = "Options"
|
||||
};
|
||||
UI_SETTINGS.items[2] = (uimenuitem_t){
|
||||
.type = UIMENU_WIDGET_TYPE_LABEL,
|
||||
.label = "Settings three"
|
||||
};
|
||||
UI_SETTINGS.items[3].type = UIMENU_WIDGET_TYPE_CHECKBOX;
|
||||
uiCheckboxInit(&UI_SETTINGS.items[3].checkbox, "Enable thing?");
|
||||
++i;
|
||||
|
||||
UI_SETTINGS.items[i].type = UI_MENU_WIDGET_TYPE_CHECKBOX;
|
||||
uiCheckboxInit(&UI_SETTINGS.items[i].checkbox, "Enable thing?");
|
||||
++i;
|
||||
|
||||
assertTrue(i <= UI_SETTINGS_ITEM_COUNT, "Settings item count mismatch");
|
||||
|
||||
uiMenuInit(&UI_SETTINGS.menu, uiSettingsSelected, uiSettingsClosed, NULL);
|
||||
uiMenuSetItems(
|
||||
&UI_SETTINGS.menu,
|
||||
UI_SETTINGS.items,
|
||||
UI_SETTINGS_ITEM_COUNT,
|
||||
2
|
||||
i, 1
|
||||
);
|
||||
|
||||
errorOk();
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include "error/error.h"
|
||||
#include "ui/widget/uimenu.h"
|
||||
|
||||
#define UI_SETTINGS_ITEM_COUNT 4
|
||||
#define UI_SETTINGS_ITEM_COUNT 6
|
||||
|
||||
typedef struct {
|
||||
uimenu_t menu;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
uibutton.c
|
||||
uicheckbox.c
|
||||
uimenu.c
|
||||
)
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "uibutton.h"
|
||||
#include "assert/assert.h"
|
||||
#include "util/memory.h"
|
||||
#include "util/string.h"
|
||||
#include "display/text/text.h"
|
||||
#include "display/color.h"
|
||||
|
||||
void uiButtonInit(uibutton_t *button, const char_t *label) {
|
||||
assertNotNull(button, "Button cannot be NULL");
|
||||
assertNotNull(label, "Label cannot be NULL");
|
||||
memoryZero(button, sizeof(uibutton_t));
|
||||
button->label = label;
|
||||
}
|
||||
|
||||
bool_t uiButtonIsHighlighted(const uibutton_t *button) {
|
||||
assertNotNull(button, "Button cannot be NULL");
|
||||
return button->highlighted;
|
||||
}
|
||||
|
||||
void uiButtonSetHighlighted(uibutton_t *button, const bool_t highlighted) {
|
||||
assertNotNull(button, "Button cannot be NULL");
|
||||
button->highlighted = highlighted;
|
||||
}
|
||||
|
||||
errorret_t uiButtonDraw(
|
||||
const uibutton_t *button,
|
||||
const float_t x,
|
||||
const float_t y
|
||||
) {
|
||||
assertNotNull(button, "Button cannot be NULL");
|
||||
errorChain(textDraw(
|
||||
x, y, button->label,
|
||||
button->highlighted ? COLOR_RED : COLOR_WHITE,
|
||||
&FONT_DEFAULT
|
||||
));
|
||||
errorOk();
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "error/error.h"
|
||||
|
||||
#define UI_BUTTON_LABEL_MAX 32
|
||||
|
||||
typedef struct {
|
||||
const char_t *label;
|
||||
bool_t highlighted;
|
||||
} uibutton_t;
|
||||
|
||||
/**
|
||||
* Initializes a button.
|
||||
*
|
||||
* @param button The button to initialize.
|
||||
* @param label Display label.
|
||||
*/
|
||||
void uiButtonInit(uibutton_t *button, const char_t *label);
|
||||
|
||||
/**
|
||||
* Returns whether the button is highlighted.
|
||||
*
|
||||
* @param button The button to query.
|
||||
* @returns True if highlighted.
|
||||
*/
|
||||
bool_t uiButtonIsHighlighted(const uibutton_t *button);
|
||||
|
||||
/**
|
||||
* Sets the highlighted state of the button.
|
||||
*
|
||||
* @param button The button to update.
|
||||
* @param highlighted The new highlighted state.
|
||||
*/
|
||||
void uiButtonSetHighlighted(uibutton_t *button, const bool_t highlighted);
|
||||
|
||||
/**
|
||||
* Draws the button at the given screen position.
|
||||
*
|
||||
* @param button The button to draw.
|
||||
* @param x Screen x position.
|
||||
* @param y Screen y position.
|
||||
* @return Any error that occurs.
|
||||
*/
|
||||
errorret_t uiButtonDraw(
|
||||
const uibutton_t *button,
|
||||
const float_t x,
|
||||
const float_t y
|
||||
);
|
||||
@@ -16,7 +16,7 @@ void uiCheckboxInit(
|
||||
const char_t *label
|
||||
) {
|
||||
memoryZero(checkbox, sizeof(uicheckbox_t));
|
||||
stringCopy(checkbox->label, label, UI_CHECKBOX_LABEL_MAX);
|
||||
checkbox->label = label;
|
||||
}
|
||||
|
||||
bool_t uiCheckboxIsChecked(const uicheckbox_t *checkbox) {
|
||||
|
||||
@@ -8,10 +8,8 @@
|
||||
#pragma once
|
||||
#include "error/error.h"
|
||||
|
||||
#define UI_CHECKBOX_LABEL_MAX 32
|
||||
|
||||
typedef struct uicheckbox_s {
|
||||
char_t label[UI_CHECKBOX_LABEL_MAX];
|
||||
const char_t *label;
|
||||
bool_t checked;
|
||||
bool_t highlighted;
|
||||
} uicheckbox_t;
|
||||
@@ -20,7 +18,7 @@ typedef struct uicheckbox_s {
|
||||
* Initializes a checkbox.
|
||||
*
|
||||
* @param checkbox The checkbox to initialize.
|
||||
* @param label Display label, truncated to UI_CHECKBOX_LABEL_MAX - 1 chars.
|
||||
* @param label Display label.
|
||||
*/
|
||||
void uiCheckboxInit(
|
||||
uicheckbox_t *checkbox,
|
||||
|
||||
+73
-21
@@ -10,6 +10,7 @@
|
||||
#include "util/memory.h"
|
||||
#include "display/text/text.h"
|
||||
#include "display/color.h"
|
||||
#include "ui/widget/uibutton.h"
|
||||
|
||||
void uiMenuInit(
|
||||
uimenu_t *menu,
|
||||
@@ -52,7 +53,9 @@ void uiMenuOpen(uimenu_t *menu) {
|
||||
assertTrue(menu->columns > 0, "Menu columns must be > 0");
|
||||
if(menu->focusItem != NULL) return;
|
||||
|
||||
uint8_t rows = (menu->itemCount + menu->columns - 1) / menu->columns;
|
||||
uint8_t focusable = uiMenuFocusableCount(menu);
|
||||
uint8_t rows = focusable > 0 ?
|
||||
(focusable + menu->columns - 1) / menu->columns : 1;
|
||||
menu->focusItem = uiFocusPush(
|
||||
menu->columns, rows,
|
||||
uiMenuFocusSelected,
|
||||
@@ -87,34 +90,49 @@ errorret_t uiMenuDraw(
|
||||
float_t colStep = width / (float_t)menu->columns;
|
||||
float_t rowHeight = (float_t)FONT_DEFAULT.tileset->tileHeight;
|
||||
|
||||
uint8_t focusIndex = menu->focusItem != NULL ?
|
||||
menu->focusItem->y * menu->columns + menu->focusItem->x :
|
||||
0xFF;
|
||||
uint8_t col = 0;
|
||||
uint8_t row = 0;
|
||||
|
||||
for(uint8_t i = 0; i < menu->itemCount; i++) {
|
||||
const uimenuitem_t *item = &menu->items[i];
|
||||
uint8_t col = i % menu->columns;
|
||||
uint8_t row = i / menu->columns;
|
||||
|
||||
if(item->type == UI_MENU_WIDGET_TYPE_LABEL) {
|
||||
if(col > 0) { row++; col = 0; }
|
||||
errorChain(textDraw(
|
||||
x,
|
||||
y + (float_t)row * rowHeight,
|
||||
item->label,
|
||||
COLOR_WHITE,
|
||||
&FONT_DEFAULT
|
||||
));
|
||||
row++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(item->type == UI_MENU_WIDGET_TYPE_SPACER) {
|
||||
if(col > 0) { row++; col = 0; }
|
||||
row++;
|
||||
continue;
|
||||
}
|
||||
|
||||
float_t ix = x + (float_t)col * colStep;
|
||||
float_t iy = y + (float_t)row * rowHeight;
|
||||
bool_t highlighted = i == focusIndex;
|
||||
|
||||
switch(item->type) {
|
||||
case UIMENU_WIDGET_TYPE_LABEL:
|
||||
errorChain(textDraw(
|
||||
ix, iy, item->label,
|
||||
highlighted ? COLOR_RED : COLOR_WHITE,
|
||||
&FONT_DEFAULT
|
||||
));
|
||||
case UI_MENU_WIDGET_TYPE_CHECKBOX:
|
||||
errorChain(uiCheckboxDraw(&item->checkbox, ix, iy));
|
||||
break;
|
||||
|
||||
case UIMENU_WIDGET_TYPE_CHECKBOX:
|
||||
errorChain(uiCheckboxDraw(&item->checkbox, ix, iy));
|
||||
case UI_MENU_WIDGET_TYPE_BUTTON:
|
||||
errorChain(uiButtonDraw(&item->button, ix, iy));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
col++;
|
||||
if(col >= menu->columns) { col = 0; row++; }
|
||||
}
|
||||
|
||||
errorOk();
|
||||
@@ -126,8 +144,9 @@ bool_t uiMenuFocusSelected(const uifocusitem_t *focusItem) {
|
||||
uimenu_t *menu = (uimenu_t *)focusItem->user;
|
||||
if(menu->selected == NULL) return true;
|
||||
|
||||
uint8_t index = focusItem->y * menu->columns + focusItem->x;
|
||||
if(index >= menu->itemCount) return true;
|
||||
uint8_t slot = focusItem->y * menu->columns + focusItem->x;
|
||||
uint8_t index = uiMenuFocusSlotToIndex(menu, slot);
|
||||
if(index == 0xFF) return true;
|
||||
|
||||
menu->selected(menu, index, &menu->items[index]);
|
||||
return true;
|
||||
@@ -138,16 +157,27 @@ bool_t uiMenuFocusChanged(const uifocusitem_t *focusItem) {
|
||||
assertNotNull(focusItem->user, "Focus item user cannot be NULL");
|
||||
uimenu_t *menu = (uimenu_t *)focusItem->user;
|
||||
|
||||
uint8_t index = focusItem->y * menu->columns + focusItem->x;
|
||||
uint8_t focusSlot = focusItem->y * menu->columns + focusItem->x;
|
||||
uint8_t slot = 0;
|
||||
|
||||
for(uint8_t i = 0; i < menu->itemCount; i++) {
|
||||
uimenuitem_t *item = &menu->items[i];
|
||||
if(item->type != UIMENU_WIDGET_TYPE_CHECKBOX) continue;
|
||||
uiCheckboxSetHighlighted(&item->checkbox, i == index);
|
||||
if(
|
||||
item->type == UI_MENU_WIDGET_TYPE_LABEL ||
|
||||
item->type == UI_MENU_WIDGET_TYPE_SPACER
|
||||
) continue;
|
||||
bool_t isActive = (slot == focusSlot);
|
||||
if(item->type == UI_MENU_WIDGET_TYPE_CHECKBOX) {
|
||||
uiCheckboxSetHighlighted(&item->checkbox, isActive);
|
||||
} else if(item->type == UI_MENU_WIDGET_TYPE_BUTTON) {
|
||||
uiButtonSetHighlighted(&item->button, isActive);
|
||||
}
|
||||
slot++;
|
||||
}
|
||||
|
||||
if(menu->changed == NULL) return true;
|
||||
if(index >= menu->itemCount) return true;
|
||||
uint8_t index = uiMenuFocusSlotToIndex(menu, focusSlot);
|
||||
if(index == 0xFF) return true;
|
||||
|
||||
menu->changed(menu, index, &menu->items[index]);
|
||||
return true;
|
||||
@@ -161,3 +191,25 @@ bool_t uiMenuFocusClosed(const uifocusitem_t *focusItem) {
|
||||
if(menu->closed != NULL) menu->closed(menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t uiMenuFocusableCount(const uimenu_t *menu) {
|
||||
assertNotNull(menu, "Menu cannot be NULL");
|
||||
uint8_t count = 0;
|
||||
for(uint8_t i = 0; i < menu->itemCount; i++) {
|
||||
uimenuwidgettype_t t = menu->items[i].type;
|
||||
if(t != UI_MENU_WIDGET_TYPE_LABEL && t != UI_MENU_WIDGET_TYPE_SPACER) count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
uint8_t uiMenuFocusSlotToIndex(const uimenu_t *menu, const uint8_t slot) {
|
||||
assertNotNull(menu, "Menu cannot be NULL");
|
||||
uint8_t focusable = 0;
|
||||
for(uint8_t i = 0; i < menu->itemCount; i++) {
|
||||
uimenuwidgettype_t t = menu->items[i].type;
|
||||
if(t == UI_MENU_WIDGET_TYPE_LABEL || t == UI_MENU_WIDGET_TYPE_SPACER) continue;
|
||||
if(focusable == slot) return i;
|
||||
focusable++;
|
||||
}
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#pragma once
|
||||
#include "error/error.h"
|
||||
#include "ui/focus/uifocus.h"
|
||||
#include "ui/widget/uibutton.h"
|
||||
#include "ui/widget/uicheckbox.h"
|
||||
|
||||
#define UI_MENU_LABEL_MAX UI_CHECKBOX_LABEL_MAX
|
||||
@@ -15,16 +16,19 @@
|
||||
typedef struct uimenu_s uimenu_t;
|
||||
|
||||
typedef enum {
|
||||
UIMENU_WIDGET_TYPE_NONE,
|
||||
UIMENU_WIDGET_TYPE_LABEL,
|
||||
UIMENU_WIDGET_TYPE_CHECKBOX,
|
||||
UI_MENU_WIDGET_TYPE_NONE,
|
||||
UI_MENU_WIDGET_TYPE_LABEL,
|
||||
UI_MENU_WIDGET_TYPE_SPACER,
|
||||
UI_MENU_WIDGET_TYPE_CHECKBOX,
|
||||
UI_MENU_WIDGET_TYPE_BUTTON,
|
||||
} uimenuwidgettype_t;
|
||||
|
||||
typedef struct {
|
||||
uimenuwidgettype_t type;
|
||||
union {
|
||||
char_t label[UI_MENU_LABEL_MAX];
|
||||
char_t *label;
|
||||
uicheckbox_t checkbox;
|
||||
uibutton_t button;
|
||||
};
|
||||
} uimenuitem_t;
|
||||
|
||||
@@ -136,7 +140,25 @@ errorret_t uiMenuDraw(
|
||||
);
|
||||
|
||||
/**
|
||||
* Internal focus callback — forwards selection to the menu's selected handler.
|
||||
* Returns the number of focusable (non-label) items in the menu.
|
||||
*
|
||||
* @param menu The menu to query.
|
||||
* @returns Count of non-label items.
|
||||
*/
|
||||
uint8_t uiMenuFocusableCount(const uimenu_t *menu);
|
||||
|
||||
/**
|
||||
* Maps a flat focus slot index to the corresponding item array index,
|
||||
* skipping over label items which are not focusable.
|
||||
*
|
||||
* @param menu The menu to query.
|
||||
* @param slot The focus slot index (y * columns + x).
|
||||
* @returns The item array index, or 0xFF if out of range.
|
||||
*/
|
||||
uint8_t uiMenuFocusSlotToIndex(const uimenu_t *menu, const uint8_t slot);
|
||||
|
||||
/**
|
||||
* Internal focus callback - forwards selection to the menu's selected handler.
|
||||
*
|
||||
* @param focusItem The active focus item; user field must point to uimenu_t.
|
||||
* @returns True.
|
||||
@@ -144,7 +166,7 @@ errorret_t uiMenuDraw(
|
||||
bool_t uiMenuFocusSelected(const uifocusitem_t *focusItem);
|
||||
|
||||
/**
|
||||
* Internal focus callback — updates checkbox highlights and fires changed.
|
||||
* Internal focus callback - updates widget highlights and fires changed.
|
||||
*
|
||||
* @param focusItem The active focus item; user field must point to uimenu_t.
|
||||
* @returns True.
|
||||
@@ -152,7 +174,7 @@ bool_t uiMenuFocusSelected(const uifocusitem_t *focusItem);
|
||||
bool_t uiMenuFocusChanged(const uifocusitem_t *focusItem);
|
||||
|
||||
/**
|
||||
* Internal focus callback — clears focusItem and fires the closed handler.
|
||||
* Internal focus callback - clears focusItem and fires the closed handler.
|
||||
*
|
||||
* @param focusItem The active focus item; user field must point to uimenu_t.
|
||||
* @returns True.
|
||||
|
||||
@@ -108,7 +108,7 @@ static void test_assertStrLenMin(void **state) {
|
||||
}
|
||||
|
||||
static void test_assertIsMainThread(void **state) {
|
||||
// The group setup recorded this thread as main — assertIsMainThread must pass.
|
||||
// The group setup recorded this thread as main - assertIsMainThread must pass.
|
||||
assertIsMainThread("test thread is main, should not assert");
|
||||
|
||||
// assertNotMainThread must fail when called from the main thread.
|
||||
|
||||
+10
-10
@@ -40,7 +40,7 @@ static int asset_setup(void **state) {
|
||||
// Save real callbacks so we can restore them in teardown.
|
||||
memoryCopy(saved_callbacks, ASSET_LOADER_CALLBACKS, sizeof(saved_callbacks));
|
||||
|
||||
// Manually init ASSET — no thread, no ZIP.
|
||||
// Manually init ASSET - no thread, no ZIP.
|
||||
memoryZero(&ASSET, sizeof(ASSET));
|
||||
for(size_t i = 0; i < ASSET_LOADING_COUNT_MAX; i++) {
|
||||
threadMutexInit(&ASSET.loading[i].mutex);
|
||||
@@ -117,7 +117,7 @@ static void test_getEntry_distinct_names(void **state) {
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// assetUpdate — state machine tests
|
||||
// assetUpdate - state machine tests
|
||||
// ============================================================
|
||||
|
||||
static void test_update_entry_reaches_loaded(void **state) {
|
||||
@@ -252,7 +252,7 @@ static void test_update_overflow_queues_entries(void **state) {
|
||||
}
|
||||
assert_int_equal(entries[ASSET_LOADING_COUNT_MAX]->state, ASSET_ENTRY_STATE_NOT_STARTED);
|
||||
|
||||
// Unlock first batch — the reaper can collect them in update 2.
|
||||
// Unlock first batch - the reaper can collect them in update 2.
|
||||
for(int i = 0; i < ASSET_LOADING_COUNT_MAX; i++) {
|
||||
assetEntryUnlock(entries[i]);
|
||||
}
|
||||
@@ -284,7 +284,7 @@ static void test_update_error_slot_stays_occupied(void **state) {
|
||||
assetUpdate();
|
||||
assert_int_equal(entry->state, ASSET_ENTRY_STATE_ERROR);
|
||||
|
||||
// Unlike LOADED, the ERROR case does NOT clear the slot — it throws instead.
|
||||
// Unlike LOADED, the ERROR case does NOT clear the slot - it throws instead.
|
||||
assert_true(loading_slot_has_entry(entry));
|
||||
|
||||
errorret_t ret = assetUpdate();
|
||||
@@ -295,7 +295,7 @@ static void test_update_error_slot_stays_occupied(void **state) {
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// assetEntryInit — input copy
|
||||
// assetEntryInit - input copy
|
||||
// ============================================================
|
||||
|
||||
static void test_getEntry_null_input_stays_null(void **state) {
|
||||
@@ -312,7 +312,7 @@ static void test_getEntry_input_copied_into_entry(void **state) {
|
||||
|
||||
assetentry_t *entry = assetGetEntry("test.texture", ASSET_LOADER_TYPE_TEXTURE, &input);
|
||||
|
||||
// input must have been copied — entry->input must point inside the entry.
|
||||
// input must have been copied - entry->input must point inside the entry.
|
||||
assert_non_null(entry->input);
|
||||
assert_ptr_equal(entry->input, &entry->inputData);
|
||||
assert_int_equal((int)entry->input->texture, 42);
|
||||
@@ -321,7 +321,7 @@ static void test_getEntry_input_copied_into_entry(void **state) {
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// assetUpdate — re-entrant sync loader
|
||||
// assetUpdate - re-entrant sync loader
|
||||
// ============================================================
|
||||
|
||||
static assetentry_t *reentrant_inner_entry = NULL;
|
||||
@@ -362,7 +362,7 @@ static void test_update_reentrant_sync_loader(void **state) {
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// assetGetEntry — dedup against non-NOT_STARTED entries
|
||||
// assetGetEntry - dedup against non-NOT_STARTED entries
|
||||
// ============================================================
|
||||
|
||||
static void test_getEntry_returns_loaded_entry(void **state) {
|
||||
@@ -464,7 +464,7 @@ static void test_requireLoaded_propagates_error(void **state) {
|
||||
|
||||
assetentry_t *entry = assetGetEntry("fail.locale", ASSET_LOADER_TYPE_LOCALE, NULL);
|
||||
|
||||
// requireLoaded spins assetUpdate until LOADED — but the loader always fails,
|
||||
// requireLoaded spins assetUpdate until LOADED - but the loader always fails,
|
||||
// so the second assetUpdate sees ERROR and throws, which errorChain propagates.
|
||||
errorret_t ret = assetRequireLoaded(entry);
|
||||
assert_true(errorIsNotOk(ret));
|
||||
@@ -489,7 +489,7 @@ int main(void) {
|
||||
cmocka_unit_test_setup_teardown(test_getEntry_null_input_stays_null, asset_setup, asset_teardown),
|
||||
cmocka_unit_test_setup_teardown(test_getEntry_input_copied_into_entry, asset_setup, asset_teardown),
|
||||
|
||||
// assetUpdate — state machine
|
||||
// assetUpdate - state machine
|
||||
cmocka_unit_test_setup_teardown(test_update_noop_on_empty_table, asset_setup, asset_teardown),
|
||||
cmocka_unit_test_setup_teardown(test_update_entry_reaches_loaded, asset_setup, asset_teardown),
|
||||
cmocka_unit_test_setup_teardown(test_update_slot_occupied_after_first_update, asset_setup, asset_teardown),
|
||||
|
||||
@@ -133,7 +133,7 @@ static int locale_teardown(void **state) {
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// assetLocaleParseHeader — pure tests (no ZIP required)
|
||||
// assetLocaleParseHeader - pure tests (no ZIP required)
|
||||
// ============================================================
|
||||
|
||||
static void test_parseHeader_english(void **state) {
|
||||
@@ -251,7 +251,7 @@ static void test_parseHeader_error_missing_nplurals(void **state) {
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// assetLocaleEvaluatePlural — pure tests
|
||||
// assetLocaleEvaluatePlural - pure tests
|
||||
// ============================================================
|
||||
|
||||
static void test_evaluatePlural_english_singular(void **state) {
|
||||
@@ -302,7 +302,7 @@ static void test_evaluatePlural_less_than_boundary(void **state) {
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// assetLocaleGetString — ZIP-based tests
|
||||
// assetLocaleGetString - ZIP-based tests
|
||||
// ============================================================
|
||||
|
||||
static void test_getString_simple(void **state) {
|
||||
@@ -355,7 +355,7 @@ static void test_getString_missing_id(void **state) {
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// assetLocaleGetStringWithArgs — ZIP-based tests
|
||||
// assetLocaleGetStringWithArgs - ZIP-based tests
|
||||
// ============================================================
|
||||
|
||||
static void test_getStringWithArgs_int(void **state) {
|
||||
@@ -392,7 +392,7 @@ static void test_getStringWithArgs_string(void **state) {
|
||||
|
||||
int main(void) {
|
||||
const struct CMUnitTest tests[] = {
|
||||
// parseHeader — pure
|
||||
// parseHeader - pure
|
||||
cmocka_unit_test(test_parseHeader_english),
|
||||
cmocka_unit_test(test_parseHeader_singular),
|
||||
cmocka_unit_test(test_parseHeader_less_than),
|
||||
@@ -402,20 +402,20 @@ int main(void) {
|
||||
cmocka_unit_test(test_parseHeader_error_nplurals_too_large),
|
||||
cmocka_unit_test(test_parseHeader_error_missing_nplurals),
|
||||
|
||||
// evaluatePlural — pure
|
||||
// evaluatePlural - pure
|
||||
cmocka_unit_test(test_evaluatePlural_english_singular),
|
||||
cmocka_unit_test(test_evaluatePlural_english_plural),
|
||||
cmocka_unit_test(test_evaluatePlural_singular_only),
|
||||
cmocka_unit_test(test_evaluatePlural_less_than_boundary),
|
||||
|
||||
// getString — in-memory ZIP
|
||||
// getString - in-memory ZIP
|
||||
cmocka_unit_test_setup_teardown(test_getString_simple, locale_setup, locale_teardown),
|
||||
cmocka_unit_test_setup_teardown(test_getString_plural_singular, locale_setup, locale_teardown),
|
||||
cmocka_unit_test_setup_teardown(test_getString_plural_many, locale_setup, locale_teardown),
|
||||
cmocka_unit_test_setup_teardown(test_getString_multiple_calls, locale_setup, locale_teardown),
|
||||
cmocka_unit_test_setup_teardown(test_getString_missing_id, locale_setup, locale_teardown),
|
||||
|
||||
// getStringWithArgs — in-memory ZIP
|
||||
// getStringWithArgs - in-memory ZIP
|
||||
cmocka_unit_test_setup_teardown(test_getStringWithArgs_int, locale_setup, locale_teardown),
|
||||
cmocka_unit_test_setup_teardown(test_getStringWithArgs_string, locale_setup, locale_teardown),
|
||||
};
|
||||
|
||||
@@ -45,7 +45,7 @@ static void test_thread_start_stop(void **state) {
|
||||
}
|
||||
|
||||
static void test_thread_should_stop(void **state) {
|
||||
// threadStop blocks until STOPPED — if threadShouldStop is broken the
|
||||
// threadStop blocks until STOPPED - if threadShouldStop is broken the
|
||||
// looping callback never exits and this test hangs / times out.
|
||||
thread_t thread;
|
||||
threadInit(&thread, helper_loop);
|
||||
@@ -108,12 +108,12 @@ typedef struct {
|
||||
static void helper_trylock(thread_t *thread) {
|
||||
trylock_data_t *data = (trylock_data_t *)thread->data;
|
||||
|
||||
// Phase 1: main holds the lock — trylock must fail.
|
||||
// Phase 1: main holds the lock - trylock must fail.
|
||||
while(data->phase != 1) {}
|
||||
data->resultWhileLocked = threadMutexTryLock(data->target);
|
||||
data->phase = 2;
|
||||
|
||||
// Phase 3: main released the lock — trylock must succeed.
|
||||
// Phase 3: main released the lock - trylock must succeed.
|
||||
while(data->phase != 3) {}
|
||||
data->resultAfterUnlock = threadMutexTryLock(data->target);
|
||||
if(data->resultAfterUnlock) {
|
||||
|
||||
@@ -4,7 +4,7 @@ Builds GameCube / Wii disc images (NTSC-J, NTSC-U, PAL) using xorrisofs /
|
||||
mkisofs + Swiss-GC system-area headers.
|
||||
|
||||
The Swiss-GC headers contain a working GCN apploader that boots any DOL via
|
||||
the El Torito catalog — no custom PPC assembly needed.
|
||||
the El Torito catalog - no custom PPC assembly needed.
|
||||
|
||||
Headers are cached in <script_dir>/../buildtools/iso/ and downloaded from the
|
||||
Swiss-GC repository on first use.
|
||||
@@ -14,8 +14,8 @@ Disc layout (produced by xorrisofs):
|
||||
sector 16 ISO 9660 PVD
|
||||
sector 17 El Torito Boot Record
|
||||
... directory records, file data
|
||||
Dusk.dol (El Torito boot image — loaded by apploader)
|
||||
dusk.dsk (asset archive — found at runtime via ISO 9660)
|
||||
Dusk.dol (El Torito boot image - loaded by apploader)
|
||||
dusk.dsk (asset archive - found at runtime via ISO 9660)
|
||||
"""
|
||||
|
||||
import argparse
|
||||
|
||||
Vendored
+4
-4
@@ -8,11 +8,11 @@
|
||||
/**
|
||||
* Descriptor for one entry in an `AssetBatch`.
|
||||
*
|
||||
* `format` — texture format constant (`Texture.FORMAT_*`). Alias for `input`
|
||||
* `format` - texture format constant (`Texture.FORMAT_*`). Alias for `input`
|
||||
* when the type is `Asset.TYPE_TEXTURE`.
|
||||
* `axis` — mesh axis constant (`Asset.MESH_AXIS_*`). Alias for `input`
|
||||
* `axis` - mesh axis constant (`Asset.MESH_AXIS_*`). Alias for `input`
|
||||
* when the type is `Asset.TYPE_MESH`.
|
||||
* `input` — generic numeric input for all other loader types.
|
||||
* `input` - generic numeric input for all other loader types.
|
||||
*/
|
||||
interface AssetBatchDescriptor {
|
||||
path: string;
|
||||
@@ -48,7 +48,7 @@ interface AssetBatch {
|
||||
lock(): this;
|
||||
/**
|
||||
* Releases all locks and clears the batch.
|
||||
* After this call the object is invalid — do not use it again.
|
||||
* After this call the object is invalid - do not use it again.
|
||||
*/
|
||||
unlock(): void;
|
||||
/**
|
||||
|
||||
Vendored
+7
-7
@@ -13,24 +13,24 @@
|
||||
interface AssetEntry {
|
||||
/** Archive-relative path used as the cache key. */
|
||||
readonly name: string;
|
||||
/** Current loading state — compare against `AssetEntry.*` state constants. */
|
||||
/** Current loading state - compare against `AssetEntry.*` state constants. */
|
||||
readonly state: number;
|
||||
/** Loader type — one of the `AssetEntry.TYPE_*` constants. */
|
||||
/** Loader type - one of the `AssetEntry.TYPE_*` constants. */
|
||||
readonly type: number;
|
||||
/** `true` when the entry has fully loaded (`state === AssetEntry.LOADED`). */
|
||||
readonly isLoaded: boolean;
|
||||
/**
|
||||
* Returns a `Texture` for this entry when it is a loaded texture asset.
|
||||
* The `Texture` holds its own asset lock — independent of this `AssetEntry`.
|
||||
* The `Texture` holds its own asset lock - independent of this `AssetEntry`.
|
||||
* Returns `undefined` if the entry is not of type `Asset.TYPE_TEXTURE` or
|
||||
* is not yet loaded.
|
||||
*/
|
||||
readonly texture: Texture | undefined;
|
||||
/** Event proxy — subscribe up to 4 callbacks for when loading completes. */
|
||||
/** Event proxy - subscribe up to 4 callbacks for when loading completes. */
|
||||
readonly onLoaded: AssetEventProxy;
|
||||
/** Event proxy — subscribe up to 4 callbacks for when the entry is disposed. */
|
||||
/** Event proxy - subscribe up to 4 callbacks for when the entry is disposed. */
|
||||
readonly onUnloaded: AssetEventProxy;
|
||||
/** Event proxy — subscribe up to 4 callbacks for when loading fails. */
|
||||
/** Event proxy - subscribe up to 4 callbacks for when loading fails. */
|
||||
readonly onError: AssetEventProxy;
|
||||
/**
|
||||
* Returns a Promise that resolves when the entry is loaded, or rejects on
|
||||
@@ -45,7 +45,7 @@ interface AssetEntry {
|
||||
requireLoaded(): this;
|
||||
/**
|
||||
* Releases the lock immediately.
|
||||
* After this call the object is invalid — do not use it again.
|
||||
* After this call the object is invalid - do not use it again.
|
||||
*/
|
||||
unlock(): void;
|
||||
toString(): string;
|
||||
|
||||
Vendored
+1
-1
@@ -6,7 +6,7 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* A loaded texture asset. Holds a lock on the underlying asset entry —
|
||||
* A loaded texture asset. Holds a lock on the underlying asset entry -
|
||||
* the lock is released automatically when the object is garbage collected.
|
||||
*/
|
||||
interface Texture {
|
||||
|
||||
+2
-2
@@ -8,11 +8,11 @@
|
||||
/** Overworld character component (player or NPC). */
|
||||
interface Overworld extends Component {
|
||||
/**
|
||||
* Entity type — `Overworld.PLAYER` or `Overworld.NPC`.
|
||||
* Entity type - `Overworld.PLAYER` or `Overworld.NPC`.
|
||||
*/
|
||||
type: number;
|
||||
/**
|
||||
* Facing direction — one of the `Overworld.FACING_*` constants.
|
||||
* Facing direction - one of the `Overworld.FACING_*` constants.
|
||||
*/
|
||||
facing: number;
|
||||
/** Component ID of the linked Renderable, or INVALID if none. */
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ interface OverworldCamera extends Component {
|
||||
/** Orthographic scale factor (larger = wider view). */
|
||||
scale: number;
|
||||
/**
|
||||
* Convenience setter — equivalent to assigning `targetEntity` and
|
||||
* Convenience setter - equivalent to assigning `targetEntity` and
|
||||
* `targetPositionComponent` individually.
|
||||
*/
|
||||
setTarget(targetEntityId: number, targetPositionComponentId: number): void;
|
||||
|
||||
Vendored
+2
-2
@@ -7,10 +7,10 @@
|
||||
|
||||
/** Physics body component. */
|
||||
interface Physics extends Component {
|
||||
/** Body simulation type — `Physics.STATIC`, `DYNAMIC`, or `KINEMATIC`. */
|
||||
/** Body simulation type - `Physics.STATIC`, `DYNAMIC`, or `KINEMATIC`. */
|
||||
bodyType: number;
|
||||
/**
|
||||
* Collision shape type — one of the `Physics.SHAPE_*` constants.
|
||||
* Collision shape type - one of the `Physics.SHAPE_*` constants.
|
||||
* Changing the type preserves existing velocity and ground state.
|
||||
*/
|
||||
shape: number;
|
||||
|
||||
Vendored
+1
-1
@@ -5,7 +5,7 @@
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/** Transform component — local/world PRS with an optional parent hierarchy. */
|
||||
/** Transform component - local/world PRS with an optional parent hierarchy. */
|
||||
interface Position extends Component {
|
||||
/**
|
||||
* Local-space position. Reading returns a Vec3 copy; assigning a Vec3
|
||||
|
||||
+2
-2
@@ -7,7 +7,7 @@
|
||||
|
||||
/** A Renderable component. Returned by `entity.add(Component.RENDERABLE)`. */
|
||||
interface Renderable extends Component {
|
||||
/** Current render type — one of the `Renderable.*` type constants. */
|
||||
/** Current render type - one of the `Renderable.*` type constants. */
|
||||
type: number;
|
||||
/** Render priority. 0 = auto. Higher = drawn later. */
|
||||
priority: number;
|
||||
@@ -28,7 +28,7 @@ interface Renderable extends Component {
|
||||
texture: Texture | undefined;
|
||||
/**
|
||||
* Sprite list. Reading returns a JS array of 10-element sub-arrays
|
||||
* `[x1,y1,z1, x2,y2,z2, u1,v1, u2,v2]` — one per sprite.
|
||||
* `[x1,y1,z1, x2,y2,z2, u1,v1, u2,v2]` - one per sprite.
|
||||
*
|
||||
* Assigning an array replaces all sprites. Each element may be:
|
||||
* - 10 numbers (3D): `[x1,y1,z1, x2,y2,z2, u1,v1, u2,v2]`
|
||||
|
||||
Vendored
+1
-1
@@ -5,7 +5,7 @@
|
||||
* https://opensource.org/licenses/MIT
|
||||
*
|
||||
* Root type declarations for the Dusk engine built-in JavaScript modules.
|
||||
* These globals are injected by the native JerryScript runtime — they are not
|
||||
* These globals are injected by the native JerryScript runtime - they are not
|
||||
* ES modules and cannot be imported.
|
||||
*
|
||||
* Reference this file from a jsconfig.json or tsconfig.json to get
|
||||
|
||||
Vendored
+1
-1
@@ -37,7 +37,7 @@ interface InputNamespace {
|
||||
/** Polling-based input system. */
|
||||
declare var Input: InputNamespace;
|
||||
|
||||
// Input action constants — injected as globals by the engine at startup.
|
||||
// Input action constants - injected as globals by the engine at startup.
|
||||
declare var INPUT_ACTION_UP: InputAction;
|
||||
declare var INPUT_ACTION_DOWN: InputAction;
|
||||
declare var INPUT_ACTION_LEFT: InputAction;
|
||||
|
||||
Vendored
+1
-1
@@ -58,6 +58,6 @@ interface BackpackNamespace {
|
||||
|
||||
declare var Backpack: BackpackNamespace;
|
||||
|
||||
// Inventory sort constants — injected as globals by the engine at startup.
|
||||
// Inventory sort constants - injected as globals by the engine at startup.
|
||||
declare var INVENTORY_SORT_BY_ID: number;
|
||||
declare var INVENTORY_SORT_BY_TYPE: number;
|
||||
|
||||
Vendored
+2
-2
@@ -29,11 +29,11 @@ interface ItemNamespace {
|
||||
|
||||
declare var Item: ItemNamespace;
|
||||
|
||||
// Item ID constants — injected as globals by the engine at startup.
|
||||
// Item ID constants - injected as globals by the engine at startup.
|
||||
declare var ITEM_ID_POTION: ItemId;
|
||||
declare var ITEM_ID_POTATO: ItemId;
|
||||
declare var ITEM_ID_APPLE: ItemId;
|
||||
|
||||
// Item type constants — injected as globals by the engine at startup.
|
||||
// Item type constants - injected as globals by the engine at startup.
|
||||
declare var ITEM_TYPE_MEDICINE: ItemType;
|
||||
declare var ITEM_TYPE_FOOD: ItemType;
|
||||
|
||||
Vendored
+1
-1
@@ -43,7 +43,7 @@ interface SceneNamespace {
|
||||
*/
|
||||
set(newScene: SceneObject | null): void;
|
||||
|
||||
/** Called each frame by the engine — drives `current.update()`. */
|
||||
/** Called each frame by the engine - drives `current.update()`. */
|
||||
update(): void;
|
||||
|
||||
/** Called each frame by the engine for dynamic/physics updates. */
|
||||
|
||||
Vendored
+1
-1
@@ -26,5 +26,5 @@ interface StoryNamespace {
|
||||
|
||||
declare var Story: StoryNamespace;
|
||||
|
||||
// Story flag constants — injected as globals by the engine at startup.
|
||||
// Story flag constants - injected as globals by the engine at startup.
|
||||
declare var STORY_FLAG_TEST: StoryFlag;
|
||||
|
||||
Reference in New Issue
Block a user