diff options
Diffstat (limited to 'arm9/src/list_menu.c')
-rw-r--r-- | arm9/src/list_menu.c | 572 |
1 files changed, 572 insertions, 0 deletions
diff --git a/arm9/src/list_menu.c b/arm9/src/list_menu.c new file mode 100644 index 00000000..5ae5a5b4 --- /dev/null +++ b/arm9/src/list_menu.c @@ -0,0 +1,572 @@ +#include "global.h" +#include "heap.h" +#include "main.h" +#include "list_menu.h" +#include "text.h" + +void ListMenuPrintEntries(struct ListMenu * list, u16 startIndex, u16 yOffset, u16 count); +void ListMenuDrawCursor(struct ListMenu * list); +BOOL ListMenuChangeSelection(struct ListMenu * list, u8 updateCursorAndCallCallback, u8 count, u8 movingDown); +void ListMenuCallSelectionChangedCallback(struct ListMenu * list, u8 onInit); + +static inline u32 MakeFontColor(u32 fgPal, u32 shdwPal, u32 bgPal) +{ + return (u32)( + ((u32)(fgPal << 24) >> 8) + | ((u32)(shdwPal << 24) >> 16) + | ((u32)(bgPal << 24) >> 24) + ); +} + +THUMB_FUNC struct ListMenu * ListMenuInit(const struct ListMenuTemplate * template, u16 cursorPos, u16 itemsAbove, u32 heap_id) +{ + struct ListMenu * list = AllocFromHeap(heap_id, sizeof(struct ListMenu)); + list->template = *template; + list->cursor = ListMenuCursorNew(heap_id); + list->cursorPos = cursorPos; + list->itemsAbove = itemsAbove; + list->unk_30 = 0; + list->unk_31 = 0; + list->taskId = 0xFF; + list->unk_33 = 0; + list->heap_id = (u8)heap_id; + list->cursorPal = list->template.cursorPal; + list->fillValue = list->template.fillValue; + list->cursorShadowPal = list->template.cursorShadowPal; + list->lettersSpacing = list->template.lettersSpacing; + list->fontId = list->template.fontId; + list->overrideEnabled = FALSE; + if (list->template.totalItems < list->template.maxShowed) + list->template.maxShowed = list->template.totalItems; + ListMenuCursorSetColor( + list->cursor, +// MakeFontColor(list->template.cursorPal, list->template.cursorShadowPal, list->fillValue) + (u32)( + ((u32)(list->template.cursorPal << 24) >> 8) + | ((u32)(list->template.cursorShadowPal << 24) >> 16) + | ((u32)(list->template.fillValue << 24) >> 24) + ) + ); + FillWindowPixelBuffer(list->template.window, list->template.fillValue); + ListMenuPrintEntries(list, list->cursorPos, 0, list->template.maxShowed); + ListMenuDrawCursor(list); + ListMenuCallSelectionChangedCallback(list, TRUE); + CopyWindowToVram(template->window); + return list; +} + +THUMB_FUNC s32 ListMenu_ProcessInput(struct ListMenu * list) +{ + list->unk_33 = 0; + + if (gMain.newKeys & REG_PAD_KEYINPUT_A_MASK) { + return list->template.items[list->cursorPos + list->itemsAbove].index; + } + else if (gMain.newKeys & REG_PAD_KEYINPUT_B_MASK) { + return LIST_CANCEL; + } + else if (gMain.newAndRepeatedKeys & REG_PAD_KEYINPUT_UP_MASK) { + if (!ListMenuChangeSelection(list, TRUE, 1, FALSE)) + list->unk_33 = 1; + return LIST_NOTHING_CHOSEN; + } + else if (gMain.newAndRepeatedKeys & REG_PAD_KEYINPUT_DOWN_MASK) { + if (!ListMenuChangeSelection(list, TRUE, 1, TRUE)) + list->unk_33 = 2; + return LIST_NOTHING_CHOSEN; + } + else + { + u16 rightButton, leftButton; + switch (list->template.scrollMultiple) + { + case LIST_NO_MULTIPLE_SCROLL: + default: + leftButton = FALSE; + rightButton = FALSE; + break; + case LIST_MULTIPLE_SCROLL_DPAD: + leftButton = gMain.newAndRepeatedKeys & REG_PAD_KEYINPUT_LEFT_MASK; + rightButton = gMain.newAndRepeatedKeys & REG_PAD_KEYINPUT_RIGHT_MASK; + break; + case LIST_MULTIPLE_SCROLL_L_R: + leftButton = gMain.newAndRepeatedKeys & REG_PAD_KEYINPUT_L_MASK; + rightButton = gMain.newAndRepeatedKeys & REG_PAD_KEYINPUT_R_MASK; + break; + } + if (leftButton) + { + if (!ListMenuChangeSelection(list, TRUE, list->template.maxShowed, FALSE)) + list->unk_33 = 3; + return LIST_NOTHING_CHOSEN; + } + else if (rightButton) + { + if (!ListMenuChangeSelection(list, TRUE, list->template.maxShowed, TRUE)) + list->unk_33 = 4; + return LIST_NOTHING_CHOSEN; + } + else + { + return LIST_NOTHING_CHOSEN; + } + } +} + +THUMB_FUNC void DestroyListMenu(struct ListMenu * list, u16 * cursorPos, u16 * itemsAbove) +{ + if (cursorPos != NULL) + *cursorPos = list->cursorPos; + if (itemsAbove != NULL) + *itemsAbove = list->itemsAbove; + DestroyListMenuCursorObj(list->cursor); + FreeToHeapExplicit(list->heap_id, list); +} + +THUMB_FUNC void RedrawListMenu(struct ListMenu * list) +{ + FillWindowPixelBuffer(list->template.window, list->template.fillValue); + ListMenuPrintEntries(list, list->cursorPos, 0, list->template.maxShowed); + ListMenuDrawCursor(list); + CopyWindowToVram(list->template.window); +} + +THUMB_FUNC s32 ListMenuTestInputInternal(struct ListMenu * list, const struct ListMenuTemplate * template, u16 cursorPos, u16 itemsAbove, u16 updateFlag, u16 input, u16 *newCursorPos, u16 *newItemsAbove) +{ + if (template != NULL) + list->template = *template; + list->cursorPos = cursorPos; + list->itemsAbove = itemsAbove; + list->unk_30 = 0; + list->unk_31 = 0; + + if (input == REG_PAD_KEYINPUT_UP_MASK) + { + ListMenuChangeSelection(list, updateFlag, 1, FALSE); + } + else if (input == REG_PAD_KEYINPUT_DOWN_MASK) + { + ListMenuChangeSelection(list, updateFlag, 1, TRUE); + } + if (newCursorPos != NULL) + { + *newCursorPos = list->cursorPos; + } + if (newItemsAbove != NULL) + { + *newItemsAbove = list->itemsAbove; + } + return -1; +} + +THUMB_FUNC s32 ListMenuTestInput(struct ListMenu * list, const struct ListMenuTemplate * template, u16 cursorPos, u16 itemsAbove, u16 input, u16 *newCursorPos, u16 *newItemsAbove) +{ + return ListMenuTestInputInternal(list, template, cursorPos, itemsAbove, FALSE, input, newCursorPos, newItemsAbove); +} + +THUMB_FUNC void ListMenuOverrideSetColors(struct ListMenu * list, u8 cursorPal, u8 fillValue, u8 cursorShadowPal) +{ + list->cursorPal = cursorPal; + list->fillValue = fillValue; + list->cursorShadowPal = cursorShadowPal; + list->overrideEnabled = TRUE; +} + +THUMB_FUNC void ListMenuGetCurrentItemArrayId(struct ListMenu * list, u16 * index_p) +{ + *index_p = list->cursorPos + list->itemsAbove; +} + +THUMB_FUNC void ListMenuGetScrollAndRow(struct ListMenu * list, u16 * cursorPos_p, u16 * itemsAbove_p) +{ + if (cursorPos_p != NULL) + *cursorPos_p = list->cursorPos; + if (itemsAbove_p != NULL) + *itemsAbove_p = list->itemsAbove; +} + +THUMB_FUNC u8 ListMenuGetUnk33(struct ListMenu * list) +{ + return list->unk_33; +} + +THUMB_FUNC s32 ListMenuGetValueByArrayId(struct ListMenu * list, s32 index) +{ + return list->template.items[index].index; +} + +THUMB_FUNC s32 ListMenuGetTemplateField(struct ListMenu * list, u32 attr) +{ + switch (attr) + { + case 0: + return (s32)list->template.moveCursorFunc; + case 1: + return (s32)list->template.itemPrintFunc; + case 2: + return (s32)list->template.totalItems; + case 3: + return (s32)list->template.maxShowed; + case 4: + break; + case 5: + return (s32)list->template.header_X; + case 6: + return (s32)list->template.item_X; + case 7: + return (s32)list->template.cursor_X; + case 8: + return (s32)list->template.upText_Y; + case 9: + return GetFontAttribute(list->template.fontId, 1) + list->template.itemVerticalPadding; + case 10: + return (s32)list->template.cursorPal; + case 11: + return (s32)list->template.fillValue; + case 12: + return (s32)list->template.cursorShadowPal; + case 13: + return (s32)list->template.lettersSpacing; + case 14: + return (s32)list->template.itemVerticalPadding; + case 15: + return (s32)list->template.scrollMultiple; + case 16: + return (s32)list->template.fontId; + case 17: + return (s32)list->template.cursorKind; + case 18: + return (s32)list->template.window; + case 19: + return (s32)list->template.unk_1C; + } + + return -1; +} + +THUMB_FUNC void ListMenuSetTemplateField(struct ListMenu * list, u32 attr, s32 value) +{ + switch (attr) + { + case 0: + list->template.moveCursorFunc = (LM_MoveCursorFunc_t)value; + break; + case 1: + list->template.itemPrintFunc = (LM_ItemPrintFunc_t)value; + break; + case 2: + list->template.totalItems = (u16)value; + break; + case 3: + list->template.maxShowed = (u16)value; + break; + case 4: + break; + case 5: + list->template.header_X = (u8)value; + break; + case 6: + list->template.item_X = (u8)value; + break; + case 7: + list->template.cursor_X = (u8)value; + break; + case 8: + list->template.upText_Y = (u8)value; + break; + case 9: + break; + case 10: + list->template.cursorPal = (u8)value; + break; + case 11: + list->template.fillValue = (u8)value; + break; + case 12: + list->template.cursorShadowPal = (u8)value; + break; + case 13: + list->template.lettersSpacing = (u8)value; + break; + case 14: + list->template.itemVerticalPadding = (u8)value; + break; + case 15: + list->template.scrollMultiple = (u8)value; + break; + case 16: + list->template.fontId = (u8)value; + break; + case 17: + list->template.cursorKind = (u8)value; + break; + case 18: + list->template.window = (struct Window *)value; + break; + case 19: + list->template.unk_1C = (u32)value; + break; + } +} + +THUMB_FUNC void ListMenuGetItemStr(struct ListMenu * list, struct ListMenuItem * items) +{ + list->template.items = items; +} + +THUMB_FUNC void ListMenuPrint(struct ListMenu * list, const u16 * str, u8 x, u8 y) +{ + if (str != NULL) + { + if (list->overrideEnabled) + { + AddTextPrinterParameterized3(list->template.window, list->fontId, str, x, y, 0xFF, MakeFontColor(list->cursorPal, list->cursorShadowPal, list->fillValue), list->lettersSpacing, 0, NULL); + } + else + { + AddTextPrinterParameterized3(list->template.window, list->template.fontId, str, x, y, 0xFF, MakeFontColor(list->template.cursorPal, list->template.cursorShadowPal, list->template.fillValue), list->template.lettersSpacing, 0, NULL); + } + } +} + +THUMB_FUNC void ListMenuPrintEntries(struct ListMenu * list, u16 startIndex, u16 yOffset, u16 count) +{ + s32 i; + u8 x, y; + u8 yMultiplier = GetFontAttribute(list->template.fontId, 1) + list->template.itemVerticalPadding; + + for (i = 0; i < count; i++) + { + if (list->template.items[startIndex].index != LIST_HEADER) + x = list->template.item_X; + else + x = list->template.header_X; + y = (yOffset + i) * yMultiplier + list->template.upText_Y; + if (list->template.itemPrintFunc != NULL) + list->template.itemPrintFunc(list, list->template.items[startIndex].index, y); + ListMenuPrint(list, list->template.items[startIndex].text, x, y); + startIndex++; + } +} + +THUMB_FUNC void ListMenuDrawCursor(struct ListMenu * list) +{ + u8 yMultiplier = GetFontAttribute(list->template.fontId, 1) + list->template.itemVerticalPadding; + u8 x = list->template.cursor_X; + u8 y = list->itemsAbove * yMultiplier + list->template.upText_Y; + switch (list->template.cursorKind) + { + case 0: + ListMenuUpdateCursorObj(list->cursor, list->template.window, x, y); + break; + case 1: + case 2: // leftover + case 3: // leftover + break; + } +} + +THUMB_FUNC void ListMenuErasePrintedCursor(struct ListMenu * list, u16 itemsAbove) +{ + switch (list->template.cursorKind) + { + case 0: + u8 yMultiplier = GetFontAttribute(list->template.fontId, 1) + list->template.itemVerticalPadding; + u8 width = 8; + u8 height = 16; + FillWindowPixelRect(list->template.window, + list->template.fillValue, + list->template.cursor_X, + itemsAbove * yMultiplier + list->template.upText_Y, + width, + height); + break; + case 1: + case 2: // leftover + case 3: // leftover + break; + } +} + +THUMB_FUNC u8 ListMenuUpdateSelectedRowIndexAndScrollOffset(struct ListMenu *list, u8 movingDown) +{ + u32 cursorPos; + u16 itemsAbove; + u16 newRow; + + itemsAbove = list->itemsAbove; + cursorPos = list->cursorPos; + + if (!movingDown) + { + if (list->template.maxShowed == 1) + newRow = 0; + else + newRow = list->template.maxShowed - ((list->template.maxShowed / 2) + (list->template.maxShowed % 2)) - 1; + + if (cursorPos == 0) + { + while (itemsAbove != 0) + { + itemsAbove--; + if (list->template.items[cursorPos + itemsAbove].index != LIST_HEADER) + { + list->itemsAbove = itemsAbove; + return 1; + } + } + return 0; + } + else + { + while (itemsAbove > newRow) + { + itemsAbove--; + if (list->template.items[cursorPos + itemsAbove].index != LIST_HEADER) + { + list->itemsAbove = itemsAbove; + return 1; + } + } + list->itemsAbove = newRow; + list->cursorPos = cursorPos - 1; + } + } + else + { + if (list->template.maxShowed == 1) + newRow = 0; + else + newRow = ((list->template.maxShowed / 2) + (list->template.maxShowed % 2)); + + if (cursorPos == list->template.totalItems - list->template.maxShowed) + { + while (itemsAbove < list->template.maxShowed - 1) + { + itemsAbove++; + if (list->template.items[cursorPos + itemsAbove].index != LIST_HEADER) + { + list->itemsAbove = itemsAbove; + return 1; + } + } + return 0; + } + else + { + while (itemsAbove < newRow) + { + itemsAbove++; + if (list->template.items[cursorPos + itemsAbove].index != LIST_HEADER) + { + list->itemsAbove = itemsAbove; + return 1; + } + } + list->itemsAbove = newRow; + list->cursorPos = cursorPos + 1; + } + } + return 2; +} + +THUMB_FUNC void ListMenuScroll(struct ListMenu * list, u8 count, u8 movingDown) +{ + if (count >= list->template.maxShowed) + { + FillWindowPixelBuffer(list->template.window, list->template.fillValue); + ListMenuPrintEntries(list, list->cursorPos, 0, list->template.maxShowed); + } + else + { + u8 yMultiplier = GetFontAttribute(list->template.fontId, 1) + list->template.itemVerticalPadding; + + if (!movingDown) + { + u16 y, width, height; + + ScrollWindow(list->template.window, 1, count * yMultiplier, (list->template.fillValue << 4) | list->template.fillValue); + ListMenuPrintEntries(list, list->cursorPos, 0, count); + + y = (list->template.maxShowed * yMultiplier) + list->template.upText_Y; + width = GetWindowWidth(list->template.window); + height = GetWindowHeight(list->template.window); + FillWindowPixelRect(list->template.window, + list->template.fillValue, + 0, y, width * 8, height * 8 - y); + } + else + { + u32 width; + + ScrollWindow(list->template.window, 0, count * yMultiplier, (list->template.fillValue << 4) | list->template.fillValue); + ListMenuPrintEntries(list, list->cursorPos + (list->template.maxShowed - count), list->template.maxShowed - count, count); + + width = GetWindowWidth(list->template.window); + FillWindowPixelRect(list->template.window, + list->template.fillValue, + 0, 0, width * 8, list->template.upText_Y); + } + } +} + +THUMB_FUNC BOOL ListMenuChangeSelection(struct ListMenu * list, u8 updateCursorAndCallCallback, u8 count, u8 movingDown) +{ + u16 oldSelectedRow; + u8 selectionChange, i, cursorCount; + + oldSelectedRow = list->itemsAbove; + cursorCount = 0; + selectionChange = 0; + for (i = 0; i < count; i++) + { + do + { + u8 ret = ListMenuUpdateSelectedRowIndexAndScrollOffset(list, movingDown); + + selectionChange |= ret; + if (ret != 2) + break; + cursorCount++; + } + while (list->template.items[list->cursorPos + list->itemsAbove].index == LIST_HEADER); + } + + if (updateCursorAndCallCallback) + { + switch (selectionChange) + { + case 0: + default: + return TRUE; + case 1: + ListMenuErasePrintedCursor(list, oldSelectedRow); + ListMenuDrawCursor(list); + ListMenuCallSelectionChangedCallback(list, FALSE); + CopyWindowToVram(list->template.window); + break; + case 2: + case 3: + ListMenuErasePrintedCursor(list, oldSelectedRow); + ListMenuScroll(list, cursorCount, movingDown); + ListMenuDrawCursor(list); + ListMenuCallSelectionChangedCallback(list, FALSE); + CopyWindowToVram(list->template.window); + break; + } + } + return FALSE; +} + +THUMB_FUNC void ListMenuCallSelectionChangedCallback(struct ListMenu * list, u8 onInit) +{ + if (list->template.moveCursorFunc != NULL) + { + list->template.moveCursorFunc(list, list->template.items[list->cursorPos + list->itemsAbove].index, onInit); + } +} + +THUMB_FUNC void ListMenuCopyToVram(struct ListMenu * list) +{ + CopyWindowToVram(list->template.window); +} |