Allow tabs to grow wider than the screen
This commit is contained in:
parent
eeb0bf572d
commit
b3674c6845
|
@ -326,6 +326,8 @@ void fontRendererInitPrerender(struct FontRenderer* renderer, struct Prerendered
|
|||
prerender->displayLists = malloc(sizeof(Gfx*) * imageIndex);
|
||||
|
||||
prerender->usedImageIndices = renderer->usedImageIndices;
|
||||
prerender->x = 0;
|
||||
prerender->y = 0;
|
||||
|
||||
imageMask = renderer->usedImageIndices;
|
||||
imageIndex = 0;
|
||||
|
@ -385,6 +387,46 @@ void prerenderedTextFree(struct PrerenderedText* prerender) {
|
|||
free(prerender);
|
||||
}
|
||||
|
||||
void prerenderShiftSingleSymbol(Gfx* gfx, int xOffset, int yOffset) {
|
||||
int x = _SHIFTR(gfx->words.w0, 12, 12) + xOffset;
|
||||
int y = _SHIFTL(gfx->words.w0, 0, 12) + yOffset;
|
||||
|
||||
gfx->words.w0 = _SHIFTL(G_TEXRECT, 24, 8) | _SHIFTL(x, 12, 12) | _SHIFTL(y, 0, 12);
|
||||
|
||||
x = _SHIFTR(gfx->words.w1, 12, 12) + xOffset;
|
||||
y = _SHIFTL(gfx->words.w1, 0, 12) + yOffset;
|
||||
|
||||
gfx->words.w1 = _SHIFTL(G_TX_RENDERTILE, 24, 3) | _SHIFTL(x, 12, 12) | _SHIFTL(y, 0, 12);
|
||||
}
|
||||
|
||||
void prerenderedTextRelocate(struct PrerenderedText* prerender, int x, int y) {
|
||||
int imageIndex = 0;
|
||||
int imageMask = prerender->usedImageIndices;
|
||||
|
||||
int xOffset = (x - prerender->x) << 2;
|
||||
int yOffset = (y - prerender->y) << 2;
|
||||
|
||||
while (imageMask) {
|
||||
if (imageMask & 0x1) {
|
||||
Gfx* gfx = prerender->displayLists[imageIndex];
|
||||
// skip color
|
||||
gfx += 2;
|
||||
|
||||
while (_SHIFTR(gfx->words.w0, 24, 8) != G_ENDDL) {
|
||||
prerenderShiftSingleSymbol(gfx, xOffset, yOffset);
|
||||
gfx += 3;
|
||||
}
|
||||
|
||||
osWritebackDCache(prerender->displayLists[imageIndex], (int)gfx - (int)prerender->displayLists[imageIndex]);
|
||||
}
|
||||
|
||||
imageMask >>= 1;
|
||||
++imageIndex;
|
||||
}
|
||||
prerender->x = x;
|
||||
prerender->y = y;
|
||||
}
|
||||
|
||||
void prerenderedTextRecolor(struct PrerenderedText* prerender, struct Coloru8* color) {
|
||||
int imageIndex = 0;
|
||||
int imageMask = prerender->usedImageIndices;
|
||||
|
@ -413,6 +455,9 @@ void fontRendererFillPrerender(struct FontRenderer* renderer, struct Prerendered
|
|||
int imageIndex = 0;
|
||||
int imageMask = renderer->usedImageIndices & prerender->usedImageIndices;
|
||||
|
||||
prerender->x = x;
|
||||
prerender->y = y;
|
||||
|
||||
while (imageMask) {
|
||||
if (imageMask & 0x1) {
|
||||
Gfx* gfx = prerender->displayLists[imageIndex];
|
||||
|
|
|
@ -67,12 +67,15 @@ Gfx* fontRendererBuildGfx(struct FontRenderer* renderer, Gfx** fontImages, int x
|
|||
struct PrerenderedText {
|
||||
Gfx** displayLists;
|
||||
short usedImageIndices;
|
||||
short x;
|
||||
short y;
|
||||
};
|
||||
|
||||
void fontRendererInitPrerender(struct FontRenderer* renderer, struct PrerenderedText* prerender);
|
||||
struct PrerenderedText* prerenderedTextNew(struct FontRenderer* renderer);
|
||||
void prerenderedTextCleanup(struct PrerenderedText* prerender);
|
||||
void prerenderedTextFree(struct PrerenderedText* prerender);
|
||||
void prerenderedTextRelocate(struct PrerenderedText* prerender, int x, int y);
|
||||
void prerenderedTextRecolor(struct PrerenderedText* prerender, struct Coloru8* color);
|
||||
|
||||
void fontRendererFillPrerender(struct FontRenderer* renderer, struct PrerenderedText* prerender, int x, int y, struct Coloru8* color);
|
||||
|
|
|
@ -21,6 +21,9 @@ struct Tab gOptionTabs[] = {
|
|||
{
|
||||
.message = "Audio",
|
||||
},
|
||||
{
|
||||
.message = "Video",
|
||||
},
|
||||
{
|
||||
.message = "Gameplay",
|
||||
},
|
||||
|
@ -59,32 +62,27 @@ void optionsMenuRebuildText(struct OptionsMenu* options) {
|
|||
}
|
||||
|
||||
enum MenuDirection optionsMenuUpdate(struct OptionsMenu* options) {
|
||||
enum MenuDirection menuDirection = MenuDirectionStay;
|
||||
|
||||
if(menuDirection == MenuDirectionStay)
|
||||
{
|
||||
switch (options->tabs.selectedTab) {
|
||||
case OptionsMenuTabsControlMapping:
|
||||
menuDirection = controlsMenuUpdate(&options->controlsMenu);
|
||||
break;
|
||||
case OptionsMenuTabsControlJoystick:
|
||||
menuDirection = joystickOptionsUpdate(&options->joystickOptions);
|
||||
break;
|
||||
case OptionsMenuTabsAudio:
|
||||
menuDirection = audioOptionsUpdate(&options->audioOptions);
|
||||
break;
|
||||
case OptionsMenuTabsGameplay:
|
||||
menuDirection = gameplayOptionsUpdate(&options->gameplayOptions);
|
||||
break;
|
||||
}
|
||||
switch (options->tabs.selectedTab) {
|
||||
case OptionsMenuTabsControlMapping:
|
||||
controlsMenuUpdate(&options->controlsMenu);
|
||||
break;
|
||||
case OptionsMenuTabsControlJoystick:
|
||||
joystickOptionsUpdate(&options->joystickOptions);
|
||||
break;
|
||||
case OptionsMenuTabsAudio:
|
||||
audioOptionsUpdate(&options->audioOptions);
|
||||
break;
|
||||
case OptionsMenuTabsGameplay:
|
||||
gameplayOptionsUpdate(&options->gameplayOptions);
|
||||
break;
|
||||
}
|
||||
|
||||
if (menuDirection == MenuDirectionUp) {
|
||||
if (controllerGetButtonDown(0, B_BUTTON)) {
|
||||
savefileSave();
|
||||
return MenuDirectionUp;
|
||||
}
|
||||
|
||||
if (menuDirection == MenuDirectionLeft) {
|
||||
if (controllerGetButtonDown(0, Z_TRIG | L_TRIG)) {
|
||||
if (options->tabs.selectedTab == 0) {
|
||||
tabsSetSelectedTab(&options->tabs, OptionsMenuTabsCount - 1);
|
||||
} else {
|
||||
|
@ -95,7 +93,7 @@ enum MenuDirection optionsMenuUpdate(struct OptionsMenu* options) {
|
|||
soundPlayerPlay(SOUNDS_BUTTONROLLOVER, 1.0f, 0.5f, NULL, NULL, SoundTypeAll);
|
||||
}
|
||||
|
||||
if (menuDirection == MenuDirectionRight) {
|
||||
if (controllerGetButtonDown(0, R_TRIG)) {
|
||||
if (options->tabs.selectedTab == OptionsMenuTabsCount - 1) {
|
||||
tabsSetSelectedTab(&options->tabs, 0);
|
||||
} else {
|
||||
|
@ -119,14 +117,29 @@ void optionsMenuRender(struct OptionsMenu* options, struct RenderState* renderSt
|
|||
gSPDisplayList(renderState->dl++, options->menuOutline);
|
||||
gSPDisplayList(renderState->dl++, ui_material_revert_list[ROUNDED_CORNERS_INDEX]);
|
||||
|
||||
gDPSetScissor(renderState->dl++,
|
||||
G_SC_NON_INTERLACE,
|
||||
MENU_LEFT + OPTIONS_PADDING,
|
||||
0,
|
||||
MENU_LEFT + MENU_WIDTH - OPTIONS_PADDING,
|
||||
SCREEN_HT
|
||||
);
|
||||
|
||||
gSPDisplayList(renderState->dl++, ui_material_list[SOLID_ENV_INDEX]);
|
||||
gSPDisplayList(renderState->dl++, options->tabs.tabOutline);
|
||||
gSPDisplayList(renderState->dl++, ui_material_revert_list[SOLID_ENV_INDEX]);
|
||||
|
||||
gSPDisplayList(renderState->dl++, ui_material_list[DEJAVU_SANS_0_INDEX]);
|
||||
renderState->dl = tabsRenderText(&options->tabs, renderState->dl);
|
||||
struct PrerenderedTextBatch* batch = prerenderedBatchStart();
|
||||
tabsRenderText(&options->tabs, batch);
|
||||
renderState->dl = prerenderedBatchFinish(batch, gDejaVuSansImages, renderState->dl);
|
||||
gSPDisplayList(renderState->dl++, ui_material_revert_list[DEJAVU_SANS_0_INDEX]);
|
||||
|
||||
gDPSetScissor(renderState->dl++,
|
||||
G_SC_NON_INTERLACE,
|
||||
0, 0,
|
||||
SCREEN_WD, SCREEN_HT
|
||||
);
|
||||
|
||||
switch (options->tabs.selectedTab) {
|
||||
case OptionsMenuTabsControlMapping:
|
||||
controlsMenuRender(&options->controlsMenu, renderState, task);
|
||||
|
|
|
@ -13,6 +13,7 @@ enum OptionsMenuTabs {
|
|||
OptionsMenuTabsControlMapping,
|
||||
OptionsMenuTabsControlJoystick,
|
||||
OptionsMenuTabsAudio,
|
||||
OptionsMenuTabsVideo,
|
||||
OptionsMenuTabsGameplay,
|
||||
|
||||
OptionsMenuTabsCount,
|
||||
|
|
|
@ -23,13 +23,26 @@ void tabsSetSelectedTab(struct Tabs* tabs, int index) {
|
|||
gDPFillRectangle(dl++, tabs->x, tabs->y + tabs->height - 1, tabs->x + tabs->width, tabs->y + tabs->height);
|
||||
gDPFillRectangle(dl++, tabs->x + tabs->width - 1, tabs->y + TAB_HEIGHT, tabs->x + tabs->width, tabs->y + tabs->height);
|
||||
|
||||
int tabOffset = 0;
|
||||
|
||||
struct TabRenderData* rightVisibleTab = &tabs->tabRenderData[tabs->selectedTab];
|
||||
|
||||
if (tabs->selectedTab + 1 < tabs->tabCount) {
|
||||
++rightVisibleTab;
|
||||
}
|
||||
|
||||
if (rightVisibleTab->x + rightVisibleTab->width >= tabs->x + tabs->width) {
|
||||
tabOffset = (tabs->x + tabs->width) - (rightVisibleTab->x + rightVisibleTab->width) + 1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < tabs->tabCount; ++i) {
|
||||
struct TabRenderData* tab = &tabs->tabRenderData[i];
|
||||
int tabTop = (i == tabs->selectedTab) ? tabs->y : (tabs->y + 1);
|
||||
int tabLeft = tab->x + tabOffset;
|
||||
|
||||
gDPFillRectangle(dl++, tab->x + tab->width - 2, tabTop, tab->x + tab->width - 1, tabs->y + TAB_HEIGHT);
|
||||
gDPFillRectangle(dl++, tabLeft + tab->width - 2, tabTop, tabLeft + tab->width - 1, tabs->y + TAB_HEIGHT);
|
||||
|
||||
fontRender(tabs->font, tabs->tabs[i].message, tab->x + LEFT_TEXT_PADDING, tabTop + TOP_TEXT_PADDING, tab->text);
|
||||
prerenderedTextRelocate(tab->text, tabLeft + LEFT_TEXT_PADDING, tabTop + TOP_TEXT_PADDING);
|
||||
}
|
||||
|
||||
gDPPipeSync(dl++);
|
||||
|
@ -39,19 +52,22 @@ void tabsSetSelectedTab(struct Tabs* tabs, int index) {
|
|||
for (int i = 0; i < tabs->tabCount; ++i) {
|
||||
struct TabRenderData* tab = &tabs->tabRenderData[i];
|
||||
int tabTop = (i == tabs->selectedTab) ? tabs->y : (tabs->y + 1);
|
||||
int tabLeft = tab->x + tabOffset;
|
||||
|
||||
gDPFillRectangle(dl++, tab->x, tabTop, tab->x + 1, tabs->y + TAB_HEIGHT);
|
||||
gDPFillRectangle(dl++, tab->x, tabTop, tab->x + tab->width - 2, tabTop + 1);
|
||||
gDPFillRectangle(dl++, tabLeft, tabTop, tabLeft + 1, tabs->y + TAB_HEIGHT);
|
||||
gDPFillRectangle(dl++, tabLeft, tabTop, tabLeft + tab->width - 2, tabTop + 1);
|
||||
}
|
||||
|
||||
struct TabRenderData* selectedTab = tabs->selectedTab < tabs->tabCount ? &tabs->tabRenderData[tabs->selectedTab] : NULL;
|
||||
|
||||
if (selectedTab) {
|
||||
gDPFillRectangle(dl++, tabs->x, tabs->y + TAB_HEIGHT, selectedTab->x, tabs->y + TAB_HEIGHT + 1);
|
||||
gDPFillRectangle(dl++, selectedTab->x + selectedTab->width, tabs->y + TAB_HEIGHT, tabs->x + tabs->width, tabs->y + TAB_HEIGHT + 1);
|
||||
gDPFillRectangle(dl++, tabs->x, tabs->y + TAB_HEIGHT, selectedTab->x + tabOffset, tabs->y + TAB_HEIGHT + 1);
|
||||
gDPFillRectangle(dl++, selectedTab->x + tabOffset + selectedTab->width, tabs->y + TAB_HEIGHT, tabs->x + tabs->width, tabs->y + TAB_HEIGHT + 1);
|
||||
}
|
||||
|
||||
gSPEndDisplayList(dl++);
|
||||
|
||||
tabs->prevOffset = tabOffset;
|
||||
}
|
||||
|
||||
void tabsInit(struct Tabs* tabs, struct Tab* tabList, int tabCount, struct Font* font, int x, int y, int width, int height) {
|
||||
|
@ -62,6 +78,7 @@ void tabsInit(struct Tabs* tabs, struct Tab* tabList, int tabCount, struct Font*
|
|||
tabs->height = height;
|
||||
tabs->x = x;
|
||||
tabs->y = y;
|
||||
tabs->prevOffset = 0;
|
||||
tabs->tabOutline = malloc(sizeof(Gfx) * (10 + 3 * tabCount));
|
||||
|
||||
tabs->tabRenderData = malloc(sizeof(struct TabRenderData) * tabCount);
|
||||
|
@ -70,7 +87,7 @@ void tabsInit(struct Tabs* tabs, struct Tab* tabList, int tabCount, struct Font*
|
|||
|
||||
for (int i = 0; i < tabCount; ++i) {
|
||||
struct Vector2s16 textSize = fontMeasure(font, tabList[i].message);
|
||||
tabs->tabRenderData[i].text = menuBuildText(font, tabList[i].message, currentX + LEFT_TEXT_PADDING, y + TOP_TEXT_PADDING);
|
||||
tabs->tabRenderData[i].text = menuBuildPrerenderedText(font, tabList[i].message, currentX + LEFT_TEXT_PADDING, y + TOP_TEXT_PADDING);
|
||||
tabs->tabRenderData[i].width = textSize.x + LEFT_TEXT_PADDING + RIGHT_TEXT_PADDING;
|
||||
tabs->tabRenderData[i].x = currentX;
|
||||
|
||||
|
@ -81,25 +98,8 @@ void tabsInit(struct Tabs* tabs, struct Tab* tabList, int tabCount, struct Font*
|
|||
tabsSetSelectedTab(tabs, 0);
|
||||
}
|
||||
|
||||
Gfx* tabsRenderText(struct Tabs* tabs, Gfx* dl) {
|
||||
gDPPipeSync(dl++);
|
||||
gDPSetEnvColor(dl++, gSelectionGray.r, gSelectionGray.g, gSelectionGray.b, gSelectionGray.a);
|
||||
|
||||
void tabsRenderText(struct Tabs* tabs, struct PrerenderedTextBatch* batch) {
|
||||
for (int i = 0; i < tabs->tabCount; ++i) {
|
||||
if (i == tabs->selectedTab) {
|
||||
gDPSetEnvColor(dl++, gColorWhite.r, gColorWhite.g, gColorWhite.b, gColorWhite.a);
|
||||
}
|
||||
|
||||
gSPDisplayList(dl++, tabs->tabRenderData[i].text);
|
||||
|
||||
if (i == tabs->selectedTab) {
|
||||
gDPPipeSync(dl++);
|
||||
gDPSetEnvColor(dl++, gSelectionGray.r, gSelectionGray.g, gSelectionGray.b, gSelectionGray.a);
|
||||
}
|
||||
prerenderedBatchAdd(batch, tabs->tabRenderData[i].text, i == tabs->selectedTab ? &gColorWhite : &gSelectionGray);
|
||||
}
|
||||
|
||||
gDPPipeSync(dl++);
|
||||
gDPSetEnvColor(dl++, gColorWhite.r, gColorWhite.g, gColorWhite.b, gColorWhite.a);
|
||||
|
||||
return dl;
|
||||
}
|
|
@ -9,7 +9,7 @@ struct Tab {
|
|||
};
|
||||
|
||||
struct TabRenderData {
|
||||
Gfx* text;
|
||||
struct PrerenderedText* text;
|
||||
short width;
|
||||
short x;
|
||||
};
|
||||
|
@ -23,12 +23,13 @@ struct Tabs {
|
|||
short selectedTab;
|
||||
short x;
|
||||
short y;
|
||||
short prevOffset;
|
||||
Gfx* tabOutline;
|
||||
struct TabRenderData* tabRenderData;
|
||||
};
|
||||
|
||||
void tabsInit(struct Tabs* tabs, struct Tab* tabList, int tabCount, struct Font* font, int x, int y, int width, int height);
|
||||
void tabsSetSelectedTab(struct Tabs* tabs, int index);
|
||||
Gfx* tabsRenderText(struct Tabs* tabs, Gfx* dl);
|
||||
void tabsRenderText(struct Tabs* tabs, struct PrerenderedTextBatch* batch);
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue