From 276ce62d95789b21fe8d2d5f078c104af4c2e8b0 Mon Sep 17 00:00:00 2001 From: sbird Date: Mon, 16 Jan 2023 22:40:36 +0100 Subject: [PATCH] [script-command, dynmultichoice] add shouldSort, initialSelected arguments. read pushed arguments front to back --- asm/macros/event.inc | 18 ++++++++++++------ include/list_menu.h | 2 ++ include/script_menu.h | 3 ++- src/list_menu.c | 16 +++++++++++----- src/scrcmd.c | 24 ++++++++++++++++-------- src/script_menu.c | 26 ++++++++++++++++++-------- 6 files changed, 61 insertions(+), 28 deletions(-) diff --git a/asm/macros/event.inc b/asm/macros/event.inc index 069477485a..4e9ab1855b 100644 --- a/asm/macros/event.inc +++ b/asm/macros/event.inc @@ -1729,29 +1729,35 @@ .2byte \quantity .endm - @ Displays a multichoice box from which the user can choose a selection, and blocks script execution until a selection is made. - @ Lists of options are provided in argv. - @ If ignoreBPress is set to a non-zero value, then the user will not be allowed to back out of the multichoice with the B button. - .macro dynmultichoice left:req, top:req, ignoreBPress:req, maxBeforeScroll:req argv:vararg + .macro _dynmultichoice left:req, top:req, ignoreBPress:req, maxBeforeScroll:req, shouldSort:req, initialSelected:req argv:vararg .byte 0xe3 .byte \left .byte \top .byte \ignoreBPress .byte \maxBeforeScroll + .byte \shouldSort + .2byte \initialSelected .byte (.Ldynmultichoice_\@_2 - .Ldynmultichoice_\@_1) / 4 .Ldynmultichoice_\@_1: .4byte \argv .Ldynmultichoice_\@_2: .endm + @ Displays a multichoice box from which the user can choose a selection, and blocks script execution until a selection is made. + @ Lists of options are provided in argv. + @ If ignoreBPress is set to a non-zero value, then the user will not be allowed to back out of the multichoice with the B button. + .macro dynmultichoice left:req, top:req, ignoreBPress:req, maxBeforeScroll:req, shouldSort:req, initialSelected:req argv:vararg + _dynamicmultichoice \left, \top, \ignoreBPress, \maxBeforeScroll, FALSE, \initialSelected, \argv + .endm + .macro dynmultipush name:req, id:req .byte 0xe4 .4byte \name .byte \id .endm - .macro dynmultistack left:req, top:req, ignoreBPress:req, maxBeforeScroll:req - dynmultichoice \left, \top, \ignoreBPress, \maxBeforeScroll, NULL + .macro dynmultistack left:req, top:req, ignoreBPress:req, maxBeforeScroll:req, shouldSort:req, initialSelected:req + _dynmultichoice \left, \top, \ignoreBPress, \maxBeforeScroll, \shouldSort, \initialSelected, NULL .endm diff --git a/include/list_menu.h b/include/list_menu.h index 9299ede6c8..23caaf4b4c 100644 --- a/include/list_menu.h +++ b/include/list_menu.h @@ -126,5 +126,7 @@ u8 AddScrollIndicatorArrowPair(const struct ScrollArrowsTemplate *arrowInfo, u16 u8 AddScrollIndicatorArrowPairParameterized(u32 arrowType, s32 commonPos, s32 firstPos, s32 secondPos, s32 fullyDownThreshold, s32 tileTag, s32 palTag, u16 *currItemPtr); void RemoveScrollIndicatorArrowPair(u8 taskId); void Task_ScrollIndicatorArrowPairOnMainMenu(u8 taskId); +bool8 ListMenuChangeSelection(struct ListMenu *list, bool8 updateCursorAndCallCallback, u8 count, bool8 movingDown); +bool8 ListMenuChangeSelectionFull(struct ListMenu *list, bool32 updateCursor, bool32 callCallback, u8 count, bool8 movingDown); #endif //GUARD_LIST_MENU_H diff --git a/include/script_menu.h b/include/script_menu.h index e4e4836097..c37b3603dd 100644 --- a/include/script_menu.h +++ b/include/script_menu.h @@ -27,8 +27,9 @@ u32 MultichoiceDynamic_StackSize(void); void MultichoiceDynamic_PushElement(struct ListMenuItem item); struct ListMenuItem *MultichoiceDynamic_PopElement(void); struct ListMenuItem *MultichoiceDynamic_PeekElement(void); +struct ListMenuItem *MultichoiceDynamic_PeekElementAt(u32 index); void MultichoiceDynamic_DestroyStack(void); -bool8 ScriptMenu_MultichoiceDynamic(u8 left, u8 top, u8 argc, struct ListMenuItem *items, bool8 ignoreBPress, u8 maxBeforeScroll); +bool8 ScriptMenu_MultichoiceDynamic(u8 left, u8 top, u8 argc, struct ListMenuItem *items, bool8 ignoreBPress, u8 maxBeforeScroll, u32 initialRow); bool8 ScriptMenu_Multichoice(u8 left, u8 top, u8 multichoiceId, bool8 ignoreBPress); bool8 ScriptMenu_MultichoiceWithDefault(u8 left, u8 top, u8 multichoiceId, bool8 ignoreBPress, u8 defaultChoice); bool8 ScriptMenu_YesNo(u8 left, u8 top); diff --git a/src/list_menu.c b/src/list_menu.c index c240564c65..4f631188bb 100644 --- a/src/list_menu.c +++ b/src/list_menu.c @@ -70,7 +70,6 @@ struct RedArrowCursor // this file's functions static u8 ListMenuInitInternal(struct ListMenuTemplate *listMenuTemplate, u16 scrollOffset, u16 selectedRow); -static bool8 ListMenuChangeSelection(struct ListMenu *list, bool8 updateCursorAndCallCallback, u8 count, bool8 movingDown); static void ListMenuPrintEntries(struct ListMenu *list, u16 startIndex, u16 yOffset, u16 count); static void ListMenuDrawCursor(struct ListMenu *list); static void ListMenuCallSelectionChangedCallback(struct ListMenu *list, u8 onInit); @@ -837,7 +836,7 @@ static void ListMenuScroll(struct ListMenu *list, u8 count, bool8 movingDown) } } -static bool8 ListMenuChangeSelection(struct ListMenu *list, bool8 updateCursorAndCallCallback, u8 count, bool8 movingDown) +bool8 ListMenuChangeSelectionFull(struct ListMenu *list, bool32 updateCursor, bool32 callCallback, u8 count, bool8 movingDown) { u16 oldSelectedRow; u8 selectionChange, i, cursorCount; @@ -857,7 +856,7 @@ static bool8 ListMenuChangeSelection(struct ListMenu *list, bool8 updateCursorAn } while (list->template.items[list->scrollOffset + list->selectedRow].id == LIST_HEADER); } - if (updateCursorAndCallCallback) + if (updateCursor) { switch (selectionChange) { @@ -867,7 +866,8 @@ static bool8 ListMenuChangeSelection(struct ListMenu *list, bool8 updateCursorAn case 1: ListMenuErasePrintedCursor(list, oldSelectedRow); ListMenuDrawCursor(list); - ListMenuCallSelectionChangedCallback(list, FALSE); + if (callCallback) + ListMenuCallSelectionChangedCallback(list, FALSE); CopyWindowToVram(list->template.windowId, COPYWIN_GFX); break; case 2: @@ -875,7 +875,8 @@ static bool8 ListMenuChangeSelection(struct ListMenu *list, bool8 updateCursorAn ListMenuErasePrintedCursor(list, oldSelectedRow); ListMenuScroll(list, cursorCount, movingDown); ListMenuDrawCursor(list); - ListMenuCallSelectionChangedCallback(list, FALSE); + if (callCallback) + ListMenuCallSelectionChangedCallback(list, FALSE); CopyWindowToVram(list->template.windowId, COPYWIN_GFX); break; } @@ -884,6 +885,11 @@ static bool8 ListMenuChangeSelection(struct ListMenu *list, bool8 updateCursorAn return FALSE; } +bool8 ListMenuChangeSelection(struct ListMenu *list, bool8 updateCursorAndCallCallback, u8 count, bool8 movingDown) +{ + ListMenuChangeSelectionFull(list, updateCursorAndCallCallback, updateCursorAndCallCallback, count, movingDown); +} + static void ListMenuCallSelectionChangedCallback(struct ListMenu *list, u8 onInit) { if (list->template.moveCursorFunc != NULL) diff --git a/src/scrcmd.c b/src/scrcmd.c index 177c27277b..e11528ccca 100644 --- a/src/scrcmd.c +++ b/src/scrcmd.c @@ -1376,12 +1376,15 @@ static void DynamicMultichoiceSortList(struct ListMenuItem *items, u32 count) bool8 ScrCmd_dynmultichoice(struct ScriptContext *ctx) { u32 i; - u8 left = ScriptReadByte(ctx); - u8 top = ScriptReadByte(ctx); - bool8 ignoreBPress = ScriptReadByte(ctx); - u8 maxBeforeScroll = ScriptReadByte(ctx); + u32 left = ScriptReadByte(ctx); + u32 top = ScriptReadByte(ctx); + bool32 ignoreBPress = ScriptReadByte(ctx); + u32 maxBeforeScroll = ScriptReadByte(ctx); + bool32 shouldSort = ScriptReadByte(ctx); + u32 initialSelected = VarGet(ScriptReadHalfword(ctx)); + u32 initialRow = 0; // Read vararg - u8 argc = ScriptReadByte(ctx); + u32 argc = ScriptReadByte(ctx); struct ListMenuItem *items; if (argc == 0) @@ -1400,6 +1403,8 @@ bool8 ScrCmd_dynmultichoice(struct ScriptContext *ctx) StringExpandPlaceholders(nameBuffer, arg); items[i].name = nameBuffer; items[i].id = i; + if (i == initialSelected) + initialRow = i; } } else @@ -1409,16 +1414,19 @@ bool8 ScrCmd_dynmultichoice(struct ScriptContext *ctx) for (i = 0; i < argc; ++i) { u8 *nameBuffer = Alloc(100); - struct ListMenuItem *currentItem = MultichoiceDynamic_PopElement(); + struct ListMenuItem *currentItem = MultichoiceDynamic_PeekElementAt(i); StringExpandPlaceholders(nameBuffer, currentItem->name); items[i].name = nameBuffer; items[i].id = currentItem->id; + if (currentItem->id == initialSelected) + initialRow = i; } - DynamicMultichoiceSortList(items, argc); + if (shouldSort) + DynamicMultichoiceSortList(items, argc); MultichoiceDynamic_DestroyStack(); } - if (ScriptMenu_MultichoiceDynamic(left, top, argc, items, ignoreBPress, maxBeforeScroll)) + if (ScriptMenu_MultichoiceDynamic(left, top, argc, items, ignoreBPress, maxBeforeScroll, initialRow)) { ScriptContext_Stop(); return TRUE; diff --git a/src/script_menu.c b/src/script_menu.c index ce0b378193..e4d6162074 100644 --- a/src/script_menu.c +++ b/src/script_menu.c @@ -33,7 +33,7 @@ static void Task_HandleScrollingMultichoiceInput(u8 taskId); static void Task_HandleMultichoiceInput(u8 taskId); static void Task_HandleYesNoInput(u8 taskId); static void Task_HandleMultichoiceGridInput(u8 taskId); -static void DrawMultichoiceMenuDynamic(u8 left, u8 top, u8 argc, struct ListMenuItem *items, bool8 ignoreBPress, u8 cursorPos, u8 maxBeforeScroll); +static void DrawMultichoiceMenuDynamic(u8 left, u8 top, u8 argc, struct ListMenuItem *items, bool8 ignoreBPress, u32 initialRow, u8 maxBeforeScroll); static void DrawMultichoiceMenu(u8 left, u8 top, u8 multichoiceId, bool8 ignoreBPress, u8 cursorPos); static void InitMultichoiceCheckWrap(bool8 ignoreBPress, u8 count, u8 windowId, u8 multichoiceId); static void DrawLinkServicesMultichoiceMenu(u8 multichoiceId); @@ -55,7 +55,7 @@ static const struct ListMenuTemplate sScriptableListMenuTemplate = .fontId = FONT_NORMAL, }; -bool8 ScriptMenu_MultichoiceDynamic(u8 left, u8 top, u8 argc, struct ListMenuItem *items, bool8 ignoreBPress, u8 maxBeforeScroll) +bool8 ScriptMenu_MultichoiceDynamic(u8 left, u8 top, u8 argc, struct ListMenuItem *items, bool8 ignoreBPress, u8 maxBeforeScroll, u32 initialRow) { if (FuncIsActiveTask(Task_HandleMultichoiceInput) == TRUE) { @@ -65,7 +65,7 @@ bool8 ScriptMenu_MultichoiceDynamic(u8 left, u8 top, u8 argc, struct ListMenuIte else { gSpecialVar_Result = 0xFF; - DrawMultichoiceMenuDynamic(left, top, argc, items, ignoreBPress, 0, maxBeforeScroll); + DrawMultichoiceMenuDynamic(left, top, argc, items, ignoreBPress, initialRow, maxBeforeScroll); return TRUE; } } @@ -203,6 +203,15 @@ struct ListMenuItem *MultichoiceDynamic_PeekElement(void) return &sDynamicMultiChoiceStack->elements[sDynamicMultiChoiceStack->top]; } +struct ListMenuItem *MultichoiceDynamic_PeekElementAt(u32 index) +{ + if (sDynamicMultiChoiceStack == NULL) + return NULL; + if (sDynamicMultiChoiceStack->top < index) + return NULL; + return &sDynamicMultiChoiceStack->elements[index]; +} + void MultichoiceDynamic_DestroyStack(void) { TRY_FREE_AND_SET_NULL(sDynamicMultiChoiceStack->elements); @@ -216,13 +225,11 @@ static void MultichoiceDynamic_MoveCursor(s32 itemIndex, bool8 onInit, struct Li taskId = FindTaskIdByFunc(Task_HandleScrollingMultichoiceInput); if (taskId != TASK_NONE) { - u16 scrollOffset; - ListMenuGetScrollAndRow(gTasks[taskId].data[0], &scrollOffset, NULL); - gScrollableMultichoice_ScrollOffset = scrollOffset; + ListMenuGetScrollAndRow(gTasks[taskId].data[0], &gScrollableMultichoice_ScrollOffset, NULL); } } -static void DrawMultichoiceMenuDynamic(u8 left, u8 top, u8 argc, struct ListMenuItem *items, bool8 ignoreBPress, u8 cursorPos, u8 maxBeforeScroll) +static void DrawMultichoiceMenuDynamic(u8 left, u8 top, u8 argc, struct ListMenuItem *items, bool8 ignoreBPress, u32 initialRow, u8 maxBeforeScroll) { u32 i; u8 windowId; @@ -230,6 +237,7 @@ static void DrawMultichoiceMenuDynamic(u8 left, u8 top, u8 argc, struct ListMenu u8 newWidth; u8 taskId; u32 windowHeight; + struct ListMenu *list; for (i = 0; i < argc; ++i) { @@ -256,7 +264,9 @@ static void DrawMultichoiceMenuDynamic(u8 left, u8 top, u8 argc, struct ListMenu gTasks[taskId].data[5] = argc; gTasks[taskId].data[7] = maxBeforeScroll; StoreWordInTwoHalfwords(&gTasks[taskId].data[3], (u32) items); - + list = (void *) gTasks[gTasks[taskId].data[0]].data; + ListMenuChangeSelectionFull(list, TRUE, FALSE, initialRow, TRUE); + ListMenuGetScrollAndRow(gTasks[taskId].data[0], &gScrollableMultichoice_ScrollOffset, NULL); if (argc > maxBeforeScroll) { // Create Scrolling Arrows