mirror of
https://github.com/risingPhil/PokeMe64.git
synced 2026-03-22 02:14:20 -05:00
Add scroll arrows when there are more items in the list than the list can show at a time. These arrows can be shown in the main menu (although there aren't enough items in there to have them shown) or in the various DistributionEventPokemonListScene menus. I also did provisions to support the same for the ScrollWidget in the about screen. Although I haven't implemented that (yet?)
278 lines
8.0 KiB
C++
Executable File
278 lines
8.0 KiB
C++
Executable File
#include "scenes/MenuScene.h"
|
|
#include "core/FontManager.h"
|
|
#include "scenes/SceneManager.h"
|
|
#include "transferpak/TransferPakManager.h"
|
|
#include "menu/MenuFunctions.h"
|
|
|
|
#include <cstdio>
|
|
#include <cmath>
|
|
|
|
static const Rectangle menuListBounds = {100, 30, 150, 0};
|
|
static const Rectangle imgScrollArrowUpBounds = {.x = 170, .y = 24, .width = 11, .height = 6};
|
|
static const Rectangle imgScrollArrowDownBounds = {.x = 170, .y = 180, .width = 11, .height = 6};
|
|
|
|
static void dialogFinishedCallback(void* context)
|
|
{
|
|
MenuScene* scene = (MenuScene*)context;
|
|
scene->onDialogDone();
|
|
}
|
|
|
|
MenuScene::MenuScene(SceneDependencies& deps, void* context)
|
|
: SceneWithDialogWidget(deps)
|
|
, context_(static_cast<MenuSceneContext*>(context))
|
|
, menu9SliceSprite_(nullptr)
|
|
, cursorSprite_(nullptr)
|
|
, uiArrowUpSprite_(nullptr)
|
|
, uiArrowDownSprite_(nullptr)
|
|
, menuList_(deps.animationManager)
|
|
, scrollArrowUp_()
|
|
, scrollArrowDown_()
|
|
, cursorWidget_(deps.animationManager)
|
|
, menuListFiller_(menuList_)
|
|
, listFocusChainSegment_(WidgetFocusChainSegment{
|
|
.current = &menuList_
|
|
})
|
|
, bButtonPressed_(false)
|
|
{
|
|
}
|
|
|
|
MenuScene::~MenuScene()
|
|
{
|
|
// we registered ourselves as context before. (setupMenu)
|
|
// this instance is about to become delete'd
|
|
// we need to reset every context referring to this instance to prevent
|
|
// crashes the next time we load the same menuentries
|
|
for(unsigned i=0; i < context_->numMenuEntries; ++i)
|
|
{
|
|
if(context_->menuEntries[i].context == this)
|
|
{
|
|
context_->menuEntries[i].context = nullptr;
|
|
}
|
|
}
|
|
}
|
|
|
|
void MenuScene::init()
|
|
{
|
|
// load these sprites before the parent init because setupDialog(style) will need them
|
|
menu9SliceSprite_ = sprite_load("rom://menu-bg-9slice.sprite");
|
|
cursorSprite_ = sprite_load("rom://hand-cursor.sprite");
|
|
uiArrowUpSprite_ = sprite_load("rom://ui-arrow-up.sprite");
|
|
uiArrowDownSprite_ = sprite_load("rom://ui-arrow-down.sprite");
|
|
|
|
SceneWithDialogWidget::init();
|
|
|
|
setupMenu();
|
|
|
|
setFocusChain(&listFocusChainSegment_);
|
|
}
|
|
|
|
void MenuScene::destroy()
|
|
{
|
|
menuList_.unregisterFocusListener(this);
|
|
menuList_.unregisterScrollWindowListener(this);
|
|
menuList_.clearWidgets();
|
|
menuList_.setStyle({0});
|
|
cursorWidget_.setStyle({0});
|
|
scrollArrowUp_.setStyle({0});
|
|
scrollArrowDown_.setStyle({0});
|
|
|
|
// destroy the parent before releasing the sprites because the dialog widget
|
|
// may still have a reference to them
|
|
SceneWithDialogWidget::destroy();
|
|
|
|
sprite_free(uiArrowDownSprite_);
|
|
uiArrowDownSprite_ = nullptr;
|
|
sprite_free(uiArrowUpSprite_);
|
|
uiArrowUpSprite_ = nullptr;
|
|
sprite_free(cursorSprite_);
|
|
cursorSprite_ = nullptr;
|
|
sprite_free(menu9SliceSprite_);
|
|
menu9SliceSprite_ = nullptr;
|
|
}
|
|
|
|
void MenuScene::render(RDPQGraphics& gfx, const Rectangle& sceneBounds)
|
|
{
|
|
menuList_.render(gfx, sceneBounds);
|
|
cursorWidget_.render(gfx, sceneBounds);
|
|
SceneWithDialogWidget::render(gfx, sceneBounds);
|
|
scrollArrowUp_.render(gfx, sceneBounds);
|
|
scrollArrowDown_.render(gfx, sceneBounds);
|
|
}
|
|
|
|
bool MenuScene::handleUserInput(joypad_port_t port, const joypad_inputs_t& inputs)
|
|
{
|
|
if(SceneWithDialogWidget::handleUserInput(port, inputs))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if(inputs.btn.b && !bButtonPressed_)
|
|
{
|
|
// we will only handle b button release.
|
|
bButtonPressed_ = true;
|
|
return true;
|
|
}
|
|
else if(!inputs.btn.b && bButtonPressed_)
|
|
{
|
|
// b button release occurred. Switch back to previous scene.
|
|
bButtonPressed_ = false;
|
|
|
|
if(context_->bButtonMeansUserWantsToSwitchCartridge)
|
|
{
|
|
DialogData* diag = new DialogData{
|
|
.shouldDeleteWhenDone = true
|
|
};
|
|
|
|
setDialogDataText(*diag, "Please turn the console off to switch gameboy cartridges!");
|
|
|
|
showDialog(diag);
|
|
}
|
|
else
|
|
{
|
|
// now do the actual switch back to the previous scene
|
|
deps_.sceneManager.goBackToPreviousScene();
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void MenuScene::onDialogDone()
|
|
{
|
|
dialogWidget_.setVisible(false);
|
|
menuList_.setVisible(true);
|
|
cursorWidget_.setVisible(true);
|
|
setFocusChain(&listFocusChainSegment_);
|
|
}
|
|
|
|
void MenuScene::focusChanged(const FocusChangeStatus& status)
|
|
{
|
|
const Rectangle newCursorBounds = {
|
|
.x = status.focusBounds.x + 2,
|
|
.y = status.focusBounds.y,
|
|
.width = cursorSprite_->width,
|
|
.height = cursorSprite_->height
|
|
};
|
|
|
|
cursorWidget_.moveToBounds(newCursorBounds);
|
|
}
|
|
|
|
void MenuScene::onScrollWindowChanged(const ScrollWindowUpdate& update)
|
|
{
|
|
scrollArrowUp_.setVisible(canScrollTo(update, UINavigationDirection::UP));
|
|
scrollArrowDown_.setVisible(canScrollTo(update, UINavigationDirection::DOWN));
|
|
}
|
|
|
|
SceneDependencies& MenuScene::getDependencies()
|
|
{
|
|
return deps_;
|
|
}
|
|
|
|
void MenuScene::setupMenu()
|
|
{
|
|
const VerticalListStyle listStyle = {
|
|
.background = {
|
|
.sprite = menu9SliceSprite_,
|
|
.spriteSettings = {
|
|
.renderMode = SpriteRenderMode::NINESLICE,
|
|
.srcRect = { 6, 6, 6, 6 }
|
|
}
|
|
},
|
|
.margin = {
|
|
.top = 5
|
|
},
|
|
.autogrow = {
|
|
.enabled = true,
|
|
.maxHeight = 150
|
|
}
|
|
};
|
|
|
|
const CursorStyle cursorStyle = {
|
|
.sprite = cursorSprite_,
|
|
.idleMoveDiff = { 5, 0, 0, 0 },
|
|
.idleAnimationDurationInMs = 500,
|
|
.moveAnimationDurationInMs = 250
|
|
};
|
|
|
|
menuList_.setStyle(listStyle);
|
|
menuList_.setBounds(menuListBounds);
|
|
menuList_.setVisible(true);
|
|
cursorWidget_.setStyle(cursorStyle);
|
|
cursorWidget_.setVisible(true);
|
|
menuList_.registerFocusListener(this);
|
|
menuList_.registerScrollWindowListener(this);
|
|
|
|
const MenuItemStyle itemStyle = {
|
|
.size = {150, 16},
|
|
.titleNotFocused = {
|
|
.fontId = arialId_,
|
|
.fontStyleId = fontStyleWhiteId_
|
|
},
|
|
.titleFocused = {
|
|
.fontId = arialId_,
|
|
.fontStyleId = fontStyleYellowId_
|
|
},
|
|
.leftMargin = 35,
|
|
.topMargin = 1
|
|
};
|
|
|
|
for(unsigned i=0; i < context_->numMenuEntries; ++i)
|
|
{
|
|
if(!context_->menuEntries[i].context)
|
|
{
|
|
context_->menuEntries[i].context = this;
|
|
}
|
|
}
|
|
|
|
menuListFiller_.addItems(context_->menuEntries, context_->numMenuEntries, itemStyle);
|
|
|
|
const ImageWidgetStyle scrollArrowUpStyle = {
|
|
.image = {
|
|
.sprite = uiArrowUpSprite_,
|
|
.spriteBounds = {0, 0, imgScrollArrowUpBounds.width, imgScrollArrowUpBounds.height}
|
|
}
|
|
};
|
|
|
|
scrollArrowUp_.setStyle(scrollArrowUpStyle);
|
|
scrollArrowUp_.setBounds(imgScrollArrowUpBounds);
|
|
|
|
const ImageWidgetStyle scrollArrowDownStyle = {
|
|
.image = {
|
|
.sprite = uiArrowDownSprite_,
|
|
.spriteBounds = { 0, 0, imgScrollArrowDownBounds.width, imgScrollArrowDownBounds.height}
|
|
}
|
|
};
|
|
|
|
// note: even though autogrow is turned on for the vertical list, it doesn't matter for the down arrow.
|
|
// because when the list is still growing, no scrolling is needed anyway, so the arrow would be invisible anyway.
|
|
scrollArrowDown_.setStyle(scrollArrowDownStyle);
|
|
scrollArrowDown_.setBounds(imgScrollArrowDownBounds);
|
|
}
|
|
|
|
void MenuScene::setupDialog(DialogWidgetStyle& style)
|
|
{
|
|
style.background.sprite = menu9SliceSprite_;
|
|
style.background.spriteSettings = {
|
|
.renderMode = SpriteRenderMode::NINESLICE,
|
|
.srcRect = { 6, 6, 6, 6 }
|
|
};
|
|
|
|
SceneWithDialogWidget::setupDialog(style);
|
|
|
|
dialogWidget_.setOnDialogFinishedCallback(dialogFinishedCallback, this);
|
|
dialogWidget_.setVisible(false);
|
|
}
|
|
|
|
void MenuScene::showDialog(DialogData* diagData)
|
|
{
|
|
SceneWithDialogWidget::showDialog(diagData);
|
|
menuList_.setVisible(false);
|
|
cursorWidget_.setVisible(false);
|
|
setFocusChain(&dialogFocusChainSegment_);
|
|
}
|
|
|
|
void deleteMenuSceneContext(void* context)
|
|
{
|
|
MenuSceneContext* menuContext = static_cast<MenuSceneContext*>(context);
|
|
delete menuContext;
|
|
} |