diff --git a/CHANGELOG.md b/CHANGELOG.md index fa39f31..822ffee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ ### Added - Ability to set the position of the top screen cover image in custom themes +- Support for fast scrolling with the L and R buttons in coverflow display mode +- Support for touch input + +### Fixed +- Use after free bug with the texture load request in Label3DView. This occurred for example when spamming B in banner list mode. ## [v1.2.0] - 29 Mar 2026 diff --git a/arm7/source/main.cpp b/arm7/source/main.cpp index 9090ec9..e1084b1 100644 --- a/arm7/source/main.cpp +++ b/arm7/source/main.cpp @@ -30,6 +30,7 @@ #include "ExitMode.h" #include "Arm7State.h" #include "mmc/tmio.h" +#include "touchScreen.h" static NocashOutputStream sNocashOutputStream; static PlainLogger sPlainLogger = PlainLogger(LogLevel::All, std::unique_ptr(&sNocashOutputStream)); @@ -42,19 +43,14 @@ static RtcIpcService sRtcIpcService; ILogger* gLogger = &sThreadSafeLogger; -static rtos_event_t sVBlankEvent; +static rtos_event_t sVCountEvent; static ExitMode sExitMode; static Arm7State sState; static volatile u8 sMcuIrqFlag = false; -static void vblankIrq(u32 irqMask) -{ - rtos_signalEvent(&sVBlankEvent); -} - static void vcountIrq(u32 irqMask) { - SHARED_KEY_XY = REG_RCNT0_H; + rtos_signalEvent(&sVCountEvent); } static void mcuIrq(u32 irq2Mask) @@ -88,12 +84,13 @@ static void checkMcuIrq(void) } } -static void initializeVBlankIrq() +static void initializeVCountIrq() { - rtos_createEvent(&sVBlankEvent); - rtos_setIrqFunc(RTOS_IRQ_VBLANK, vblankIrq); - rtos_enableIrqMask(RTOS_IRQ_VBLANK); - gfx_setVBlankIrqEnabled(true); + rtos_createEvent(&sVCountEvent); + gfx_setVCountMatchLine(96); + rtos_setIrqFunc(RTOS_IRQ_VCOUNT, vcountIrq); + rtos_enableIrqMask(RTOS_IRQ_VCOUNT); + gfx_setVCountMatchIrqEnabled(true); } static void clearSoundRegisters() @@ -145,12 +142,7 @@ static void initializeArm7() sSoundIpcService.Start(); sRtcIpcService.Start(); - gfx_setVCountMatchLine(96); - rtos_setIrqFunc(RTOS_IRQ_VCOUNT, vcountIrq); - rtos_enableIrqMask(RTOS_IRQ_VCOUNT); - gfx_setVCountMatchIrqEnabled(true); - - initializeVBlankIrq(); + initializeVCountIrq(); if (isDSiMode()) { @@ -158,6 +150,8 @@ static void initializeArm7() rtos_enableIrq2Mask(RTOS_IRQ2_MCU); } + touch_init(); + ipc_setArm7SyncBits(7); } @@ -233,7 +227,16 @@ int main() while (true) { - rtos_waitEvent(&sVBlankEvent, true, true); + rtos_waitEvent(&sVCountEvent, true, true); + u16 keys = REG_RCNT0_H | RCNT0_H_DATA_PEN; + touchPosition touchPos; + if (touch_update(touchPos)) + { + keys &= ~RCNT0_H_DATA_PEN; // pen down + SHARED_TOUCH_X = touchPos.px; + SHARED_TOUCH_Y = touchPos.py; + } + SHARED_KEY_XY = keys; updateArm7(); } diff --git a/arm7/source/touchScreen.cpp b/arm7/source/touchScreen.cpp new file mode 100644 index 0000000..2d1667d --- /dev/null +++ b/arm7/source/touchScreen.cpp @@ -0,0 +1,146 @@ +#include "common.h" +#include +#include + +// See: https://github.com/blocksds/libnds/blob/master/source/arm7/input.c + +// === Touchscreen filter configuration === + +// Replace Z1/Z2 values with X/Y noisiness measurements. +// #define TOUCH_DEBUG_NOISINESS + +// The number of frames to debounce/hold pen presses for. +// Set to 0 to disable. +#define PEN_DOWN_DEBOUNCE 1 +// The shift (1 << N) used for the IIR filter to average noisy samples across +// time. Set to 0 to disable. +#define TOUCH_MAX_NOISE_PEN_UP_IIR_SHIFT 5 + +// The maximum value of noisiness for pressing a pen down (measurement now valid). +#define TOUCH_MAX_NOISE_PEN_DOWN 38 +// The minimum value of noisiness for lifting a pen up (measurement no longer valid). +#define TOUCH_MAX_NOISE_PEN_UP 50 + +// === Touchscreen filter === + +// IIR filter constants. +#define TOUCH_MAX_NOISE_PEN_UP_IIR_RATIO (1 << TOUCH_MAX_NOISE_PEN_UP_IIR_SHIFT) +#define TOUCH_MAX_NOISE_PEN_UP_IIR_MIN (TOUCH_MAX_NOISE_PEN_UP - TOUCH_MAX_NOISE_PEN_UP_IIR_RATIO) + +typedef struct { + u16 value; // 1..4095, 0 if invalid + u16 noisiness; // 0..4095, ~15-16 = 1 pixel +} libnds_touchMeasurementFilterResult; + +/** + * @brief Perform filtering on the raw touch samples provided to return one + * averaged sample and an estimate of how noisy it is, while skipping outliers. + * + * Internal. See touchFilter.c for more information. + */ +extern "C" libnds_touchMeasurementFilterResult libnds_touchMeasurementFilter(u16 values[5]); + +void touch_init() +{ + touchInit(); +} + +bool touch_update(touchPosition& touchPos) +{ +#if PEN_DOWN_DEBOUNCE > 0 + static touchPosition lastTouchPosition; + static bool lastPenDown = false; + static u8 penDownDebounce = 0; +#else + touchPosition lastTouchPosition; + bool lastPenDown = false; +#endif + + bool penDown = touchPenDown(); + if (penDown) + { + // Set penDown to false for later fallthroughs to noPenDown. + // It will be set to true if all the touch filtering ensures the readout is valid. + penDown = false; + + // Measure new touch position. + touchRawArray data; + if (!touchReadData(&data)) + goto noPenDown; + + libnds_touchMeasurementFilterResult rawXresult = libnds_touchMeasurementFilter(data.rawX); + if (!rawXresult.value) + goto noPenDown; + libnds_touchMeasurementFilterResult rawYresult = libnds_touchMeasurementFilter(data.rawY); + if (!rawYresult.value) + goto noPenDown; + + // Valid sample read. + u16 noisiness = rawXresult.noisiness > rawYresult.noisiness ? rawXresult.noisiness : rawYresult.noisiness; + if (noisiness <= (lastPenDown ? TOUCH_MAX_NOISE_PEN_UP : TOUCH_MAX_NOISE_PEN_DOWN)) + { + lastTouchPosition.z1 = libnds_touchMeasurementFilter(data.z1).value; + lastTouchPosition.z2 = libnds_touchMeasurementFilter(data.z2).value; + +#if TOUCH_MAX_NOISE_PEN_UP_IIR_SHIFT > 0 + // Apply an IIR filter on noisy X/Y samples. + // Skip the IIR filter if the pen was just pressed. + int n = (noisiness - TOUCH_MAX_NOISE_PEN_UP_IIR_MIN); + if (noisiness <= 0 || !lastPenDown) + { + lastTouchPosition.rawx = rawXresult.value; + lastTouchPosition.rawy = rawYresult.value; + } + else if (noisiness <= TOUCH_MAX_NOISE_PEN_UP_IIR_RATIO) + { + lastTouchPosition.rawx = + ((rawXresult.value * (TOUCH_MAX_NOISE_PEN_UP_IIR_RATIO - n)) + + (lastTouchPosition.rawx * n)) >> TOUCH_MAX_NOISE_PEN_UP_IIR_SHIFT; + lastTouchPosition.rawy = + ((rawYresult.value * (TOUCH_MAX_NOISE_PEN_UP_IIR_RATIO - n)) + + (lastTouchPosition.rawy * n)) >> TOUCH_MAX_NOISE_PEN_UP_IIR_SHIFT; + } +#else + lastTouchPosition.rawx = rawXresult.value; + lastTouchPosition.rawy = rawYresult.value; +#endif + + touchApplyCalibration(lastTouchPosition.rawx, lastTouchPosition.rawy, &lastTouchPosition.px, &lastTouchPosition.py); + penDown = true; + } + +#ifdef TOUCH_DEBUG_NOISINESS + lastTouchPosition.z1 = rawXresult.noisiness; + lastTouchPosition.z2 = rawYresult.noisiness; +#endif + } + +noPenDown: +#if PEN_DOWN_DEBOUNCE > 0 + // Perform simple debouncing. + // Hold new presses for PEN_DOWN_DEBOUNCE frames. + if (!penDownDebounce) + { + if (lastPenDown != penDown) + { + lastPenDown = penDown; + if (penDown) + penDownDebounce = PEN_DOWN_DEBOUNCE; + } + } + else + { + penDownDebounce--; + } +#else + lastPenDown = penDown; +#endif + + // Return the touch position and pen down. + if (lastPenDown) + { + touchPos = lastTouchPosition; + } + + return lastPenDown; +} diff --git a/arm7/source/touchScreen.h b/arm7/source/touchScreen.h new file mode 100644 index 0000000..8b5186d --- /dev/null +++ b/arm7/source/touchScreen.h @@ -0,0 +1,5 @@ +#pragma once +#include + +void touch_init(); +bool touch_update(touchPosition& touchPos); diff --git a/arm9/gfx/upIcon.grit b/arm9/gfx/upIcon.grit new file mode 100644 index 0000000..9392dda --- /dev/null +++ b/arm9/gfx/upIcon.grit @@ -0,0 +1,7 @@ +# tile format +-gt + +# graphics bit depth is 4 (16 color) +-gB4 + +-p! \ No newline at end of file diff --git a/arm9/gfx/upIcon.png b/arm9/gfx/upIcon.png new file mode 100644 index 0000000..c13e674 Binary files /dev/null and b/arm9/gfx/upIcon.png differ diff --git a/arm9/source/App.cpp b/arm9/source/App.cpp index 1102b80..28b4d44 100644 --- a/arm9/source/App.cpp +++ b/arm9/source/App.cpp @@ -43,7 +43,7 @@ App::App(IAppSettingsService& appSettingsService, IBgmService& bgmService) , _subVramContext(nullptr, &_subObjVram, nullptr, nullptr) , _appSettingsService(appSettingsService) , _bgmService(bgmService) - , _inputProvider(&_inputSource) + , _inputProvider(&_keyInputSource, &_touchInputSource) , _inputRepeater(&_inputProvider, InputKey::DpadLeft | InputKey::DpadRight | InputKey::DpadUp | InputKey::DpadDown | InputKey::L | InputKey::R, 25, 8) @@ -134,7 +134,7 @@ void App::Run() StoreVramState(_vramStateBeforeMakeBottomScreenView); - _romBrowserBottomScreenView = std::make_unique( + _romBrowserBottomScreenView = RomBrowserBottomScreenView::CreateShared( &_romBrowserBottomScreenViewModel, RomBrowserDisplayModeFactory().GetRomBrowserDisplayMode( _romBrowserController.GetRomBrowserDisplaySettings().layout), @@ -301,8 +301,8 @@ void App::HandleShowGameInfoTrigger() // gameInfoDialog->SetGraphics(_chipViewVram); // _dialogPresenter.ShowDialog(std::move(gameInfoDialog)); - auto cheatsViewModel = std::make_unique(_romBrowserController.GetTriggerFileInfo(), &_romBrowserController); - auto cheatsDialog = std::make_unique( + auto cheatsViewModel = SharedPtr::MakeShared(_romBrowserController.GetTriggerFileInfo(), &_romBrowserController); + auto cheatsDialog = CheatsBottomSheetView::CreateShared( std::move(cheatsViewModel), &_theme->GetMaterialColorScheme(), _theme->GetFontRepository(), &_focusManager); _dialogPresenter.ShowDialog(std::move(cheatsDialog)); } @@ -316,7 +316,7 @@ void App::HandleHideGameInfoTrigger() void App::HandleShowDisplaySettingsTrigger() { - auto displaySettingsDialog = std::make_unique( + auto displaySettingsDialog = DisplaySettingsBottomSheetView::CreateShared( &_displaySettingsBottomSheetViewModel, &_theme->GetMaterialColorScheme(), _theme->GetFontRepository()); displaySettingsDialog->SetGraphics(_iconButtonViewVram); _dialogPresenter.ShowDialog(std::move(displaySettingsDialog)); @@ -337,11 +337,11 @@ void App::HandleNavigateTrigger() void App::HandleFolderLoadDoneTrigger() { - _romBrowserTopScreenView.reset(); + _romBrowserTopScreenView.Reset(); RestoreVramState(_vramStateAfterMakeBottomScreenView); auto displayMode = RomBrowserDisplayModeFactory().GetRomBrowserDisplayMode( _romBrowserController.GetRomBrowserDisplaySettings().layout); - _romBrowserTopScreenView = std::make_unique( + _romBrowserTopScreenView = RomBrowserTopScreenView::CreateShared( _romBrowserController.GetRomBrowserViewModel(), displayMode, _materialThemeFileIconFactory.get(), @@ -358,7 +358,7 @@ void App::HandleChangeDisplayModeTrigger(RomBrowserState newState) RestoreVramState(_vramStateBeforeMakeBottomScreenView); auto displayMode = RomBrowserDisplayModeFactory().GetRomBrowserDisplayMode( _romBrowserController.GetRomBrowserDisplaySettings().layout); - _romBrowserBottomScreenView = std::make_unique( + _romBrowserBottomScreenView = RomBrowserBottomScreenView::CreateShared( &_romBrowserBottomScreenViewModel, displayMode, _materialThemeFileIconFactory.get(), @@ -366,7 +366,7 @@ void App::HandleChangeDisplayModeTrigger(RomBrowserState newState) &_vblankTextureLoader); _romBrowserBottomScreenView->InitVram(_mainVramContext); StoreVramState(_vramStateAfterMakeBottomScreenView); - _romBrowserTopScreenView = std::make_unique( + _romBrowserTopScreenView = RomBrowserTopScreenView::CreateShared( _romBrowserController.GetRomBrowserViewModel(), displayMode, _materialThemeFileIconFactory.get(), @@ -405,7 +405,7 @@ void App::Update() bool isRomBrowserVisible = IsRomBrowserVisible(); if (isRomBrowserVisible && !_exit && curState != RomBrowserState::Launching) { - _focusManager.Update(_inputRepeater); + HandleInput(); } if (_topBackground) @@ -523,3 +523,49 @@ void App::RestoreVramState(const VramState& vramState) _texturePaletteVram.SetState(vramState._texPlttVramState); _subObjVram.SetState(vramState._subObjVramState); } + +void App::HandleInput() +{ + _focusManager.Update(_inputRepeater); + Point touchPoint; + if (_inputRepeater.Triggered(InputKey::Touch) && + _inputRepeater.GetCurrentTouchPoint(touchPoint)) + { + // pen down + if (_dialogPresenter.IsBottomSheetVisible()) + { + _dialogPresenter.HandlePenDown(touchPoint, _focusManager); + } + else + { + _romBrowserBottomScreenView->HandlePenDown(touchPoint, _focusManager); + } + _lastTouchPoint = touchPoint; + } + else if (_inputRepeater.Released(InputKey::Touch)) + { + // pen up + if (_dialogPresenter.IsBottomSheetVisible()) + { + _dialogPresenter.HandlePenUp(_lastTouchPoint, _focusManager); + } + else + { + _romBrowserBottomScreenView->HandlePenUp(_lastTouchPoint, _focusManager); + } + } + else if (_inputRepeater.Current(InputKey::Touch) + && _inputRepeater.GetCurrentTouchPoint(touchPoint)) + { + // pen move + if (_dialogPresenter.IsBottomSheetVisible()) + { + _dialogPresenter.HandlePenMove(touchPoint, _focusManager); + } + else + { + _romBrowserBottomScreenView->HandlePenMove(touchPoint, _focusManager); + } + _lastTouchPoint = touchPoint; + } +} diff --git a/arm9/source/App.h b/arm9/source/App.h index e7e19cd..f424e6c 100644 --- a/arm9/source/App.h +++ b/arm9/source/App.h @@ -12,6 +12,7 @@ #include "gui/DescendingStackVramManager.h" #include "material/scheme/scheme.h" #include "gui/input/PadInputSource.h" +#include "gui/input/TouchInputSource.h" #include "gui/input/SampledInputProvider.h" #include "gui/input/InputRepeater.h" #include "gui/VBlankTextureLoader.h" @@ -62,9 +63,9 @@ private: Rgb6Palette _rgb6Palette; Animator _fadeAnimator; - TaskQueue<32, 32> _ioTaskQueue; + TaskQueue<32, sizeof(TaskBase) + 32> _ioTaskQueue; u32 _ioTaskThreadStack[2048 / 4]; - TaskQueue<32, 32> _bgTaskQueue; + TaskQueue<32, sizeof(TaskBase) + 32> _bgTaskQueue; u32 _bgTaskThreadStack[2048 / 4]; std::unique_ptr _theme; @@ -75,12 +76,13 @@ private: IBgmService& _bgmService; volatile bool _exit = false; - PadInputSource _inputSource; + PadInputSource _keyInputSource; + TouchInputSource _touchInputSource; SampledInputProvider _inputProvider; InputRepeater _inputRepeater; - std::unique_ptr _romBrowserBottomScreenView; - std::unique_ptr _romBrowserTopScreenView; + SharedPtr _romBrowserBottomScreenView; + SharedPtr _romBrowserTopScreenView; RomBrowserController _romBrowserController; @@ -103,10 +105,13 @@ private: bool _vcountIrqStarted = false; + Point _lastTouchPoint = Point(0, 0); + void InitVramMapping() const; void DisplaySplashScreen() const; void LoadTheme(); void VCountIrq(); + void HandleInput(); void HandleTrigger(RomBrowserStateTrigger trigger, RomBrowserState newState); void HandleShowGameInfoTrigger(); void HandleHideGameInfoTrigger(); diff --git a/arm9/source/DialogPresenter.cpp b/arm9/source/DialogPresenter.cpp index 263ea25..5aac8cd 100644 --- a/arm9/source/DialogPresenter.cpp +++ b/arm9/source/DialogPresenter.cpp @@ -16,10 +16,12 @@ DialogPresenter::DialogPresenter(FocusManager* focusManager, StackVramManager* v _baseVramState = _vramManager->GetState(); } -void DialogPresenter::ShowDialog(std::unique_ptr dialog) +void DialogPresenter::ShowDialog(SharedPtr dialog) { if (!_nextDialog) + { _nextDialog = std::move(dialog); + } } void DialogPresenter::CloseDialog() @@ -93,7 +95,7 @@ void DialogPresenter::Update() else { _newState = State::Idle; - _currentDialog.reset(); + _currentDialog.Reset(); } break; } @@ -152,4 +154,28 @@ void DialogPresenter::InitVram() REG_BLDCNT = 0x3944; REG_BLDALPHA = (16 << 8) | 0; -} \ No newline at end of file +} + +void DialogPresenter::HandlePenDown(const Point& touchPoint, FocusManager& focusManager) +{ + if (_curState == State::BottomSheetVisible && _currentDialog) + { + _currentDialog->HandlePenDown(touchPoint, focusManager); + } +} + +void DialogPresenter::HandlePenMove(const Point& touchPoint, FocusManager& focusManager) +{ + if (_curState == State::BottomSheetVisible && _currentDialog) + { + _currentDialog->HandlePenMove(touchPoint, focusManager); + } +} + +void DialogPresenter::HandlePenUp(const Point& lastTouchPoint, FocusManager& focusManager) +{ + if (_curState == State::BottomSheetVisible && _currentDialog) + { + _currentDialog->HandlePenUp(lastTouchPoint, focusManager); + } +} diff --git a/arm9/source/DialogPresenter.h b/arm9/source/DialogPresenter.h index c84be26..1984084 100644 --- a/arm9/source/DialogPresenter.h +++ b/arm9/source/DialogPresenter.h @@ -15,7 +15,7 @@ public: /// @brief Requests to show the given dialog. /// @param dialog The dialog to show. - void ShowDialog(std::unique_ptr dialog); + void ShowDialog(SharedPtr dialog); /// @brief Closes the current dialog. void CloseDialog(); @@ -42,6 +42,21 @@ public: /// @brief Initializes vram that is needed for showing dialogs. void InitVram(); + /// @brief Handles a pen down event. + /// @param touchPoint The touch point. + /// @param focusManager The focus manager. + void HandlePenDown(const Point& touchPoint, FocusManager& focusManager); + + /// @brief Handles a pen move event. + /// @param touchPoint The touch point. + /// @param focusManager The focus manager. + void HandlePenMove(const Point& touchPoint, FocusManager& focusManager); + + /// @brief Handles a pen up event. + /// @param lastTouchPoint The last touch point. + /// @param focusManager The focus manager. + void HandlePenUp(const Point& lastTouchPoint, FocusManager& focusManager); + /// @brief Clears the focus that was stored when a dialog was opened. void ClearOldFocus() { @@ -55,6 +70,11 @@ public: return _oldFocus; } + bool IsBottomSheetVisible() const + { + return _curState != State::Idle; + } + private: enum class State { @@ -66,8 +86,8 @@ private: FocusManager* _focusManager; StackVramManager* _vramManager; u32 _baseVramState; - std::unique_ptr _currentDialog; - std::unique_ptr _nextDialog; + SharedPtr _currentDialog; + SharedPtr _nextDialog; bool _initVram = false; SharedPtr _oldFocus = nullptr; Animator _scrimAnimator; diff --git a/arm9/source/core/EnableSharedFromThis.h b/arm9/source/core/EnableSharedFromThis.h index 4aa7f19..f104359 100644 --- a/arm9/source/core/EnableSharedFromThis.h +++ b/arm9/source/core/EnableSharedFromThis.h @@ -20,7 +20,7 @@ class EnableSharedFromThis : public EnableSharedFromThisBase template friend class SharedPtr; -protected: +public: SharedPtr SharedFromThis() { return __sharedFromThisWeakPtr.Lock(); diff --git a/arm9/source/core/SharedPtr.h b/arm9/source/core/SharedPtr.h index 194e41d..deb6e3f 100644 --- a/arm9/source/core/SharedPtr.h +++ b/arm9/source/core/SharedPtr.h @@ -207,3 +207,10 @@ private: } } }; + +#define SHARED_ONLY(className) \ + friend class MakeSharedRefCount; \ +public: \ + static SharedPtr CreateShared(auto&&... args) \ + { return SharedPtr::MakeShared(std::forward(args)...); } \ +private: diff --git a/arm9/source/core/math/fixed.h b/arm9/source/core/math/fixed.h index 4946ee1..f40bc77 100644 --- a/arm9/source/core/math/fixed.h +++ b/arm9/source/core/math/fixed.h @@ -46,7 +46,7 @@ public: constexpr fixed(long double value) : _value(std::round(value * (1 << FractionBits))) { } - + constexpr T Int() const { return _value >> FractionBits; @@ -161,11 +161,27 @@ public: return FromRawValue(this->_value >> rhs); } - constexpr fix16 abs() const + constexpr fix16 Abs() const { return FromRawValue(std::abs(this->_value)); } + constexpr fix16 Clamp(fix16 min, fix16 max) const + { + if (this->_value < min._value) + { + return min; + } + else if (this->_value > max._value) + { + return max; + } + else + { + return *this; + } + } + template constexpr fix32 LongMul(const fix16& other) const { @@ -265,21 +281,45 @@ public: return this->_value < other._value; } + template + constexpr friend bool operator<(TLhs lhs, const fix32& rhs) + { + return fix32(lhs)._value < rhs._value; + } + constexpr bool operator<=(const fix32& other) const { return this->_value <= other._value; } + template + constexpr friend bool operator<=(TLhs lhs, const fix32& rhs) + { + return fix32(lhs)._value <= rhs._value; + } + constexpr bool operator>(const fix32& other) const { return this->_value > other._value; } + template + constexpr friend bool operator>(TLhs lhs, const fix32& rhs) + { + return fix32(lhs)._value > rhs._value; + } + constexpr bool operator>=(const fix32& other) const { return this->_value >= other._value; } + template + constexpr friend bool operator>=(TLhs lhs, const fix32& rhs) + { + return fix32(lhs)._value >= rhs._value; + } + constexpr fix32 operator-() const { return FromRawValue(-this->_value); @@ -337,6 +377,22 @@ public: return FromRawValue(std::abs(this->_value)); } + constexpr fix32 Clamp(fix32 min, fix32 max) const + { + if (this->_value < min._value) + { + return min; + } + else if (this->_value > max._value) + { + return max; + } + else + { + return *this; + } + } + template constexpr fix64 LongMul(const fix16& other) const { @@ -354,6 +410,11 @@ public: return fix64::FromRawValue((s64)this->_value * other); } + constexpr fix64 LongMul(double other) const + { + return LongMul(fix32(other)); + } + template constexpr fix32 operator*(const fix16& other) const { @@ -371,6 +432,11 @@ public: return FromRawValue(this->_value * other); } + constexpr fix32 operator*(double other) const + { + return fix32(LongMul(fix32(other))); + } + constexpr friend fix32 operator*(int lhs, const fix32& rhs) { return FromRawValue(lhs * rhs.GetRawValue()); diff --git a/arm9/source/core/task/Task.cpp b/arm9/source/core/task/Task.cpp index 092a771..08cef25 100644 --- a/arm9/source/core/task/Task.cpp +++ b/arm9/source/core/task/Task.cpp @@ -1,9 +1,20 @@ #include "common.h" #include "Task.h" -void TaskBase::Execute() +void TaskBase::RequestCancel() { u32 irqs = rtos_disableIrqs(); + _cancelRequested = true; + if (_state == TaskState::NotStarted) + { + _state = TaskState::Canceled; + rtos_wakeupQueue(&_threadQueue); + } + rtos_restoreIrqs(irqs); +} + +void TaskBase::Execute(u32 irqs) +{ if (_state == TaskState::NotStarted) { _state = TaskState::Running; @@ -12,7 +23,9 @@ void TaskBase::Execute() SetFinalState(finalState); } else + { rtos_restoreIrqs(irqs); + } } void TaskBase::SetFinalState(TaskState finalState) diff --git a/arm9/source/core/task/Task.h b/arm9/source/core/task/Task.h index 8268c15..f9684fa 100644 --- a/arm9/source/core/task/Task.h +++ b/arm9/source/core/task/Task.h @@ -3,14 +3,17 @@ #include #include #include +#include "core/LinkedListLink.h" #include "TaskResult.h" class TaskBase { public: + LinkedListLink link; + virtual ~TaskBase() { } - void Execute(); + void Execute(u32 irqs); TaskState GetState() const { return _state; } @@ -24,7 +27,7 @@ public: bool GetDestroyWhenComplete() const { return _destroyWhenComplete; } void SetDestroyWhenComplete() { _destroyWhenComplete = true; } - void RequestCancel() { _cancelRequested = true; } + void RequestCancel(); bool IsCancelRequested() const { return _cancelRequested; } protected: diff --git a/arm9/source/core/task/TaskQueue.cpp b/arm9/source/core/task/TaskQueue.cpp index c001c04..7712ea4 100644 --- a/arm9/source/core/task/TaskQueue.cpp +++ b/arm9/source/core/task/TaskQueue.cpp @@ -1,23 +1,22 @@ #include "common.h" #include "TaskQueue.h" -void TaskQueueBase::ThreadMain(TaskBase** queue, u32 queueLength) +void TaskQueueBase::ThreadMain() { while (true) { _idle = false; - u32 readPtr = _queueReadPtr; - while (readPtr != _queueWritePtr) + while (true) { - TaskBase* task = queue[readPtr]; - if (readPtr == queueLength - 1) - readPtr = 0; - else - readPtr++; - _queueReadPtr = readPtr; + u32 irqs = rtos_disableIrqs(); + auto task = _taskList.GetHead(); if (!task) - continue; - task->Execute(); + { + rtos_restoreIrqs(irqs); + break; + } + _taskList.Remove(task); + task->Execute(irqs); if (task->GetDestroyWhenComplete()) { // this will destroy the task diff --git a/arm9/source/core/task/TaskQueue.h b/arm9/source/core/task/TaskQueue.h index 2b07f2c..e46b038 100644 --- a/arm9/source/core/task/TaskQueue.h +++ b/arm9/source/core/task/TaskQueue.h @@ -4,6 +4,7 @@ #include #include #include "core/BitVector.h" +#include "core/LinkedList.h" #include "Task.h" class TaskQueueBase; @@ -11,25 +12,13 @@ class TaskQueueBase; class QueueTaskBase { public: - // forbid copies - QueueTaskBase(const QueueTaskBase&) = delete; - QueueTaskBase& operator=(const QueueTaskBase&) = delete; - - // move assignment - QueueTaskBase& operator=(QueueTaskBase&& other) - { - _taskQueue = other._taskQueue; - _task = other._task; - other._taskQueue = nullptr; - other._task = nullptr; - return *this; - } - ~QueueTaskBase() { // extra check here for optimizing out the dispose call after move assignment if (_task) + { Dispose(); + } } void Dispose(); @@ -47,12 +36,10 @@ public: protected: TaskBase* _task; + TaskQueueBase* _taskQueue; QueueTaskBase(TaskBase* task, TaskQueueBase* taskQueue) : _task(task), _taskQueue(taskQueue) { } - -private: - TaskQueueBase* _taskQueue; }; template @@ -62,6 +49,26 @@ public: QueueTask() : QueueTaskBase(nullptr, nullptr) { } + QueueTask(const QueueTask&) = delete; + QueueTask& operator=(const QueueTask&) = delete; + + QueueTask(QueueTask&& other) + : QueueTaskBase(other._task, other._taskQueue) + { + other._task = nullptr; + other._taskQueue = nullptr; + } + + QueueTask& operator=(QueueTask&& other) + { + Dispose(); + _taskQueue = other._taskQueue; + _task = other._task; + other._taskQueue = nullptr; + other._task = nullptr; + return *this; + } + QueueTask(Task* task, TaskQueueBase* taskQueue) : QueueTaskBase(task, taskQueue) { } @@ -91,12 +98,11 @@ public: protected: rtos_event_t _event; - vu32 _queueReadPtr = 0; - vu32 _queueWritePtr = 0; + LinkedList _taskList; volatile bool _endThreadWhenDone = false; volatile bool _idle = true; - void ThreadMain(TaskBase** queue, u32 queueLength); + void ThreadMain(); TaskQueueBase() { @@ -124,6 +130,10 @@ public: u32 irqs = rtos_disableIrqs(); if (task->IsCompleted()) { + if (task->link.prev != nullptr || task->link.next != nullptr) + { + _taskList.Remove(task); + } task->~TaskBase(); u32 slot = ((u32)task - (u32)_taskPool) / ((MaxTaskSize + 3) & ~3); _poolOccupation.Set(slot, 0); @@ -159,13 +169,12 @@ public: bool IsIdle() const { - return _queueReadPtr == _queueWritePtr && _idle; + return _taskList.GetHead() == nullptr && _idle; } private: u32 _taskPool[QueueLength][(MaxTaskSize + 3) / 4]; BitVector _poolOccupation; - TaskBase* _queue[QueueLength]; rtos_thread_t _thread; bool _threadStarted = false; @@ -191,12 +200,11 @@ private: [[gnu::noinline]] void Enqueue(TaskBase* task) override { - u32 writePtr = _queueWritePtr; - _queue[writePtr] = task; - if (writePtr == QueueLength - 1) - _queueWritePtr = 0; - else - _queueWritePtr = writePtr + 1; + u32 irqs = rtos_disableIrqs(); + { + _taskList.InsertTail(task); + } + rtos_restoreIrqs(irqs); rtos_signalEvent(&_event); } @@ -207,6 +215,6 @@ private: void ThreadMain() { - TaskQueueBase::ThreadMain(&_queue[0], QueueLength); + TaskQueueBase::ThreadMain(); } }; \ No newline at end of file diff --git a/arm9/source/gui/input/IInputSource.h b/arm9/source/gui/input/IKeyInputSource.h similarity index 70% rename from arm9/source/gui/input/IInputSource.h rename to arm9/source/gui/input/IKeyInputSource.h index 1444817..ca547f2 100644 --- a/arm9/source/gui/input/IInputSource.h +++ b/arm9/source/gui/input/IKeyInputSource.h @@ -2,10 +2,10 @@ #include "InputKey.h" /// @brief Interface for a source of key input. -class IInputSource +class IKeyInputSource { public: - virtual ~IInputSource() { } + virtual ~IKeyInputSource() { } virtual InputKey Sample() const = 0; }; diff --git a/arm9/source/gui/input/ITouchInputSource.h b/arm9/source/gui/input/ITouchInputSource.h new file mode 100644 index 0000000..64510c4 --- /dev/null +++ b/arm9/source/gui/input/ITouchInputSource.h @@ -0,0 +1,14 @@ +#pragma once +#include "core/math/Point.h" + +/// @brief Interface for a source of touch input. +class ITouchInputSource +{ +public: + virtual ~ITouchInputSource() { } + + /// @brief Samples the touch input. + /// @param touchPosition When the pen is down, the current touch position. + /// @return \c true when the pen is down, or \c false otherwise. + virtual bool Sample(Point& touchPosition) const = 0; +}; diff --git a/arm9/source/gui/input/InputKey.h b/arm9/source/gui/input/InputKey.h index f0f0a61..1c81db9 100644 --- a/arm9/source/gui/input/InputKey.h +++ b/arm9/source/gui/input/InputKey.h @@ -15,7 +15,9 @@ enum class InputKey : u16 L = 1 << 9, X = 1 << 10, Y = 1 << 11, - Debug = 1 << 13 + Debug = 1 << 13, + Touch = 1 << 14, + Lid = 1 << 15 }; inline InputKey operator&(InputKey lhs, InputKey rhs) diff --git a/arm9/source/gui/input/InputProvider.h b/arm9/source/gui/input/InputProvider.h index bd60356..792eb03 100644 --- a/arm9/source/gui/input/InputProvider.h +++ b/arm9/source/gui/input/InputProvider.h @@ -1,5 +1,5 @@ #pragma once - +#include "core/math/Point.h" #include "InputKey.h" class InputProvider @@ -14,6 +14,23 @@ public: /// @return \c true if any of the keys in the \p mask is being held, or \c false otherwise. bool Current(InputKey mask) const { return static_cast(_currentKeys & mask); } + /// @brief Returns the current touch point if the screen is being touched. + /// @param touchPoint The current touch point if the screen is being touched. + /// @return \c true if the screen is being touched, or \c false otherwise. + bool GetCurrentTouchPoint(Point& touchPoint) + { + if (Current(InputKey::Touch)) + { + touchPoint = _currentTouchPoint; + return true; + } + else + { + touchPoint = Point(0, 0); + return false; + } + } + /// @brief Returns a bitmask of the keys that went from unpressed to pressed in the latest update. /// @return A bitmask of the keys that went from unpressed to pressed in the latest update. InputKey GetTriggeredKeys() const @@ -46,13 +63,16 @@ public: _currentKeys = InputKey::None; _triggeredKeys = InputKey::None; _releasedKeys = InputKey::None; + _currentTouchPoint = Point(0, 0); } protected: InputKey _currentKeys; InputKey _triggeredKeys; InputKey _releasedKeys; + Point _currentTouchPoint; InputProvider() - : _currentKeys(InputKey::None), _triggeredKeys(InputKey::None), _releasedKeys(InputKey::None) { } + : _currentKeys(InputKey::None), _triggeredKeys(InputKey::None), _releasedKeys(InputKey::None) + , _currentTouchPoint(0, 0) { } }; diff --git a/arm9/source/gui/input/InputRepeater.cpp b/arm9/source/gui/input/InputRepeater.cpp index fcc284e..bb7a730 100644 --- a/arm9/source/gui/input/InputRepeater.cpp +++ b/arm9/source/gui/input/InputRepeater.cpp @@ -27,7 +27,9 @@ void InputRepeater::Update() } } else + { _state = State::Idle; + } } else if (_state == State::NextRepeat) { @@ -40,13 +42,24 @@ void InputRepeater::Update() } } else + { _state = State::Idle; + } } InputKey lastRepKeys = _currentKeys & _repeatMask; _currentKeys = curKeys | repKeys; _triggeredKeys = _inputProvider->GetTriggeredKeys() | repKeys; _releasedKeys = _inputProvider->GetReleasedKeys() | (lastRepKeys & (lastRepKeys ^ repKeys)); + Point touchPoint; + if (_inputProvider->GetCurrentTouchPoint(touchPoint)) + { + _currentTouchPoint = touchPoint; + } + else + { + _currentTouchPoint = Point(0, 0); + } } void InputRepeater::Reset() diff --git a/arm9/source/gui/input/InputRepeater.h b/arm9/source/gui/input/InputRepeater.h index 7b948e8..79de994 100644 --- a/arm9/source/gui/input/InputRepeater.h +++ b/arm9/source/gui/input/InputRepeater.h @@ -7,7 +7,7 @@ class InputRepeater : public InputProvider public: InputRepeater(InputProvider* inputProvider, InputKey repeatMask, u16 firstRepeatDelay, u16 nextRepeatDelay) : _inputProvider(inputProvider), _state(State::Idle) - , _frameCounter(0), _repeatMask(repeatMask) + , _frameCounter(0), _repeatMask(repeatMask & ~InputKey::Touch) , _firstRepeatDelayFrames(firstRepeatDelay) , _nextRepeatDelayFrames(nextRepeatDelay) { } diff --git a/arm9/source/gui/input/PadInputSource.h b/arm9/source/gui/input/PadInputSource.h index 1f78e29..092c544 100644 --- a/arm9/source/gui/input/PadInputSource.h +++ b/arm9/source/gui/input/PadInputSource.h @@ -1,17 +1,18 @@ #pragma once #include "common.h" #include -#include "IInputSource.h" +#include "IKeyInputSource.h" #include "sharedMemory.h" /// @brief Input source from the physical DS buttons. -class PadInputSource : public IInputSource +class PadInputSource : public IKeyInputSource { public: InputKey Sample() const override { u16 arm9Mask = (~REG_KEYINPUT & 0x3FF); - u16 arm7Mask = (~SHARED_KEY_XY & 0xB); + u16 arm7Mask = (~SHARED_KEY_XY & 0xCB); + arm7Mask = (arm7Mask & 0xB) | ((arm7Mask & 0xC0) >> 2); return static_cast((arm9Mask | (arm7Mask << 10))); } }; diff --git a/arm9/source/gui/input/SampledInputProvider.cpp b/arm9/source/gui/input/SampledInputProvider.cpp index a8bf77f..d318138 100644 --- a/arm9/source/gui/input/SampledInputProvider.cpp +++ b/arm9/source/gui/input/SampledInputProvider.cpp @@ -7,16 +7,44 @@ void SampledInputProvider::Update() InputKey trig = InputKey::None; InputKey rel = InputKey::None; + Point touchPoint(0, 0); + int touchPointCount = 0; while (_inputBufferReadPtr != _inputBufferWritePtr) { - InputKey nextKeys = _inputBuffer[_inputBufferReadPtr]; + InputKey nextKeys = _keyInputBuffer[_inputBufferReadPtr]; trig |= (nextKeys ^ curKeys) & nextKeys; rel |= (nextKeys ^ curKeys) & curKeys; curKeys = nextKeys; + if ((nextKeys & InputKey::Touch) != InputKey::None) + { + touchPoint.x += _touchInputBuffer[_inputBufferReadPtr].x; + touchPoint.y += _touchInputBuffer[_inputBufferReadPtr].y; + touchPointCount++; + } + else + { + touchPoint = Point(0, 0); + touchPointCount = 0; + } _inputBufferReadPtr = (_inputBufferReadPtr + 1) & 3; } _triggeredKeys = trig; _releasedKeys = rel; _currentKeys = curKeys; + if (touchPointCount == 0) + { + if ((_triggeredKeys & InputKey::Touch) != InputKey::None || + (_currentKeys & InputKey::Touch) != InputKey::None) + { + _releasedKeys = _releasedKeys | InputKey::Touch; + } + _triggeredKeys = _triggeredKeys & ~InputKey::Touch; + _currentKeys = _currentKeys & ~InputKey::Touch; + } + else + { + _currentTouchPoint.x = touchPoint.x / touchPointCount; + _currentTouchPoint.y = touchPoint.y / touchPointCount; + } } diff --git a/arm9/source/gui/input/SampledInputProvider.h b/arm9/source/gui/input/SampledInputProvider.h index 9b264f0..cb06875 100644 --- a/arm9/source/gui/input/SampledInputProvider.h +++ b/arm9/source/gui/input/SampledInputProvider.h @@ -1,20 +1,23 @@ #pragma once #include "InputProvider.h" -#include "IInputSource.h" +#include "IKeyInputSource.h" +#include "ITouchInputSource.h" -/// @brief Input provider providing input from an \see IInputSource. +/// @brief Input provider providing input from an \see IKeyInputSource. class SampledInputProvider : public InputProvider { public: - explicit SampledInputProvider(const IInputSource* inputSource) - : _inputSource(inputSource), _inputBufferReadPtr(0), _inputBufferWritePtr(0) { } + explicit SampledInputProvider(const IKeyInputSource* keyInputSource, const ITouchInputSource* touchInputSource) + : _keyInputSource(keyInputSource), _touchInputSource(touchInputSource) + , _inputBufferReadPtr(0), _inputBufferWritePtr(0) { } void Update() override; /// @brief Samples the input source. void Sample() { - _inputBuffer[_inputBufferWritePtr] = _inputSource->Sample(); + _keyInputBuffer[_inputBufferWritePtr] = _keyInputSource->Sample(); + _touchInputSource->Sample(_touchInputBuffer[_inputBufferWritePtr]); _inputBufferWritePtr = (_inputBufferWritePtr + 1) & 3; } @@ -26,9 +29,11 @@ public: } private: - const IInputSource* _inputSource; + const IKeyInputSource* _keyInputSource; + const ITouchInputSource* _touchInputSource; - InputKey _inputBuffer[4]; + InputKey _keyInputBuffer[4]; + Point _touchInputBuffer[4]; u8 _inputBufferReadPtr; u8 _inputBufferWritePtr; }; diff --git a/arm9/source/gui/input/TouchInputSource.h b/arm9/source/gui/input/TouchInputSource.h new file mode 100644 index 0000000..e2c545d --- /dev/null +++ b/arm9/source/gui/input/TouchInputSource.h @@ -0,0 +1,24 @@ +#pragma once +#include "common.h" +#include +#include "ITouchInputSource.h" +#include "sharedMemory.h" + +/// @brief Input source from the physical DS touch screen. +class TouchInputSource : public ITouchInputSource +{ +public: + bool Sample(Point& touchPosition) const override + { + if (SHARED_KEY_XY & (1 << 6)) + { + touchPosition = Point(0, 0); + return false; + } + else + { + touchPosition = Point(SHARED_TOUCH_X, SHARED_TOUCH_Y); + return true; + } + } +}; diff --git a/arm9/source/gui/views/Label2DView.h b/arm9/source/gui/views/Label2DView.h index 5b4daee..85fddfb 100644 --- a/arm9/source/gui/views/Label2DView.h +++ b/arm9/source/gui/views/Label2DView.h @@ -3,15 +3,17 @@ class Label2DView : public LabelView { -public: - Label2DView(u32 width, u32 height, u32 maxStringLength, const nft2_header_t* font) - : LabelView(width, height, maxStringLength, font, false) { } + SHARED_ONLY(Label2DView) +public: void InitVram(const VramContext& vramContext) override; void Draw(GraphicsContext& graphicsContext) override; void VBlank() override; private: + Label2DView(u32 width, u32 height, u32 maxStringLength, const nft2_header_t* font) + : LabelView(width, height, maxStringLength, font, false) { } + void UpdateTileBuffer() override; bool _tileBufferUpdated = false; diff --git a/arm9/source/gui/views/Label3DView.cpp b/arm9/source/gui/views/Label3DView.cpp index b369c3a..d184512 100644 --- a/arm9/source/gui/views/Label3DView.cpp +++ b/arm9/source/gui/views/Label3DView.cpp @@ -12,6 +12,11 @@ Label3DView::Label3DView(u32 width, u32 height, u32 maxStringLength, const nft2_ : LabelView(width, height, maxStringLength, font, true) , _vblankTextureLoader(vblankTextureLoader) { } +Label3DView::~Label3DView() +{ + _vblankTextureLoader->CancelLoad(_textureLoadRequest); +} + void Label3DView::InitVram(const VramContext& vramContext) { const auto texVramManager = vramContext.GetTexVramManager(); diff --git a/arm9/source/gui/views/Label3DView.h b/arm9/source/gui/views/Label3DView.h index 5990d2c..5656d45 100644 --- a/arm9/source/gui/views/Label3DView.h +++ b/arm9/source/gui/views/Label3DView.h @@ -4,17 +4,21 @@ class alignas(32) Label3DView : public LabelView { + SHARED_ONLY(Label3DView) + public: - Label3DView(u32 width, u32 height, u32 maxStringLength, const nft2_header_t* font, - VBlankTextureLoader* vblankTextureLoader); + ~Label3DView() override; void InitVram(const VramContext& vramContext) override; void Draw(GraphicsContext& graphicsContext) override; private: + Label3DView(u32 width, u32 height, u32 maxStringLength, const nft2_header_t* font, + VBlankTextureLoader* vblankTextureLoader); + void UpdateTileBuffer() override; u32 _texVramOffset = 0; VBlankTextureLoader* _vblankTextureLoader; VBlankTextureLoadRequest _textureLoadRequest; -}; \ No newline at end of file +}; diff --git a/arm9/source/gui/views/RecyclerView.cpp b/arm9/source/gui/views/RecyclerView.cpp index 03a98c8..2b4e32d 100644 --- a/arm9/source/gui/views/RecyclerView.cpp +++ b/arm9/source/gui/views/RecyclerView.cpp @@ -4,7 +4,7 @@ #include "gui/input/InputProvider.h" #include "RecyclerView.h" -RecyclerView::RecyclerView(Private, int x, int y, int width, int height, Mode mode) +RecyclerView::RecyclerView(int x, int y, int width, int height, Mode mode) : _width(width), _height(height), _mode(mode), _rows(0), _columns(0) , _viewPoolFreeCount(0), _viewPoolTotalCount(0) , _xOffset(0), _yOffset(0), _xPadding(0), _yPadding(0) @@ -341,6 +341,117 @@ bool RecyclerView::HandleInput(const InputProvider& inputProvider, FocusManager& return View::HandleInput(inputProvider, focusManager); } +void RecyclerView::HandlePenDown(const Point& touchPoint, FocusManager& focusManager) +{ + if (GetBounds().Contains(touchPoint)) + { + _penDown = true; + _penDownPosition = touchPoint; + _hasScrollStarted = false; + _penDownScrollOffset = _scrollOffsetAnimator.GetValue(); + + for (u32 i = _viewPoolFreeCount; i < _viewPoolTotalCount; i++) + { + _viewPool[i].view->HandlePenDown(touchPoint, focusManager); + } + } +} + +void RecyclerView::HandlePenMove(const Point& touchPoint, FocusManager& focusManager) +{ + if (!_penDown) + { + return; + } + + if (!_hasScrollStarted) + { + for (u32 i = _viewPoolFreeCount; i < _viewPoolTotalCount; i++) + { + _viewPool[i].view->HandlePenMove(touchPoint, focusManager); + if (focusManager.GetCurrentFocus().GetPointer() == _viewPool[i].view.GetPointer()) + { + SetSelectedItem(_viewPool[i].itemIdx); + } + } + + int dx = touchPoint.x - _penDownPosition.x; + int dy = touchPoint.y - _penDownPosition.y; + if (dx * dx + dy * dy > 7 * 7) + { + bool shouldScrollStart = (_mode == Mode::HorizontalGrid || _mode == Mode::HorizontalList) + ? (std::abs(touchPoint.x - _penDownPosition.x) > std::abs(touchPoint.y - _penDownPosition.y)) + : (std::abs(touchPoint.x - _penDownPosition.x) < std::abs(touchPoint.y - _penDownPosition.y)); + + if (shouldScrollStart) + { + _hasScrollStarted = true; + } + else + { + _penDown = false; //wrong direction drag, so cancel it + } + + for (u32 i = _viewPoolFreeCount; i < _viewPoolTotalCount; i++) + { + _viewPool[i].view->HandlePenUp(Point(-1, -1), focusManager); + } + } + } + else + { + int newScrollOffset; + if (_mode == Mode::HorizontalGrid || _mode == Mode::HorizontalList) + { + newScrollOffset = _penDownScrollOffset + touchPoint.x - _penDownPosition.x; + if (-newScrollOffset < 0) + { + newScrollOffset = 0; + _penDownScrollOffset = 0; + _penDownPosition.x = touchPoint.x; + } + else if (newScrollOffset < GetMaxScrollOffset()) + { + newScrollOffset = GetMaxScrollOffset(); + _penDownScrollOffset = newScrollOffset; + _penDownPosition.x = touchPoint.x; + } + } + else + { + newScrollOffset = _penDownScrollOffset + touchPoint.y - _penDownPosition.y; + if (-newScrollOffset < 0) + { + newScrollOffset = 0; + _penDownScrollOffset = 0; + _penDownPosition.y = touchPoint.y; + } + else if (newScrollOffset < GetMaxScrollOffset()) + { + newScrollOffset = GetMaxScrollOffset(); + _penDownScrollOffset = newScrollOffset; + _penDownPosition.y = touchPoint.y; + } + } + + SetScrollOffset(newScrollOffset, false); + } +} + +void RecyclerView::HandlePenUp(const Point& lastTouchPoint, FocusManager& focusManager) +{ + for (u32 i = _viewPoolFreeCount; i < _viewPoolTotalCount; i++) + { + _viewPool[i].view->HandlePenUp(lastTouchPoint, focusManager); + if (focusManager.GetCurrentFocus().GetPointer() == _viewPool[i].view.GetPointer()) + { + SetSelectedItem(_viewPool[i].itemIdx); + } + } + + _penDown = false; +} + Point RecyclerView::GetItemPosition(int itemIdx) { int x = 0; diff --git a/arm9/source/gui/views/RecyclerView.h b/arm9/source/gui/views/RecyclerView.h index cb8fa7d..9cc575d 100644 --- a/arm9/source/gui/views/RecyclerView.h +++ b/arm9/source/gui/views/RecyclerView.h @@ -1,15 +1,14 @@ #pragma once #include -#include "core/EnableSharedFromThis.h" #include "View.h" #include "RecyclerAdapter.h" #include "gui/FocusManager.h" #include "animation/Animator.h" #include "RecyclerViewBase.h" -class RecyclerView : public RecyclerViewBase, public EnableSharedFromThis +class RecyclerView : public RecyclerViewBase { - struct Private { explicit Private() = default; }; + SHARED_ONLY(RecyclerView) public: enum class Mode @@ -24,13 +23,6 @@ public: VerticalGrid }; - RecyclerView(Private, int x, int y, int width, int height, Mode mode); - - static SharedPtr CreateShared(int x, int y, int width, int height, Mode mode) - { - return SharedPtr::MakeShared(Private(), x, y, width, height, mode); - } - ~RecyclerView(); void SetAdapter(SharedPtr adapter, int initialSelectedIndex = 0) override; @@ -47,6 +39,9 @@ public: SharedPtr MoveFocus(const SharedPtr& currentFocus, FocusMoveDirection direction, View* source) override; bool HandleInput(const InputProvider& inputProvider, FocusManager& focusManager) override; + void HandlePenDown(const Point& touchPoint, FocusManager& focusManager) override; + void HandlePenMove(const Point& touchPoint, FocusManager& focusManager) override; + void HandlePenUp(const Point& lastTouchPoint, FocusManager& focusManager) override; void Focus(FocusManager& focusManager) override { @@ -107,6 +102,12 @@ private: int _curRangeStart; int _curRangeLength; Animator _scrollOffsetAnimator; + bool _penDown = false; + Point _penDownPosition = Point(0, 0); + bool _hasScrollStarted = false; + int _penDownScrollOffset = 0; + + RecyclerView(int x, int y, int width, int height, Mode mode); void UpdatePosition(ViewPoolEntry& viewPoolEntry); ViewPoolEntry* GetViewPoolEntryByItemIndex(int itemIdx); diff --git a/arm9/source/gui/views/View.h b/arm9/source/gui/views/View.h index 2837722..101166e 100644 --- a/arm9/source/gui/views/View.h +++ b/arm9/source/gui/views/View.h @@ -3,6 +3,7 @@ #include "core/math/Point.h" #include "core/math/Rectangle.h" #include "core/SharedPtr.h" +#include "core/EnableSharedFromThis.h" #include "../FocusManager.h" #include "../FocusMoveDirection.h" @@ -11,7 +12,7 @@ class VramContext; class InputProvider; /// @brief Base class for views. -class View +class View : public EnableSharedFromThis { public: /// @brief Link used for views that contain other views. @@ -58,6 +59,21 @@ public: return false; } + /// @brief Handles a pen down event. + /// @param touchPoint The touch point. + /// @param focusManager The focus manager. + virtual void HandlePenDown(const Point& touchPoint, FocusManager& focusManager) { } + + /// @brief Handles a pen move event. + /// @param touchPoint The touch point. + /// @param focusManager The focus manager. + virtual void HandlePenMove(const Point& touchPoint, FocusManager& focusManager) { } + + /// @brief Handles a pen up event. + /// @param lastTouchPoint The last touch point. + /// @param focusManager The focus manager. + virtual void HandlePenUp(const Point& lastTouchPoint, FocusManager& focusManager) { } + /// @brief Gets the bounds of the view. /// @return The bounds of the view. virtual Rectangle GetBounds() const = 0; diff --git a/arm9/source/gui/views/ViewContainer.cpp b/arm9/source/gui/views/ViewContainer.cpp new file mode 100644 index 0000000..793350e --- /dev/null +++ b/arm9/source/gui/views/ViewContainer.cpp @@ -0,0 +1,58 @@ +#include "common.h" +#include "ViewContainer.h" + +void ViewContainer::InitVram(const VramContext& vramContext) +{ + for (auto& view : _children) + { + view.InitVram(vramContext); + } +} + +void ViewContainer::Update() +{ + for (auto& view : _children) + { + view.Update(); + } +} + +void ViewContainer::Draw(GraphicsContext& graphicsContext) +{ + for (auto& view : _children) + { + view.Draw(graphicsContext); + } +} + +void ViewContainer::VBlank() +{ + for (auto& view : _children) + { + view.VBlank(); + } +} + +void ViewContainer::HandlePenDown(const Point& touchPoint, FocusManager& focusManager) +{ + for (auto& view : _children) + { + view.HandlePenDown(touchPoint, focusManager); + } +} + +void ViewContainer::HandlePenMove(const Point& touchPoint, FocusManager& focusManager) +{ + for (auto& view : _children) + { + view.HandlePenMove(touchPoint, focusManager); + } +} + +void ViewContainer::HandlePenUp(const Point& lastTouchPoint, FocusManager& focusManager) +{ + for (auto& view : _children) + { + view.HandlePenUp(lastTouchPoint, focusManager); + } +} diff --git a/arm9/source/gui/views/ViewContainer.h b/arm9/source/gui/views/ViewContainer.h index e8e41be..0d04dfd 100644 --- a/arm9/source/gui/views/ViewContainer.h +++ b/arm9/source/gui/views/ViewContainer.h @@ -6,37 +6,13 @@ class ViewContainer : public View { public: - void InitVram(const VramContext& vramContext) override - { - for (auto& view : _children) - { - view.InitVram(vramContext); - } - } - - void Update() override - { - for (auto& view : _children) - { - view.Update(); - } - } - - void Draw(GraphicsContext& graphicsContext) override - { - for (auto& view : _children) - { - view.Draw(graphicsContext); - } - } - - void VBlank() override - { - for (auto& view : _children) - { - view.VBlank(); - } - } + void InitVram(const VramContext& vramContext) override; + void Update() override; + void Draw(GraphicsContext& graphicsContext) override; + void VBlank() override; + void HandlePenDown(const Point& touchPoint, FocusManager& focusManager) override; + void HandlePenMove(const Point& touchPoint, FocusManager& focusManager) override; + void HandlePenUp(const Point& lastTouchPoint, FocusManager& focusManager) override; protected: /// @brief Adds a child to the head of the list. @@ -55,6 +31,14 @@ protected: view->SetParent(this); } + /// @brief Removes a child from the list. + /// @param view The child to remove. + void RemoveChild(View* view) + { + _children.Remove(view); + view->SetParent(nullptr); + } + private: LinkedList _children; }; diff --git a/arm9/source/romBrowser/DisplayMode/BannerListFileRecyclerAdapter.cpp b/arm9/source/romBrowser/DisplayMode/BannerListFileRecyclerAdapter.cpp index 648effe..572ac26 100644 --- a/arm9/source/romBrowser/DisplayMode/BannerListFileRecyclerAdapter.cpp +++ b/arm9/source/romBrowser/DisplayMode/BannerListFileRecyclerAdapter.cpp @@ -3,6 +3,7 @@ #include "core/task/TaskQueue.h" #include "../views/BannerListItemView.h" #include "../Theme/IRomBrowserViewFactory.h" +#include "romBrowser/viewModels/RomBrowserItemViewModel.h" #include "BannerListFileRecyclerAdapter.h" void BannerListFileRecyclerAdapter::GetViewSize(int& width, int& height) const @@ -13,7 +14,8 @@ void BannerListFileRecyclerAdapter::GetViewSize(int& width, int& height) const SharedPtr BannerListFileRecyclerAdapter::CreateView() const { - return _romBrowserViewFactory->CreateBannerListItemView(_vblankTextureLoader); + return _romBrowserViewFactory->CreateBannerListItemView( + std::make_unique(_romBrowserController), _vblankTextureLoader); } void BannerListFileRecyclerAdapter::BindView(SharedPtr view, int index) const @@ -27,6 +29,7 @@ TaskResult BannerListFileRecyclerAdapter::BindView(SharedPtr view, i const InternalFileInfo* internalFileInfo, const vu8& cancelRequested) const { auto listItemView = static_cast(view.GetPointer()); + listItemView->GetViewModel().SetIndex(index); const auto& fileInfo = _fileInfoManager->GetItem(index); bool fileNameAsTitle = true; if (internalFileInfo) @@ -65,12 +68,20 @@ TaskResult BannerListFileRecyclerAdapter::BindView(SharedPtr view, i return TaskResult::Completed(); } +void BannerListFileRecyclerAdapter::SetQueueTask(const SharedPtr& view, QueueTask queueTask) const +{ + auto listItemView = static_cast(view.GetPointer()); + listItemView->GetViewModel().SetQueueTask(std::move(queueTask)); +} + void BannerListFileRecyclerAdapter::ReleaseView(SharedPtr view, int index) const { LOG_DEBUG("Releasing %d\n", index); auto listItemView = static_cast(view.GetPointer()); listItemView->SetIcon(nullptr); listItemView->SetGameTitle(u""); + listItemView->GetViewModel().SetIndex(-1); + listItemView->GetViewModel().CancelQueueTask(); _fileInfoManager->ReleaseFileInfo(index); } diff --git a/arm9/source/romBrowser/DisplayMode/BannerListFileRecyclerAdapter.h b/arm9/source/romBrowser/DisplayMode/BannerListFileRecyclerAdapter.h index 171c6ba..ca3f387 100644 --- a/arm9/source/romBrowser/DisplayMode/BannerListFileRecyclerAdapter.h +++ b/arm9/source/romBrowser/DisplayMode/BannerListFileRecyclerAdapter.h @@ -8,11 +8,11 @@ class IRomBrowserViewFactory; class BannerListFileRecyclerAdapter : public FileRecyclerAdapter { public: - BannerListFileRecyclerAdapter(FileInfoManager* fileInfoManager, + BannerListFileRecyclerAdapter(IRomBrowserController* romBrowserController, FileInfoManager* fileInfoManager, TaskQueueBase* taskQueue, const IThemeFileIconFactory* themeFileIconFactory, const IRomBrowserViewFactory* romBrowserViewFactory, VBlankTextureLoader* vblankTextureLoader) - : FileRecyclerAdapter(fileInfoManager, taskQueue, themeFileIconFactory) + : FileRecyclerAdapter(romBrowserController, fileInfoManager, taskQueue, themeFileIconFactory) , _romBrowserViewFactory(romBrowserViewFactory) , _vblankTextureLoader(vblankTextureLoader) { } @@ -30,4 +30,5 @@ private: TaskResult BindView(SharedPtr view, int index, const InternalFileInfo* internalFileInfo, const vu8& cancelRequested) const override; + void SetQueueTask(const SharedPtr& view, QueueTask queueTask) const override; }; diff --git a/arm9/source/romBrowser/DisplayMode/CoverFlowFileRecyclerAdapter.cpp b/arm9/source/romBrowser/DisplayMode/CoverFlowFileRecyclerAdapter.cpp index 23cc1b0..11ff06d 100644 --- a/arm9/source/romBrowser/DisplayMode/CoverFlowFileRecyclerAdapter.cpp +++ b/arm9/source/romBrowser/DisplayMode/CoverFlowFileRecyclerAdapter.cpp @@ -15,13 +15,15 @@ void CoverFlowFileRecyclerAdapter::GetViewSize(int& width, int& height) const SharedPtr CoverFlowFileRecyclerAdapter::CreateView() const { - return SharedPtr::MakeShared(_vblankTextureLoader); + return CoverView::CreateShared( + std::make_unique(_romBrowserController), _vblankTextureLoader); } TaskResult CoverFlowFileRecyclerAdapter::BindView(SharedPtr view, int index, const InternalFileInfo* internalFileInfo, const vu8& cancelRequested) const { auto coverView = static_cast(view.GetPointer()); + coverView->GetViewModel().SetIndex(index); auto cover = _fileInfoManager->GetFileCover(index); if (cancelRequested) { @@ -39,11 +41,19 @@ TaskResult CoverFlowFileRecyclerAdapter::BindView(SharedPtr view, in return TaskResult::Completed(); } +void CoverFlowFileRecyclerAdapter::SetQueueTask(const SharedPtr& view, QueueTask queueTask) const +{ + auto coverView = static_cast(view.GetPointer()); + coverView->GetViewModel().SetQueueTask(std::move(queueTask)); +} + void CoverFlowFileRecyclerAdapter::ReleaseView(SharedPtr view, int index) const { LOG_DEBUG("Releasing %d\n", index); auto coverView = static_cast(view.GetPointer()); coverView->ClearCover(); + coverView->GetViewModel().SetIndex(-1); + coverView->GetViewModel().CancelQueueTask(); _fileInfoManager->ReleaseFileInfo(index); } diff --git a/arm9/source/romBrowser/DisplayMode/CoverFlowFileRecyclerAdapter.h b/arm9/source/romBrowser/DisplayMode/CoverFlowFileRecyclerAdapter.h index f5e537e..0e2ab8a 100644 --- a/arm9/source/romBrowser/DisplayMode/CoverFlowFileRecyclerAdapter.h +++ b/arm9/source/romBrowser/DisplayMode/CoverFlowFileRecyclerAdapter.h @@ -8,12 +8,12 @@ class ICoverRepository; class CoverFlowFileRecyclerAdapter : public FileRecyclerAdapter { public: - CoverFlowFileRecyclerAdapter(FileInfoManager* fileInfoManager, + CoverFlowFileRecyclerAdapter(IRomBrowserController* romBrowserController, FileInfoManager* fileInfoManager, TaskQueueBase* taskQueue, const IThemeFileIconFactory* themeFileIconFactory, const IRomBrowserViewFactory* romBrowserViewFactory, VBlankTextureLoader* vblankTextureLoader, const ICoverRepository* coverRepository) - : FileRecyclerAdapter(fileInfoManager, taskQueue, themeFileIconFactory) + : FileRecyclerAdapter(romBrowserController, fileInfoManager, taskQueue, themeFileIconFactory) , _romBrowserViewFactory(romBrowserViewFactory) , _vblankTextureLoader(vblankTextureLoader) , _coverRepository(coverRepository) { } @@ -31,4 +31,5 @@ private: TaskResult BindView(SharedPtr view, int index, const InternalFileInfo* internalFileInfo, const vu8& cancelRequested) const override; + void SetQueueTask(const SharedPtr& view, QueueTask queueTask) const override; }; diff --git a/arm9/source/romBrowser/DisplayMode/IconGridFileRecyclerAdapter.cpp b/arm9/source/romBrowser/DisplayMode/IconGridFileRecyclerAdapter.cpp index 79f3cc0..a1bc2f4 100644 --- a/arm9/source/romBrowser/DisplayMode/IconGridFileRecyclerAdapter.cpp +++ b/arm9/source/romBrowser/DisplayMode/IconGridFileRecyclerAdapter.cpp @@ -3,6 +3,7 @@ #include "core/task/TaskQueue.h" #include "../views/IconGridItemView.h" #include "../Theme/IRomBrowserViewFactory.h" +#include "romBrowser/viewModels/RomBrowserItemViewModel.h" #include "IconGridFileRecyclerAdapter.h" void IconGridFileRecyclerAdapter::GetViewSize(int& width, int& height) const @@ -13,7 +14,7 @@ void IconGridFileRecyclerAdapter::GetViewSize(int& width, int& height) const SharedPtr IconGridFileRecyclerAdapter::CreateView() const { - return _romBrowserViewFactory->CreateIconGridItemView(); + return _romBrowserViewFactory->CreateIconGridItemView(std::make_unique(_romBrowserController)); } void IconGridFileRecyclerAdapter::BindView(SharedPtr view, int index) const @@ -27,6 +28,7 @@ TaskResult IconGridFileRecyclerAdapter::BindView(SharedPtr view, int const InternalFileInfo* internalFileInfo, const vu8& cancelRequested) const { auto iconGridItemView = static_cast(view.GetPointer()); + iconGridItemView->GetViewModel().SetIndex(index); auto icon = internalFileInfo ? internalFileInfo->CreateGameIcon() : nullptr; if (!icon) { @@ -54,11 +56,19 @@ TaskResult IconGridFileRecyclerAdapter::BindView(SharedPtr view, int return TaskResult::Completed(); } +void IconGridFileRecyclerAdapter::SetQueueTask(const SharedPtr& view, QueueTask queueTask) const +{ + auto iconGridItemView = static_cast(view.GetPointer()); + iconGridItemView->GetViewModel().SetQueueTask(std::move(queueTask)); +} + void IconGridFileRecyclerAdapter::ReleaseView(SharedPtr view, int index) const { LOG_DEBUG("Releasing %d\n", index); auto iconGridItemView = static_cast(view.GetPointer()); iconGridItemView->SetIcon(nullptr); + iconGridItemView->GetViewModel().SetIndex(-1); + iconGridItemView->GetViewModel().CancelQueueTask(); _fileInfoManager->ReleaseFileInfo(index); } diff --git a/arm9/source/romBrowser/DisplayMode/IconGridFileRecyclerAdapter.h b/arm9/source/romBrowser/DisplayMode/IconGridFileRecyclerAdapter.h index 72412fc..56fc5ea 100644 --- a/arm9/source/romBrowser/DisplayMode/IconGridFileRecyclerAdapter.h +++ b/arm9/source/romBrowser/DisplayMode/IconGridFileRecyclerAdapter.h @@ -7,10 +7,10 @@ class IRomBrowserViewFactory; class IconGridFileRecyclerAdapter : public FileRecyclerAdapter { public: - IconGridFileRecyclerAdapter(FileInfoManager* fileInfoManager, + IconGridFileRecyclerAdapter(IRomBrowserController* romBrowserController, FileInfoManager* fileInfoManager, TaskQueueBase* taskQueue, const IThemeFileIconFactory* themeFileIconFactory, const IRomBrowserViewFactory* romBrowserViewFactory) - : FileRecyclerAdapter(fileInfoManager, taskQueue, themeFileIconFactory) + : FileRecyclerAdapter(romBrowserController, fileInfoManager, taskQueue, themeFileIconFactory) , _romBrowserViewFactory(romBrowserViewFactory) { } void GetViewSize(int& width, int& height) const override; @@ -26,4 +26,5 @@ private: TaskResult BindView(SharedPtr view, int index, const InternalFileInfo* internalFileInfo, const vu8& cancelRequested) const override; + void SetQueueTask(const SharedPtr& view, QueueTask queueTask) const override; }; diff --git a/arm9/source/romBrowser/DisplayMode/RomBrowserBannerListDisplayMode.h b/arm9/source/romBrowser/DisplayMode/RomBrowserBannerListDisplayMode.h index 8b95e4b..5b0a395 100644 --- a/arm9/source/romBrowser/DisplayMode/RomBrowserBannerListDisplayMode.h +++ b/arm9/source/romBrowser/DisplayMode/RomBrowserBannerListDisplayMode.h @@ -10,7 +10,7 @@ public: bool IsVertical() const override { return true; } - std::unique_ptr CreateAppBarView(const IRomBrowserViewFactory* romBrowserViewFactory, + SharedPtr CreateAppBarView(const IRomBrowserViewFactory* romBrowserViewFactory, int startButtonCount, int endButtonCount) const override { return romBrowserViewFactory->CreateAppBarView(0, 0, @@ -29,7 +29,7 @@ public: RomBrowserViewModel* viewModel, const IThemeFileIconFactory* themeFileIconFactory, const IRomBrowserViewFactory* romBrowserViewFactory, VBlankTextureLoader* vblankTextureLoader) const override { - return SharedPtr::MakeShared( + return SharedPtr::MakeShared(viewModel->GetRomBrowserController(), &viewModel->GetFileInfoManager(), viewModel->GetIoTaskQueue(), themeFileIconFactory, romBrowserViewFactory, vblankTextureLoader); } diff --git a/arm9/source/romBrowser/DisplayMode/RomBrowserDisplayMode.h b/arm9/source/romBrowser/DisplayMode/RomBrowserDisplayMode.h index 6d32c17..b6bec9b 100644 --- a/arm9/source/romBrowser/DisplayMode/RomBrowserDisplayMode.h +++ b/arm9/source/romBrowser/DisplayMode/RomBrowserDisplayMode.h @@ -14,7 +14,7 @@ class RomBrowserDisplayMode public: virtual bool IsVertical() const = 0; virtual bool ShowCoverOnTopScreen() const { return true; } - virtual std::unique_ptr CreateAppBarView(const IRomBrowserViewFactory* romBrowserViewFactory, + virtual SharedPtr CreateAppBarView(const IRomBrowserViewFactory* romBrowserViewFactory, int startButtonCount, int endButtonCount) const = 0; virtual SharedPtr CreateRecyclerView(const IRomBrowserViewFactory* romBrowserViewFactory) const = 0; virtual SharedPtr CreateRecyclerAdapter( diff --git a/arm9/source/romBrowser/DisplayMode/RomBrowserHorizontalCoverFlowDisplayMode.h b/arm9/source/romBrowser/DisplayMode/RomBrowserHorizontalCoverFlowDisplayMode.h index 9fced8b..48b0555 100644 --- a/arm9/source/romBrowser/DisplayMode/RomBrowserHorizontalCoverFlowDisplayMode.h +++ b/arm9/source/romBrowser/DisplayMode/RomBrowserHorizontalCoverFlowDisplayMode.h @@ -9,7 +9,7 @@ public: bool IsVertical() const override { return false; } bool ShowCoverOnTopScreen() const override { return false; } - std::unique_ptr CreateAppBarView(const IRomBrowserViewFactory* romBrowserViewFactory, + SharedPtr CreateAppBarView(const IRomBrowserViewFactory* romBrowserViewFactory, int startButtonCount, int endButtonCount) const override { return romBrowserViewFactory->CreateAppBarView(0, 0, diff --git a/arm9/source/romBrowser/DisplayMode/RomBrowserHorizontalIconGridDisplayMode.h b/arm9/source/romBrowser/DisplayMode/RomBrowserHorizontalIconGridDisplayMode.h index 8078a50..73bc0e6 100644 --- a/arm9/source/romBrowser/DisplayMode/RomBrowserHorizontalIconGridDisplayMode.h +++ b/arm9/source/romBrowser/DisplayMode/RomBrowserHorizontalIconGridDisplayMode.h @@ -10,7 +10,7 @@ public: bool IsVertical() const override { return false; } - std::unique_ptr CreateAppBarView(const IRomBrowserViewFactory* romBrowserViewFactory, + SharedPtr CreateAppBarView(const IRomBrowserViewFactory* romBrowserViewFactory, int startButtonCount, int endButtonCount) const override { return romBrowserViewFactory->CreateAppBarView(0, 0, @@ -29,7 +29,7 @@ public: RomBrowserViewModel* viewModel, const IThemeFileIconFactory* themeFileIconFactory, const IRomBrowserViewFactory* romBrowserViewFactory, VBlankTextureLoader* vblankTextureLoader) const override { - return SharedPtr::MakeShared( + return SharedPtr::MakeShared(viewModel->GetRomBrowserController(), &viewModel->GetFileInfoManager(), viewModel->GetIoTaskQueue(), themeFileIconFactory, romBrowserViewFactory); } diff --git a/arm9/source/romBrowser/DisplayMode/RomBrowserVerticalIconGridDisplayMode.h b/arm9/source/romBrowser/DisplayMode/RomBrowserVerticalIconGridDisplayMode.h index bcf43a6..c26600f 100644 --- a/arm9/source/romBrowser/DisplayMode/RomBrowserVerticalIconGridDisplayMode.h +++ b/arm9/source/romBrowser/DisplayMode/RomBrowserVerticalIconGridDisplayMode.h @@ -10,7 +10,7 @@ public: bool IsVertical() const override { return true; } - std::unique_ptr CreateAppBarView(const IRomBrowserViewFactory* romBrowserViewFactory, + SharedPtr CreateAppBarView(const IRomBrowserViewFactory* romBrowserViewFactory, int startButtonCount, int endButtonCount) const override { return romBrowserViewFactory->CreateAppBarView(0, 0, @@ -29,7 +29,7 @@ public: RomBrowserViewModel* viewModel, const IThemeFileIconFactory* themeFileIconFactory, const IRomBrowserViewFactory* romBrowserViewFactory, VBlankTextureLoader* vblankTextureLoader) const override { - return SharedPtr::MakeShared( + return SharedPtr::MakeShared(viewModel->GetRomBrowserController(), &viewModel->GetFileInfoManager(), viewModel->GetIoTaskQueue(), themeFileIconFactory, romBrowserViewFactory); } diff --git a/arm9/source/romBrowser/FileRecyclerAdapter.cpp b/arm9/source/romBrowser/FileRecyclerAdapter.cpp index f33e9ed..87ff88d 100644 --- a/arm9/source/romBrowser/FileRecyclerAdapter.cpp +++ b/arm9/source/romBrowser/FileRecyclerAdapter.cpp @@ -11,8 +11,14 @@ u32 FileRecyclerAdapter::GetItemCount() const void FileRecyclerAdapter::BindView(SharedPtr view, int index) const { LOG_DEBUG("Binding %d\n", index); - _taskQueue->Enqueue([=, this] (const vu8& cancelRequested) + auto queueTask = _taskQueue->Enqueue([=, this] (const vu8& cancelRequested) { + if (cancelRequested) + { + LOG_DEBUG("Task to load %d was canceled\n", index); + return TaskResult::Canceled(); + } + LOG_DEBUG("Started task to load %d\n", index); _fileInfoManager->LoadFileInfo(index); auto internalFileInfo = _fileInfoManager->GetInternalFileInfo(index); @@ -23,4 +29,5 @@ void FileRecyclerAdapter::BindView(SharedPtr view, int index) const } return BindView(view, index, internalFileInfo, cancelRequested); }); + SetQueueTask(view, std::move(queueTask)); } diff --git a/arm9/source/romBrowser/FileRecyclerAdapter.h b/arm9/source/romBrowser/FileRecyclerAdapter.h index ee2d6fd..af5b755 100644 --- a/arm9/source/romBrowser/FileRecyclerAdapter.h +++ b/arm9/source/romBrowser/FileRecyclerAdapter.h @@ -7,6 +7,7 @@ class IVramManager; class InternalFileInfo; class IThemeFileIconFactory; class VramContext; +class IRomBrowserController; class FileRecyclerAdapter : public RecyclerAdapter { @@ -22,16 +23,18 @@ public: virtual void InitVram(const VramContext& vramContext) { } protected: + IRomBrowserController* _romBrowserController; FileInfoManager* _fileInfoManager; TaskQueueBase* _taskQueue; u32 _iconFrameCounter; const IThemeFileIconFactory* _themeFileIconFactory; - FileRecyclerAdapter(FileInfoManager* fileInfoManager, TaskQueueBase* taskQueue, - const IThemeFileIconFactory* themeFileIconFactory) - : _fileInfoManager(fileInfoManager), _taskQueue(taskQueue) + FileRecyclerAdapter(IRomBrowserController* romBrowserController, FileInfoManager* fileInfoManager, + TaskQueueBase* taskQueue, const IThemeFileIconFactory* themeFileIconFactory) + : _romBrowserController(romBrowserController), _fileInfoManager(fileInfoManager), _taskQueue(taskQueue) , _iconFrameCounter(0), _themeFileIconFactory(themeFileIconFactory) { } virtual TaskResult BindView(SharedPtr view, int index, const InternalFileInfo* internalFileInfo, const vu8& cancelRequested) const = 0; + virtual void SetQueueTask(const SharedPtr& view, QueueTask queueTask) const = 0; }; diff --git a/arm9/source/romBrowser/Theme/IRomBrowserViewFactory.h b/arm9/source/romBrowser/Theme/IRomBrowserViewFactory.h index 7a4d25c..93a63ea 100644 --- a/arm9/source/romBrowser/Theme/IRomBrowserViewFactory.h +++ b/arm9/source/romBrowser/Theme/IRomBrowserViewFactory.h @@ -12,24 +12,26 @@ class VBlankTextureLoader; class RomBrowserViewModel; class IThemeFileIconFactory; class FileRecyclerAdapter; +class RomBrowserItemViewModel; class IRomBrowserViewFactory { public: virtual ~IRomBrowserViewFactory() = 0; - virtual SharedPtr CreateIconGridItemView() const = 0; + virtual SharedPtr CreateIconGridItemView(std::unique_ptr viewModel) const = 0; virtual IconGridItemView::VramToken UploadIconGridItemViewGraphics( const VramContext& vramContext) const { return IconGridItemView::VramToken(0); } - virtual SharedPtr CreateBannerListItemView(VBlankTextureLoader* vblankTextureLoader) const = 0; + virtual SharedPtr CreateBannerListItemView(std::unique_ptr viewModel, + VBlankTextureLoader* vblankTextureLoader) const = 0; virtual BannerListItemView::VramToken UploadBannerListItemViewGraphics( const VramContext& vramContext) const { return BannerListItemView::VramToken(0); } - virtual std::unique_ptr CreateAppBarView(int x, int y, AppBarView::Orientation orientation, + virtual SharedPtr CreateAppBarView(int x, int y, AppBarView::Orientation orientation, int startButtonCount, int endButtonCount) const = 0; - virtual std::unique_ptr CreateFileInfoView() const = 0; + virtual SharedPtr CreateFileInfoView() const = 0; virtual SharedPtr CreateCoverFlowRecyclerView() const = 0; diff --git a/arm9/source/romBrowser/Theme/Material/CarouselRecyclerView.cpp b/arm9/source/romBrowser/Theme/Material/CarouselRecyclerView.cpp index f2ff13e..7483433 100644 --- a/arm9/source/romBrowser/Theme/Material/CarouselRecyclerView.cpp +++ b/arm9/source/romBrowser/Theme/Material/CarouselRecyclerView.cpp @@ -10,6 +10,8 @@ #include "romBrowser/FileType/FileCover.h" #include "core/math/SinTable.h" #include "carouselMask.h" +#include "animation/Interpolator.h" +#include "gui/input/InputProvider.h" #include "CarouselRecyclerView.h" #define COVER_SPACING 4 @@ -41,8 +43,10 @@ void CarouselRecyclerView::Update() return; } - int rangeStartIndex = GetSelectedItem() - 4; - int rangeEndIndex = GetSelectedItem() + 1 + 4; + _scrollAnimator.Update(); + + int rangeStartIndex = _scrollAnimator.GetValue().Int() - 4; + int rangeEndIndex = _scrollAnimator.GetValue().Int() + 1 + 4; rangeStartIndex = std::clamp(rangeStartIndex, 0, (int)_itemCount - 1); rangeEndIndex = std::clamp(rangeEndIndex, 0, (int)_itemCount); @@ -66,8 +70,7 @@ void CarouselRecyclerView::Update() for (u32 i = _viewPoolFreeCount; i < _viewPool.size(); i++) { - _viewPoolEx[i].xPositionAnimator.Update(); - _viewPoolEx[i].widthAnimator.Update(); + UpdateItemPosition(i); _viewPool[i].view->Update(); } } @@ -76,8 +79,8 @@ void CarouselRecyclerView::Draw(GraphicsContext& graphicsContext) { for (u32 i = _viewPoolFreeCount; i < _viewPool.size(); i++) { - fix32<12> x = (_viewPoolEx[i].xPositionAnimator.GetValue() + 0.5).Int(); - fix32<12> width = (_viewPoolEx[i].widthAnimator.GetValue() + 0.5).Int(); + fix32<12> x = (_viewPoolEx[i].xPosition + 0.5).Int(); + fix32<12> width = (_viewPoolEx[i].width + 0.5).Int(); fix32<12> left = x; if (left < HORIZONTAL_PADDING) { @@ -180,48 +183,179 @@ void CarouselRecyclerView::RenderRoundedCorners(GraphicsContext& graphicsContext Gx::End(); } -void CarouselRecyclerView::UpdateItemPosition(int viewPoolIndex, bool initial) +bool CarouselRecyclerView::HandleInput(const InputProvider& inputProvider, FocusManager& focusManager) { - ViewPoolEntry* item = &_viewPool[viewPoolIndex]; - ViewPoolEntryEx* itemEx = &_viewPoolEx[viewPoolIndex]; - int selectedIndex = GetSelectedItem(); - if (selectedIndex == -1) + if (_itemCount != 0 && inputProvider.Triggered(InputKey::L | InputKey::R)) { - selectedIndex = 0; + int direction = inputProvider.Triggered(InputKey::L) ? -1 : 1; + int selected = std::clamp(_selectedItem->itemIdx + 10 * direction, 0, (int)_itemCount - 1); + + focusManager.Unfocus(); + SetSelectedItem(selected, false); + focusManager.Focus(_selectedItem->view); + return true; } - int itemIndex = item->itemIdx; - fix32<12> x; - fix32<12> width; - if (itemIndex < selectedIndex) + + return View::HandleInput(inputProvider, focusManager); +} + +void CarouselRecyclerView::HandlePenDown(const Point& touchPoint, FocusManager& focusManager) +{ + if (GetBounds().Contains(touchPoint)) { - x = SELECTED_COVER_X + (SMALL_COVER_WIDTH + COVER_SPACING) * (itemIndex - selectedIndex); - width = SMALL_COVER_WIDTH; + _penDown = true; + _penDownPosition = touchPoint; + _hasScrollStarted = false; + _penDownScrollOffset = _scrollAnimator.GetValue(); + + if (_itemCount > 0) + { + _selectedItem->view->HandlePenDown(touchPoint, focusManager); + } + for (u32 i = _viewPoolFreeCount; i < _viewPool.size(); i++) + { + auto bounds = _viewPool[i].view->GetBounds(); + bounds = Rectangle(_viewPoolEx[i].xPosition.Int(), bounds.GetTop(), _viewPoolEx[i].width.Int(), bounds.GetHeight()); + if (bounds.Contains(touchPoint)) + { + _viewPool[i].view->HandlePenDown(touchPoint, focusManager); + } + } } - else if (itemIndex == selectedIndex + 1) +} + +void CarouselRecyclerView::HandlePenMove(const Point& touchPoint, FocusManager& focusManager) +{ + if (!_penDown) { - x = NEXT_COVER_X; - width = NEXT_COVER_WIDTH; + return; } - else if (itemIndex > selectedIndex + 1) + + if (!_hasScrollStarted) { - x = NEXT_COVER_X + NEXT_COVER_WIDTH + COVER_SPACING - + (SMALL_COVER_WIDTH + COVER_SPACING) * (itemIndex - selectedIndex - 2); - width = SMALL_COVER_WIDTH; + for (u32 i = _viewPoolFreeCount; i < _viewPool.size(); i++) + { + _viewPool[i].view->HandlePenMove(touchPoint, focusManager); + if (focusManager.GetCurrentFocus().GetPointer() == _viewPool[i].view.GetPointer()) + { + SetSelectedItem(_viewPool[i].itemIdx, false); + } + } + + int dx = touchPoint.x - _penDownPosition.x; + int dy = touchPoint.y - _penDownPosition.y; + if (dx * dx + dy * dy > 7 * 7) + { + bool shouldScrollStart = std::abs(touchPoint.x - _penDownPosition.x) > std::abs(touchPoint.y - _penDownPosition.y); + if (shouldScrollStart) + { + _hasScrollStarted = true; + } + else + { + _penDown = false; //wrong direction drag, so cancel it + } + + for (u32 i = _viewPoolFreeCount; i < _viewPool.size(); i++) + { + _viewPool[i].view->HandlePenUp(Point(-1, -1), focusManager); + } + } } else { - x = SELECTED_COVER_X; - width = SELECTED_COVER_WIDTH; + fix32<12> newScrollOffset = _penDownScrollOffset + fix32<12>(_penDownPosition.x - touchPoint.x) * (2.5 / COVER_WIDTH); + if (newScrollOffset < 0) + { + newScrollOffset = 0; + _penDownScrollOffset = 0; + _penDownPosition.x = touchPoint.x; + } + else if (newScrollOffset > (int)_itemCount - 1) + { + newScrollOffset = (int)_itemCount - 1; + _penDownScrollOffset = newScrollOffset; + _penDownPosition.x = touchPoint.x; + } + + _scrollAnimator = Animator>(newScrollOffset); + } +} + +void CarouselRecyclerView::HandlePenUp(const Point& lastTouchPoint, FocusManager& focusManager) +{ + if (_hasScrollStarted) + { + SetSelectedItem((_scrollAnimator.GetValue() + 0.5).Int(), false); + focusManager.Focus(_selectedItem->view); + } + + for (u32 i = _viewPoolFreeCount; i < _viewPool.size(); i++) + { + _viewPool[i].view->HandlePenUp(lastTouchPoint, focusManager); + if (focusManager.GetCurrentFocus().GetPointer() == _viewPool[i].view.GetPointer()) + { + SetSelectedItem(_viewPool[i].itemIdx, false); + } + } + + _penDown = false; +} + +void CarouselRecyclerView::SetSelectedItem(int itemIdx, bool initial) +{ + CoverFlowRecyclerViewBase::SetSelectedItem(itemIdx, initial); + + if (itemIdx < 0 || itemIdx >= (int)_itemCount) + { + return; } if (initial) { - itemEx->xPositionAnimator = Animator(x); - itemEx->widthAnimator = Animator(width); + _scrollAnimator = Animator>(itemIdx); } else { - itemEx->xPositionAnimator.Goto(x, md::sys::motion::duration::medium4, &md::sys::motion::easing::standard); - itemEx->widthAnimator.Goto(width, md::sys::motion::duration::medium4, &md::sys::motion::easing::standard); + _scrollAnimator.Goto(itemIdx, md::sys::motion::duration::medium4, &md::sys::motion::easing::standard); } } + +void CarouselRecyclerView::UpdateItemPosition(int viewPoolIndex) +{ + auto& item = _viewPool[viewPoolIndex]; + auto& itemEx = _viewPoolEx[viewPoolIndex]; + int itemIndex = item.itemIdx; + fix32<12> absOffsetFromCenter = (itemIndex - _scrollAnimator.GetValue()).Abs(); + fix32<12> initialOffsetFromCenter = absOffsetFromCenter.Clamp(0, 1); + fix32<12> initialOffsetFromNext = (absOffsetFromCenter - 1).Clamp(0, 1); + + fix32<12> x; + fix32<12> width; + if (itemIndex < _scrollAnimator.GetValue()) + { + // everything before selected + x = SELECTED_COVER_X - (SMALL_COVER_WIDTH + COVER_SPACING) * absOffsetFromCenter; + width = Interpolator::InterpolateLinear>(SELECTED_COVER_WIDTH, SMALL_COVER_WIDTH, initialOffsetFromCenter); + } + else if (initialOffsetFromCenter < 1) + { + // from selected to next + x = Interpolator::InterpolateLinear>(SELECTED_COVER_X, NEXT_COVER_X, initialOffsetFromCenter); + width = Interpolator::InterpolateLinear>(SELECTED_COVER_WIDTH, NEXT_COVER_WIDTH, initialOffsetFromCenter); + } + else + { + // everything after next + x = NEXT_COVER_X + + Interpolator::InterpolateLinear>(0, NEXT_COVER_WIDTH + COVER_SPACING, initialOffsetFromNext); + if (absOffsetFromCenter - 2 > 0) + { + x = x + (SMALL_COVER_WIDTH + COVER_SPACING) * (absOffsetFromCenter - 2); + } + width = Interpolator::InterpolateLinear>(NEXT_COVER_WIDTH, SMALL_COVER_WIDTH, initialOffsetFromNext); + } + + itemEx.xPosition = x; + itemEx.width = width; +} diff --git a/arm9/source/romBrowser/Theme/Material/CarouselRecyclerView.h b/arm9/source/romBrowser/Theme/Material/CarouselRecyclerView.h index b168bbf..7615dc6 100644 --- a/arm9/source/romBrowser/Theme/Material/CarouselRecyclerView.h +++ b/arm9/source/romBrowser/Theme/Material/CarouselRecyclerView.h @@ -7,38 +7,44 @@ class MaterialColorScheme; class CarouselRecyclerView : public CoverFlowRecyclerViewBase { - struct Private { explicit Private() = default; }; + SHARED_ONLY(CarouselRecyclerView) public: - CarouselRecyclerView(Private, const MaterialColorScheme* materialColorScheme) - : _materialColorScheme(materialColorScheme) { } - - static SharedPtr CreateShared(const MaterialColorScheme* materialColorScheme) - { - return SharedPtr::MakeShared(Private(), materialColorScheme); - } - static void UploadGraphics(const VramContext& vramContext); void Update() override; void Draw(GraphicsContext &graphicsContext) override; + bool HandleInput(const InputProvider& inputProvider, FocusManager& focusManager) override; + void HandlePenDown(const Point& touchPoint, FocusManager& focusManager) override; + void HandlePenMove(const Point& touchPoint, FocusManager& focusManager) override; + void HandlePenUp(const Point& lastTouchPoint, FocusManager& focusManager) override; + private: struct ViewPoolEntryEx { - Animator> xPositionAnimator; - Animator> widthAnimator; + fix32<12> xPosition; + fix32<12> width; }; std::array _viewPoolEx; const MaterialColorScheme* _materialColorScheme; + Animator> _scrollAnimator = Animator>(0); + bool _penDown = false; + Point _penDownPosition = Point(0, 0); + bool _hasScrollStarted = false; + fix32<12> _penDownScrollOffset = 0; static u32 sMaskTextureVramOffset; + CarouselRecyclerView(const MaterialColorScheme* materialColorScheme) + : _materialColorScheme(materialColorScheme) { } + void RenderCoverMask(GraphicsContext& graphicsContext, fix32<12> left, fix32<12> right) const; void RenderRoundedCorners(GraphicsContext& graphicsContext, fix32<12> x, fix32<12> width) const; - void UpdateItemPosition(int viewPoolIndex, bool initial) override; + void SetSelectedItem(int itemIdx, bool initial) override; + void UpdateItemPosition(int viewPoolIndex); void SwapViewPoolEntry(int indexA, int indexB) override { diff --git a/arm9/source/romBrowser/Theme/Material/MaterialAppBarView.cpp b/arm9/source/romBrowser/Theme/Material/MaterialAppBarView.cpp index d20eff7..951efd8 100644 --- a/arm9/source/romBrowser/Theme/Material/MaterialAppBarView.cpp +++ b/arm9/source/romBrowser/Theme/Material/MaterialAppBarView.cpp @@ -9,7 +9,7 @@ MaterialAppBarView::MaterialAppBarView(int x, int y, Orientation orientation, { for (int i = 0; i < _startButtonCount + _endButtonCount; i++) { - _buttons[i] = SharedPtr::MakeShared( + _buttons[i] = IconButton2DView::CreateShared( IconButtonView::Type::Standard, IconButtonView::State::NoToggle, md::sys::color::inverseOnSurface, diff --git a/arm9/source/romBrowser/Theme/Material/MaterialAppBarView.h b/arm9/source/romBrowser/Theme/Material/MaterialAppBarView.h index 0792f4f..3de2196 100644 --- a/arm9/source/romBrowser/Theme/Material/MaterialAppBarView.h +++ b/arm9/source/romBrowser/Theme/Material/MaterialAppBarView.h @@ -3,9 +3,12 @@ class MaterialAppBarView : public AppBarView { + SHARED_ONLY(MaterialAppBarView) + public: + void InitVram(const VramContext& vramContext) override; + +private: MaterialAppBarView(int x, int y, Orientation orientation, int startButtonCount, int endButtonCount, const MaterialColorScheme* materialColorScheme); - - void InitVram(const VramContext& vramContext) override; }; diff --git a/arm9/source/romBrowser/Theme/Material/MaterialBannerListItemView.cpp b/arm9/source/romBrowser/Theme/Material/MaterialBannerListItemView.cpp index 46a4f7f..ac0dd43 100644 --- a/arm9/source/romBrowser/Theme/Material/MaterialBannerListItemView.cpp +++ b/arm9/source/romBrowser/Theme/Material/MaterialBannerListItemView.cpp @@ -18,12 +18,12 @@ #include "gui/views/Label2DView.h" #include "MaterialBannerListItemView.h" -MaterialBannerListItemView::MaterialBannerListItemView(const MaterialColorScheme* materialColorScheme, - const IFontRepository* fontRepository) - : BannerListItemView( - std::make_unique(160, 16, 50, fontRepository->GetFont(FontType::Medium10)), - std::make_unique(160, 16, 50, fontRepository->GetFont(FontType::Regular10)), - std::make_unique(160, 16, 50, fontRepository->GetFont(FontType::Regular10))) +MaterialBannerListItemView::MaterialBannerListItemView(std::unique_ptr viewModel, + const MaterialColorScheme* materialColorScheme, const IFontRepository* fontRepository) + : BannerListItemView(std::move(viewModel), + Label2DView::CreateShared(160, 16, 50, fontRepository->GetFont(FontType::Medium10)), + Label2DView::CreateShared(160, 16, 50, fontRepository->GetFont(FontType::Regular10)), + Label2DView::CreateShared(160, 16, 50, fontRepository->GetFont(FontType::Regular10))) , _materialColorScheme(materialColorScheme) { } void MaterialBannerListItemView::Draw(GraphicsContext& graphicsContext) diff --git a/arm9/source/romBrowser/Theme/Material/MaterialBannerListItemView.h b/arm9/source/romBrowser/Theme/Material/MaterialBannerListItemView.h index 7b082cb..bba63bd 100644 --- a/arm9/source/romBrowser/Theme/Material/MaterialBannerListItemView.h +++ b/arm9/source/romBrowser/Theme/Material/MaterialBannerListItemView.h @@ -7,10 +7,9 @@ class IFontRepository; class MaterialBannerListItemView : public BannerListItemView { -public: - MaterialBannerListItemView(const MaterialColorScheme* materialColorScheme, - const IFontRepository* fontRepository); + SHARED_ONLY(MaterialBannerListItemView) +public: void Draw(GraphicsContext& graphicsContext) override; Rectangle GetBounds() const override @@ -28,4 +27,7 @@ public: private: const MaterialColorScheme* _materialColorScheme; u32 _bgVramOffset; + + MaterialBannerListItemView(std::unique_ptr viewModel, + const MaterialColorScheme* materialColorScheme, const IFontRepository* fontRepository); }; diff --git a/arm9/source/romBrowser/Theme/Material/MaterialCoverFlowFileRecyclerAdapter.cpp b/arm9/source/romBrowser/Theme/Material/MaterialCoverFlowFileRecyclerAdapter.cpp index 65a43f2..e6e41a8 100644 --- a/arm9/source/romBrowser/Theme/Material/MaterialCoverFlowFileRecyclerAdapter.cpp +++ b/arm9/source/romBrowser/Theme/Material/MaterialCoverFlowFileRecyclerAdapter.cpp @@ -15,13 +15,15 @@ void MaterialCoverFlowFileRecyclerAdapter::GetViewSize(int& width, int& height) SharedPtr MaterialCoverFlowFileRecyclerAdapter::CreateView() const { - return SharedPtr::MakeShared(_vblankTextureLoader); + return MaterialCoverView::CreateShared( + std::make_unique(_romBrowserController), _vblankTextureLoader); } TaskResult MaterialCoverFlowFileRecyclerAdapter::BindView(SharedPtr view, int index, const InternalFileInfo* internalFileInfo, const vu8& cancelRequested) const { auto coverView = static_cast(view.GetPointer()); + coverView->GetViewModel().SetIndex(index); auto cover = _fileInfoManager->GetFileCover(index); if (cancelRequested) { @@ -39,10 +41,18 @@ TaskResult MaterialCoverFlowFileRecyclerAdapter::BindView(SharedPtr return TaskResult::Completed(); } +void MaterialCoverFlowFileRecyclerAdapter::SetQueueTask(const SharedPtr& view, QueueTask queueTask) const +{ + auto coverView = static_cast(view.GetPointer()); + coverView->GetViewModel().SetQueueTask(std::move(queueTask)); +} + void MaterialCoverFlowFileRecyclerAdapter::ReleaseView(SharedPtr view, int index) const { LOG_DEBUG("Releasing %d\n", index); auto coverView = static_cast(view.GetPointer()); coverView->ClearCover(); + coverView->GetViewModel().SetIndex(-1); + coverView->GetViewModel().CancelQueueTask(); _fileInfoManager->ReleaseFileInfo(index); } \ No newline at end of file diff --git a/arm9/source/romBrowser/Theme/Material/MaterialCoverFlowFileRecyclerAdapter.h b/arm9/source/romBrowser/Theme/Material/MaterialCoverFlowFileRecyclerAdapter.h index 4b27b55..53b2803 100644 --- a/arm9/source/romBrowser/Theme/Material/MaterialCoverFlowFileRecyclerAdapter.h +++ b/arm9/source/romBrowser/Theme/Material/MaterialCoverFlowFileRecyclerAdapter.h @@ -8,12 +8,12 @@ class ICoverRepository; class MaterialCoverFlowFileRecyclerAdapter : public FileRecyclerAdapter { public: - MaterialCoverFlowFileRecyclerAdapter(FileInfoManager* fileInfoManager, + MaterialCoverFlowFileRecyclerAdapter(IRomBrowserController* romBrowserController, FileInfoManager* fileInfoManager, TaskQueueBase* taskQueue, const IThemeFileIconFactory* themeFileIconFactory, const IRomBrowserViewFactory* romBrowserViewFactory, VBlankTextureLoader* vblankTextureLoader, const ICoverRepository* coverRepository) - : FileRecyclerAdapter(fileInfoManager, taskQueue, themeFileIconFactory) + : FileRecyclerAdapter(romBrowserController, fileInfoManager, taskQueue, themeFileIconFactory) , _romBrowserViewFactory(romBrowserViewFactory) , _vblankTextureLoader(vblankTextureLoader) , _coverRepository(coverRepository) { } @@ -29,4 +29,5 @@ private: TaskResult BindView(SharedPtr view, int index, const InternalFileInfo* internalFileInfo, const vu8& cancelRequested) const override; + void SetQueueTask(const SharedPtr& view, QueueTask queueTask) const override; }; diff --git a/arm9/source/romBrowser/Theme/Material/MaterialCoverView.cpp b/arm9/source/romBrowser/Theme/Material/MaterialCoverView.cpp index a90beaf..4a93c58 100644 --- a/arm9/source/romBrowser/Theme/Material/MaterialCoverView.cpp +++ b/arm9/source/romBrowser/Theme/Material/MaterialCoverView.cpp @@ -4,6 +4,7 @@ #include "gui/Gx.h" #include "gui/materialDesign.h" #include "gui/GraphicsContext.h" +#include "gui/input/InputProvider.h" #include "MaterialCoverView.h" void MaterialCoverView::InitVram(const VramContext& vramContext) @@ -17,6 +18,11 @@ void MaterialCoverView::InitVram(const VramContext& vramContext) } } +void MaterialCoverView::Update() +{ + _viewModel->DisposeQueueTaskWhenComplete(); +} + void MaterialCoverView::Draw(GraphicsContext& graphicsContext) { if (_cover.Lock() && _textureLoadRequest.GetState() == VBlankTextureLoadRequestState::LoadComplete) @@ -44,6 +50,27 @@ void MaterialCoverView::Draw(GraphicsContext& graphicsContext) } } +bool MaterialCoverView::HandleInput(const InputProvider& inputProvider, FocusManager& focusManager) +{ + return _inputHandler.HandleInput(inputProvider, focusManager) + || View::HandleInput(inputProvider, focusManager); +} + +void MaterialCoverView::HandlePenDown(const Point& touchPoint, FocusManager& focusManager) +{ + _inputHandler.HandlePenDown(touchPoint, focusManager); +} + +void MaterialCoverView::HandlePenMove(const Point& touchPoint, FocusManager& focusManager) +{ + _inputHandler.HandlePenMove(touchPoint, focusManager); +} + +void MaterialCoverView::HandlePenUp(const Point& lastTouchPoint, FocusManager& focusManager) +{ + _inputHandler.HandlePenUp(lastTouchPoint, focusManager); +} + void MaterialCoverView::UploadCoverGraphics() { if (auto cover = _cover.Lock()) diff --git a/arm9/source/romBrowser/Theme/Material/MaterialCoverView.h b/arm9/source/romBrowser/Theme/Material/MaterialCoverView.h index eff98da..82cf65d 100644 --- a/arm9/source/romBrowser/Theme/Material/MaterialCoverView.h +++ b/arm9/source/romBrowser/Theme/Material/MaterialCoverView.h @@ -3,13 +3,14 @@ #include "gui/views/View.h" #include "romBrowser/FileType/FileCover.h" #include "gui/VBlankTextureLoader.h" +#include "romBrowser/viewModels/RomBrowserItemViewModel.h" +#include "romBrowser/views/RomBrowserItemInputHandler.h" class MaterialCoverView : public View { -public: - explicit MaterialCoverView(VBlankTextureLoader* vblankTextureLoader) - : _vblankTextureLoader(vblankTextureLoader) { } + SHARED_ONLY(MaterialCoverView) +public: ~MaterialCoverView() override { _vblankTextureLoader->CancelLoad(_textureLoadRequest); @@ -17,11 +18,17 @@ public: void InitVram(const VramContext& vramContext) override; + void Update() override; void Draw(GraphicsContext& graphicsContext) override; + bool HandleInput(const InputProvider& inputProvider, FocusManager& focusManager) override; + void HandlePenDown(const Point& touchPoint, FocusManager& focusManager) override; + void HandlePenMove(const Point& touchPoint, FocusManager& focusManager) override; + void HandlePenUp(const Point& lastTouchPoint, FocusManager& focusManager) override; + Rectangle GetBounds() const override { - return Rectangle(_position.x - (COVER_WIDTH / 2), _position.y - (COVER_HEIGHT / 2), COVER_WIDTH, COVER_HEIGHT); + return Rectangle(_position.x, _position.y, COVER_WIDTH, COVER_HEIGHT); } void SetCover(SharedPtr cover) @@ -38,10 +45,21 @@ public: void UploadCoverGraphics(); + RomBrowserItemViewModel& GetViewModel() const + { + return *_viewModel; + } + private: + std::unique_ptr _viewModel; VBlankTextureLoader* _vblankTextureLoader; AtomicSharedPtr _cover; VBlankTextureLoadRequest _textureLoadRequest; u32 _texVramOffset = 0; u32 _plttVramOffset = 0; + RomBrowserItemInputHandler _inputHandler; + + MaterialCoverView(std::unique_ptr viewModel, VBlankTextureLoader* vblankTextureLoader) + : _viewModel(std::move(viewModel)), _vblankTextureLoader(vblankTextureLoader) + , _inputHandler(this, _viewModel.get()) { } }; diff --git a/arm9/source/romBrowser/Theme/Material/MaterialFileInfoCardView.cpp b/arm9/source/romBrowser/Theme/Material/MaterialFileInfoCardView.cpp index d8ec052..4cfcd29 100644 --- a/arm9/source/romBrowser/Theme/Material/MaterialFileInfoCardView.cpp +++ b/arm9/source/romBrowser/Theme/Material/MaterialFileInfoCardView.cpp @@ -13,17 +13,17 @@ MaterialFileInfoCardView::MaterialFileInfoCardView(const MaterialColorScheme* materialColorScheme, const IFontRepository* fontRepository) - : _firstLine(176, 16, 50, fontRepository->GetFont(FontType::Medium11)) - , _secondLine(176, 16, 50, fontRepository->GetFont(FontType::Regular10)) - , _thirdLine(176, 16, 50, fontRepository->GetFont(FontType::Regular10)) - , _filenameLabelView(220, 16, 200, fontRepository->GetFont(FontType::Medium7_5)) + : _firstLine(Label2DView::CreateShared(176, 16, 50, fontRepository->GetFont(FontType::Medium11))) + , _secondLine(Label2DView::CreateShared(176, 16, 50, fontRepository->GetFont(FontType::Regular10))) + , _thirdLine(Label2DView::CreateShared(176, 16, 50, fontRepository->GetFont(FontType::Regular10))) + , _filenameLabelView(Label2DView::CreateShared(220, 16, 200, fontRepository->GetFont(FontType::Medium7_5))) , _materialColorScheme(materialColorScheme) { - AddChildTail(&_firstLine); - AddChildTail(&_secondLine); - AddChildTail(&_thirdLine); - _filenameLabelView.SetEllipsisStyle(LabelView::EllipsisStyle::Marquee); - AddChildTail(&_filenameLabelView); + AddChildTail(_firstLine.GetPointer()); + AddChildTail(_secondLine.GetPointer()); + AddChildTail(_thirdLine.GetPointer()); + _filenameLabelView->SetEllipsisStyle(LabelView::EllipsisStyle::Marquee); + AddChildTail(_filenameLabelView.GetPointer()); } void MaterialFileInfoCardView::InitVram(const VramContext& vramContext) @@ -41,10 +41,10 @@ void MaterialFileInfoCardView::InitVram(const VramContext& vramContext) void MaterialFileInfoCardView::Update() { BannerView::Update(); - _firstLine.SetPosition(_position.x + 70, _position.y + 130 - 8); - _secondLine.SetPosition(_position.x + 70, _position.y + 145 - 8); - _thirdLine.SetPosition(_position.x + 70, _position.y + 159 - 8); - _filenameLabelView.SetPosition(_position.x + 18, _position.y + 168); + _firstLine->SetPosition(_position.x + 70, _position.y + 130 - 8); + _secondLine->SetPosition(_position.x + 70, _position.y + 145 - 8); + _thirdLine->SetPosition(_position.x + 70, _position.y + 159 - 8); + _filenameLabelView->SetPosition(_position.x + 18, _position.y + 168); if (_icon) { _icon->SetPosition(_position.x + 24, _position.y + 136 - 8); @@ -54,14 +54,14 @@ void MaterialFileInfoCardView::Update() void MaterialFileInfoCardView::Draw(GraphicsContext& graphicsContext) { - _firstLine.SetBackgroundColor(_materialColorScheme->secondaryContainer); - _firstLine.SetForegroundColor(_materialColorScheme->onSecondaryContainer); - _secondLine.SetBackgroundColor(_materialColorScheme->secondaryContainer); - _secondLine.SetForegroundColor(_materialColorScheme->onSecondaryContainer); - _thirdLine.SetBackgroundColor(_materialColorScheme->secondaryContainer); - _thirdLine.SetForegroundColor(_materialColorScheme->onSecondaryContainer); - _filenameLabelView.SetBackgroundColor(_materialColorScheme->secondaryContainer); - _filenameLabelView.SetForegroundColor(_materialColorScheme->onSurfaceVariant); + _firstLine->SetBackgroundColor(_materialColorScheme->secondaryContainer); + _firstLine->SetForegroundColor(_materialColorScheme->onSecondaryContainer); + _secondLine->SetBackgroundColor(_materialColorScheme->secondaryContainer); + _secondLine->SetForegroundColor(_materialColorScheme->onSecondaryContainer); + _thirdLine->SetBackgroundColor(_materialColorScheme->secondaryContainer); + _thirdLine->SetForegroundColor(_materialColorScheme->onSecondaryContainer); + _filenameLabelView->SetBackgroundColor(_materialColorScheme->secondaryContainer); + _filenameLabelView->SetForegroundColor(_materialColorScheme->onSurfaceVariant); BannerView::Draw(graphicsContext); diff --git a/arm9/source/romBrowser/Theme/Material/MaterialFileInfoCardView.h b/arm9/source/romBrowser/Theme/Material/MaterialFileInfoCardView.h index d81ec2a..69e9f38 100644 --- a/arm9/source/romBrowser/Theme/Material/MaterialFileInfoCardView.h +++ b/arm9/source/romBrowser/Theme/Material/MaterialFileInfoCardView.h @@ -9,55 +9,54 @@ class IFontRepository; class MaterialFileInfoCardView : public BannerView { -public: - MaterialFileInfoCardView(const MaterialColorScheme* materialColorScheme, - const IFontRepository* fontRepository); + SHARED_ONLY(MaterialFileInfoCardView) +public: void InitVram(const VramContext& vramContext) override; void Update() override; void Draw(GraphicsContext& graphicsContext) override; void SetFirstLineAsync(TaskQueueBase* taskQueue, const char* firstLine, bool ellipsis) override { - _firstLine.SetEllipsisStyle(ellipsis ? LabelView::EllipsisStyle::Ellipsis : LabelView::EllipsisStyle::None); + _firstLine->SetEllipsisStyle(ellipsis ? LabelView::EllipsisStyle::Ellipsis : LabelView::EllipsisStyle::None); if (taskQueue) - _firstLine.SetTextAsync(taskQueue, firstLine); + _firstLine->SetTextAsync(taskQueue, firstLine); else - _firstLine.SetText(firstLine); + _firstLine->SetText(firstLine); } void SetFirstLineAsync(TaskQueueBase* taskQueue, const char16_t* firstLine, u32 length, bool ellipsis) override { - _firstLine.SetEllipsisStyle(ellipsis ? LabelView::EllipsisStyle::Ellipsis : LabelView::EllipsisStyle::None); + _firstLine->SetEllipsisStyle(ellipsis ? LabelView::EllipsisStyle::Ellipsis : LabelView::EllipsisStyle::None); if (taskQueue) - _firstLine.SetTextAsync(taskQueue, firstLine, length); + _firstLine->SetTextAsync(taskQueue, firstLine, length); else - _firstLine.SetText(firstLine, length); + _firstLine->SetText(firstLine, length); } void SetSecondLineAsync(TaskQueueBase* taskQueue, const char16_t* secondLine, u32 length) override { if (taskQueue) - _secondLine.SetTextAsync(taskQueue, secondLine, length); + _secondLine->SetTextAsync(taskQueue, secondLine, length); else - _secondLine.SetText(secondLine, length); + _secondLine->SetText(secondLine, length); } void SetThirdLineAsync(TaskQueueBase* taskQueue, const char16_t* thirdLine, u32 length) override { if (taskQueue) - _thirdLine.SetTextAsync(taskQueue, thirdLine, length); + _thirdLine->SetTextAsync(taskQueue, thirdLine, length); else - _thirdLine.SetText(thirdLine, length); + _thirdLine->SetText(thirdLine, length); } void SetFileNameAsync(TaskQueueBase* taskQueue, const TCHAR* fileName, bool useAsTitle) override { BannerView::SetFileNameAsync(taskQueue, fileName, useAsTitle); if (taskQueue) - _filenameLabelView.SetTextAsync(taskQueue, fileName); + _filenameLabelView->SetTextAsync(taskQueue, fileName); else - _filenameLabelView.SetText(fileName); + _filenameLabelView->SetText(fileName); } Rectangle GetBounds() const override @@ -66,10 +65,13 @@ public: } private: - Label2DView _firstLine; - Label2DView _secondLine; - Label2DView _thirdLine; - Label2DView _filenameLabelView; + SharedPtr _firstLine; + SharedPtr _secondLine; + SharedPtr _thirdLine; + SharedPtr _filenameLabelView; u32 _iconCellVramOffset; const MaterialColorScheme* _materialColorScheme; + + MaterialFileInfoCardView(const MaterialColorScheme* materialColorScheme, + const IFontRepository* fontRepository); }; diff --git a/arm9/source/romBrowser/Theme/Material/MaterialIconGridItemView.cpp b/arm9/source/romBrowser/Theme/Material/MaterialIconGridItemView.cpp index adf68db..9bf2c0a 100644 --- a/arm9/source/romBrowser/Theme/Material/MaterialIconGridItemView.cpp +++ b/arm9/source/romBrowser/Theme/Material/MaterialIconGridItemView.cpp @@ -20,7 +20,7 @@ void MaterialIconGridItemView::Draw(GraphicsContext& graphicsContext) return; auto backColor = _materialColorScheme->inverseOnSurface; - auto frontColor = _isFocused + auto frontColor = (_isFocused || _inputHandler.IsPenDown()) ? _materialColorScheme->mainIconBg : _materialColorScheme->surfaceBright; u16 selectedIconCellPltt[16]; diff --git a/arm9/source/romBrowser/Theme/Material/MaterialIconGridItemView.h b/arm9/source/romBrowser/Theme/Material/MaterialIconGridItemView.h index f9f3bce..6f3048e 100644 --- a/arm9/source/romBrowser/Theme/Material/MaterialIconGridItemView.h +++ b/arm9/source/romBrowser/Theme/Material/MaterialIconGridItemView.h @@ -5,10 +5,9 @@ class MaterialColorScheme; class MaterialIconGridItemView : public IconGridItemView { -public: - explicit MaterialIconGridItemView(const MaterialColorScheme* materialColorScheme) - : _materialColorScheme(materialColorScheme) { } + SHARED_ONLY(MaterialIconGridItemView) +public: void Draw(GraphicsContext& graphicsContext) override; Rectangle GetBounds() const override @@ -26,4 +25,7 @@ public: private: const MaterialColorScheme* _materialColorScheme; u32 _bgVramOffset; -}; \ No newline at end of file + + MaterialIconGridItemView(std::unique_ptr viewModel, const MaterialColorScheme* materialColorScheme) + : IconGridItemView(std::move(viewModel)), _materialColorScheme(materialColorScheme) { } +}; diff --git a/arm9/source/romBrowser/Theme/Material/MaterialRomBrowserViewFactory.h b/arm9/source/romBrowser/Theme/Material/MaterialRomBrowserViewFactory.h index 5128dc5..74b0f3e 100644 --- a/arm9/source/romBrowser/Theme/Material/MaterialRomBrowserViewFactory.h +++ b/arm9/source/romBrowser/Theme/Material/MaterialRomBrowserViewFactory.h @@ -18,9 +18,9 @@ public: const IFontRepository* fontRepository) : _materialColorScheme(materialColorScheme), _fontRepository(fontRepository) { } - SharedPtr CreateIconGridItemView() const override + SharedPtr CreateIconGridItemView(std::unique_ptr viewModel) const override { - return SharedPtr::MakeShared(_materialColorScheme); + return MaterialIconGridItemView::CreateShared(std::move(viewModel), _materialColorScheme); } IconGridItemView::VramToken UploadIconGridItemViewGraphics( @@ -29,9 +29,10 @@ public: return MaterialIconGridItemView::UploadGraphics(vramContext); } - SharedPtr CreateBannerListItemView(VBlankTextureLoader* vblankTextureLoader) const override + SharedPtr CreateBannerListItemView(std::unique_ptr viewModel, + VBlankTextureLoader* vblankTextureLoader) const override { - return SharedPtr::MakeShared(_materialColorScheme, _fontRepository); + return MaterialBannerListItemView::CreateShared(std::move(viewModel), _materialColorScheme, _fontRepository); } BannerListItemView::VramToken UploadBannerListItemViewGraphics( @@ -40,15 +41,15 @@ public: return MaterialBannerListItemView::UploadGraphics(vramContext); } - std::unique_ptr CreateAppBarView(int x, int y, AppBarView::Orientation orientation, + SharedPtr CreateAppBarView(int x, int y, AppBarView::Orientation orientation, int startButtonCount, int endButtonCount) const override { - return std::make_unique(x, y, orientation, startButtonCount, endButtonCount, _materialColorScheme); + return MaterialAppBarView::CreateShared(x, y, orientation, startButtonCount, endButtonCount, _materialColorScheme); } - std::unique_ptr CreateFileInfoView() const override + SharedPtr CreateFileInfoView() const override { - return std::make_unique(_materialColorScheme, _fontRepository); + return MaterialFileInfoCardView::CreateShared(_materialColorScheme, _fontRepository); } SharedPtr CreateCoverFlowRecyclerView() const override @@ -60,7 +61,7 @@ public: RomBrowserViewModel* viewModel, const IThemeFileIconFactory* themeFileIconFactory, VBlankTextureLoader* vblankTextureLoader) const override { - return SharedPtr::MakeShared( + return SharedPtr::MakeShared(viewModel->GetRomBrowserController(), &viewModel->GetFileInfoManager(), viewModel->GetIoTaskQueue(), themeFileIconFactory, this, vblankTextureLoader, &viewModel->GetCoverRepository()); } diff --git a/arm9/source/romBrowser/Theme/custom/CustomAppBarView.cpp b/arm9/source/romBrowser/Theme/custom/CustomAppBarView.cpp index c435f95..8ffdfd2 100644 --- a/arm9/source/romBrowser/Theme/custom/CustomAppBarView.cpp +++ b/arm9/source/romBrowser/Theme/custom/CustomAppBarView.cpp @@ -12,7 +12,7 @@ CustomAppBarView::CustomAppBarView(int x, int y, Orientation orientation, { for (int i = 0; i < _startButtonCount + _endButtonCount; i++) { - _buttons[i] = SharedPtr::MakeShared( + _buttons[i] = IconButton3DView::CreateShared( IconButtonView::Type::Tonal, IconButtonView::State::NoToggle, md::sys::color::inverseOnSurface, diff --git a/arm9/source/romBrowser/Theme/custom/CustomAppBarView.h b/arm9/source/romBrowser/Theme/custom/CustomAppBarView.h index 9ee7730..e566cdf 100644 --- a/arm9/source/romBrowser/Theme/custom/CustomAppBarView.h +++ b/arm9/source/romBrowser/Theme/custom/CustomAppBarView.h @@ -3,14 +3,16 @@ class CustomAppBarView : public AppBarView { -public: - CustomAppBarView(int x, int y, Orientation orientation, - int startButtonCount, int endButtonCount, const MaterialColorScheme* materialColorScheme, - u32 scrimTexVramOffset, u32 scrimPlttVramOffset); + SHARED_ONLY(CustomAppBarView) +public: void Draw(GraphicsContext& graphicsContext) override; private: u32 _scrimTexVramOffset = 0; u32 _scrimPlttVramOffset = 0; + + CustomAppBarView(int x, int y, Orientation orientation, + int startButtonCount, int endButtonCount, const MaterialColorScheme* materialColorScheme, + u32 scrimTexVramOffset, u32 scrimPlttVramOffset); }; diff --git a/arm9/source/romBrowser/Theme/custom/CustomBannerListItemView.cpp b/arm9/source/romBrowser/Theme/custom/CustomBannerListItemView.cpp index 2c03c06..ec47070 100644 --- a/arm9/source/romBrowser/Theme/custom/CustomBannerListItemView.cpp +++ b/arm9/source/romBrowser/Theme/custom/CustomBannerListItemView.cpp @@ -31,16 +31,17 @@ #define LINE_HEIGHT 16 #define MAX_LINE_STRING_LENGTH 50 -CustomBannerListItemView::CustomBannerListItemView(const CustomThemeInfo* customThemeInfo, - const MaterialColorScheme* materialColorScheme, const IFontRepository* fontRepository, - u32 texVramOffset, u32 plttVramOffset, u32 selectedTexVramOffset, u32 selectedPlttVramOffset, +CustomBannerListItemView::CustomBannerListItemView(std::unique_ptr viewModel, + const CustomThemeInfo* customThemeInfo, const MaterialColorScheme* materialColorScheme, + const IFontRepository* fontRepository, u32 texVramOffset, u32 plttVramOffset, + u32 selectedTexVramOffset, u32 selectedPlttVramOffset, VBlankTextureLoader* vblankTextureLoader) - : BannerListItemView( - std::make_unique(LINE_WIDTH, LINE_HEIGHT, MAX_LINE_STRING_LENGTH, + : BannerListItemView(std::move(viewModel), + Label3DView::CreateShared(LINE_WIDTH, LINE_HEIGHT, MAX_LINE_STRING_LENGTH, fontRepository->GetFont(FontType::Medium10), vblankTextureLoader), - std::make_unique(LINE_WIDTH, LINE_HEIGHT, MAX_LINE_STRING_LENGTH, + Label3DView::CreateShared(LINE_WIDTH, LINE_HEIGHT, MAX_LINE_STRING_LENGTH, fontRepository->GetFont(FontType::Regular10), vblankTextureLoader), - std::make_unique(LINE_WIDTH, LINE_HEIGHT, MAX_LINE_STRING_LENGTH, + Label3DView::CreateShared(LINE_WIDTH, LINE_HEIGHT, MAX_LINE_STRING_LENGTH, fontRepository->GetFont(FontType::Regular10), vblankTextureLoader)) , _customThemeInfo(customThemeInfo) , _materialColorScheme(materialColorScheme) diff --git a/arm9/source/romBrowser/Theme/custom/CustomBannerListItemView.h b/arm9/source/romBrowser/Theme/custom/CustomBannerListItemView.h index b3a40bf..d7814e4 100644 --- a/arm9/source/romBrowser/Theme/custom/CustomBannerListItemView.h +++ b/arm9/source/romBrowser/Theme/custom/CustomBannerListItemView.h @@ -1,6 +1,6 @@ #pragma once #include "gui/views/LabelView.h" -#include "../../views/BannerListItemView.h" +#include "romBrowser/views/BannerListItemView.h" class MaterialColorScheme; class IFontRepository; @@ -8,11 +8,9 @@ class CustomThemeInfo; class CustomBannerListItemView : public BannerListItemView { -public: - CustomBannerListItemView(const CustomThemeInfo* customThemeInfo, const MaterialColorScheme* materialColorScheme, - const IFontRepository* fontRepository, u32 texVramOffset, u32 plttVramOffset, - u32 selectedTexVramOffset, u32 selectedPlttVramOffset, VBlankTextureLoader* vblankTextureLoader); + SHARED_ONLY(CustomBannerListItemView) +public: void Draw(GraphicsContext& graphicsContext) override; Rectangle GetBounds() const override @@ -27,4 +25,9 @@ private: u32 _plttVramOffset = 0; u32 _selectedTexVramOffset = 0; u32 _selectedPlttVramOffset = 0; + + CustomBannerListItemView(std::unique_ptr viewModel, const CustomThemeInfo* customThemeInfo, + const MaterialColorScheme* materialColorScheme, const IFontRepository* fontRepository, + u32 texVramOffset, u32 plttVramOffset, u32 selectedTexVramOffset, u32 selectedPlttVramOffset, + VBlankTextureLoader* vblankTextureLoader); }; diff --git a/arm9/source/romBrowser/Theme/custom/CustomFileInfoView.cpp b/arm9/source/romBrowser/Theme/custom/CustomFileInfoView.cpp index dc8eab5..6a557ff 100644 --- a/arm9/source/romBrowser/Theme/custom/CustomFileInfoView.cpp +++ b/arm9/source/romBrowser/Theme/custom/CustomFileInfoView.cpp @@ -6,26 +6,30 @@ #include "CustomFileInfoView.h" CustomFileInfoView::CustomFileInfoView(const CustomThemeInfo* customThemeInfo, const IFontRepository* fontRepository) - : _firstLine(customThemeInfo->topBannerTextLine0Info.GetWidth(), 16, 50, fontRepository->GetFont(FontType::Medium11)) - , _secondLine(customThemeInfo->topBannerTextLine1Info.GetWidth(), 16, 50, fontRepository->GetFont(FontType::Regular10)) - , _thirdLine(customThemeInfo->topBannerTextLine2Info.GetWidth(), 16, 50, fontRepository->GetFont(FontType::Regular10)) - , _filenameLabelView(customThemeInfo->topFileNameTextInfo.GetWidth(), 16, 256, fontRepository->GetFont(FontType::Medium7_5)) + : _firstLine(Label2DView::CreateShared( + customThemeInfo->topBannerTextLine0Info.GetWidth(), 16, 50, fontRepository->GetFont(FontType::Medium11))) + , _secondLine(Label2DView::CreateShared( + customThemeInfo->topBannerTextLine1Info.GetWidth(), 16, 50, fontRepository->GetFont(FontType::Regular10))) + , _thirdLine(Label2DView::CreateShared( + customThemeInfo->topBannerTextLine2Info.GetWidth(), 16, 50, fontRepository->GetFont(FontType::Regular10))) + , _filenameLabelView(Label2DView::CreateShared( + customThemeInfo->topFileNameTextInfo.GetWidth(), 16, 256, fontRepository->GetFont(FontType::Medium7_5))) , _customThemeInfo(customThemeInfo) { - AddChildTail(&_firstLine); - AddChildTail(&_secondLine); - AddChildTail(&_thirdLine); - _filenameLabelView.SetEllipsisStyle(LabelView::EllipsisStyle::Marquee); - AddChildTail(&_filenameLabelView); + AddChildTail(_firstLine.GetPointer()); + AddChildTail(_secondLine.GetPointer()); + AddChildTail(_thirdLine.GetPointer()); + _filenameLabelView->SetEllipsisStyle(LabelView::EllipsisStyle::Marquee); + AddChildTail(_filenameLabelView.GetPointer()); } void CustomFileInfoView::Update() { BannerView::Update(); - _firstLine.SetPosition(_customThemeInfo->topBannerTextLine0Info.GetPosition()); - _secondLine.SetPosition(_customThemeInfo->topBannerTextLine1Info.GetPosition()); - _thirdLine.SetPosition(_customThemeInfo->topBannerTextLine2Info.GetPosition()); - _filenameLabelView.SetPosition(_customThemeInfo->topFileNameTextInfo.GetPosition()); + _firstLine->SetPosition(_customThemeInfo->topBannerTextLine0Info.GetPosition()); + _secondLine->SetPosition(_customThemeInfo->topBannerTextLine1Info.GetPosition()); + _thirdLine->SetPosition(_customThemeInfo->topBannerTextLine2Info.GetPosition()); + _filenameLabelView->SetPosition(_customThemeInfo->topFileNameTextInfo.GetPosition()); if (_icon) { _icon->SetPosition(_customThemeInfo->topIconInfo.GetPosition()); @@ -35,14 +39,14 @@ void CustomFileInfoView::Update() void CustomFileInfoView::Draw(GraphicsContext& graphicsContext) { - _firstLine.SetBackgroundColor(_customThemeInfo->topBannerTextLine0Info.GetBlendColor()); - _firstLine.SetForegroundColor(_customThemeInfo->topBannerTextLine0Info.GetTextColor()); - _secondLine.SetBackgroundColor(_customThemeInfo->topBannerTextLine1Info.GetBlendColor()); - _secondLine.SetForegroundColor(_customThemeInfo->topBannerTextLine1Info.GetTextColor()); - _thirdLine.SetBackgroundColor(_customThemeInfo->topBannerTextLine2Info.GetBlendColor()); - _thirdLine.SetForegroundColor(_customThemeInfo->topBannerTextLine2Info.GetTextColor()); - _filenameLabelView.SetBackgroundColor(_customThemeInfo->topFileNameTextInfo.GetBlendColor()); - _filenameLabelView.SetForegroundColor(_customThemeInfo->topFileNameTextInfo.GetTextColor()); + _firstLine->SetBackgroundColor(_customThemeInfo->topBannerTextLine0Info.GetBlendColor()); + _firstLine->SetForegroundColor(_customThemeInfo->topBannerTextLine0Info.GetTextColor()); + _secondLine->SetBackgroundColor(_customThemeInfo->topBannerTextLine1Info.GetBlendColor()); + _secondLine->SetForegroundColor(_customThemeInfo->topBannerTextLine1Info.GetTextColor()); + _thirdLine->SetBackgroundColor(_customThemeInfo->topBannerTextLine2Info.GetBlendColor()); + _thirdLine->SetForegroundColor(_customThemeInfo->topBannerTextLine2Info.GetTextColor()); + _filenameLabelView->SetBackgroundColor(_customThemeInfo->topFileNameTextInfo.GetBlendColor()); + _filenameLabelView->SetForegroundColor(_customThemeInfo->topFileNameTextInfo.GetTextColor()); BannerView::Draw(graphicsContext); diff --git a/arm9/source/romBrowser/Theme/custom/CustomFileInfoView.h b/arm9/source/romBrowser/Theme/custom/CustomFileInfoView.h index 9676cc7..8177783 100644 --- a/arm9/source/romBrowser/Theme/custom/CustomFileInfoView.h +++ b/arm9/source/romBrowser/Theme/custom/CustomFileInfoView.h @@ -9,53 +9,53 @@ class CustomThemeInfo; class CustomFileInfoView : public BannerView { -public: - CustomFileInfoView(const CustomThemeInfo* customThemeInfo, const IFontRepository* fontRepository); + SHARED_ONLY(CustomFileInfoView) +public: void Update() override; void Draw(GraphicsContext& graphicsContext) override; void SetFirstLineAsync(TaskQueueBase* taskQueue, const char* firstLine, bool ellipsis) override { - _firstLine.SetEllipsisStyle(ellipsis ? LabelView::EllipsisStyle::Ellipsis : LabelView::EllipsisStyle::None); + _firstLine->SetEllipsisStyle(ellipsis ? LabelView::EllipsisStyle::Ellipsis : LabelView::EllipsisStyle::None); if (taskQueue) - _firstLine.SetTextAsync(taskQueue, firstLine); + _firstLine->SetTextAsync(taskQueue, firstLine); else - _firstLine.SetText(firstLine); + _firstLine->SetText(firstLine); } void SetFirstLineAsync(TaskQueueBase* taskQueue, const char16_t* firstLine, u32 length, bool ellipsis) override { - _firstLine.SetEllipsisStyle(ellipsis ? LabelView::EllipsisStyle::Ellipsis : LabelView::EllipsisStyle::None); + _firstLine->SetEllipsisStyle(ellipsis ? LabelView::EllipsisStyle::Ellipsis : LabelView::EllipsisStyle::None); if (taskQueue) - _firstLine.SetTextAsync(taskQueue, firstLine, length); + _firstLine->SetTextAsync(taskQueue, firstLine, length); else - _firstLine.SetText(firstLine, length); + _firstLine->SetText(firstLine, length); } void SetSecondLineAsync(TaskQueueBase* taskQueue, const char16_t* secondLine, u32 length) override { if (taskQueue) - _secondLine.SetTextAsync(taskQueue, secondLine, length); + _secondLine->SetTextAsync(taskQueue, secondLine, length); else - _secondLine.SetText(secondLine, length); + _secondLine->SetText(secondLine, length); } void SetThirdLineAsync(TaskQueueBase* taskQueue, const char16_t* thirdLine, u32 length) override { if (taskQueue) - _thirdLine.SetTextAsync(taskQueue, thirdLine, length); + _thirdLine->SetTextAsync(taskQueue, thirdLine, length); else - _thirdLine.SetText(thirdLine, length); + _thirdLine->SetText(thirdLine, length); } void SetFileNameAsync(TaskQueueBase* taskQueue, const TCHAR* fileName, bool useAsTitle) override { BannerView::SetFileNameAsync(taskQueue, fileName, useAsTitle); if (taskQueue) - _filenameLabelView.SetTextAsync(taskQueue, fileName); + _filenameLabelView->SetTextAsync(taskQueue, fileName); else - _filenameLabelView.SetText(fileName); + _filenameLabelView->SetText(fileName); } Rectangle GetBounds() const override @@ -64,9 +64,11 @@ public: } private: - Label2DView _firstLine; - Label2DView _secondLine; - Label2DView _thirdLine; - Label2DView _filenameLabelView; + SharedPtr _firstLine; + SharedPtr _secondLine; + SharedPtr _thirdLine; + SharedPtr _filenameLabelView; const CustomThemeInfo* _customThemeInfo; + + CustomFileInfoView(const CustomThemeInfo* customThemeInfo, const IFontRepository* fontRepository); }; diff --git a/arm9/source/romBrowser/Theme/custom/CustomIconGridItemView.cpp b/arm9/source/romBrowser/Theme/custom/CustomIconGridItemView.cpp index 0b6de73..4674fb8 100644 --- a/arm9/source/romBrowser/Theme/custom/CustomIconGridItemView.cpp +++ b/arm9/source/romBrowser/Theme/custom/CustomIconGridItemView.cpp @@ -26,8 +26,8 @@ void CustomIconGridItemView::Draw(GraphicsContext& graphicsContext) false, false, false, GX_DEPTH_FUNC_LESS, false, 31, 0); Gx::Color(0x7FFF); - u32 tex = _isFocused ? _selectedTexVramOffset : _texVramOffset; - u32 pltt = _isFocused ? _selectedPlttVramOffset : _plttVramOffset; + u32 tex = (_isFocused || _inputHandler.IsPenDown()) ? _selectedTexVramOffset : _texVramOffset; + u32 pltt = (_isFocused || _inputHandler.IsPenDown()) ? _selectedPlttVramOffset : _plttVramOffset; Gx::TexImageParam(tex >> 3, false, false, false, false, GX_TEXSIZE_64, GX_TEXSIZE_64, GX_TEXFMT_A3I5, false, GX_TEXGEN_NONE); Gx::TexPlttBase(pltt >> 4); diff --git a/arm9/source/romBrowser/Theme/custom/CustomIconGridItemView.h b/arm9/source/romBrowser/Theme/custom/CustomIconGridItemView.h index f3a817b..eeb34e7 100644 --- a/arm9/source/romBrowser/Theme/custom/CustomIconGridItemView.h +++ b/arm9/source/romBrowser/Theme/custom/CustomIconGridItemView.h @@ -5,12 +5,9 @@ class CustomThemeInfo; class CustomIconGridItemView : public IconGridItemView { -public: - CustomIconGridItemView(const CustomThemeInfo* customThemeInfo, u32 texVramOffset, u32 plttVramOffset, - u32 selectedTexVramOffset, u32 selectedPlttVramOffset) - : _customThemeInfo(customThemeInfo), _texVramOffset(texVramOffset), _plttVramOffset(plttVramOffset) - , _selectedTexVramOffset(selectedTexVramOffset), _selectedPlttVramOffset(selectedPlttVramOffset) { } + SHARED_ONLY(CustomIconGridItemView) +public: void Draw(GraphicsContext& graphicsContext) override; Rectangle GetBounds() const override @@ -24,4 +21,9 @@ private: u32 _plttVramOffset; u32 _selectedTexVramOffset; u32 _selectedPlttVramOffset; + + CustomIconGridItemView(std::unique_ptr viewModel, const CustomThemeInfo* customThemeInfo, + u32 texVramOffset, u32 plttVramOffset, u32 selectedTexVramOffset, u32 selectedPlttVramOffset) + : IconGridItemView(std::move(viewModel)), _customThemeInfo(customThemeInfo), _texVramOffset(texVramOffset), _plttVramOffset(plttVramOffset) + , _selectedTexVramOffset(selectedTexVramOffset), _selectedPlttVramOffset(selectedPlttVramOffset) { } }; \ No newline at end of file diff --git a/arm9/source/romBrowser/Theme/custom/CustomRomBrowserViewFactory.h b/arm9/source/romBrowser/Theme/custom/CustomRomBrowserViewFactory.h index 431b350..6b32be5 100644 --- a/arm9/source/romBrowser/Theme/custom/CustomRomBrowserViewFactory.h +++ b/arm9/source/romBrowser/Theme/custom/CustomRomBrowserViewFactory.h @@ -21,15 +21,16 @@ public: const IFontRepository* fontRepository) : _customThemeInfo(customThemeInfo), _materialColorScheme(materialColorScheme), _fontRepository(fontRepository) { } - SharedPtr CreateIconGridItemView() const override + SharedPtr CreateIconGridItemView(std::unique_ptr viewModel) const override { - return SharedPtr::MakeShared(_customThemeInfo, _gridCellTexVramOffset, _gridCellPlttVramOffset, + return CustomIconGridItemView::CreateShared(std::move(viewModel), _customThemeInfo, _gridCellTexVramOffset, _gridCellPlttVramOffset, _gridCellSelectedTexVramOffset, _gridCellSelectedPlttVramOffset); } - SharedPtr CreateBannerListItemView(VBlankTextureLoader* vblankTextureLoader) const override + SharedPtr CreateBannerListItemView(std::unique_ptr viewModel, + VBlankTextureLoader* vblankTextureLoader) const override { - return SharedPtr::MakeShared(_customThemeInfo, _materialColorScheme, _fontRepository, + return CustomBannerListItemView::CreateShared(std::move(viewModel), _customThemeInfo, _materialColorScheme, _fontRepository, _bannerListCellTexVramOffset, _bannerListCellPlttVramOffset, _bannerListCellSelectedTexVramOffset, _bannerListCellSelectedPlttVramOffset, vblankTextureLoader); } @@ -39,16 +40,16 @@ public: return BannerListItemView::VramToken(0); } - std::unique_ptr CreateAppBarView(int x, int y, AppBarView::Orientation orientation, + SharedPtr CreateAppBarView(int x, int y, AppBarView::Orientation orientation, int startButtonCount, int endButtonCount) const override { - return std::make_unique(x, y, orientation, startButtonCount, endButtonCount, _materialColorScheme, + return CustomAppBarView::CreateShared(x, y, orientation, startButtonCount, endButtonCount, _materialColorScheme, _scrimTexVramOffset, _scrimPlttVramOffset); } - std::unique_ptr CreateFileInfoView() const override + SharedPtr CreateFileInfoView() const override { - return std::make_unique(_customThemeInfo, _fontRepository); + return CustomFileInfoView::CreateShared(_customThemeInfo, _fontRepository); } SharedPtr CreateCoverFlowRecyclerView() const override @@ -60,7 +61,7 @@ public: RomBrowserViewModel* viewModel, const IThemeFileIconFactory* themeFileIconFactory, VBlankTextureLoader* vblankTextureLoader) const override { - return SharedPtr::MakeShared( + return SharedPtr::MakeShared(viewModel->GetRomBrowserController(), &viewModel->GetFileInfoManager(), viewModel->GetIoTaskQueue(), themeFileIconFactory, this, vblankTextureLoader, &viewModel->GetCoverRepository()); } diff --git a/arm9/source/romBrowser/viewModels/CheatsViewModel.cpp b/arm9/source/romBrowser/viewModels/CheatsViewModel.cpp index be7bc9b..85c62b2 100644 --- a/arm9/source/romBrowser/viewModels/CheatsViewModel.cpp +++ b/arm9/source/romBrowser/viewModels/CheatsViewModel.cpp @@ -24,7 +24,7 @@ CheatsViewModel::CheatsViewModel(const FileInfo& romFileInfo, IRomBrowserControl }); } -void CheatsViewModel::ActivateSelectedItem() +void CheatsViewModel::ActivateItem(int index) { if (_state != State::DisplayCheats) { @@ -36,19 +36,19 @@ void CheatsViewModel::ActivateSelectedItem() u32 numberOfSubEntries = 0; auto subEntries = cheatCategory->GetSubEntries(numberOfSubEntries); - if (numberOfSubEntries == 0) + if (numberOfSubEntries == 0 || index < 0 || index >= (int)numberOfSubEntries) { // There is nothing to activate return; } - auto& entry = subEntries[_selectedItem]; + auto& entry = subEntries[index]; if (entry.IsCheatCategory()) { // Category activated if (_categoryStackLevel + 1 != _categoryStack.size()) { - _categoryStack[++_categoryStackLevel] = { &entry, (u32)_selectedItem }; + _categoryStack[++_categoryStackLevel] = { &entry, (u32)index }; _selectedItem = 0; } } diff --git a/arm9/source/romBrowser/viewModels/CheatsViewModel.h b/arm9/source/romBrowser/viewModels/CheatsViewModel.h index 7b0d2c3..f4264cf 100644 --- a/arm9/source/romBrowser/viewModels/CheatsViewModel.h +++ b/arm9/source/romBrowser/viewModels/CheatsViewModel.h @@ -25,8 +25,8 @@ public: CheatsViewModel(const FileInfo& romFileInfo, IRomBrowserController* romBrowserController); - /// @brief Activates the selected cheat or category. - void ActivateSelectedItem(); + /// @brief Activates the cheat or category at the specified \p index. + void ActivateItem(int index); /// @brief Navigates up in the cheat hierachy, or closes the cheats panel when at the root. /// @return \c true when navigation happened in the cheats tree, or \c false when the cheats panel was closed. @@ -54,9 +54,9 @@ public: /// @param selectedItem The index of the selected item to set. void SetSelectedItem(int selectedItem) { _selectedItem = selectedItem; } - /// @brief Returns whether the category name should be displayed. - /// @return \c true when the category name should be displayed, or \c false otherwise. - bool ShouldShowCategoryName() const + /// @brief Returns whether the current displayed category is a sub-category. + /// @return \c true when the current displayed category is a sub-category, or \c false otherwise. + bool IsInSubCategory() const { return _categoryStackLevel > 0; } diff --git a/arm9/source/romBrowser/viewModels/RomBrowserItemViewModel.cpp b/arm9/source/romBrowser/viewModels/RomBrowserItemViewModel.cpp new file mode 100644 index 0000000..3419fbe --- /dev/null +++ b/arm9/source/romBrowser/viewModels/RomBrowserItemViewModel.cpp @@ -0,0 +1,33 @@ +#include "common.h" +#include "romBrowser/IRomBrowserController.h" +#include "RomBrowserViewModel.h" +#include "romBrowser/FileType/Nds/NdsFileType.h" +#include "RomBrowserItemViewModel.h" + +void RomBrowserItemViewModel::Activate() +{ + if (_index >= 0) + { + const auto& item = _romBrowserController->GetRomBrowserViewModel()->GetFileInfoManager().GetItem(_index); + if (item.GetFileType()->GetClassification() == FileTypeClassification::Folder) + { + _romBrowserController->NavigateToPath(item.GetFileName()); + } + else + { + _romBrowserController->LaunchFile(item); + } + } +} + +void RomBrowserItemViewModel::ShowGameInfo() +{ + if (_index >= 0) + { + const auto& item = _romBrowserController->GetRomBrowserViewModel()->GetFileInfoManager().GetItem(_index); + if (item.GetFileType() == &NdsFileType::sInstance) + { + _romBrowserController->ShowGameInfo(item); + } + } +} diff --git a/arm9/source/romBrowser/viewModels/RomBrowserItemViewModel.h b/arm9/source/romBrowser/viewModels/RomBrowserItemViewModel.h new file mode 100644 index 0000000..dcdbf72 --- /dev/null +++ b/arm9/source/romBrowser/viewModels/RomBrowserItemViewModel.h @@ -0,0 +1,43 @@ +#pragma once +#include "core/task/TaskQueue.h" + +class IRomBrowserController; + +class RomBrowserItemViewModel +{ +public: + explicit RomBrowserItemViewModel(IRomBrowserController* romBrowserController) + : _romBrowserController(romBrowserController) { } + + void Activate(); + void ShowGameInfo(); + + void SetIndex(int index) + { + _index = index; + } + + void SetQueueTask(QueueTask queueTask) + { + _queueTask = std::move(queueTask); + } + + void CancelQueueTask() + { + _queueTask.CancelTask(); + } + + void DisposeQueueTaskWhenComplete() + { + if (_queueTask.GetTask().IsCompleted()) + { + _queueTask.Dispose(); + } + } + +private: + int _index = -1; + QueueTask _queueTask; + + IRomBrowserController* _romBrowserController; +}; diff --git a/arm9/source/romBrowser/viewModels/RomBrowserViewModel.cpp b/arm9/source/romBrowser/viewModels/RomBrowserViewModel.cpp index 9412adb..37f91c0 100644 --- a/arm9/source/romBrowser/viewModels/RomBrowserViewModel.cpp +++ b/arm9/source/romBrowser/viewModels/RomBrowserViewModel.cpp @@ -40,29 +40,7 @@ RomBrowserViewModel::RomBrowserViewModel(IRomBrowserController* romBrowserContro _selectedItem = _fileInfoManager->GetItemIndex(initialSelectedFileName); } -void RomBrowserViewModel::ItemActivated() -{ - const auto& item = _fileInfoManager->GetItem(_selectedItem); - if (item.GetFileType()->GetClassification() == FileTypeClassification::Folder) - { - _romBrowserController->NavigateToPath(item.GetFileName()); - } - else - { - _romBrowserController->LaunchFile(item); - } -} - void RomBrowserViewModel::NavigateUp() { _romBrowserController->NavigateUp(); } - -void RomBrowserViewModel::ShowGameInfo() -{ - const auto& item = _fileInfoManager->GetItem(_selectedItem); - if (item.GetFileType() == &NdsFileType::sInstance) - { - _romBrowserController->ShowGameInfo(item); - } -} \ No newline at end of file diff --git a/arm9/source/romBrowser/viewModels/RomBrowserViewModel.h b/arm9/source/romBrowser/viewModels/RomBrowserViewModel.h index 5e4aeb9..1d75a5d 100644 --- a/arm9/source/romBrowser/viewModels/RomBrowserViewModel.h +++ b/arm9/source/romBrowser/viewModels/RomBrowserViewModel.h @@ -13,6 +13,7 @@ class RomBrowserViewModel public: RomBrowserViewModel(IRomBrowserController* romBrowserController, const char* initialSelectedFileName = nullptr); + IRomBrowserController* GetRomBrowserController() const { return _romBrowserController; } FileInfoManager& GetFileInfoManager() const { return *_fileInfoManager; } TaskQueueBase* GetIoTaskQueue() const { return _romBrowserController->GetIoTaskQueue(); } TaskQueueBase* GetBgTaskQueue() const { return _romBrowserController->GetBgTaskQueue(); } @@ -24,9 +25,7 @@ public: constexpr u32 GetIconFrameCounter() const { return _iconFrameCounter; } void SetIconFrameCounter(u32 iconFrameCounter) { _iconFrameCounter = iconFrameCounter; } - void ItemActivated(); void NavigateUp(); - void ShowGameInfo(); private: IRomBrowserController* _romBrowserController; diff --git a/arm9/source/romBrowser/views/BannerListItemView.cpp b/arm9/source/romBrowser/views/BannerListItemView.cpp index 5811d2d..b6987e8 100644 --- a/arm9/source/romBrowser/views/BannerListItemView.cpp +++ b/arm9/source/romBrowser/views/BannerListItemView.cpp @@ -1,21 +1,26 @@ #include "common.h" #include "gui/IVramManager.h" #include "gui/GraphicsContext.h" +#include "gui/input/InputProvider.h" #include "BannerListItemView.h" -BannerListItemView::BannerListItemView(std::unique_ptr firstLine, - std::unique_ptr secondLine, std::unique_ptr thirdLine) - : _firstLine(std::move(firstLine)) +BannerListItemView::BannerListItemView(std::unique_ptr viewModel, + SharedPtr firstLine, SharedPtr secondLine, SharedPtr thirdLine) + : _viewModel(std::move(viewModel)) + , _firstLine(std::move(firstLine)) , _secondLine(std::move(secondLine)) , _thirdLine(std::move(thirdLine)) + , _inputHandler(this, _viewModel.get()) { - AddChildTail(_firstLine.get()); - AddChildTail(_secondLine.get()); - AddChildTail(_thirdLine.get()); + AddChildTail(_firstLine.GetPointer()); + AddChildTail(_secondLine.GetPointer()); + AddChildTail(_thirdLine.GetPointer()); } void BannerListItemView::Update() { + _viewModel->DisposeQueueTaskWhenComplete(); + ViewContainer::Update(); if (_icon) @@ -23,3 +28,24 @@ void BannerListItemView::Update() _icon->Update(); } } + +bool BannerListItemView::HandleInput(const InputProvider& inputProvider, FocusManager& focusManager) +{ + return _inputHandler.HandleInput(inputProvider, focusManager) + || View::HandleInput(inputProvider, focusManager); +} + +void BannerListItemView::HandlePenDown(const Point& touchPoint, FocusManager& focusManager) +{ + _inputHandler.HandlePenDown(touchPoint, focusManager); +} + +void BannerListItemView::HandlePenMove(const Point& touchPoint, FocusManager& focusManager) +{ + _inputHandler.HandlePenMove(touchPoint, focusManager); +} + +void BannerListItemView::HandlePenUp(const Point& lastTouchPoint, FocusManager& focusManager) +{ + _inputHandler.HandlePenUp(lastTouchPoint, focusManager); +} diff --git a/arm9/source/romBrowser/views/BannerListItemView.h b/arm9/source/romBrowser/views/BannerListItemView.h index 2df16cb..f7f3993 100644 --- a/arm9/source/romBrowser/views/BannerListItemView.h +++ b/arm9/source/romBrowser/views/BannerListItemView.h @@ -2,6 +2,8 @@ #include "BannerView.h" #include "gui/views/LabelView.h" #include "../FileType/FileIcon.h" +#include "romBrowser/viewModels/RomBrowserItemViewModel.h" +#include "RomBrowserItemInputHandler.h" class BannerListItemView : public BannerView { @@ -19,11 +21,13 @@ public: constexpr u32 GetVramOffset() const { return _vramOffset; } }; - BannerListItemView(std::unique_ptr firstLine, - std::unique_ptr secondLine, std::unique_ptr thirdLine); - void Update() override; + bool HandleInput(const InputProvider& inputProvider, FocusManager& focusManager) override; + void HandlePenDown(const Point& touchPoint, FocusManager& focusManager) override; + void HandlePenMove(const Point& touchPoint, FocusManager& focusManager) override; + void HandlePenUp(const Point& lastTouchPoint, FocusManager& focusManager) override; + virtual void SetGraphics(const VramToken& vramToken) { } void SetFirstLineAsync(TaskQueueBase* taskQueue, const char* firstLine, bool ellipsis) override @@ -60,8 +64,18 @@ public: _thirdLine->SetText(thirdLine, length); } + RomBrowserItemViewModel& GetViewModel() const + { + return *_viewModel; + } + protected: - std::unique_ptr _firstLine; - std::unique_ptr _secondLine; - std::unique_ptr _thirdLine; + std::unique_ptr _viewModel; + SharedPtr _firstLine; + SharedPtr _secondLine; + SharedPtr _thirdLine; + RomBrowserItemInputHandler _inputHandler; + + BannerListItemView(std::unique_ptr viewModel, SharedPtr firstLine, + SharedPtr secondLine, SharedPtr thirdLine); }; diff --git a/arm9/source/romBrowser/views/BottomSheetView.cpp b/arm9/source/romBrowser/views/BottomSheetView.cpp new file mode 100644 index 0000000..ea6ccf1 --- /dev/null +++ b/arm9/source/romBrowser/views/BottomSheetView.cpp @@ -0,0 +1,34 @@ +#include "common.h" +#include "BottomSheetView.h" + +void BottomSheetView::HandlePenDown(const Point& touchPoint, FocusManager& focusManager) +{ + DialogView::HandlePenDown(touchPoint, focusManager); + + if (!GetBounds().Contains(touchPoint)) + { + _oobPenDown = true; + } +} + +void BottomSheetView::HandlePenMove(const Point& touchPoint, FocusManager& focusManager) +{ + DialogView::HandlePenMove(touchPoint, focusManager); + + if (GetBounds().Contains(touchPoint)) + { + _oobPenDown = false; + } +} + +void BottomSheetView::HandlePenUp(const Point& lastTouchPoint, FocusManager& focusManager) +{ + DialogView::HandlePenUp(lastTouchPoint, focusManager); + + if (_oobPenDown && !GetBounds().Contains(lastTouchPoint)) + { + Close(); + } + + _oobPenDown = false; +} diff --git a/arm9/source/romBrowser/views/BottomSheetView.h b/arm9/source/romBrowser/views/BottomSheetView.h index aafb6dd..d50800c 100644 --- a/arm9/source/romBrowser/views/BottomSheetView.h +++ b/arm9/source/romBrowser/views/BottomSheetView.h @@ -5,6 +5,10 @@ class BottomSheetView : public DialogView { public: + void HandlePenDown(const Point& touchPoint, FocusManager& focusManager) override; + void HandlePenMove(const Point& touchPoint, FocusManager& focusManager) override; + void HandlePenUp(const Point& lastTouchPoint, FocusManager& focusManager) override; + Rectangle GetBounds() const override { return Rectangle(_position.x, _position.y, 256 - _position.x, 192 - _position.y); @@ -16,4 +20,10 @@ public: } constexpr DialogType GetDialogType() const override { return DialogType::BottomSheet; } + +protected: + virtual void Close() = 0; + +private: + bool _oobPenDown = false; }; diff --git a/arm9/source/romBrowser/views/ChipView.cpp b/arm9/source/romBrowser/views/ChipView.cpp index 210ec4e..ca3e672 100644 --- a/arm9/source/romBrowser/views/ChipView.cpp +++ b/arm9/source/romBrowser/views/ChipView.cpp @@ -40,13 +40,13 @@ void ChipView::Draw(GraphicsContext& graphicsContext) DirectPalette(chipPltt), _position.y, _position.y + 20); if (!_isFocused) { - _label.SetBackgroundColor(_materialColorScheme->secondaryContainer); - _label.SetForegroundColor(_materialColorScheme->onSecondaryContainer); + _label->SetBackgroundColor(_materialColorScheme->secondaryContainer); + _label->SetForegroundColor(_materialColorScheme->onSecondaryContainer); } else { - _label.SetBackgroundColor(fgColor); - _label.SetForegroundColor(_materialColorScheme->onSecondaryContainer); + _label->SetBackgroundColor(fgColor); + _label->SetForegroundColor(_materialColorScheme->onSecondaryContainer); } } else @@ -70,13 +70,13 @@ void ChipView::Draw(GraphicsContext& graphicsContext) if (!_isFocused) { - _label.SetBackgroundColor(_materialColorScheme->GetColor(_backgroundColor)); - _label.SetForegroundColor(_materialColorScheme->onSurfaceVariant); + _label->SetBackgroundColor(_materialColorScheme->GetColor(_backgroundColor)); + _label->SetForegroundColor(_materialColorScheme->onSurfaceVariant); } else { - _label.SetBackgroundColor(fgColor); - _label.SetForegroundColor(_materialColorScheme->onSurfaceVariant); + _label->SetBackgroundColor(fgColor); + _label->SetForegroundColor(_materialColorScheme->onSurfaceVariant); } } @@ -88,7 +88,7 @@ void ChipView::Draw(GraphicsContext& graphicsContext) .WithPriority(graphicsContext.GetPriority()) .Build(oams[0]); OamBuilder::OamWithSize<64, 32>( - _position.x + width - 48 - 16, + _position.x + width - 48 - 16, _position.y, _vramOffset >> 7) .WithPalette16(paletteRow) .WithPriority(graphicsContext.GetPriority()) @@ -97,8 +97,8 @@ void ChipView::Draw(GraphicsContext& graphicsContext) DrawIcon(graphicsContext, fgColor); - _label.SetPosition(_position.x + (_iconVramOffset == 0xFFFFFFFF ? 10 : 22), _position.y + 3); - _label.Draw(graphicsContext); + _label->SetPosition(_position.x + (_iconVramOffset == 0xFFFFFFFF ? 10 : 22), _position.y + 3); + _label->Draw(graphicsContext); } void ChipView::DrawIcon(GraphicsContext& graphicsContext, const Rgb<8, 8, 8>& fgColor) @@ -135,4 +135,4 @@ ChipView::VramToken ChipView::UploadGraphics(IVramManager& vramManager) u32 vramOffset = vramManager.Alloc(chipFilledTilesLen); dma_ntrCopy32(3, chipFilledTiles, vramManager.GetVramAddress(vramOffset), chipFilledTilesLen); return ChipView::VramToken(vramOffset); -} \ No newline at end of file +} diff --git a/arm9/source/romBrowser/views/ChipView.h b/arm9/source/romBrowser/views/ChipView.h index af60300..1d9c45b 100644 --- a/arm9/source/romBrowser/views/ChipView.h +++ b/arm9/source/romBrowser/views/ChipView.h @@ -13,6 +13,8 @@ class IVramManager; class ChipView : public View { + SHARED_ONLY(ChipView) + public: class VramToken { @@ -27,22 +29,16 @@ public: constexpr u32 GetVramOffset() const { return _vramOffset; } }; - explicit ChipView(md::sys::color backgroundColor, const MaterialColorScheme* materialColorScheme, - const IFontRepository* fontRepository) - : _vramOffset(0), _isSelected(false), _backgroundColor(backgroundColor) - , _label(CHIP_VIEW_MAX_WIDTH - 20, 16, 30, fontRepository->GetFont(FontType::Medium10)) - , _iconVramOffset(0xFFFFFFFF), _materialColorScheme(materialColorScheme) { } + void InitVram(const VramContext& vramContext) override { _label->InitVram(vramContext); } - void InitVram(const VramContext& vramContext) override { _label.InitVram(vramContext); } - - void SetText(const char16_t* text) { _label.SetText(text); } - void SetText(const char16_t* text, u32 length) { _label.SetText(text, length); } - QueueTask SetTextAsync(TaskQueueBase* taskQueue, const char16_t* text) { return _label.SetTextAsync(taskQueue, text); } - QueueTask SetTextAsync(TaskQueueBase* taskQueue, const char16_t* text, u32 length) { return _label.SetTextAsync(taskQueue, text, length); } + void SetText(const char16_t* text) { _label->SetText(text); } + void SetText(const char16_t* text, u32 length) { _label->SetText(text, length); } + QueueTask SetTextAsync(TaskQueueBase* taskQueue, const char16_t* text) { return _label->SetTextAsync(taskQueue, text); } + QueueTask SetTextAsync(TaskQueueBase* taskQueue, const char16_t* text, u32 length) { return _label->SetTextAsync(taskQueue, text, length); } void Draw(GraphicsContext& graphicsContext) override; - void VBlank() override { _label.VBlank(); } + void VBlank() override { _label->VBlank(); } void SetGraphics(const VramToken& vramToken) { @@ -63,9 +59,13 @@ public: { int width; if (_iconVramOffset == 0xFFFFFFFF) - width = 10 + _label.GetStringWidth() + 10; + { + width = 10 + _label->GetStringWidth() + 10; + } else - width = 22 + _label.GetStringWidth() + 10; + { + width = 22 + _label->GetStringWidth() + 10; + } width = std::clamp(width, CHIP_VIEW_MIN_WIDTH, CHIP_VIEW_MAX_WIDTH); return width; } @@ -83,9 +83,15 @@ private: u32 _vramOffset; bool _isSelected; md::sys::color _backgroundColor; - Label2DView _label; + SharedPtr _label; u32 _iconVramOffset; const MaterialColorScheme* _materialColorScheme; + ChipView(md::sys::color backgroundColor, const MaterialColorScheme* materialColorScheme, + const IFontRepository* fontRepository) + : _vramOffset(0), _isSelected(false), _backgroundColor(backgroundColor) + , _label(Label2DView::CreateShared(CHIP_VIEW_MAX_WIDTH - 20, 16, 30, fontRepository->GetFont(FontType::Medium10))) + , _iconVramOffset(0xFFFFFFFF), _materialColorScheme(materialColorScheme) { } + void DrawIcon(GraphicsContext& graphicsContext, const Rgb<8, 8, 8>& fgColor); }; \ No newline at end of file diff --git a/arm9/source/romBrowser/views/CoverFlowRecyclerView.cpp b/arm9/source/romBrowser/views/CoverFlowRecyclerView.cpp index 75b8db3..967f86d 100644 --- a/arm9/source/romBrowser/views/CoverFlowRecyclerView.cpp +++ b/arm9/source/romBrowser/views/CoverFlowRecyclerView.cpp @@ -5,6 +5,7 @@ #include "gui/Gx.h" #include "gui/GraphicsContext.h" #include "gui/materialDesign.h" +#include "gui/input/InputProvider.h" #include "core/math/SinTable.h" #include "romBrowser/FileType/FileCover.h" #include "CoverFlowRecyclerView.h" @@ -18,8 +19,10 @@ void CoverFlowRecyclerView::Update() return; } - int rangeStartIndex = GetSelectedItem() - 4; - int rangeEndIndex = GetSelectedItem() + 1 + 4; + _scrollAnimator.Update(); + + int rangeStartIndex = _scrollAnimator.GetValue().Int() - 4; + int rangeEndIndex = _scrollAnimator.GetValue().Int() + 1 + 4; rangeStartIndex = std::clamp(rangeStartIndex, 0, (int)_itemCount - 1); rangeEndIndex = std::clamp(rangeEndIndex, 0, (int)_itemCount); @@ -43,10 +46,8 @@ void CoverFlowRecyclerView::Update() for (u32 i = _viewPoolFreeCount; i < _viewPool.size(); i++) { - _viewPoolEx[i].yAngleAnimator.Update(); - _viewPoolEx[i].xPositionAnimator.Update(); - _viewPoolEx[i].zPositionAnimator.Update(); - _viewPool[i].view->SetPosition(_viewPoolEx[i].xPositionAnimator.GetValue().Int(), 32 + 80); + UpdateItemPosition(i); + _viewPool[i].view->SetPosition(_viewPoolEx[i].xPosition.Int(), 32 + 80); _viewPool[i].view->Update(); } } @@ -86,9 +87,9 @@ void CoverFlowRecyclerView::Draw(GraphicsContext& graphicsContext) graphicsContext.SetPolygonId(i); Gx::MtxPush(); { - fix32<12> x = _viewPoolEx[i].xPositionAnimator.GetValue(); - u32 angle = _viewPoolEx[i].yAngleAnimator.GetValue(); - fix32<12> z = _viewPoolEx[i].zPositionAnimator.GetValue(); + fix32<12> x = _viewPoolEx[i].xPosition; + u32 angle = _viewPoolEx[i].yAngle; + fix32<12> z = _viewPoolEx[i].zPosition; auto sinCos = gSinTable.SinCos(angle); mtx43_t rotMtx = { @@ -110,47 +111,144 @@ void CoverFlowRecyclerView::Draw(GraphicsContext& graphicsContext) Gx::MtxMode(GX_MTX_MODE_POSITION_VECTOR); } -void CoverFlowRecyclerView::UpdateItemPosition(int viewPoolIndex, bool initial) +bool CoverFlowRecyclerView::HandleInput(const InputProvider& inputProvider, FocusManager& focusManager) { - ViewPoolEntry* item = &_viewPool[viewPoolIndex]; - ViewPoolEntryEx* itemEx = &_viewPoolEx[viewPoolIndex]; - int selectedIndex = GetSelectedItem(); - if (selectedIndex == -1) + if (_itemCount != 0 && inputProvider.Triggered(InputKey::L | InputKey::R)) { - selectedIndex = 0; + int direction = inputProvider.Triggered(InputKey::L) ? -1 : 1; + int selected = std::clamp(_selectedItem->itemIdx + 10 * direction, 0, (int)_itemCount - 1); + + focusManager.Unfocus(); + SetSelectedItem(selected, false); + focusManager.Focus(_selectedItem->view); + return true; } - int itemIndex = item->itemIdx; - fix32<12> x; - fix32<12> z = 0; - u32 angle; - if (itemIndex < selectedIndex) + + return View::HandleInput(inputProvider, focusManager); +} + +void CoverFlowRecyclerView::HandlePenDown(const Point& touchPoint, FocusManager& focusManager) +{ + if (GetBounds().Contains(touchPoint)) { - x = 256 / 2 - (COVER_HEIGHT / 4) + COVER_SPACING * (itemIndex - selectedIndex); - angle = std::clamp((selectedIndex - itemIndex) * 10 + 45, -90, 90) * (1 << 16) / 360; - z = -(selectedIndex - itemIndex) * 30 - 20; + _penDown = true; + _penDownPosition = touchPoint; + _hasScrollStarted = false; + _penDownScrollOffset = _scrollAnimator.GetValue(); + + if (_itemCount > 0) + { + _selectedItem->view->HandlePenDown(touchPoint, focusManager); + } } - else if (itemIndex > selectedIndex) +} + +void CoverFlowRecyclerView::HandlePenMove(const Point& touchPoint, FocusManager& focusManager) +{ + if (!_penDown) { - x = 256 / 2 + (COVER_HEIGHT / 4) + COVER_SPACING * (itemIndex - selectedIndex); - angle = std::clamp((selectedIndex - itemIndex) * 10 - 45, -90, 90) * (1 << 16) / 360; - z = (selectedIndex - itemIndex) * 30 - 20; + return; + } + + if (!_hasScrollStarted) + { + if (_itemCount > 0) + { + _selectedItem->view->HandlePenMove(touchPoint, focusManager); + } + + int dx = touchPoint.x - _penDownPosition.x; + int dy = touchPoint.y - _penDownPosition.y; + if (dx * dx + dy * dy > 7 * 7) + { + bool shouldScrollStart = std::abs(touchPoint.x - _penDownPosition.x) > std::abs(touchPoint.y - _penDownPosition.y); + if (shouldScrollStart) + { + _hasScrollStarted = true; + } + else + { + _penDown = false; //wrong direction drag, so cancel it + } + + if (_itemCount > 0) + { + _selectedItem->view->HandlePenUp(Point(-1, -1), focusManager); + } + } } else { - x = 256 / 2; - angle = 0; + fix32<12> newScrollOffset = _penDownScrollOffset + fix32<12>(_penDownPosition.x - touchPoint.x) * (2.5 / COVER_WIDTH); + if (newScrollOffset < 0) + { + newScrollOffset = 0; + _penDownScrollOffset = 0; + _penDownPosition.x = touchPoint.x; + } + else if (newScrollOffset > (int)_itemCount - 1) + { + newScrollOffset = (int)_itemCount - 1; + _penDownScrollOffset = newScrollOffset; + _penDownPosition.x = touchPoint.x; + } + + _scrollAnimator = Animator>(newScrollOffset); + } +} + +void CoverFlowRecyclerView::HandlePenUp(const Point& lastTouchPoint, FocusManager& focusManager) +{ + if (_hasScrollStarted) + { + SetSelectedItem((_scrollAnimator.GetValue() + 0.5).Int(), false); + } + + if (_itemCount > 0) + { + _selectedItem->view->HandlePenUp(lastTouchPoint, focusManager); + focusManager.Focus(_selectedItem->view); + } + + _penDown = false; +} + +void CoverFlowRecyclerView::SetSelectedItem(int itemIdx, bool initial) +{ + CoverFlowRecyclerViewBase::SetSelectedItem(itemIdx, initial); + + if (itemIdx < 0 || itemIdx >= (int)_itemCount) + { + return; } if (initial) { - itemEx->yAngleAnimator = Animator(angle); - itemEx->xPositionAnimator = Animator(x); - itemEx->zPositionAnimator = Animator(z); + _scrollAnimator = Animator>(itemIdx); } else { - itemEx->yAngleAnimator.Goto(angle, md::sys::motion::duration::medium4, &md::sys::motion::easing::standard); - itemEx->xPositionAnimator.Goto(x, md::sys::motion::duration::medium4, &md::sys::motion::easing::standard); - itemEx->zPositionAnimator.Goto(z, md::sys::motion::duration::medium4, &md::sys::motion::easing::standard); + _scrollAnimator.Goto(itemIdx, md::sys::motion::duration::medium4, &md::sys::motion::easing::standard); } } + +void CoverFlowRecyclerView::UpdateItemPosition(int viewPoolIndex) +{ + auto& item = _viewPool[viewPoolIndex]; + auto& itemEx = _viewPoolEx[viewPoolIndex]; + int itemIndex = item.itemIdx; + fix32<12> absOffsetFromCenter = (itemIndex - _scrollAnimator.GetValue()).Abs(); + fix32<12> initialOffsetFromCenter = absOffsetFromCenter.Clamp(0, 1); + fix32<12> x = (COVER_HEIGHT / 4) * initialOffsetFromCenter + COVER_SPACING * absOffsetFromCenter; + int angle = -(fix32<16>((absOffsetFromCenter * 10 + 45 * initialOffsetFromCenter).Clamp(-90, 90)) / 360).GetRawValue(); + fix32<12> z = -absOffsetFromCenter * 30 - 20 * initialOffsetFromCenter; + if (itemIndex <= _scrollAnimator.GetValue().Int()) + { + x = -x; + angle = -angle; + } + + itemEx.yAngle = angle; + itemEx.xPosition = x + 256 / 2; + itemEx.zPosition = z; +} diff --git a/arm9/source/romBrowser/views/CoverFlowRecyclerView.h b/arm9/source/romBrowser/views/CoverFlowRecyclerView.h index 0c8baf4..4ab7eb0 100644 --- a/arm9/source/romBrowser/views/CoverFlowRecyclerView.h +++ b/arm9/source/romBrowser/views/CoverFlowRecyclerView.h @@ -5,30 +5,37 @@ class CoverFlowRecyclerView : public CoverFlowRecyclerViewBase { - struct Private { explicit Private() = default; }; + SHARED_ONLY(CoverFlowRecyclerView) public: - explicit CoverFlowRecyclerView(Private) { } - - static SharedPtr CreateShared() - { - return SharedPtr::MakeShared(Private()); - } - void Update() override; void Draw(GraphicsContext& graphicsContext) override; + bool HandleInput(const InputProvider& inputProvider, FocusManager& focusManager) override; + void HandlePenDown(const Point& touchPoint, FocusManager& focusManager) override; + void HandlePenMove(const Point& touchPoint, FocusManager& focusManager) override; + void HandlePenUp(const Point& lastTouchPoint, FocusManager& focusManager) override; + private: struct ViewPoolEntryEx { - Animator yAngleAnimator; - Animator> xPositionAnimator; - Animator> zPositionAnimator; + int yAngle; + fix32<12> xPosition; + fix32<12> zPosition; }; std::array _viewPoolEx; + Animator> _scrollAnimator = Animator>(0); + bool _penDown = false; + Point _penDownPosition = Point(0, 0); + bool _hasScrollStarted = false; + fix32<12> _penDownScrollOffset = 0; - void UpdateItemPosition(int viewPoolIndex, bool initial) override; + explicit CoverFlowRecyclerView() { } + + void SetSelectedItem(int itemIdx, bool initial) override; + + void UpdateItemPosition(int viewPoolIndex); void SwapViewPoolEntry(int indexA, int indexB) override { diff --git a/arm9/source/romBrowser/views/CoverFlowRecyclerViewBase.cpp b/arm9/source/romBrowser/views/CoverFlowRecyclerViewBase.cpp index 3d47331..0bcbe93 100644 --- a/arm9/source/romBrowser/views/CoverFlowRecyclerViewBase.cpp +++ b/arm9/source/romBrowser/views/CoverFlowRecyclerViewBase.cpp @@ -115,7 +115,6 @@ CoverFlowRecyclerViewBase::ViewPoolEntry* CoverFlowRecyclerViewBase::BindViewPoo _viewPoolFreeCount--; entry.itemIdx = itemIdx; _adapter->BindView(entry.view, itemIdx); - UpdateItemPosition(viewPoolIndex, true); return &entry; } @@ -185,9 +184,4 @@ void CoverFlowRecyclerViewBase::SetSelectedItem(int itemIdx, bool initial) { _selectedItem = BindViewPoolEntry(itemIdx); } - - for (u32 i = _viewPoolFreeCount; i < _viewPool.size(); i++) - { - UpdateItemPosition(i, initial); - } } diff --git a/arm9/source/romBrowser/views/CoverFlowRecyclerViewBase.h b/arm9/source/romBrowser/views/CoverFlowRecyclerViewBase.h index 375de64..52cf846 100644 --- a/arm9/source/romBrowser/views/CoverFlowRecyclerViewBase.h +++ b/arm9/source/romBrowser/views/CoverFlowRecyclerViewBase.h @@ -1,9 +1,8 @@ #pragma once #include -#include "core/EnableSharedFromThis.h" #include "gui/views/RecyclerViewBase.h" -class CoverFlowRecyclerViewBase : public RecyclerViewBase, public EnableSharedFromThis +class CoverFlowRecyclerViewBase : public RecyclerViewBase { public: ~CoverFlowRecyclerViewBase() override; @@ -53,8 +52,7 @@ protected: void BindRange(int start, int end); void ReleaseViewPoolEntry(int itemIdx); void ReleaseRange(int start, int end); - void SetSelectedItem(int itemIdx, bool initial); - virtual void UpdateItemPosition(int viewPoolIndex, bool initial) = 0; + virtual void SetSelectedItem(int itemIdx, bool initial); virtual void SwapViewPoolEntry(int indexA, int indexB) { diff --git a/arm9/source/romBrowser/views/CoverView.cpp b/arm9/source/romBrowser/views/CoverView.cpp index a28ea53..015b499 100644 --- a/arm9/source/romBrowser/views/CoverView.cpp +++ b/arm9/source/romBrowser/views/CoverView.cpp @@ -4,6 +4,7 @@ #include "gui/Gx.h" #include "gui/materialDesign.h" #include "gui/GraphicsContext.h" +#include "gui/input/InputProvider.h" #include "CoverView.h" void CoverView::InitVram(const VramContext& vramContext) @@ -17,6 +18,11 @@ void CoverView::InitVram(const VramContext& vramContext) } } +void CoverView::Update() +{ + _viewModel->DisposeQueueTaskWhenComplete(); +} + void CoverView::Draw(GraphicsContext& graphicsContext) { if (_cover.Lock() && _textureLoadRequest.GetState() == VBlankTextureLoadRequestState::LoadComplete) @@ -93,3 +99,24 @@ void CoverView::UploadCoverGraphics() _vblankTextureLoader->RequestLoad(_textureLoadRequest); } } + +bool CoverView::HandleInput(const InputProvider& inputProvider, FocusManager& focusManager) +{ + return _inputHandler.HandleInput(inputProvider, focusManager) + || View::HandleInput(inputProvider, focusManager); +} + +void CoverView::HandlePenDown(const Point& touchPoint, FocusManager& focusManager) +{ + _inputHandler.HandlePenDown(touchPoint, focusManager); +} + +void CoverView::HandlePenMove(const Point& touchPoint, FocusManager& focusManager) +{ + _inputHandler.HandlePenMove(touchPoint, focusManager); +} + +void CoverView::HandlePenUp(const Point& lastTouchPoint, FocusManager& focusManager) +{ + _inputHandler.HandlePenUp(lastTouchPoint, focusManager); +} diff --git a/arm9/source/romBrowser/views/CoverView.h b/arm9/source/romBrowser/views/CoverView.h index df62e4f..7213274 100644 --- a/arm9/source/romBrowser/views/CoverView.h +++ b/arm9/source/romBrowser/views/CoverView.h @@ -4,15 +4,14 @@ #include "gui/views/View.h" #include "../FileType/FileCover.h" #include "gui/VBlankTextureLoader.h" - -#define COVER_THICKNESS (fix32<12>(0.23).GetRawValue()) +#include "romBrowser/viewModels/RomBrowserItemViewModel.h" +#include "RomBrowserItemInputHandler.h" class CoverView : public View { -public: - explicit CoverView(VBlankTextureLoader* vblankTextureLoader) - : _vblankTextureLoader(vblankTextureLoader) { } + SHARED_ONLY(CoverView) +public: ~CoverView() override { _vblankTextureLoader->CancelLoad(_textureLoadRequest); @@ -20,8 +19,14 @@ public: void InitVram(const VramContext& vramContext) override; + void Update() override; void Draw(GraphicsContext& graphicsContext) override; + bool HandleInput(const InputProvider& inputProvider, FocusManager& focusManager) override; + void HandlePenDown(const Point& touchPoint, FocusManager& focusManager) override; + void HandlePenMove(const Point& touchPoint, FocusManager& focusManager) override; + void HandlePenUp(const Point& lastTouchPoint, FocusManager& focusManager) override; + Rectangle GetBounds() const override { return Rectangle(_position.x - (COVER_WIDTH / 2), _position.y - (COVER_HEIGHT / 2), COVER_WIDTH, COVER_HEIGHT); @@ -41,10 +46,21 @@ public: void UploadCoverGraphics(); + RomBrowserItemViewModel& GetViewModel() const + { + return *_viewModel; + } + private: + std::unique_ptr _viewModel; VBlankTextureLoader* _vblankTextureLoader; AtomicSharedPtr _cover; VBlankTextureLoadRequest _textureLoadRequest; u32 _texVramOffset = 0; u32 _plttVramOffset = 0; + RomBrowserItemInputHandler _inputHandler; + + CoverView(std::unique_ptr viewModel, VBlankTextureLoader* vblankTextureLoader) + : _viewModel(std::move(viewModel)), _vblankTextureLoader(vblankTextureLoader) + , _inputHandler(this, _viewModel.get()) { } }; diff --git a/arm9/source/romBrowser/views/DisplaySettingsBottomSheetView.cpp b/arm9/source/romBrowser/views/DisplaySettingsBottomSheetView.cpp index 3e186a8..3de9fab 100644 --- a/arm9/source/romBrowser/views/DisplaySettingsBottomSheetView.cpp +++ b/arm9/source/romBrowser/views/DisplaySettingsBottomSheetView.cpp @@ -52,18 +52,18 @@ DisplaySettingsBottomSheetView::DisplaySettingsBottomSheetView( DisplaySettingsViewModel* viewModel, const MaterialColorScheme* materialColorScheme, const IFontRepository* fontRepository) : _viewModel(viewModel) - , _titleLabel(128, 16, 25, fontRepository->GetFont(FontType::Medium11)) - , _layoutLabel(64, 16, 25, fontRepository->GetFont(FontType::Regular10)) - , _sortingLabel(64, 16, 25, fontRepository->GetFont(FontType::Regular10)) + , _titleLabel(Label2DView::CreateShared(128, 16, 25, fontRepository->GetFont(FontType::Medium11))) + , _layoutLabel(Label2DView::CreateShared(64, 16, 25, fontRepository->GetFont(FontType::Regular10))) + , _sortingLabel(Label2DView::CreateShared(64, 16, 25, fontRepository->GetFont(FontType::Regular10))) , _materialColorScheme(materialColorScheme) // , _filtersLabel(64, 16, 25, fontRepository->GetFont(FontType::Regular10)) { - _titleLabel.SetText(u"Display Settings"); - AddChildTail(&_titleLabel); - _layoutLabel.SetText(u"Layout"); - AddChildTail(&_layoutLabel); - _sortingLabel.SetText(u"Sorting"); - AddChildTail(&_sortingLabel); + _titleLabel->SetText(u"Display Settings"); + AddChildTail(_titleLabel.GetPointer()); + _layoutLabel->SetText(u"Layout"); + AddChildTail(_layoutLabel.GetPointer()); + _sortingLabel->SetText(u"Sorting"); + AddChildTail(_sortingLabel.GetPointer()); // _filtersLabel.SetText(u"Filters"); // AddChildTail(&_filtersLabel); @@ -90,7 +90,7 @@ DisplaySettingsBottomSheetView::DisplaySettingsBottomSheetView( SharedPtr DisplaySettingsBottomSheetView::CreateLayoutOptionIconButton() { - auto layoutOption = SharedPtr::MakeShared( + auto layoutOption = IconButton2DView::CreateShared( IconButtonView::Type::Tonal, IconButtonView::State::ToggleUnselected, md::sys::color::surfaceContainerLow, @@ -113,7 +113,7 @@ SharedPtr DisplaySettingsBottomSheetView::CreateLayoutOptionIc SharedPtr DisplaySettingsBottomSheetView::CreateSortOptionIconButton() { - auto sortOption = SharedPtr::MakeShared( + auto sortOption = IconButton2DView::CreateShared( IconButtonView::Type::Tonal, IconButtonView::State::ToggleUnselected, md::sys::color::surfaceContainerLow, @@ -175,9 +175,9 @@ void DisplaySettingsBottomSheetView::InitVram(const VramContext& vramContext) void DisplaySettingsBottomSheetView::UpdateLabels() { - _titleLabel.SetPosition(TITLE_LABEL_X, _position.y + TITLE_LABEL_Y); - _layoutLabel.SetPosition(LAYOUT_LABEL_X, _position.y + LAYOUT_LABEL_Y); - _sortingLabel.SetPosition(SORTING_LABEL_X, _position.y + SORTING_LABEL_Y); + _titleLabel->SetPosition(TITLE_LABEL_X, _position.y + TITLE_LABEL_Y); + _layoutLabel->SetPosition(LAYOUT_LABEL_X, _position.y + LAYOUT_LABEL_Y); + _sortingLabel->SetPosition(SORTING_LABEL_X, _position.y + SORTING_LABEL_Y); // _filtersLabel.SetPosition(FILTERS_LABEL_X, _position.y + FILTERS_LABEL_Y); } @@ -222,12 +222,12 @@ void DisplaySettingsBottomSheetView::Draw(GraphicsContext& graphicsContext) graphicsContext.SetClipArea(GetBounds()); u32 oldPrio = graphicsContext.SetPriority(1); { - _titleLabel.SetBackgroundColor(_materialColorScheme->GetColor(md::sys::color::surfaceContainerLow)); - _titleLabel.SetForegroundColor(_materialColorScheme->onSurface); - _layoutLabel.SetBackgroundColor(_materialColorScheme->GetColor(md::sys::color::surfaceContainerLow)); - _layoutLabel.SetForegroundColor(_materialColorScheme->onSurfaceVariant); - _sortingLabel.SetBackgroundColor(_materialColorScheme->GetColor(md::sys::color::surfaceContainerLow)); - _sortingLabel.SetForegroundColor(_materialColorScheme->onSurfaceVariant); + _titleLabel->SetBackgroundColor(_materialColorScheme->GetColor(md::sys::color::surfaceContainerLow)); + _titleLabel->SetForegroundColor(_materialColorScheme->onSurface); + _layoutLabel->SetBackgroundColor(_materialColorScheme->GetColor(md::sys::color::surfaceContainerLow)); + _layoutLabel->SetForegroundColor(_materialColorScheme->onSurfaceVariant); + _sortingLabel->SetBackgroundColor(_materialColorScheme->GetColor(md::sys::color::surfaceContainerLow)); + _sortingLabel->SetForegroundColor(_materialColorScheme->onSurfaceVariant); // _filtersLabel.SetBackgroundColor(_materialColorScheme->GetColor(md::sys::color::surfaceContainerLow)); // _filtersLabel.SetForegroundColor(_materialColorScheme->onSurfaceVariant); BottomSheetView::Draw(graphicsContext); @@ -364,6 +364,11 @@ void DisplaySettingsBottomSheetView::SetGraphics( // filterOption.SetGraphics(iconButtonVramToken); } +void DisplaySettingsBottomSheetView::Close() +{ + _viewModel->Close(); +} + u32 DisplaySettingsBottomSheetView::LoadIcon(IVramManager& vramManager, const unsigned int* tiles, u32 tilesLength) const { diff --git a/arm9/source/romBrowser/views/DisplaySettingsBottomSheetView.h b/arm9/source/romBrowser/views/DisplaySettingsBottomSheetView.h index b02d86a..f92d7a2 100644 --- a/arm9/source/romBrowser/views/DisplaySettingsBottomSheetView.h +++ b/arm9/source/romBrowser/views/DisplaySettingsBottomSheetView.h @@ -11,10 +11,9 @@ class IFontRepository; class DisplaySettingsBottomSheetView : public BottomSheetView { -public: - DisplaySettingsBottomSheetView(DisplaySettingsViewModel* viewModel, - const MaterialColorScheme* materialColorScheme, const IFontRepository* fontRepository); + SHARED_ONLY(DisplaySettingsBottomSheetView) +public: void InitVram(const VramContext& vramContext) override; void Update() override; void Draw(GraphicsContext& graphicsContext) override; @@ -29,12 +28,15 @@ public: focusManager.Focus(_layoutOptions[0]); } +protected: + void Close() override; + private: DisplaySettingsViewModel* _viewModel; - Label2DView _titleLabel; - Label2DView _layoutLabel; - Label2DView _sortingLabel; + SharedPtr _titleLabel; + SharedPtr _layoutLabel; + SharedPtr _sortingLabel; // LabelView _filtersLabel; std::array, 4> _layoutOptions; @@ -47,6 +49,9 @@ private: SharedPtr CreateSortOptionIconButton(); // IconButton2DView CreateFilterOptionIconButton(); + DisplaySettingsBottomSheetView(DisplaySettingsViewModel* viewModel, + const MaterialColorScheme* materialColorScheme, const IFontRepository* fontRepository); + void UpdateLabels(); u32 LoadIcon(IVramManager& vramManager, const unsigned int* tiles, u32 tilesLength) const; diff --git a/arm9/source/romBrowser/views/IconButton2DView.cpp b/arm9/source/romBrowser/views/IconButton2DView.cpp index bc37be6..3eb2c9f 100644 --- a/arm9/source/romBrowser/views/IconButton2DView.cpp +++ b/arm9/source/romBrowser/views/IconButton2DView.cpp @@ -17,7 +17,7 @@ void IconButton2DView::Draw(GraphicsContext& graphicsContext) return; u32 iconPaletteRow; - if (_isFocused) + if (_isFocused || _penDown) { const auto& bgColor = _materialColorScheme->GetColor(_backgroundColor); const auto& selectorBaseColor = _materialColorScheme->GetColor(GetCircleBackgroundColor()); diff --git a/arm9/source/romBrowser/views/IconButton2DView.h b/arm9/source/romBrowser/views/IconButton2DView.h index 12ce7c0..fd3e1d2 100644 --- a/arm9/source/romBrowser/views/IconButton2DView.h +++ b/arm9/source/romBrowser/views/IconButton2DView.h @@ -3,6 +3,8 @@ class IconButton2DView : public IconButtonView { + SHARED_ONLY(IconButton2DView) + public: class VramToken { @@ -17,12 +19,6 @@ public: constexpr u32 GetVramOffset() const { return _vramOffset; } }; - IconButton2DView() : IconButtonView() { } - - IconButton2DView(Type type, State state, - md::sys::color backgroundColor, const MaterialColorScheme* materialColorScheme) - : IconButtonView(type, state, backgroundColor, materialColorScheme) { } - void Draw(GraphicsContext& graphicsContext) override; void SetGraphics(const VramToken& vramToken) @@ -34,4 +30,8 @@ public: private: u32 _selectorVramOffset; + + IconButton2DView(Type type, State state, + md::sys::color backgroundColor, const MaterialColorScheme* materialColorScheme) + : IconButtonView(type, state, backgroundColor, materialColorScheme) { } }; diff --git a/arm9/source/romBrowser/views/IconButton3DView.cpp b/arm9/source/romBrowser/views/IconButton3DView.cpp index ac886d5..6ff3386 100644 --- a/arm9/source/romBrowser/views/IconButton3DView.cpp +++ b/arm9/source/romBrowser/views/IconButton3DView.cpp @@ -19,7 +19,7 @@ void IconButton3DView::Draw(GraphicsContext& graphicsContext) return; u32 iconPaletteRow; - if (_isFocused) + if (_isFocused || _penDown) { const auto& selectorBaseColor = _materialColorScheme->GetColor(GetCircleBackgroundColor()); const auto& fgColor = _materialColorScheme->GetColor(GetForegroundColor()); diff --git a/arm9/source/romBrowser/views/IconButton3DView.h b/arm9/source/romBrowser/views/IconButton3DView.h index 349c214..f455bfb 100644 --- a/arm9/source/romBrowser/views/IconButton3DView.h +++ b/arm9/source/romBrowser/views/IconButton3DView.h @@ -5,13 +5,9 @@ class IconButton3DView : public IconButtonView { + SHARED_ONLY(IconButton3DView) + public: - IconButton3DView() : IconButtonView() { } - - IconButton3DView(Type type, State state, - md::sys::color backgroundColor, const MaterialColorScheme* materialColorScheme) - : IconButtonView(type, state, backgroundColor, materialColorScheme) { } - void Draw(GraphicsContext& graphicsContext) override; static void UploadGraphics(const VramContext& vramContext); @@ -19,5 +15,9 @@ public: private: static u32 sSelectorTextureVramOffset; + IconButton3DView(Type type, State state, + md::sys::color backgroundColor, const MaterialColorScheme* materialColorScheme) + : IconButtonView(type, state, backgroundColor, materialColorScheme) { } + void DrawSelector(GraphicsContext& graphicsContext, const Rgb<8, 8, 8>& color); }; diff --git a/arm9/source/romBrowser/views/IconButtonView.cpp b/arm9/source/romBrowser/views/IconButtonView.cpp index f3e3f33..98d74af 100644 --- a/arm9/source/romBrowser/views/IconButtonView.cpp +++ b/arm9/source/romBrowser/views/IconButtonView.cpp @@ -7,12 +7,46 @@ bool IconButtonView::HandleInput(const InputProvider& inputProvider, FocusManage if (inputProvider.Triggered(InputKey::A)) { if (_action) + { _action(this, _actionArg); + } + return true; } return View::HandleInput(inputProvider, focusManager); } +void IconButtonView::HandlePenDown(const Point& touchPoint, FocusManager& focusManager) +{ + if (GetBounds().Contains(touchPoint)) + { + _penDown = true; + } +} + +void IconButtonView::HandlePenMove(const Point& touchPoint, FocusManager& focusManager) +{ + if (!GetBounds().Contains(touchPoint)) + { + _penDown = false; + } +} + +void IconButtonView::HandlePenUp(const Point& lastTouchPoint, FocusManager& focusManager) +{ + if (_penDown && GetBounds().Contains(lastTouchPoint)) + { + focusManager.Focus(SharedFromThis()); + + if (_action) + { + _action(this, _actionArg); + } + } + + _penDown = false; +} + bool IconButtonView::IsCircleBackgroundVisible() const { switch (_type) diff --git a/arm9/source/romBrowser/views/IconButtonView.h b/arm9/source/romBrowser/views/IconButtonView.h index 1a55e86..9dacb63 100644 --- a/arm9/source/romBrowser/views/IconButtonView.h +++ b/arm9/source/romBrowser/views/IconButtonView.h @@ -24,16 +24,6 @@ public: ToggleSelected }; - IconButtonView() - : _iconVramOffset(0), _action(nullptr), _actionArg(nullptr) - , _type(Type::Standard), _state(State::NoToggle) { } - - IconButtonView(Type type, State state, - md::sys::color backgroundColor, const MaterialColorScheme* materialColorScheme) - : _iconVramOffset(0), _backgroundColor(backgroundColor) - , _action(nullptr), _actionArg(nullptr), _type(type), _state(state) - , _materialColorScheme(materialColorScheme) { } - void SetIconVramOffset(u32 vramOffset) { _iconVramOffset = vramOffset; } Rectangle GetBounds() const override @@ -53,6 +43,9 @@ public: } bool HandleInput(const InputProvider& inputProvider, FocusManager& focusManager) override; + void HandlePenDown(const Point& touchPoint, FocusManager& focusManager) override; + void HandlePenMove(const Point& touchPoint, FocusManager& focusManager) override; + void HandlePenUp(const Point& lastTouchPoint, FocusManager& focusManager) override; protected: u32 _iconVramOffset; @@ -62,6 +55,13 @@ protected: Type _type; State _state; const MaterialColorScheme* _materialColorScheme; + bool _penDown = false; + + IconButtonView(Type type, State state, + md::sys::color backgroundColor, const MaterialColorScheme* materialColorScheme) + : _iconVramOffset(0), _backgroundColor(backgroundColor) + , _action(nullptr), _actionArg(nullptr), _type(type), _state(state) + , _materialColorScheme(materialColorScheme) { } bool IsCircleBackgroundVisible() const; md::sys::color GetCircleBackgroundColor() const; diff --git a/arm9/source/romBrowser/views/IconGridItemView.cpp b/arm9/source/romBrowser/views/IconGridItemView.cpp index 57c3c9c..0e591a6 100644 --- a/arm9/source/romBrowser/views/IconGridItemView.cpp +++ b/arm9/source/romBrowser/views/IconGridItemView.cpp @@ -1,6 +1,7 @@ #include "common.h" #include "gui/IVramManager.h" #include "gui/VramContext.h" +#include "gui/input/InputProvider.h" #include "IconGridItemView.h" void IconGridItemView::InitVram(const VramContext& vramContext) @@ -15,8 +16,31 @@ void IconGridItemView::InitVram(const VramContext& vramContext) void IconGridItemView::Update() { + _viewModel->DisposeQueueTaskWhenComplete(); + if (_icon) { _icon->Update(); } } + +bool IconGridItemView::HandleInput(const InputProvider& inputProvider, FocusManager& focusManager) +{ + return _inputHandler.HandleInput(inputProvider, focusManager) + || View::HandleInput(inputProvider, focusManager); +} + +void IconGridItemView::HandlePenDown(const Point& touchPoint, FocusManager& focusManager) +{ + _inputHandler.HandlePenDown(touchPoint, focusManager); +} + +void IconGridItemView::HandlePenMove(const Point& touchPoint, FocusManager& focusManager) +{ + _inputHandler.HandlePenMove(touchPoint, focusManager); +} + +void IconGridItemView::HandlePenUp(const Point& lastTouchPoint, FocusManager& focusManager) +{ + _inputHandler.HandlePenUp(lastTouchPoint, focusManager); +} diff --git a/arm9/source/romBrowser/views/IconGridItemView.h b/arm9/source/romBrowser/views/IconGridItemView.h index 5d3b6bb..7d80a12 100644 --- a/arm9/source/romBrowser/views/IconGridItemView.h +++ b/arm9/source/romBrowser/views/IconGridItemView.h @@ -1,7 +1,9 @@ #pragma once #include +#include "romBrowser/viewModels/RomBrowserItemViewModel.h" #include "gui/views/View.h" #include "../FileType/FileIcon.h" +#include "RomBrowserItemInputHandler.h" class MaterialColorScheme; @@ -24,6 +26,11 @@ public: void InitVram(const VramContext& vramContext) override; void Update() override; + bool HandleInput(const InputProvider& inputProvider, FocusManager& focusManager) override; + void HandlePenDown(const Point& touchPoint, FocusManager& focusManager) override; + void HandlePenMove(const Point& touchPoint, FocusManager& focusManager) override; + void HandlePenUp(const Point& lastTouchPoint, FocusManager& focusManager) override; + void SetIcon(std::unique_ptr icon) { _icon = std::move(icon); @@ -43,11 +50,18 @@ public: virtual void SetGraphics(const VramToken& vramToken) { } + RomBrowserItemViewModel& GetViewModel() const + { + return *_viewModel; + } + protected: + std::unique_ptr _viewModel; std::unique_ptr _icon; vu16* _iconVram; u32 _iconVramOffset; + RomBrowserItemInputHandler _inputHandler; - IconGridItemView() - : _icon(nullptr) { } -}; \ No newline at end of file + explicit IconGridItemView(std::unique_ptr viewModel) + : _viewModel(std::move(viewModel)), _inputHandler(this, _viewModel.get()) { } +}; diff --git a/arm9/source/romBrowser/views/NdsGameDetailsBottomSheetView.cpp b/arm9/source/romBrowser/views/NdsGameDetailsBottomSheetView.cpp index ecfd634..678f492 100644 --- a/arm9/source/romBrowser/views/NdsGameDetailsBottomSheetView.cpp +++ b/arm9/source/romBrowser/views/NdsGameDetailsBottomSheetView.cpp @@ -13,8 +13,8 @@ NdsGameDetailsBottomSheetView::NdsGameDetailsBottomSheetView( IRomBrowserController* romBrowserController, const MaterialColorScheme* materialColorScheme, const IFontRepository* fontRepository) : _romBrowserController(romBrowserController) - , _cheatsChip(SharedPtr::MakeShared(md::sys::color::surfaceContainerLow, materialColorScheme, fontRepository)) - , _favoriteChip(SharedPtr::MakeShared(md::sys::color::surfaceContainerLow, materialColorScheme, fontRepository)) + , _cheatsChip(ChipView::CreateShared(md::sys::color::surfaceContainerLow, materialColorScheme, fontRepository)) + , _favoriteChip(ChipView::CreateShared(md::sys::color::surfaceContainerLow, materialColorScheme, fontRepository)) { _cheatsChip->SetText(u"Cheats"); _cheatsChip->SetSelected(false); @@ -77,4 +77,9 @@ bool NdsGameDetailsBottomSheetView::HandleInput(const InputProvider& inputProvid return true; } return false; -} \ No newline at end of file +} + +void NdsGameDetailsBottomSheetView::Close() +{ + _romBrowserController->HideGameInfo(); +} diff --git a/arm9/source/romBrowser/views/NdsGameDetailsBottomSheetView.h b/arm9/source/romBrowser/views/NdsGameDetailsBottomSheetView.h index 6aee452..d2cd672 100644 --- a/arm9/source/romBrowser/views/NdsGameDetailsBottomSheetView.h +++ b/arm9/source/romBrowser/views/NdsGameDetailsBottomSheetView.h @@ -8,12 +8,9 @@ class IFontRepository; class NdsGameDetailsBottomSheetView : public BottomSheetView { -public: - NdsGameDetailsBottomSheetView( - IRomBrowserController* romBrowserController, - const MaterialColorScheme* materialColorScheme, - const IFontRepository* fontRepository); + SHARED_ONLY(NdsGameDetailsBottomSheetView) +public: void SetGraphics(const ChipView::VramToken& chipVramToken) { _cheatsChip->SetGraphics(chipVramToken); @@ -34,10 +31,18 @@ public: bool HandleInput(const InputProvider& inputProvider, FocusManager& focusManager) override; +protected: + void Close() override; + private: IRomBrowserController* _romBrowserController; u32 _smallHeartIconVramOffset; u32 _smallHeartIconFilledVramOffset; SharedPtr _cheatsChip; SharedPtr _favoriteChip; + + NdsGameDetailsBottomSheetView( + IRomBrowserController* romBrowserController, + const MaterialColorScheme* materialColorScheme, + const IFontRepository* fontRepository); }; \ No newline at end of file diff --git a/arm9/source/romBrowser/views/RomBrowserAppBarView.cpp b/arm9/source/romBrowser/views/RomBrowserAppBarView.cpp index a85dff8..edb7f8c 100644 --- a/arm9/source/romBrowser/views/RomBrowserAppBarView.cpp +++ b/arm9/source/romBrowser/views/RomBrowserAppBarView.cpp @@ -21,7 +21,7 @@ RomBrowserAppBarView::RomBrowserAppBarView( : _viewModel(viewModel) { _appBarView = displayMode.CreateAppBarView(romBrowserViewFactory, 1, 1); - _appBarView->SetParent(this); + AddChildTail(_appBarView.GetPointer()); _appBarView->SetButtonAction(APP_BAR_BUTTON_BACK, [] (IconButtonView* sender, void* arg) { @@ -35,7 +35,7 @@ RomBrowserAppBarView::RomBrowserAppBarView( void RomBrowserAppBarView::InitVram(const VramContext& vramContext) { - _appBarView->InitVram(vramContext); + ViewContainer::InitVram(vramContext); const auto objVramManager = vramContext.GetObjVramManager(); if (objVramManager) @@ -99,28 +99,13 @@ void RomBrowserAppBarView::InitVram(const VramContext& vramContext) } } -void RomBrowserAppBarView::Update() -{ - _appBarView->Update(); -} - -void RomBrowserAppBarView::Draw(GraphicsContext& graphicsContext) -{ - _appBarView->Draw(graphicsContext); -} - -void RomBrowserAppBarView::VBlank() -{ - _appBarView->VBlank(); -} - SharedPtr RomBrowserAppBarView::MoveFocus(const SharedPtr& currentFocus, FocusMoveDirection direction, View* source) { if (!currentFocus) { return nullptr; } - if (source == _appBarView.get()) + if (source == _appBarView.GetPointer()) { return View::MoveFocus(currentFocus, direction, source); } @@ -130,4 +115,3 @@ SharedPtr RomBrowserAppBarView::MoveFocus(const SharedPtr& currentFo } return nullptr; } - diff --git a/arm9/source/romBrowser/views/RomBrowserAppBarView.h b/arm9/source/romBrowser/views/RomBrowserAppBarView.h index 558f3fd..a5b6594 100644 --- a/arm9/source/romBrowser/views/RomBrowserAppBarView.h +++ b/arm9/source/romBrowser/views/RomBrowserAppBarView.h @@ -1,22 +1,17 @@ #pragma once -#include "gui/views/View.h" +#include "gui/views/ViewContainer.h" #include "AppBarView.h" #include "../viewModels/RomBrowserAppBarViewModel.h" class RomBrowserDisplayMode; class IRomBrowserViewFactory; -class RomBrowserAppBarView : public View +class RomBrowserAppBarView : public ViewContainer { -public: - RomBrowserAppBarView( - RomBrowserAppBarViewModel* viewModel, const RomBrowserDisplayMode& displayMode, - const IRomBrowserViewFactory* romBrowserViewFactory); + SHARED_ONLY(RomBrowserAppBarView) +public: void InitVram(const VramContext& vramContext) override; - void Update() override; - void Draw(GraphicsContext& graphicsContext) override; - void VBlank() override; Rectangle GetBounds() const override { @@ -42,5 +37,9 @@ private: }; RomBrowserAppBarViewModel* _viewModel; - std::unique_ptr _appBarView; + SharedPtr _appBarView; + + RomBrowserAppBarView( + RomBrowserAppBarViewModel* viewModel, const RomBrowserDisplayMode& displayMode, + const IRomBrowserViewFactory* romBrowserViewFactory); }; diff --git a/arm9/source/romBrowser/views/RomBrowserBottomScreenView.cpp b/arm9/source/romBrowser/views/RomBrowserBottomScreenView.cpp index a35db07..20645f1 100644 --- a/arm9/source/romBrowser/views/RomBrowserBottomScreenView.cpp +++ b/arm9/source/romBrowser/views/RomBrowserBottomScreenView.cpp @@ -21,37 +21,43 @@ RomBrowserBottomScreenView::RomBrowserBottomScreenView( , _romBrowserViewFactory(romBrowserViewFactory) , _romBrowserDisplayMode(displayMode) , _themeFileIconFactory(themeFileIconFactory) - , _romBrowserAppBarView(_viewModel->GetRomBrowserAppBarViewModel(), - *displayMode, romBrowserViewFactory) + , _romBrowserAppBarView(RomBrowserAppBarView::CreateShared(_viewModel->GetRomBrowserAppBarViewModel(), + *displayMode, romBrowserViewFactory)) , _vblankTextureLoader(vblankTextureLoader) { - _romBrowserAppBarView.SetParent(this); + _romBrowserAppBarView->SetParent(this); } void RomBrowserBottomScreenView::InitVram(const VramContext& vramContext) { - _romBrowserAppBarView.InitVram(vramContext); + _romBrowserAppBarView->InitVram(vramContext); } void RomBrowserBottomScreenView::Update() { - _romBrowserAppBarView.Update(); + _romBrowserAppBarView->Update(); if (_romBrowserView && _viewModel->IsRomBrowserVisible()) + { _romBrowserView->Update(); + } } void RomBrowserBottomScreenView::Draw(GraphicsContext& graphicsContext) { - _romBrowserAppBarView.Draw(graphicsContext); + _romBrowserAppBarView->Draw(graphicsContext); if (_romBrowserView && _viewModel->IsRomBrowserVisible()) + { _romBrowserView->Draw(graphicsContext); + } } void RomBrowserBottomScreenView::VBlank() { - _romBrowserAppBarView.VBlank(); + _romBrowserAppBarView->VBlank(); if (_romBrowserView && _viewModel->IsRomBrowserVisible()) + { _romBrowserView->VBlank(); + } } SharedPtr RomBrowserBottomScreenView::MoveFocus(const SharedPtr& currentFocus, FocusMoveDirection direction, View* source) @@ -60,31 +66,39 @@ SharedPtr RomBrowserBottomScreenView::MoveFocus(const SharedPtr& cur { return nullptr; } - if (source == &_romBrowserAppBarView) + if (source == _romBrowserAppBarView.GetPointer()) { if (_romBrowserDisplayMode->IsVertical()) { if (direction == FocusMoveDirection::Right) + { return _romBrowserView->MoveFocus(currentFocus, direction, this); + } } else { if (direction == FocusMoveDirection::Down) + { return _romBrowserView->MoveFocus(currentFocus, direction, this); + } } return nullptr; } - else if (source == _romBrowserView.get()) + else if (source == _romBrowserView.GetPointer()) { if (_romBrowserDisplayMode->IsVertical()) { if (direction == FocusMoveDirection::Left) - return _romBrowserAppBarView.MoveFocus(currentFocus, direction, this); + { + return _romBrowserAppBarView->MoveFocus(currentFocus, direction, this); + } } else { if (direction == FocusMoveDirection::Up) - return _romBrowserAppBarView.MoveFocus(currentFocus, direction, this); + { + return _romBrowserAppBarView->MoveFocus(currentFocus, direction, this); + } } return nullptr; } @@ -101,11 +115,38 @@ bool RomBrowserBottomScreenView::HandleInput(const InputProvider& inputProvider, return View::HandleInput(inputProvider, focusManager); } +void RomBrowserBottomScreenView::HandlePenDown(const Point& touchPoint, FocusManager& focusManager) +{ + _romBrowserAppBarView->HandlePenDown(touchPoint, focusManager); + if (_romBrowserView && _viewModel->IsRomBrowserVisible()) + { + _romBrowserView->HandlePenDown(touchPoint, focusManager); + } +} + +void RomBrowserBottomScreenView::HandlePenMove(const Point& touchPoint, FocusManager& focusManager) +{ + _romBrowserAppBarView->HandlePenMove(touchPoint, focusManager); + if (_romBrowserView && _viewModel->IsRomBrowserVisible()) + { + _romBrowserView->HandlePenMove(touchPoint, focusManager); + } +} + +void RomBrowserBottomScreenView::HandlePenUp(const Point& lastTouchPoint, FocusManager& focusManager) +{ + _romBrowserAppBarView->HandlePenUp(lastTouchPoint, focusManager); + if (_romBrowserView && _viewModel->IsRomBrowserVisible()) + { + _romBrowserView->HandlePenUp(lastTouchPoint, focusManager); + } +} + void RomBrowserBottomScreenView::RomBrowserViewModelInvalidated(const VramContext& vramContext) { if (_viewModel->GetRomBrowserViewModel().IsValid()) { - _romBrowserView = std::make_unique( + _romBrowserView = RomBrowserView::CreateShared( _viewModel->GetRomBrowserViewModel(), *_romBrowserDisplayMode, _themeFileIconFactory, _romBrowserViewFactory, _vblankTextureLoader); _romBrowserView->SetParent(this); @@ -113,6 +154,6 @@ void RomBrowserBottomScreenView::RomBrowserViewModelInvalidated(const VramContex } else { - _romBrowserView.reset(); + _romBrowserView.Reset(); } } \ No newline at end of file diff --git a/arm9/source/romBrowser/views/RomBrowserBottomScreenView.h b/arm9/source/romBrowser/views/RomBrowserBottomScreenView.h index aa21ef7..f4bd7bb 100644 --- a/arm9/source/romBrowser/views/RomBrowserBottomScreenView.h +++ b/arm9/source/romBrowser/views/RomBrowserBottomScreenView.h @@ -13,14 +13,9 @@ class VBlankTextureLoader; class RomBrowserBottomScreenView : public View { -public: - RomBrowserBottomScreenView( - RomBrowserBottomScreenViewModel* viewModel, - const RomBrowserDisplayMode* displayMode, - const IThemeFileIconFactory* themeFileIconFactory, - const IRomBrowserViewFactory* romBrowserViewFactory, - VBlankTextureLoader* vblankTextureLoader); + SHARED_ONLY(RomBrowserBottomScreenView) +public: void InitVram(const VramContext& vramContext) override; void Update() override; void Draw(GraphicsContext& graphicsContext) override; @@ -36,16 +31,21 @@ public: void Focus(FocusManager& focusManager) { if (!_romBrowserView || !_romBrowserView->Focus(focusManager)) - _romBrowserAppBarView.Focus(focusManager); + { + _romBrowserAppBarView->Focus(focusManager); + } } bool HandleInput(const InputProvider& inputProvider, FocusManager& focusManager) override; + void HandlePenDown(const Point& touchPoint, FocusManager& focusManager) override; + void HandlePenMove(const Point& touchPoint, FocusManager& focusManager) override; + void HandlePenUp(const Point& lastTouchPoint, FocusManager& focusManager) override; void RomBrowserViewModelInvalidated(const VramContext& vramContext); bool IsAppBarFocused(const FocusManager& focusManager) const { - return focusManager.IsFocusInside(&_romBrowserAppBarView); + return focusManager.IsFocusInside(_romBrowserAppBarView.GetPointer()); } private: @@ -54,7 +54,14 @@ private: const RomBrowserDisplayMode* _romBrowserDisplayMode; const IThemeFileIconFactory* _themeFileIconFactory; - RomBrowserAppBarView _romBrowserAppBarView; - std::unique_ptr _romBrowserView; + SharedPtr _romBrowserAppBarView; + SharedPtr _romBrowserView; VBlankTextureLoader* _vblankTextureLoader; + + RomBrowserBottomScreenView( + RomBrowserBottomScreenViewModel* viewModel, + const RomBrowserDisplayMode* displayMode, + const IThemeFileIconFactory* themeFileIconFactory, + const IRomBrowserViewFactory* romBrowserViewFactory, + VBlankTextureLoader* vblankTextureLoader); }; diff --git a/arm9/source/romBrowser/views/RomBrowserItemInputHandler.cpp b/arm9/source/romBrowser/views/RomBrowserItemInputHandler.cpp new file mode 100644 index 0000000..0a55296 --- /dev/null +++ b/arm9/source/romBrowser/views/RomBrowserItemInputHandler.cpp @@ -0,0 +1,76 @@ +#include "common.h" +#include "gui/FocusManager.h" +#include "gui/input/InputProvider.h" +#include "gui/views/View.h" +#include "romBrowser/viewModels/RomBrowserItemViewModel.h" +#include "RomBrowserItemInputHandler.h" + +#define LONG_PRESS_FRAMES 30 + +bool RomBrowserItemInputHandler::HandleInput(const InputProvider& inputProvider, FocusManager& focusManager) +{ + if (inputProvider.Triggered(InputKey::A)) + { + _viewModel->Activate(); + return true; + } + else if (inputProvider.Triggered(InputKey::Y)) + { + _viewModel->ShowGameInfo(); + return true; + } + else + { + return false; + } +} + +void RomBrowserItemInputHandler::HandlePenDown(const Point& touchPoint, FocusManager& focusManager) +{ + if (_view->GetBounds().Contains(touchPoint)) + { + _penDown = true; + _penDownFrames = 0; + } +} + +void RomBrowserItemInputHandler::HandlePenMove(const Point& touchPoint, FocusManager& focusManager) +{ + if (_penDown && _view->GetBounds().Contains(touchPoint)) + { + if (++_penDownFrames == LONG_PRESS_FRAMES) + { + // Long press + if (focusManager.GetCurrentFocus().GetPointer() != _view) + { + focusManager.Focus(_view->SharedFromThis()); + } + + _viewModel->ShowGameInfo(); + + _penDown = false; // pen action is complete + } + } + else + { + _penDown = false; + } +} + +void RomBrowserItemInputHandler::HandlePenUp(const Point& lastTouchPoint, FocusManager& focusManager) +{ + if (_penDown && _view->GetBounds().Contains(lastTouchPoint)) + { + // Short tap + if (focusManager.GetCurrentFocus().GetPointer() == _view) + { + _viewModel->Activate(); + } + else + { + focusManager.Focus(_view->SharedFromThis()); + } + } + + _penDown = false; +} diff --git a/arm9/source/romBrowser/views/RomBrowserItemInputHandler.h b/arm9/source/romBrowser/views/RomBrowserItemInputHandler.h new file mode 100644 index 0000000..cc3be78 --- /dev/null +++ b/arm9/source/romBrowser/views/RomBrowserItemInputHandler.h @@ -0,0 +1,27 @@ +#pragma once +#include "core/math/Point.h" + +class InputProvider; +class FocusManager; +class RomBrowserItemViewModel; +class View; + +class RomBrowserItemInputHandler +{ +public: + RomBrowserItemInputHandler(View* view, RomBrowserItemViewModel* viewModel) + : _view(view), _viewModel(viewModel) { } + + bool HandleInput(const InputProvider& inputProvider, FocusManager& focusManager); + void HandlePenDown(const Point& touchPoint, FocusManager& focusManager); + void HandlePenMove(const Point& touchPoint, FocusManager& focusManager); + void HandlePenUp(const Point& lastTouchPoint, FocusManager& focusManager); + + bool IsPenDown() const { return _penDown; } + +private: + View* _view; + RomBrowserItemViewModel* _viewModel; + bool _penDown = false; + int _penDownFrames = 0; +}; diff --git a/arm9/source/romBrowser/views/RomBrowserTopScreenView.cpp b/arm9/source/romBrowser/views/RomBrowserTopScreenView.cpp index 5eba4bd..fb23a50 100644 --- a/arm9/source/romBrowser/views/RomBrowserTopScreenView.cpp +++ b/arm9/source/romBrowser/views/RomBrowserTopScreenView.cpp @@ -22,7 +22,7 @@ RomBrowserTopScreenView::RomBrowserTopScreenView( , _showCover(displayMode->ShowCoverOnTopScreen()) , _coverPosition(romBrowserViewFactory->GetTopCoverPosition()) { - AddChildTail(_fileInfoView.get()); + AddChildTail(_fileInfoView.GetPointer()); } void RomBrowserTopScreenView::InitVram(const VramContext& vramContext) diff --git a/arm9/source/romBrowser/views/RomBrowserTopScreenView.h b/arm9/source/romBrowser/views/RomBrowserTopScreenView.h index d8aee8c..0eb61bb 100644 --- a/arm9/source/romBrowser/views/RomBrowserTopScreenView.h +++ b/arm9/source/romBrowser/views/RomBrowserTopScreenView.h @@ -11,12 +11,9 @@ class IRomBrowserViewFactory; class RomBrowserTopScreenView : public ViewContainer { -public: - RomBrowserTopScreenView(SharedPtr viewModel, - const RomBrowserDisplayMode* displayMode, - const IThemeFileIconFactory* themeFileIconFactory, - const IRomBrowserViewFactory* romBrowserViewFactory); + SHARED_ONLY(RomBrowserTopScreenView) +public: void InitVram(const VramContext& vramContext) override; void Update() override; void VBlank() override; @@ -29,7 +26,7 @@ public: private: SharedPtr _viewModel; const IThemeFileIconFactory* _themeFileIconFactory; - std::unique_ptr _fileInfoView; + SharedPtr _fileInfoView; std::unique_ptr _selectedFileIcon; SharedPtr _selectedFileCover; int _lastSelectedItem = -1; @@ -37,4 +34,9 @@ private: bool _coverGraphicsUploaded = false; bool _showCover; Point _coverPosition; + + RomBrowserTopScreenView(SharedPtr viewModel, + const RomBrowserDisplayMode* displayMode, + const IThemeFileIconFactory* themeFileIconFactory, + const IRomBrowserViewFactory* romBrowserViewFactory); }; \ No newline at end of file diff --git a/arm9/source/romBrowser/views/RomBrowserView.cpp b/arm9/source/romBrowser/views/RomBrowserView.cpp index 756d90e..0784859 100644 --- a/arm9/source/romBrowser/views/RomBrowserView.cpp +++ b/arm9/source/romBrowser/views/RomBrowserView.cpp @@ -13,7 +13,7 @@ RomBrowserView::RomBrowserView( : _viewModel(std::move(viewModel)), _isVertical(displayMode.IsVertical()) { _fileGridView = displayMode.CreateRecyclerView(romBrowserViewFactory); - _fileGridView->SetParent(this); + AddChildTail(_fileGridView.GetPointer()); _fileRecyclerAdapter = displayMode.CreateRecyclerAdapter( _viewModel.GetPointer(), themeFileIconFactory, romBrowserViewFactory, vblankTextureLoader); } @@ -32,16 +32,6 @@ void RomBrowserView::Update() _viewModel->SetSelectedItem(_fileGridView->GetSelectedItem()); } -void RomBrowserView::Draw(GraphicsContext& graphicsContext) -{ - _fileGridView->Draw(graphicsContext); -} - -void RomBrowserView::VBlank() -{ - _fileGridView->VBlank(); -} - SharedPtr RomBrowserView::MoveFocus(const SharedPtr& currentFocus, FocusMoveDirection direction, View* source) { if (!currentFocus) @@ -72,24 +62,3 @@ SharedPtr RomBrowserView::MoveFocus(const SharedPtr& currentFocus, F } return nullptr; } - -bool RomBrowserView::HandleInput(const InputProvider& inputProvider, FocusManager& focusManager) -{ - if (inputProvider.Triggered(InputKey::A)) - { - if (focusManager.IsFocusInside(_fileGridView.GetPointer())) - { - _viewModel->ItemActivated(); - return true; - } - } - else if (inputProvider.Triggered(InputKey::Y)) - { - if (focusManager.IsFocusInside(_fileGridView.GetPointer())) - { - _viewModel->ShowGameInfo(); - return true; - } - } - return View::HandleInput(inputProvider, focusManager); -} diff --git a/arm9/source/romBrowser/views/RomBrowserView.h b/arm9/source/romBrowser/views/RomBrowserView.h index c52c26b..4cefd1b 100644 --- a/arm9/source/romBrowser/views/RomBrowserView.h +++ b/arm9/source/romBrowser/views/RomBrowserView.h @@ -9,20 +9,13 @@ class IRomBrowserViewFactory; -class RomBrowserView : public View +class RomBrowserView : public ViewContainer { -public: - RomBrowserView( - SharedPtr viewModel, - const RomBrowserDisplayMode& displayMode, - const IThemeFileIconFactory* themeFileIconFactory, - const IRomBrowserViewFactory* romBrowserViewFactory, - VBlankTextureLoader* vblankTextureLoader); + SHARED_ONLY(RomBrowserView) +public: void InitVram(const VramContext& vramContext) override; void Update() override; - void Draw(GraphicsContext& graphicsContext) override; - void VBlank() override; Rectangle GetBounds() const override { @@ -41,11 +34,16 @@ public: SharedPtr MoveFocus( const SharedPtr& currentFocus, FocusMoveDirection direction, View* source) override; - bool HandleInput(const InputProvider& inputProvider, FocusManager& focusManager) override; - private: SharedPtr _viewModel; SharedPtr _fileGridView; SharedPtr _fileRecyclerAdapter; bool _isVertical; + + RomBrowserView( + SharedPtr viewModel, + const RomBrowserDisplayMode& displayMode, + const IThemeFileIconFactory* themeFileIconFactory, + const IRomBrowserViewFactory* romBrowserViewFactory, + VBlankTextureLoader* vblankTextureLoader); }; diff --git a/arm9/source/romBrowser/views/cheats/CheatListItemView.cpp b/arm9/source/romBrowser/views/cheats/CheatListItemView.cpp index c11f8f4..9fd2732 100644 --- a/arm9/source/romBrowser/views/cheats/CheatListItemView.cpp +++ b/arm9/source/romBrowser/views/cheats/CheatListItemView.cpp @@ -4,6 +4,7 @@ #include "gui/palette/GradientPalette.h" #include "gui/GraphicsContext.h" #include "gui/OamBuilder.h" +#include "gui/input/InputProvider.h" #include "CheatListItemView.h" #define ICON_X 4 @@ -12,19 +13,20 @@ #define NAME_LABEL_X 24 #define NAME_LABEL_Y 5 -CheatListItemView::CheatListItemView(const VramOffsets& vramOffsets, +CheatListItemView::CheatListItemView(SharedPtr viewModel, const VramOffsets& vramOffsets, const MaterialColorScheme* materialColorScheme, const IFontRepository* fontRepository) - : _nameLabel(196, 16, 256, fontRepository->GetFont(FontType::Regular10)) + : _viewModel(std::move(viewModel)) + , _nameLabel(Label2DView::CreateShared(196, 16, 256, fontRepository->GetFont(FontType::Regular10))) , _vramOffsets(vramOffsets) , _materialColorScheme(materialColorScheme) { - _nameLabel.SetEllipsisStyle(LabelView::EllipsisStyle::Ellipsis); - AddChildTail(&_nameLabel); + _nameLabel->SetEllipsisStyle(LabelView::EllipsisStyle::Ellipsis); + AddChildTail(_nameLabel.GetPointer()); } void CheatListItemView::Update() { - _nameLabel.SetPosition(_position.x + NAME_LABEL_X, _position.y + NAME_LABEL_Y); + _nameLabel->SetPosition(_position.x + NAME_LABEL_X, _position.y + NAME_LABEL_Y); if (_cheatEntry != nullptr && !_cheatEntry->IsCheatCategory()) { _iconVramOffset = _cheatEntry->GetIsCheatActive() @@ -33,11 +35,11 @@ void CheatListItemView::Update() } if (IsFocused()) { - _nameLabel.SetEllipsisStyle(LabelView::EllipsisStyle::Marquee); + _nameLabel->SetEllipsisStyle(LabelView::EllipsisStyle::Marquee); } else { - _nameLabel.SetEllipsisStyle(LabelView::EllipsisStyle::Ellipsis); + _nameLabel->SetEllipsisStyle(LabelView::EllipsisStyle::Ellipsis); } ViewContainer::Update(); } @@ -56,8 +58,8 @@ void CheatListItemView::Draw(GraphicsContext& graphicsContext) backColor = RgbMixer::Lerp(backColor, selectorFullColor, 10, 100); } - _nameLabel.SetBackgroundColor(backColor); - _nameLabel.SetForegroundColor(_materialColorScheme->onSurface); + _nameLabel->SetBackgroundColor(backColor); + _nameLabel->SetForegroundColor(_materialColorScheme->onSurface); if (IsFocused()) { @@ -97,3 +99,55 @@ void CheatListItemView::Draw(GraphicsContext& graphicsContext) .Build(iconOam[0]); } } + +bool CheatListItemView::HandleInput(const InputProvider& inputProvider, FocusManager& focusManager) +{ + if (inputProvider.Triggered(InputKey::A)) + { + _viewModel->ActivateItem(_index); + return true; + } + + return ViewContainer::HandleInput(inputProvider, focusManager); +} + +void CheatListItemView::HandlePenDown(const Point& touchPoint, FocusManager& focusManager) +{ + if (GetBounds().Contains(touchPoint)) + { + _penDown = true; + } +} + +void CheatListItemView::HandlePenMove(const Point& touchPoint, FocusManager& focusManager) +{ + if (!GetBounds().Contains(touchPoint)) + { + _penDown = false; + } +} + +void CheatListItemView::HandlePenUp(const Point& lastTouchPoint, FocusManager& focusManager) +{ + if (_penDown && GetBounds().Contains(lastTouchPoint)) + { + if (lastTouchPoint.x - _position.x < 24) + { + focusManager.Focus(SharedFromThis()); + _viewModel->ActivateItem(_index); + } + else + { + if (focusManager.GetCurrentFocus().GetPointer() == this) + { + _viewModel->ActivateItem(_index); + } + else + { + focusManager.Focus(SharedFromThis()); + } + } + } + + _penDown = false; +} diff --git a/arm9/source/romBrowser/views/cheats/CheatListItemView.h b/arm9/source/romBrowser/views/cheats/CheatListItemView.h index a9366e9..ed784d1 100644 --- a/arm9/source/romBrowser/views/cheats/CheatListItemView.h +++ b/arm9/source/romBrowser/views/cheats/CheatListItemView.h @@ -2,6 +2,7 @@ #include "gui/views/ViewContainer.h" #include "gui/views/Label2DView.h" #include "cheats/CheatEntry.h" +#include "romBrowser/viewModels/CheatsViewModel.h" class MaterialColorScheme; class IFontRepository; @@ -9,6 +10,8 @@ class IFontRepository; /// @brief List item view for the cheats panel, representing a single cheat or cheat category. class CheatListItemView : public ViewContainer { + SHARED_ONLY(CheatListItemView) + public: struct VramOffsets { @@ -18,10 +21,12 @@ public: u32 cheatSelectorVramOffset = 0; }; - CheatListItemView(const VramOffsets& vramOffsets, const MaterialColorScheme* materialColorScheme, const IFontRepository* fontRepository); - void Update() override; void Draw(GraphicsContext& graphicsContext) override; + bool HandleInput(const InputProvider& inputProvider, FocusManager& focusManager) override; + void HandlePenDown(const Point& touchPoint, FocusManager& focusManager) override; + void HandlePenMove(const Point& touchPoint, FocusManager& focusManager) override; + void HandlePenUp(const Point& lastTouchPoint, FocusManager& focusManager) override; Rectangle GetBounds() const override { @@ -30,13 +35,14 @@ public: void SetName(const char* name) { - _nameLabel.SetText(name); + _nameLabel->SetText(name); } - void SetEntry(const CheatEntry* cheatEntry) + void SetEntry(const CheatEntry* cheatEntry, int index) { _cheatEntry = cheatEntry; - _nameLabel.SetText(cheatEntry->GetName()); + _index = index; + _nameLabel->SetText(cheatEntry->GetName()); if (cheatEntry->IsCheatCategory()) { _iconVramOffset = _vramOffsets.folderIconVramOffset; @@ -44,9 +50,15 @@ public: } private: - Label2DView _nameLabel; + SharedPtr _viewModel; + SharedPtr _nameLabel; VramOffsets _vramOffsets; const MaterialColorScheme* _materialColorScheme; u32 _iconVramOffset = 0; const CheatEntry* _cheatEntry = nullptr; + int _index = -1; + bool _penDown = false; + + CheatListItemView(SharedPtr viewModel, const VramOffsets& vramOffsets, + const MaterialColorScheme* materialColorScheme, const IFontRepository* fontRepository); }; diff --git a/arm9/source/romBrowser/views/cheats/CheatsAdapter.h b/arm9/source/romBrowser/views/cheats/CheatsAdapter.h index b55a2a0..d3e712d 100644 --- a/arm9/source/romBrowser/views/cheats/CheatsAdapter.h +++ b/arm9/source/romBrowser/views/cheats/CheatsAdapter.h @@ -7,9 +7,10 @@ class CheatsAdapter : public RecyclerAdapter { public: - CheatsAdapter(const CheatEntry* cheatCategory, const MaterialColorScheme* materialColorScheme, - const IFontRepository* fontRepository, const CheatListItemView::VramOffsets& vramOffsets) - : _cheatCategory(cheatCategory), _materialColorScheme(materialColorScheme) + CheatsAdapter(const CheatEntry* cheatCategory, SharedPtr cheatsViewModel, + const MaterialColorScheme* materialColorScheme, const IFontRepository* fontRepository, + const CheatListItemView::VramOffsets& vramOffsets) + : _cheatCategory(cheatCategory), _cheatsViewModel(std::move(cheatsViewModel)), _materialColorScheme(materialColorScheme) , _fontRepository(fontRepository), _vramOffsets(vramOffsets) { } u32 GetItemCount() const override @@ -27,7 +28,7 @@ public: SharedPtr CreateView() const override { - return SharedPtr::MakeShared(_vramOffsets, _materialColorScheme, _fontRepository); + return CheatListItemView::CreateShared(_cheatsViewModel, _vramOffsets, _materialColorScheme, _fontRepository); } void BindView(SharedPtr view, int index) const override @@ -35,7 +36,7 @@ public: auto listItemView = static_cast(view.GetPointer()); u32 numberOfSubEntries = 0; auto subEntries = _cheatCategory->GetSubEntries(numberOfSubEntries); - listItemView->SetEntry(&subEntries[index]); + listItemView->SetEntry(&subEntries[index], index); } void ReleaseView(SharedPtr view, int index) const override @@ -45,6 +46,7 @@ public: private: const CheatEntry* _cheatCategory; + SharedPtr _cheatsViewModel; const MaterialColorScheme* _materialColorScheme; const IFontRepository* _fontRepository; CheatListItemView::VramOffsets _vramOffsets; diff --git a/arm9/source/romBrowser/views/cheats/CheatsBottomSheetView.cpp b/arm9/source/romBrowser/views/cheats/CheatsBottomSheetView.cpp index 0ab46b3..0daf05f 100644 --- a/arm9/source/romBrowser/views/cheats/CheatsBottomSheetView.cpp +++ b/arm9/source/romBrowser/views/cheats/CheatsBottomSheetView.cpp @@ -7,6 +7,7 @@ #include "gui/palette/GradientPalette.h" #include "gui/OamBuilder.h" #include "folderIcon.h" +#include "upIcon.h" #include "checkboxChecked.h" #include "checkboxUnchecked.h" #include "cheatSelector.h" @@ -30,28 +31,37 @@ #define LIST_WIDTH 224 #define LIST_HEIGHT 108 -CheatsBottomSheetView::CheatsBottomSheetView(std::unique_ptr viewModel, +CheatsBottomSheetView::CheatsBottomSheetView(SharedPtr viewModel, const MaterialColorScheme* materialColorScheme, const IFontRepository* fontRepository, FocusManager* focusManager) : _viewModel(std::move(viewModel)) - , _titleLabel(64, 16, 25, fontRepository->GetFont(FontType::Medium11)) - , _secondaryLabel(177, 16, 64, fontRepository->GetFont(FontType::Regular10)) - , _descriptionLabel(224, 16, 256, fontRepository->GetFont(FontType::Medium7_5)) + , _titleLabel(Label2DView::CreateShared(64, 16, 25, fontRepository->GetFont(FontType::Medium11))) + , _secondaryLabel(Label2DView::CreateShared(153, 16, 64, fontRepository->GetFont(FontType::Regular10))) + , _descriptionLabel(Label2DView::CreateShared(224, 16, 256, fontRepository->GetFont(FontType::Medium7_5))) , _cheatListRecycler(RecyclerView::CreateShared( LIST_X, LIST_Y, LIST_WIDTH, LIST_HEIGHT, RecyclerView::Mode::VerticalList)) + , _upButton(IconButton2DView::CreateShared( + IconButtonView::Type::Standard, + IconButtonView::State::NoToggle, + md::sys::color::inverseOnSurface, + materialColorScheme)) , _materialColorScheme(materialColorScheme) , _fontRepository(fontRepository) , _focusManager(focusManager) { - _titleLabel.SetText(u"Cheats"); - _secondaryLabel.SetText(u"No cheats found."); - _secondaryLabel.SetEllipsisStyle(LabelView::EllipsisStyle::Ellipsis); - _descriptionLabel.SetEllipsisStyle(LabelView::EllipsisStyle::Marquee); - _descriptionLabel.SetText(""); - AddChildTail(&_titleLabel); - AddChildTail(&_secondaryLabel); - AddChildTail(&_descriptionLabel); + _titleLabel->SetText(u"Cheats"); + _secondaryLabel->SetText(u"No cheats found."); + _secondaryLabel->SetEllipsisStyle(LabelView::EllipsisStyle::Ellipsis); + _descriptionLabel->SetEllipsisStyle(LabelView::EllipsisStyle::Marquee); + _descriptionLabel->SetText(u""); + AddChildTail(_titleLabel.GetPointer()); + AddChildTail(_secondaryLabel.GetPointer()); + AddChildTail(_descriptionLabel.GetPointer()); AddChildTail(_cheatListRecycler.GetPointer()); + _upButton->SetAction([] (IconButtonView*, void* arg) + { + ((CheatsBottomSheetView*)arg)->_viewModel->NavigateUp(); + }, this); } void CheatsBottomSheetView::InitVram(const VramContext& vramContext) @@ -61,21 +71,17 @@ void CheatsBottomSheetView::InitVram(const VramContext& vramContext) const auto objVramManager = vramContext.GetObjVramManager(); if (objVramManager) { - _vramOffsets.folderIconVramOffset = objVramManager->Alloc(folderIconTilesLen); - dma_ntrCopy32(3, folderIconTiles, - objVramManager->GetVramAddress(_vramOffsets.folderIconVramOffset), folderIconTilesLen); - - _vramOffsets.checkboxUncheckedIconVramOffset = objVramManager->Alloc(checkboxUncheckedTilesLen); - dma_ntrCopy32(3, checkboxUncheckedTiles, - objVramManager->GetVramAddress(_vramOffsets.checkboxUncheckedIconVramOffset), checkboxUncheckedTilesLen); - - _vramOffsets.checkboxCheckedIconVramOffset = objVramManager->Alloc(checkboxCheckedTilesLen); - dma_ntrCopy32(3, checkboxCheckedTiles, - objVramManager->GetVramAddress(_vramOffsets.checkboxCheckedIconVramOffset), checkboxCheckedTilesLen); - - _vramOffsets.cheatSelectorVramOffset = objVramManager->Alloc(cheatSelectorTilesLen); - dma_ntrCopy32(3, cheatSelectorTiles, - objVramManager->GetVramAddress(_vramOffsets.cheatSelectorVramOffset), cheatSelectorTilesLen); + _vramOffsets.folderIconVramOffset + = LoadSprite(*objVramManager, folderIconTiles, folderIconTilesLen); + _vramOffsets.checkboxUncheckedIconVramOffset + = LoadSprite(*objVramManager, checkboxUncheckedTiles, checkboxUncheckedTilesLen); + _vramOffsets.checkboxCheckedIconVramOffset + = LoadSprite(*objVramManager, checkboxCheckedTiles, checkboxCheckedTilesLen); + _vramOffsets.cheatSelectorVramOffset + = LoadSprite(*objVramManager, cheatSelectorTiles, cheatSelectorTilesLen); + auto iconButtonVramToken = IconButton2DView::UploadGraphics(*objVramManager); + _upButton->SetGraphics(iconButtonVramToken); + _upButton->SetIconVramOffset(LoadSprite(*objVramManager, upIconTiles, upIconTilesLen)); } _objVramManager = vramContext.GetObjVramManager(); @@ -83,23 +89,34 @@ void CheatsBottomSheetView::InitVram(const VramContext& vramContext) void CheatsBottomSheetView::Update() { - _titleLabel.SetPosition(TITLE_LABEL_X, _position.y + TITLE_LABEL_Y); + if (_upButton->GetParent() == nullptr && _viewModel->IsInSubCategory()) + { + AddChildTail(_upButton.GetPointer()); + } + else if (_upButton->GetParent() != nullptr && !_viewModel->IsInSubCategory()) + { + RemoveChild(_upButton.GetPointer()); + } + + _titleLabel->SetPosition(TITLE_LABEL_X, _position.y + TITLE_LABEL_Y); if (_viewModel->GetState() == CheatsViewModel::State::DisplayCheats) { - _secondaryLabel.SetPosition(CATEGORY_NAME_LABEL_X, _position.y + CATEGORY_NAME_LABEL_Y); + _secondaryLabel->SetPosition(CATEGORY_NAME_LABEL_X, _position.y + CATEGORY_NAME_LABEL_Y); } else { - _secondaryLabel.SetPosition(NO_CHEATS_FOUND_LABEL_X, _position.y + NO_CHEATS_FOUND_LABEL_Y); + _secondaryLabel->SetPosition(NO_CHEATS_FOUND_LABEL_X, _position.y + NO_CHEATS_FOUND_LABEL_Y); } - _descriptionLabel.SetPosition(DESCRIPTION_LABEL_X, _position.y + DESCRIPTION_LABEL_Y); + _descriptionLabel->SetPosition(DESCRIPTION_LABEL_X, _position.y + DESCRIPTION_LABEL_Y); _cheatListRecycler->SetPosition(LIST_X, _position.y + LIST_Y); + _upButton->SetPosition(212, _position.y + CATEGORY_NAME_LABEL_Y - 8); if (_viewModel->GetState() == CheatsViewModel::State::DisplayCheats) { if (!_cheatsAdapter && _objVramManager != nullptr) { + _currentCheatCategory = _viewModel->GetCurrentCheatCategory(); _cheatsAdapter = SharedPtr::MakeShared( - _viewModel->GetCurrentCheatCategory(), _materialColorScheme, _fontRepository, _vramOffsets); + _currentCheatCategory, _viewModel, _materialColorScheme, _fontRepository, _vramOffsets); _cheatListRecycler->SetAdapter(_cheatsAdapter); // Ugly hack @@ -108,6 +125,12 @@ void CheatsBottomSheetView::Update() _cheatListRecycler->InitVram(VramContext(nullptr, _objVramManager, nullptr, nullptr)); _cheatListRecycler->Focus(*_focusManager); } + else if (_currentCheatCategory != _viewModel->GetCurrentCheatCategory() + && _viewModel->GetCurrentCheatCategory() != nullptr) + { + // _secondaryLabel->SetText(_viewModel->GetCurrentCheatCategory()->GetName()); + UpdateCheatList(); + } } BottomSheetView::Update(); int selectedItem = _cheatListRecycler->GetSelectedItem(); @@ -175,21 +198,26 @@ void CheatsBottomSheetView::Draw(GraphicsContext& graphicsContext) .Build(maskOam[7]); } - _titleLabel.SetBackgroundColor(backColor); - _titleLabel.SetForegroundColor(_materialColorScheme->onSurface); - _titleLabel.Draw(graphicsContext); + _titleLabel->SetBackgroundColor(backColor); + _titleLabel->SetForegroundColor(_materialColorScheme->onSurface); + _titleLabel->Draw(graphicsContext); if (_viewModel->GetState() == CheatsViewModel::State::NoCheats || - _viewModel->ShouldShowCategoryName()) + _viewModel->IsInSubCategory()) { - _secondaryLabel.SetBackgroundColor(backColor); - _secondaryLabel.SetForegroundColor(_materialColorScheme->onSurfaceVariant); - _secondaryLabel.Draw(graphicsContext); + _secondaryLabel->SetBackgroundColor(backColor); + _secondaryLabel->SetForegroundColor(_materialColorScheme->onSurfaceVariant); + _secondaryLabel->Draw(graphicsContext); } - _descriptionLabel.SetBackgroundColor(backColor); - _descriptionLabel.SetForegroundColor(_materialColorScheme->onSurfaceVariant); - _descriptionLabel.Draw(graphicsContext); + _descriptionLabel->SetBackgroundColor(backColor); + _descriptionLabel->SetForegroundColor(_materialColorScheme->onSurfaceVariant); + _descriptionLabel->Draw(graphicsContext); + + if (_viewModel->IsInSubCategory()) + { + _upButton->Draw(graphicsContext); + } } graphicsContext.SetPriority(oldPrio); graphicsContext.ResetClipArea(); @@ -197,29 +225,9 @@ void CheatsBottomSheetView::Draw(GraphicsContext& graphicsContext) bool CheatsBottomSheetView::HandleInput(const InputProvider& inputProvider, FocusManager& focusManager) { - if (inputProvider.Triggered(InputKey::A)) + if (inputProvider.Triggered(InputKey::B)) { - if (focusManager.IsFocusInside(_cheatListRecycler.GetPointer())) - { - auto oldCategory = _viewModel->GetCurrentCheatCategory(); - _viewModel->ActivateSelectedItem(); - if (oldCategory != _viewModel->GetCurrentCheatCategory()) - { - _secondaryLabel.SetText(_viewModel->GetCurrentCheatCategory()->GetName()); - UpdateCheatList(); - } - - return true; - } - } - else if (inputProvider.Triggered(InputKey::B)) - { - auto oldCategory = _viewModel->GetCurrentCheatCategory(); - if (_viewModel->NavigateUp() && - oldCategory != _viewModel->GetCurrentCheatCategory()) - { - UpdateCheatList(); - } + _viewModel->NavigateUp(); return true; } else if (inputProvider.Triggered(InputKey::Y)) @@ -235,13 +243,16 @@ bool CheatsBottomSheetView::HandleInput(const InputProvider& inputProvider, Focu return false; } +void CheatsBottomSheetView::Close() +{ + _viewModel->Close(); +} + void CheatsBottomSheetView::UpdateCheatList() { - // Need to unfocus first, otherwise the focus manager still contains a pointer to a view that is going to be destroyed - _focusManager->Unfocus(); - + _currentCheatCategory = _viewModel->GetCurrentCheatCategory(); _cheatsAdapter = SharedPtr::MakeShared( - _viewModel->GetCurrentCheatCategory(), _materialColorScheme, _fontRepository, _vramOffsets); + _currentCheatCategory, _viewModel, _materialColorScheme, _fontRepository, _vramOffsets); _cheatListRecycler->SetAdapter(_cheatsAdapter, _viewModel->GetSelectedItem()); // Ugly hack @@ -257,13 +268,20 @@ void CheatsBottomSheetView::UpdateDescriptionText() int selectedItem = _viewModel->GetSelectedItem(); if (selectedItem < 0) { - _descriptionLabel.SetText(""); + _descriptionLabel->SetText(""); } else { auto cheatCategory = _viewModel->GetCurrentCheatCategory(); u32 numberOfSubEntries = 0; auto subEntries = cheatCategory->GetSubEntries(numberOfSubEntries); - _descriptionLabel.SetText(subEntries[selectedItem].GetDescription()); + _descriptionLabel->SetText(subEntries[selectedItem].GetDescription()); } } + +u32 CheatsBottomSheetView::LoadSprite(IVramManager& vramManager, const unsigned int* tiles, u32 tilesLength) const +{ + u32 vramOffset = vramManager.Alloc(tilesLength); + dma_ntrCopy32(3, tiles, vramManager.GetVramAddress(vramOffset), tilesLength); + return vramOffset; +} diff --git a/arm9/source/romBrowser/views/cheats/CheatsBottomSheetView.h b/arm9/source/romBrowser/views/cheats/CheatsBottomSheetView.h index fb9d2da..b30da0d 100644 --- a/arm9/source/romBrowser/views/cheats/CheatsBottomSheetView.h +++ b/arm9/source/romBrowser/views/cheats/CheatsBottomSheetView.h @@ -7,6 +7,7 @@ #include "romBrowser/viewModels/CheatsViewModel.h" #include "CheatsAdapter.h" #include "CheatListItemView.h" +#include "romBrowser/views/IconButton2DView.h" class MaterialColorScheme; class IFontRepository; @@ -15,11 +16,9 @@ class IVramManager; /// @brief Bottom sheet for browsing and enabling/disabling cheats. class CheatsBottomSheetView : public BottomSheetView { -public: - CheatsBottomSheetView(std::unique_ptr viewModel, - const MaterialColorScheme* materialColorScheme, const IFontRepository* fontRepository, - FocusManager* focusManager); + SHARED_ONLY(CheatsBottomSheetView) +public: void InitVram(const VramContext& vramContext) override; void Update() override; void Draw(GraphicsContext& graphicsContext) override; @@ -30,20 +29,30 @@ public: _cheatListRecycler->Focus(focusManager); } +protected: + void Close() override; + private: - std::unique_ptr _viewModel; - Label2DView _titleLabel; - Label2DView _secondaryLabel; - Label2DView _descriptionLabel; + SharedPtr _viewModel; + SharedPtr _titleLabel; + SharedPtr _secondaryLabel; + SharedPtr _descriptionLabel; SharedPtr _cheatListRecycler; SharedPtr _cheatsAdapter; + SharedPtr _upButton; const MaterialColorScheme* _materialColorScheme; const IFontRepository* _fontRepository; IVramManager* _objVramManager = nullptr; FocusManager* _focusManager; CheatListItemView::VramOffsets _vramOffsets; u32 _savedVramState = 0; + const CheatEntry* _currentCheatCategory = nullptr; + + CheatsBottomSheetView(SharedPtr viewModel, + const MaterialColorScheme* materialColorScheme, const IFontRepository* fontRepository, + FocusManager* focusManager); void UpdateCheatList(); void UpdateDescriptionText(); + u32 LoadSprite(IVramManager& vramManager, const unsigned int* tiles, u32 tilesLength) const; }; diff --git a/common/sharedMemory.h b/common/sharedMemory.h index c594dc0..66c2fdd 100644 --- a/common/sharedMemory.h +++ b/common/sharedMemory.h @@ -1,3 +1,5 @@ #pragma once #define SHARED_KEY_XY (*(vu16*)0x02FFFFA8) +#define SHARED_TOUCH_X (*(vu16*)0x02FFFFAA) +#define SHARED_TOUCH_Y (*(vu16*)0x02FFFFAC)