7 Commits

142 changed files with 3387 additions and 1234 deletions

View File

@@ -2,6 +2,16 @@
## [Unreleased]
## [v1.3.0] - 18 Apr 2026
### 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
### Added

View File

@@ -23,7 +23,7 @@ General usage documentation can be found here: [Usage](docs/Usage.md).
We recommend using WSL (Windows Subsystem for Linux), or MSYS2 to compile this repository.
The steps provided will assume you already have one of those environments set up.
1. Install [BlocksDS](https://blocksds.skylyrac.net/docs/setup/options/)
1. Install [BlocksDS](https://blocksds.skylyrac.net/docs/setup/)
## Compiling

View File

@@ -88,6 +88,12 @@
"b": 200
}
},
"topCover": {
"position": {
"x": 75,
"y": 18
}
},
"gridIcon": {
"blendColor": {
"r": 200,

View File

@@ -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<IOutputStream>(&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();
}

146
arm7/source/touchScreen.cpp Normal file
View File

@@ -0,0 +1,146 @@
#include "common.h"
#include <nds/input.h>
#include <nds/arm7/touch.h>
// 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;
}

View File

@@ -0,0 +1,5 @@
#pragma once
#include <nds/touch.h>
void touch_init();
bool touch_update(touchPosition& touchPos);

7
arm9/gfx/upIcon.grit Normal file
View File

@@ -0,0 +1,7 @@
# tile format
-gt
# graphics bit depth is 4 (16 color)
-gB4
-p!

BIN
arm9/gfx/upIcon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 B

View File

@@ -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 = 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<CheatsViewModel>(_romBrowserController.GetTriggerFileInfo(), &_romBrowserController);
auto cheatsDialog = std::make_unique<CheatsBottomSheetView>(
auto cheatsViewModel = SharedPtr<CheatsViewModel>::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<DisplaySettingsBottomSheetView>(
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 = 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 = 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 = 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;
}
}

View File

@@ -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"
@@ -28,7 +29,6 @@
#include "romBrowser/RomBrowserController.h"
#include "DialogPresenter.h"
#include "themes/ITheme.h"
#include "core/SharedPtr.h"
#include "animation/Animator.h"
class alignas(32) App : public IProcess
@@ -63,9 +63,9 @@ private:
Rgb6Palette _rgb6Palette;
Animator<int> _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<ITheme> _theme;
@@ -76,12 +76,13 @@ private:
IBgmService& _bgmService;
volatile bool _exit = false;
PadInputSource _inputSource;
PadInputSource _keyInputSource;
TouchInputSource _touchInputSource;
SampledInputProvider _inputProvider;
InputRepeater _inputRepeater;
std::unique_ptr<RomBrowserBottomScreenView> _romBrowserBottomScreenView;
std::unique_ptr<RomBrowserTopScreenView> _romBrowserTopScreenView;
SharedPtr<RomBrowserBottomScreenView> _romBrowserBottomScreenView;
SharedPtr<RomBrowserTopScreenView> _romBrowserTopScreenView;
RomBrowserController _romBrowserController;
@@ -104,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();

View File

@@ -16,10 +16,12 @@ DialogPresenter::DialogPresenter(FocusManager* focusManager, StackVramManager* v
_baseVramState = _vramManager->GetState();
}
void DialogPresenter::ShowDialog(std::unique_ptr<DialogView> dialog)
void DialogPresenter::ShowDialog(SharedPtr<DialogView> 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;
}
@@ -153,3 +155,27 @@ void DialogPresenter::InitVram()
REG_BLDCNT = 0x3944;
REG_BLDALPHA = (16 << 8) | 0;
}
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);
}
}

View File

@@ -1,5 +1,6 @@
#pragma once
#include <memory>
#include "core/SharedPtr.h"
#include "animation/Animator.h"
#include "gui/views/DialogView.h"
@@ -14,7 +15,7 @@ public:
/// @brief Requests to show the given dialog.
/// @param dialog The dialog to show.
void ShowDialog(std::unique_ptr<DialogView> dialog);
void ShowDialog(SharedPtr<DialogView> dialog);
/// @brief Closes the current dialog.
void CloseDialog();
@@ -41,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()
{
@@ -49,11 +65,16 @@ public:
/// @brief Gets the focus that was stored when a dialog was opened.
/// @return The view that was focused when the current dialog was opened.
constexpr View* GetOldFocus() const
constexpr SharedPtr<View> GetOldFocus() const
{
return _oldFocus;
}
bool IsBottomSheetVisible() const
{
return _curState != State::Idle;
}
private:
enum class State
{
@@ -65,10 +86,10 @@ private:
FocusManager* _focusManager;
StackVramManager* _vramManager;
u32 _baseVramState;
std::unique_ptr<DialogView> _currentDialog;
std::unique_ptr<DialogView> _nextDialog;
SharedPtr<DialogView> _currentDialog;
SharedPtr<DialogView> _nextDialog;
bool _initVram = false;
View* _oldFocus = nullptr;
SharedPtr<View> _oldFocus = nullptr;
Animator<int> _scrimAnimator;
Animator<int> _yAnimator;
State _curState = State::Idle;

View File

@@ -0,0 +1,35 @@
#include "common.h"
#include <libtwl/rtos/rtosIrq.h>
#include "AtomicSharedPtr.h"
void AtomicSharedPtrBase::Reset(void* newObject, RefCount* newRefCount, bool increaseNewRefCount)
{
u32 irq = rtos_disableIrqs(); // 1
auto refCount = _refCount;
_object = newObject;
_refCount = newRefCount;
if (increaseNewRefCount && _refCount)
{
_refCount->refCount++;
}
if (refCount && --refCount->refCount == 0) [[gnu::unlikely]]
{
refCount->weakRefCount++; // ensure the ref count is not destructed elsewhere
rtos_restoreIrqs(irq); // 1
refCount->DestructObject();
irq = rtos_disableIrqs(); // 2
if (--refCount->weakRefCount == 0) [[gnu::unlikely]]
{
rtos_restoreIrqs(irq); // 2
delete refCount;
}
else
{
rtos_restoreIrqs(irq); // 2
}
}
else
{
rtos_restoreIrqs(irq); // 1
}
}

View File

@@ -0,0 +1,134 @@
#pragma once
#include <type_traits>
#include <libtwl/rtos/rtosIrq.h>
#include "SharedPtr.h"
class AtomicSharedPtrBase
{
public:
void Reset()
{
Reset(nullptr, nullptr, false);
}
protected:
void* volatile _object;
RefCount* volatile _refCount;
AtomicSharedPtrBase()
: _object(nullptr), _refCount(nullptr) { }
AtomicSharedPtrBase(void* object, RefCount* refCount)
: _object(object), _refCount(refCount) { }
~AtomicSharedPtrBase()
{
Reset(nullptr, nullptr, false);
}
void Reset(void* newObject, RefCount* newRefCount, bool increaseNewRefCount);
};
template <class T>
class AtomicSharedPtr : public AtomicSharedPtrBase
{
public:
AtomicSharedPtr() { }
AtomicSharedPtr(std::nullptr_t) { }
AtomicSharedPtr(const SharedPtr<T>& sharedPtr)
: AtomicSharedPtrBase(sharedPtr._object, sharedPtr._refCount)
{
if (_refCount)
{
shared_ptr_increase_ref_count(_refCount->refCount);
}
}
template <class Y> requires std::assignable_from<T*&, Y*>
AtomicSharedPtr(const SharedPtr<Y>& sharedPtr)
: AtomicSharedPtrBase(static_cast<T*>(sharedPtr.GetPointer()), sharedPtr._refCount)
{
if (_refCount)
{
shared_ptr_increase_ref_count(_refCount->refCount);
}
}
template <class Y>
explicit AtomicSharedPtr(const SharedPtr<Y>& sharedPtr)
: AtomicSharedPtrBase(static_cast<T*>(sharedPtr.GetPointer()), sharedPtr._refCount)
{
if (_refCount)
{
shared_ptr_increase_ref_count(_refCount->refCount);
}
}
AtomicSharedPtr(SharedPtr<T>&& sharedPtr)
: AtomicSharedPtrBase(sharedPtr._object, sharedPtr._refCount)
{
sharedPtr._object = nullptr;
sharedPtr._refCount = nullptr;
}
template <class Y> requires std::assignable_from<T*&, Y*>
AtomicSharedPtr(SharedPtr<Y>&& sharedPtr)
: AtomicSharedPtrBase(static_cast<T*>(sharedPtr.GetPointer()), sharedPtr._refCount)
{
sharedPtr._object = nullptr;
sharedPtr._refCount = nullptr;
}
template <class Y>
explicit AtomicSharedPtr(SharedPtr<Y>&& sharedPtr)
: AtomicSharedPtrBase(static_cast<T*>(sharedPtr.GetPointer()), sharedPtr._refCount)
{
sharedPtr._object = nullptr;
sharedPtr._refCount = nullptr;
}
AtomicSharedPtr& operator=(const SharedPtr<T>& sharedPtr)
{
Reset(sharedPtr._object, sharedPtr._refCount, true);
return *this;
}
template <class Y> requires std::assignable_from<T*&, Y*>
AtomicSharedPtr<T>& operator=(const SharedPtr<Y>& sharedPtr)
{
Reset(static_cast<T*>(sharedPtr.GetPointer()), sharedPtr._refCount, true);
return *this;
}
AtomicSharedPtr& operator=(SharedPtr<T>&& sharedPtr)
{
Reset(sharedPtr._object, sharedPtr._refCount, false);
sharedPtr._object = nullptr;
sharedPtr._refCount = nullptr;
return *this;
}
template <class Y> requires std::assignable_from<T*&, Y*>
AtomicSharedPtr<T>& operator=(SharedPtr<Y>&& sharedPtr)
{
Reset(static_cast<T*>(sharedPtr.GetPointer()), sharedPtr._refCount, false);
sharedPtr._object = nullptr;
sharedPtr._refCount = nullptr;
return *this;
}
SharedPtr<T> Lock() const
{
u32 irq = rtos_disableIrqs();
auto object = static_cast<T*>(_object);
auto refCount = _refCount;
if (refCount)
{
refCount->refCount++;
}
rtos_restoreIrqs(irq);
return SharedPtr<T>(object, refCount);
}
};

View File

@@ -0,0 +1,42 @@
#pragma once
#include "SharedPtr.h"
#include "WeakPtr.h"
class EnableSharedFromThisBase
{
template <class Y>
friend class SharedPtr;
template <class Y>
friend class EnableSharedFromThis;
private:
EnableSharedFromThisBase() = default;
};
template <class T>
class EnableSharedFromThis : public EnableSharedFromThisBase
{
template <class Y>
friend class SharedPtr;
public:
SharedPtr<T> SharedFromThis()
{
return __sharedFromThisWeakPtr.Lock();
}
WeakPtr<T> WeakFromThis()
{
return __sharedFromThisWeakPtr;
}
private:
WeakPtr<T> __sharedFromThisWeakPtr;
template <class Y>
void __SetSharedFromThisWeakPtr(const SharedPtr<Y>& sharedPtr)
{
__sharedFromThisWeakPtr = WeakPtr<Y>(sharedPtr.GetPointer(), sharedPtr._refCount);
}
};

View File

@@ -0,0 +1,58 @@
#pragma once
#include <array>
extern "C" void shared_ptr_increase_ref_count(vu32& refCount);
class RefCount
{
public:
vu32 refCount;
vu32 weakRefCount;
virtual ~RefCount() = default;
virtual void DestructObject() = 0;
protected:
explicit RefCount()
: refCount(1), weakRefCount(0) { }
};
template <class T>
class StandaloneRefCount : public RefCount
{
public:
explicit StandaloneRefCount(T* object)
: _object(object) { }
void DestructObject() final
{
delete _object;
}
private:
T* _object;
};
template <class T>
class alignas(T) MakeSharedRefCount : public RefCount
{
public:
explicit MakeSharedRefCount(auto&&... args)
{
new (_object.data()) T(std::forward<decltype(args)>(args)...);
}
T* GetObject()
{
return reinterpret_cast<T*>(_object.data());
}
void DestructObject() final
{
reinterpret_cast<T*>(_object.data())->~T();
}
private:
std::array<u8, sizeof(T)> _object alignas(T);
};

View File

@@ -0,0 +1,31 @@
#include "common.h"
#include <libtwl/rtos/rtosIrq.h>
#include "SharedPtr.h"
void SharedPtrBase::ResetIntern()
{
auto refCount = _refCount;
_object = nullptr;
_refCount = nullptr;
u32 irq = rtos_disableIrqs(); // 1
if (--refCount->refCount == 0) [[gnu::unlikely]]
{
refCount->weakRefCount++; // ensure the ref count is not destructed elsewhere
rtos_restoreIrqs(irq); // 1
refCount->DestructObject();
irq = rtos_disableIrqs(); // 2
if (--refCount->weakRefCount == 0) [[gnu::unlikely]]
{
rtos_restoreIrqs(irq); // 2
delete refCount;
}
else
{
rtos_restoreIrqs(irq); // 2
}
}
else
{
rtos_restoreIrqs(irq); // 1
}
}

View File

@@ -1,163 +1,216 @@
#pragma once
#include <type_traits>
#include "RefCount.h"
static inline u32 arm_getCpsr()
{
u32 cpsr;
asm volatile("mrs %0, cpsr" : "=r" (cpsr));
return cpsr;
}
static inline void arm_setCpsrControl(u32 cpsrControl)
{
asm volatile("msr cpsr_c, %0" :: "r" (cpsrControl) : "cc");
}
static inline u32 arm_disableIrqs(void)
{
u32 oldCpsr = arm_getCpsr();
arm_setCpsrControl(oldCpsr | 0x80);
return oldCpsr;
}
static inline void arm_restoreIrqs(u32 oldCpsr)
{
arm_setCpsrControl(oldCpsr);
}
class EnableSharedFromThisBase;
template <class T>
class SharedPtr
class EnableSharedFromThis;
class SharedPtrBase
{
T* _pointer;
vu32* _refCount;
public:
SharedPtr()
: _pointer(nullptr), _refCount(nullptr) { (void)sizeof(T); }
explicit SharedPtr(T* pointer)
: _pointer(pointer), _refCount(pointer ? new u32(1) : nullptr) { (void)sizeof(T); }
SharedPtr(const SharedPtr& other)
void Reset()
{
u32 irq = arm_disableIrqs();
_pointer = other._pointer;
_refCount = other._refCount;
if (_pointer)
if (_refCount != nullptr)
{
(*_refCount)++;
ResetIntern();
}
arm_restoreIrqs(irq);
}
SharedPtr(SharedPtr&& other)
: _pointer(other._pointer), _refCount(other._refCount)
{
other._pointer = nullptr;
other._refCount = nullptr;
}
protected:
void* _object;
RefCount* _refCount;
~SharedPtr()
SharedPtrBase()
: _object(nullptr), _refCount(nullptr) { }
SharedPtrBase(void* object, RefCount* refCount)
: _object(object), _refCount(refCount) { }
SharedPtrBase(const void* object, RefCount* refCount)
: _object((void*)object), _refCount(refCount) { }
~SharedPtrBase()
{
Reset();
}
[[gnu::noinline]]
void ResetIntern();
};
template <class T>
class SharedPtr : public SharedPtrBase
{
template <class Y> friend class WeakPtr;
template <class Y> friend class SharedPtr;
template <class Y> friend class AtomicSharedPtr;
template <class Y> friend class EnableSharedFromThis;
public:
SharedPtr() { }
SharedPtr(std::nullptr_t) { }
explicit SharedPtr(T* object)
: SharedPtrBase(object, object == nullptr ? nullptr : new StandaloneRefCount<T>(object))
{
if (_object != nullptr)
{
if constexpr (std::is_convertible<T*, EnableSharedFromThisBase*>::value)
{
_refCount->weakRefCount = 1;
GetPointer()->__SetSharedFromThisWeakPtr(*this);
}
}
}
template <class Y> requires std::assignable_from<T*&, Y*>
explicit SharedPtr(Y* object)
: SharedPtrBase(static_cast<T*>(object), object == nullptr ? nullptr : new StandaloneRefCount<Y>(object))
{
if (object != nullptr)
{
if constexpr (std::is_convertible<Y*, EnableSharedFromThisBase*>::value)
{
_refCount->weakRefCount = 1;
GetPointer()->__SetSharedFromThisWeakPtr(*this);
}
}
}
SharedPtr(const SharedPtr& other)
: SharedPtrBase(other._object, other._refCount)
{
if (_refCount)
{
shared_ptr_increase_ref_count(_refCount->refCount);
}
}
template <class Y> requires std::assignable_from<T*&, Y*>
SharedPtr(const SharedPtr<Y>& other)
: SharedPtrBase(static_cast<T*>(other.GetPointer()), other._refCount)
{
if (_refCount)
{
shared_ptr_increase_ref_count(_refCount->refCount);
}
}
template <class Y>
explicit SharedPtr(const SharedPtr<Y>& other)
: SharedPtrBase(static_cast<T*>(other.GetPointer()), other._refCount)
{
if (_refCount)
{
shared_ptr_increase_ref_count(_refCount->refCount);
}
}
SharedPtr(SharedPtr&& other)
: SharedPtrBase(other._object, other._refCount)
{
other._object = nullptr;
other._refCount = nullptr;
}
template <class Y> requires std::assignable_from<T*&, Y*>
SharedPtr(SharedPtr<Y>&& other)
: SharedPtrBase(static_cast<T*>(other.GetPointer()), other._refCount)
{
other._object = nullptr;
other._refCount = nullptr;
}
template <class Y>
explicit SharedPtr(SharedPtr<Y>&& other)
: SharedPtrBase(static_cast<T*>(other.GetPointer()), other._refCount)
{
other._object = nullptr;
other._refCount = nullptr;
}
static SharedPtr<T> MakeShared(auto&&... args)
{
auto refCount = new MakeSharedRefCount<T>(std::forward<decltype(args)>(args)...);
return SharedPtr<T>(refCount->GetObject(), refCount, true);
}
SharedPtr& operator=(const SharedPtr& other)
{
u32 irq = arm_disableIrqs();
T* pointer = _pointer;
if (pointer)
Reset();
_object = other._object;
_refCount = other._refCount;
if (_refCount)
{
vu32* refCount = _refCount;
u32 newValue = *refCount - 1;
*refCount = newValue;
_pointer = other._pointer;
_refCount = other._refCount;
if (_pointer)
{
(*_refCount)++;
}
arm_restoreIrqs(irq);
if (newValue == 0)
{
delete pointer;
delete refCount;
}
}
else
{
_pointer = other._pointer;
_refCount = other._refCount;
if (_pointer)
{
(*_refCount)++;
}
arm_restoreIrqs(irq);
shared_ptr_increase_ref_count(_refCount->refCount);
}
return *this;
}
template <class Y> requires std::assignable_from<T*&, Y*>
SharedPtr<T>& operator=(const SharedPtr<Y>& other)
{
Reset();
_object = static_cast<T*>(other.GetPointer());
_refCount = other._refCount;
if (_refCount)
{
shared_ptr_increase_ref_count(_refCount->refCount);
}
return *this;
}
[[gnu::noinline]]
SharedPtr& operator=(SharedPtr&& other)
{
u32 irq = arm_disableIrqs();
T* pointer = _pointer;
if (pointer)
{
vu32* refCount = _refCount;
u32 newValue = *refCount - 1;
*refCount = newValue;
_pointer = other._pointer;
_refCount = other._refCount;
other._pointer = nullptr;
other._refCount = nullptr;
arm_restoreIrqs(irq);
if (newValue == 0)
{
delete pointer;
delete refCount;
}
}
else
{
_pointer = other._pointer;
_refCount = other._refCount;
other._pointer = nullptr;
other._refCount = nullptr;
arm_restoreIrqs(irq);
}
Reset();
_object = other._object;
_refCount = other._refCount;
other._object = nullptr;
other._refCount = nullptr;
return *this;
}
[[gnu::noinline]]
void Reset()
template <class Y> requires std::assignable_from<T*&, Y*>
SharedPtr<T>& operator=(SharedPtr<Y>&& other)
{
u32 irq = arm_disableIrqs();
T* pointer = _pointer;
if (pointer)
{
vu32* refCount = _refCount;
u32 newValue = *refCount - 1;
*refCount = newValue;
_pointer = nullptr;
_refCount = nullptr;
arm_restoreIrqs(irq);
if (newValue == 0)
{
delete pointer;
delete refCount;
}
}
else
{
arm_restoreIrqs(irq);
}
Reset();
_object = static_cast<T*>(other.GetPointer());
_refCount = other._refCount;
other._object = nullptr;
other._refCount = nullptr;
return *this;
}
constexpr T& operator*() const { return *_pointer; }
constexpr T* operator->() const { return _pointer; }
T& operator*() const { return *static_cast<T*>(_object); }
T* operator->() const { return static_cast<T*>(_object); }
T* GetPointer() const { return static_cast<T*>(_object); }
constexpr T* GetPointer() const { return _pointer; }
constexpr u32 GetRefCount() const { return _refCount ? *_refCount : 0; }
constexpr bool IsValid() const { return _pointer; }
bool IsValid() const { return _object != nullptr; }
operator bool() const { return _object != nullptr; }
private:
SharedPtr(T* object, RefCount* refCount)
: SharedPtrBase(object, refCount) { }
SharedPtr(T* object, RefCount* refCount, bool doSharedFromThis)
: SharedPtrBase(object, refCount)
{
if (doSharedFromThis)
{
if constexpr (std::is_convertible<T*, EnableSharedFromThisBase*>::value)
{
_refCount->weakRefCount = 1;
GetPointer()->__SetSharedFromThisWeakPtr(*this);
}
}
}
};
#define SHARED_ONLY(className) \
friend class MakeSharedRefCount<className>; \
public: \
static SharedPtr<className> CreateShared(auto&&... args) \
{ return SharedPtr<className>::MakeShared(std::forward<decltype(args)>(args)...); } \
private:

View File

@@ -0,0 +1,15 @@
.section .itcm
.arm
// r0 = &refCount
.global shared_ptr_increase_ref_count
.type shared_ptr_increase_ref_count, %function
shared_ptr_increase_ref_count:
mrs r2, cpsr
orr r1, r2, #0x80
msr cpsr_c, r1
ldr r12, [r0]
add r12, r12, #1
str r12, [r0]
msr cpsr_c, r2
bx lr

View File

@@ -0,0 +1,35 @@
#include "common.h"
#include <libtwl/rtos/rtosIrq.h>
#include "WeakPtr.h"
void WeakPtrBase::ResetIntern()
{
u32 irq = rtos_disableIrqs();
auto refCount = _refCount;
if (--refCount->weakRefCount == 0)
{
_refCount = nullptr;
rtos_restoreIrqs(irq);
delete refCount;
}
else
{
rtos_restoreIrqs(irq);
}
}
bool WeakPtrBase::LockIntern() const
{
u32 irq = rtos_disableIrqs();
if (_refCount->refCount != 0)
{
_refCount->refCount++;
rtos_restoreIrqs(irq);
return true;
}
else
{
rtos_restoreIrqs(irq);
return false;
}
}

158
arm9/source/core/WeakPtr.h Normal file
View File

@@ -0,0 +1,158 @@
#pragma once
#include <type_traits>
#include "RefCount.h"
#include "SharedPtr.h"
class WeakPtrBase
{
public:
~WeakPtrBase()
{
Reset();
}
void Reset()
{
if (_refCount)
{
Reset();
}
}
protected:
RefCount* _refCount;
WeakPtrBase()
: _refCount(nullptr) { }
explicit WeakPtrBase(RefCount* refCount)
: _refCount(refCount) { }
void ResetIntern();
bool LockIntern() const;
};
template <class T>
class WeakPtr : public WeakPtrBase
{
template <class Y> friend class WeakPtr;
template <class Y> friend class EnableSharedFromThis;
public:
WeakPtr() { }
WeakPtr(std::nullptr_t) { }
WeakPtr(const WeakPtr& other)
: WeakPtrBase(other._refCount), _object(other._object)
{
if (_refCount)
{
shared_ptr_increase_ref_count(_refCount->weakRefCount);
}
}
WeakPtr(WeakPtr&& other)
: WeakPtrBase(other._refCount), _object(other._object)
{
other._refCount = nullptr;
other._object = nullptr;
}
template <class Y> requires std::assignable_from<T*&, Y*>
WeakPtr(const SharedPtr<Y>& sharedPtr)
: WeakPtrBase(sharedPtr._refCount), _object(static_cast<T*>(sharedPtr.GetPointer()))
{
if (_refCount)
{
shared_ptr_increase_ref_count(_refCount->weakRefCount);
}
}
template <class Y>
explicit WeakPtr(const SharedPtr<Y>& sharedPtr)
: WeakPtrBase(sharedPtr._refCount), _object(static_cast<T*>(sharedPtr.GetPointer()))
{
if (_refCount)
{
shared_ptr_increase_ref_count(_refCount->weakRefCount);
}
}
WeakPtr& operator=(const WeakPtr& other)
{
Reset();
_object = other._object;
_refCount = other._refCount;
if (_refCount)
{
shared_ptr_increase_ref_count(_refCount->weakRefCount);
}
return *this;
}
template <class Y> requires std::assignable_from<T*&, Y*>
WeakPtr<T>& operator=(const WeakPtr<Y>& other)
{
Reset();
_object = static_cast<T*>(static_cast<Y*>(other._object));
_refCount = other._refCount;
if (_refCount)
{
shared_ptr_increase_ref_count(_refCount->weakRefCount);
}
return *this;
}
template <class Y> requires std::assignable_from<T*&, Y*>
WeakPtr<T>& operator=(const SharedPtr<Y>& sharedPtr)
{
Reset();
_object = static_cast<T*>(sharedPtr.GetPointer());
_refCount = sharedPtr._refCount;
if (_refCount)
{
shared_ptr_increase_ref_count(_refCount->weakRefCount);
}
return *this;
}
WeakPtr& operator=(WeakPtr&& other)
{
Reset();
_object = other._object;
_refCount = other._refCount;
other._object = nullptr;
other._refCount = nullptr;
return *this;
}
template <class Y> requires std::assignable_from<T*&, Y*>
WeakPtr<T>& operator=(WeakPtr<Y>&& other)
{
Reset();
_object = static_cast<T*>(static_cast<Y*>(other._object));
_refCount = other._refCount;
other._object = nullptr;
other._refCount = nullptr;
return *this;
}
SharedPtr<T> Lock() const
{
if (_refCount && LockIntern())
{
return SharedPtr<T>(_object, _refCount);
}
else
{
return SharedPtr<T>();
}
}
private:
T* _object;
WeakPtr(T* object, RefCount* refCount)
: WeakPtrBase(refCount), _object(object) { }
};

View File

@@ -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 <u32 OtherFractionBits>
constexpr fix32<FractionBits + OtherFractionBits> LongMul(const fix16<OtherFractionBits>& other) const
{
@@ -265,21 +281,45 @@ public:
return this->_value < other._value;
}
template <typename TLhs>
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 <typename TLhs>
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 <typename TLhs>
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 <typename TLhs>
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 <u32 OtherFractionBits>
constexpr fix64<FractionBits + OtherFractionBits> LongMul(const fix16<OtherFractionBits>& other) const
{
@@ -354,6 +410,11 @@ public:
return fix64<FractionBits>::FromRawValue((s64)this->_value * other);
}
constexpr fix64<FractionBits> LongMul(double other) const
{
return LongMul(fix32(other));
}
template <u32 OtherFractionBits>
constexpr fix32 operator*(const fix16<OtherFractionBits>& 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());

View File

@@ -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)

View File

@@ -3,14 +3,17 @@
#include <memory>
#include <libtwl/rtos/rtosIrq.h>
#include <libtwl/rtos/rtosThread.h>
#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:

View File

@@ -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

View File

@@ -4,6 +4,7 @@
#include <libtwl/rtos/rtosEvent.h>
#include <libtwl/rtos/rtosThread.h>
#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 <typename T>
@@ -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<T>* task, TaskQueueBase* taskQueue)
: QueueTaskBase(task, taskQueue) { }
@@ -91,12 +98,11 @@ public:
protected:
rtos_event_t _event;
vu32 _queueReadPtr = 0;
vu32 _queueWritePtr = 0;
LinkedList<TaskBase, &TaskBase::link> _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<QueueLength> _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();
}
};

View File

@@ -3,7 +3,7 @@
#include "input/InputProvider.h"
#include "FocusManager.h"
void FocusManager::Focus(View* newFocus)
void FocusManager::Focus(const SharedPtr<View>& newFocus)
{
if (!newFocus)
{
@@ -11,48 +11,71 @@ void FocusManager::Focus(View* newFocus)
return;
}
if (_currentFocus)
_currentFocus->SetFocused(false);
if (auto currentFocus = _currentFocus.Lock())
{
currentFocus->SetFocused(false);
}
newFocus->SetFocused(true);
_currentFocus = newFocus;
}
void FocusManager::Unfocus()
{
if (_currentFocus)
_currentFocus->SetFocused(false);
_currentFocus = nullptr;
if (auto currentFocus = _currentFocus.Lock())
{
currentFocus->SetFocused(false);
}
_currentFocus.Reset();
}
void FocusManager::Update(const InputProvider& inputProvider)
{
if (!_currentFocus || !_currentFocus->GetParent())
auto currentFocus = _currentFocus.Lock();
if (!currentFocus || !currentFocus->GetParent())
return; // todo
View* newFocus = nullptr;
SharedPtr<View> newFocus;
if (inputProvider.Triggered(InputKey::DpadUp))
newFocus = _currentFocus->GetParent()->MoveFocus(_currentFocus, FocusMoveDirection::Up, _currentFocus);
{
newFocus = currentFocus->GetParent()->MoveFocus(currentFocus, FocusMoveDirection::Up, currentFocus.GetPointer());
}
else if (inputProvider.Triggered(InputKey::DpadDown))
newFocus = _currentFocus->GetParent()->MoveFocus(_currentFocus, FocusMoveDirection::Down, _currentFocus);
{
newFocus = currentFocus->GetParent()->MoveFocus(currentFocus, FocusMoveDirection::Down, currentFocus.GetPointer());
}
else if (inputProvider.Triggered(InputKey::DpadLeft))
newFocus = _currentFocus->GetParent()->MoveFocus(_currentFocus, FocusMoveDirection::Left, _currentFocus);
{
newFocus = currentFocus->GetParent()->MoveFocus(currentFocus, FocusMoveDirection::Left, currentFocus.GetPointer());
}
else if (inputProvider.Triggered(InputKey::DpadRight))
newFocus = _currentFocus->GetParent()->MoveFocus(_currentFocus, FocusMoveDirection::Right, _currentFocus);
{
newFocus = currentFocus->GetParent()->MoveFocus(currentFocus, FocusMoveDirection::Right, currentFocus.GetPointer());
}
else
_currentFocus->HandleInput(inputProvider, *this);
{
currentFocus->HandleInput(inputProvider, *this);
}
if (newFocus)
{
Focus(newFocus);
}
}
bool FocusManager::IsFocusInside(const View* view) const
{
auto focusView = _currentFocus;
while (focusView)
if (auto currentFocus = _currentFocus.Lock())
{
if (view == focusView)
return true;
focusView = focusView->GetParent();
auto focusView = currentFocus.GetPointer();
while (focusView)
{
if (view == focusView)
{
return true;
}
focusView = focusView->GetParent();
}
}
return false;
}

View File

@@ -1,4 +1,6 @@
#pragma once
#include <core/SharedPtr.h>
#include <core/WeakPtr.h>
class View;
class InputProvider;
@@ -9,7 +11,7 @@ class FocusManager
public:
/// @brief Focuses the given view.
/// @param newFocus The view to focus.
void Focus(View* newFocus);
void Focus(const SharedPtr<View>& newFocus);
/// @brief Clears the current focus.
void Unfocus();
@@ -20,7 +22,7 @@ public:
/// @brief Gets the currently focused view.
/// @return A pointer to the view that is currently focused, or null if none.
constexpr View* GetCurrentFocus() const { return _currentFocus; }
constexpr SharedPtr<View> GetCurrentFocus() const { return _currentFocus.Lock(); }
/// @brief Checks whether the current focus lies inside the given view.
/// @param view The view to check for.
@@ -28,5 +30,5 @@ public:
bool IsFocusInside(const View* view) const;
private:
View* _currentFocus = nullptr;
WeakPtr<View> _currentFocus;
};

View File

@@ -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;
};

View File

@@ -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;
};

View File

@@ -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)

View File

@@ -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<bool>(_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) { }
};

View File

@@ -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()

View File

@@ -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) { }

View File

@@ -1,17 +1,18 @@
#pragma once
#include "common.h"
#include <nds/input.h>
#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<InputKey>((arm9Mask | (arm7Mask << 10)));
}
};

View File

@@ -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;
}
}

View File

@@ -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;
};

View File

@@ -0,0 +1,24 @@
#pragma once
#include "common.h"
#include <nds/input.h>
#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;
}
}
};

View File

@@ -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;

View File

@@ -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();

View File

@@ -4,14 +4,18 @@
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;

View File

@@ -20,19 +20,15 @@ public:
/// @brief Creates and returns a view for this adapter.
/// @return The created view.
virtual View* CreateView() const = 0;
/// @brief Destroys a \p view for this adapter that was previously created with CreateView.
/// @param view The view to destroy.
virtual void DestroyView(View* view) const = 0;
virtual SharedPtr<View> CreateView() const = 0;
/// @brief Binds the given \p view to the item at the given \p index.
/// @param view The view to bind.
/// @param index The item index to bind to.
virtual void BindView(View* view, int index) const = 0;
virtual void BindView(SharedPtr<View> view, int index) const = 0;
/// @brief Releases a \p view that was previously bound with BindView, such that it can be reused.
/// @param view The view to release.
/// @param index The item index that was bound to the view.
virtual void ReleaseView(View* view, int index) const = 0;
virtual void ReleaseView(SharedPtr<View> view, int index) const = 0;
};

View File

@@ -20,21 +20,21 @@ RecyclerView::~RecyclerView()
{
if (_adapter)
{
for (u32 i = 0; i < _viewPoolTotalCount; i++)
for (u32 i = _viewPoolFreeCount; i < _viewPoolTotalCount; i++)
{
_adapter->DestroyView(_viewPool[i].view);
_adapter->ReleaseView(_viewPool[i].view, _viewPool[i].itemIdx);
}
}
}
void RecyclerView::SetAdapter(const RecyclerAdapter* adapter, int initialSelectedIndex)
void RecyclerView::SetAdapter(SharedPtr<const RecyclerAdapter> adapter, int initialSelectedIndex)
{
if (_adapter)
{
_selectedItem = nullptr;
for (u32 i = 0; i < _viewPoolTotalCount; i++)
for (u32 i = _viewPoolFreeCount; i < _viewPoolTotalCount; i++)
{
_adapter->DestroyView(_viewPool[i].view);
_adapter->ReleaseView(_viewPool[i].view, _viewPool[i].itemIdx);
}
_viewPool.reset();
_viewPoolFreeCount = 0;
@@ -44,7 +44,7 @@ void RecyclerView::SetAdapter(const RecyclerAdapter* adapter, int initialSelecte
_curRangeStart = 0;
_curRangeLength = 0;
}
_adapter = adapter;
_adapter = std::move(adapter);
_adapter->GetViewSize(_itemWidth, _itemHeight);
_itemCount = _adapter->GetItemCount();
if (_mode == Mode::HorizontalList || _mode == Mode::HorizontalGrid)
@@ -178,7 +178,7 @@ void RecyclerView::VBlank()
}
}
View* RecyclerView::MoveFocus(View* currentFocus, FocusMoveDirection direction, View* source)
SharedPtr<View> RecyclerView::MoveFocus(const SharedPtr<View>& currentFocus, FocusMoveDirection direction, View* source)
{
if (_itemCount == 0)
{
@@ -195,9 +195,9 @@ View* RecyclerView::MoveFocus(View* currentFocus, FocusMoveDirection direction,
}
}
View* RecyclerView::MoveFocusHorizontal(View* currentFocus, FocusMoveDirection direction, View* source)
SharedPtr<View> RecyclerView::MoveFocusHorizontal(const SharedPtr<View>& currentFocus, FocusMoveDirection direction, View* source)
{
if (!_selectedItem || currentFocus != _selectedItem->view)
if (!_selectedItem || currentFocus.GetPointer() != _selectedItem->view.GetPointer())
{
// incoming focus
if (direction != FocusMoveDirection::Down)
@@ -207,7 +207,7 @@ View* RecyclerView::MoveFocusHorizontal(View* currentFocus, FocusMoveDirection d
int idx = (-_xOffset + currentFocus->GetPosition().x - _xPadding + ((_xSpacing + _itemWidth) >> 1)) / (_xSpacing + _itemWidth) * _rows;
SetSelectedItem(std::clamp(idx, 0, ((int)_itemCount - 1) / _rows * _rows));
return _selectedItem != nullptr ? _selectedItem->view : this;
return _selectedItem != nullptr ? _selectedItem->view : SharedFromThis();
}
int row = _selectedItem->itemIdx % _rows;
@@ -248,22 +248,28 @@ View* RecyclerView::MoveFocusHorizontal(View* currentFocus, FocusMoveDirection d
SetSelectedItem(std::clamp(idx, 0, (int)_itemCount - 1));
}
return _selectedItem != nullptr ? _selectedItem->view : this;
return _selectedItem != nullptr ? _selectedItem->view : SharedFromThis();
}
View* RecyclerView::MoveFocusVertical(View* currentFocus, FocusMoveDirection direction, View* source)
SharedPtr<View> RecyclerView::MoveFocusVertical(const SharedPtr<View>& currentFocus, FocusMoveDirection direction, View* source)
{
if (!_selectedItem || currentFocus != _selectedItem->view)
if (!_selectedItem || currentFocus.GetPointer() != _selectedItem->view.GetPointer())
{
// incoming focus
if (direction != FocusMoveDirection::Right)
if (direction == FocusMoveDirection::Right)
{
return nullptr;
int idx = (-_yOffset + currentFocus->GetPosition().y - _yPadding + ((_ySpacing + _itemHeight) >> 1)) / (_ySpacing + _itemHeight) * _columns;
SetSelectedItem(std::clamp(idx, 0, ((int)_itemCount - 1) / _columns * _columns));
return _selectedItem != nullptr ? _selectedItem->view : SharedFromThis();
}
else if (direction == FocusMoveDirection::Down)
{
int idx = (-_xOffset + currentFocus->GetPosition().x - _xPadding + ((_xSpacing + _itemWidth) >> 1)) / (_xSpacing + _itemWidth);
SetSelectedItem(std::clamp(idx, 0, _columns - 1));
return _selectedItem != nullptr ? _selectedItem->view : SharedFromThis();
}
int idx = (-_yOffset + currentFocus->GetPosition().y - _yPadding + ((_ySpacing + _itemHeight) >> 1)) / (_ySpacing + _itemHeight) * _columns;
SetSelectedItem(std::clamp(idx, 0, ((int)_itemCount - 1) / _columns * _columns));
return _selectedItem != nullptr ? _selectedItem->view : this;
return nullptr;
}
int column = _selectedItem->itemIdx % _columns;
@@ -304,7 +310,7 @@ View* RecyclerView::MoveFocusVertical(View* currentFocus, FocusMoveDirection dir
SetSelectedItem(std::clamp(idx, 0, (int)_itemCount - 1));
}
return _selectedItem != nullptr ? _selectedItem->view : this;
return _selectedItem != nullptr ? _selectedItem->view : SharedFromThis();
}
bool RecyclerView::HandleInput(const InputProvider& inputProvider, FocusManager& focusManager)
@@ -341,6 +347,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;

View File

@@ -8,6 +8,8 @@
class RecyclerView : public RecyclerViewBase
{
SHARED_ONLY(RecyclerView)
public:
enum class Mode
{
@@ -21,10 +23,9 @@ public:
VerticalGrid
};
RecyclerView(int x, int y, int width, int height, Mode mode);
~RecyclerView();
void SetAdapter(const RecyclerAdapter* adapter, int initialSelectedIndex = 0) override;
void SetAdapter(SharedPtr<const RecyclerAdapter> adapter, int initialSelectedIndex = 0) override;
void InitVram(const VramContext& vramContext) override;
void Update() override;
void Draw(GraphicsContext& graphicsContext) override;
@@ -35,16 +36,23 @@ public:
return Rectangle(_position, _width, _height);
}
View* MoveFocus(View* currentFocus, FocusMoveDirection direction, View* source) override;
SharedPtr<View> MoveFocus(const SharedPtr<View>& 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
{
if (_selectedItem)
{
focusManager.Focus(_selectedItem->view);
}
else
focusManager.Focus(this);
{
focusManager.Focus(SharedFromThis());
}
}
int GetSelectedItem() const override
@@ -69,7 +77,7 @@ public:
private:
struct ViewPoolEntry
{
View* view;
SharedPtr<View> view;
int itemIdx;
};
@@ -94,6 +102,12 @@ private:
int _curRangeStart;
int _curRangeLength;
Animator<int> _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);
@@ -107,6 +121,6 @@ private:
void EnsureVisible(int itemIdx, bool animate);
Point GetItemPosition(int itemIdx);
View* MoveFocusHorizontal(View* currentFocus, FocusMoveDirection direction, View* source);
View* MoveFocusVertical(View* currentFocus, FocusMoveDirection direction, View* source);
SharedPtr<View> MoveFocusHorizontal(const SharedPtr<View>& currentFocus, FocusMoveDirection direction, View* source);
SharedPtr<View> MoveFocusVertical(const SharedPtr<View>& currentFocus, FocusMoveDirection direction, View* source);
};

View File

@@ -2,16 +2,17 @@
#include "View.h"
#include "RecyclerAdapter.h"
#include "gui/FocusManager.h"
#include "core/SharedPtr.h"
/// @brief Abstract base class for a recycler view that displays a possibly large collection of items
/// provided by an adapter in an efficient way.
class RecyclerViewBase : public View
{
public:
virtual void SetAdapter(const RecyclerAdapter* adapter, int initialSelectedIndex = 0) = 0;
virtual void SetAdapter(SharedPtr<const RecyclerAdapter> adapter, int initialSelectedIndex = 0) = 0;
virtual void Focus(FocusManager& focusManager) = 0;
virtual int GetSelectedItem() const = 0;
protected:
const RecyclerAdapter* _adapter = nullptr;
SharedPtr<const RecyclerAdapter> _adapter;
};

View File

@@ -2,6 +2,8 @@
#include "core/LinkedListLink.h"
#include "core/math/Point.h"
#include "core/math/Rectangle.h"
#include "core/SharedPtr.h"
#include "core/EnableSharedFromThis.h"
#include "../FocusManager.h"
#include "../FocusMoveDirection.h"
@@ -10,7 +12,7 @@ class VramContext;
class InputProvider;
/// @brief Base class for views.
class View
class View : public EnableSharedFromThis<View>
{
public:
/// @brief Link used for views that contain other views.
@@ -37,7 +39,7 @@ public:
/// @param direction The direction to move the focus in.
/// @param source The view that requested this view to move focus.
/// @return The newly focused view, or null if the focus didn't change.
virtual View* MoveFocus(View* currentFocus, FocusMoveDirection direction, View* source)
virtual SharedPtr<View> MoveFocus(const SharedPtr<View>& currentFocus, FocusMoveDirection direction, View* source)
{
if (_parent && _parent != source)
return _parent->MoveFocus(currentFocus, direction, this);
@@ -57,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;

View File

@@ -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);
}
}

View File

@@ -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<View, &View::listLink> _children;
};

View File

@@ -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
@@ -11,27 +12,24 @@ void BannerListFileRecyclerAdapter::GetViewSize(int& width, int& height) const
height = 44;
}
View* BannerListFileRecyclerAdapter::CreateView() const
SharedPtr<View> BannerListFileRecyclerAdapter::CreateView() const
{
return _romBrowserViewFactory->CreateBannerListItemView(_vblankTextureLoader);
return _romBrowserViewFactory->CreateBannerListItemView(
std::make_unique<RomBrowserItemViewModel>(_romBrowserController), _vblankTextureLoader);
}
void BannerListFileRecyclerAdapter::DestroyView(View* view) const
void BannerListFileRecyclerAdapter::BindView(SharedPtr<View> view, int index) const
{
delete static_cast<BannerListItemView*>(view);
}
void BannerListFileRecyclerAdapter::BindView(View* view, int index) const
{
auto listItemView = static_cast<BannerListItemView*>(view);
auto listItemView = static_cast<BannerListItemView*>(view.GetPointer());
listItemView->SetGraphics(_bannerListItemViewGraphics);
FileRecyclerAdapter::BindView(view, index);
}
TaskResult<void> BannerListFileRecyclerAdapter::BindView(View* view, int index,
TaskResult<void> BannerListFileRecyclerAdapter::BindView(SharedPtr<View> view, int index,
const InternalFileInfo* internalFileInfo, const vu8& cancelRequested) const
{
auto listItemView = static_cast<BannerListItemView*>(view);
auto listItemView = static_cast<BannerListItemView*>(view.GetPointer());
listItemView->GetViewModel().SetIndex(index);
const auto& fileInfo = _fileInfoManager->GetItem(index);
bool fileNameAsTitle = true;
if (internalFileInfo)
@@ -70,12 +68,20 @@ TaskResult<void> BannerListFileRecyclerAdapter::BindView(View* view, int index,
return TaskResult<void>::Completed();
}
void BannerListFileRecyclerAdapter::ReleaseView(View* view, int index) const
void BannerListFileRecyclerAdapter::SetQueueTask(const SharedPtr<View>& view, QueueTask<void> queueTask) const
{
auto listItemView = static_cast<BannerListItemView*>(view.GetPointer());
listItemView->GetViewModel().SetQueueTask(std::move(queueTask));
}
void BannerListFileRecyclerAdapter::ReleaseView(SharedPtr<View> view, int index) const
{
LOG_DEBUG("Releasing %d\n", index);
auto listItemView = static_cast<BannerListItemView*>(view);
auto listItemView = static_cast<BannerListItemView*>(view.GetPointer());
listItemView->SetIcon(nullptr);
listItemView->SetGameTitle(u"");
listItemView->GetViewModel().SetIndex(-1);
listItemView->GetViewModel().CancelQueueTask();
_fileInfoManager->ReleaseFileInfo(index);
}

View File

@@ -8,19 +8,18 @@ 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) { }
void GetViewSize(int& width, int& height) const override;
View* CreateView() const override;
void DestroyView(View* view) const override;
void BindView(View* view, int index) const override;
void ReleaseView(View* view, int index) const override;
SharedPtr<View> CreateView() const override;
void BindView(SharedPtr<View> view, int index) const override;
void ReleaseView(SharedPtr<View> view, int index) const override;
void InitVram(const VramContext& vramContext) override;
@@ -29,6 +28,7 @@ private:
BannerListItemView::VramToken _bannerListItemViewGraphics;
VBlankTextureLoader* _vblankTextureLoader;
TaskResult<void> BindView(View* view, int index,
TaskResult<void> BindView(SharedPtr<View> view, int index,
const InternalFileInfo* internalFileInfo, const vu8& cancelRequested) const override;
void SetQueueTask(const SharedPtr<View>& view, QueueTask<void> queueTask) const override;
};

View File

@@ -13,21 +13,17 @@ void CoverFlowFileRecyclerAdapter::GetViewSize(int& width, int& height) const
height = 44;
}
View* CoverFlowFileRecyclerAdapter::CreateView() const
SharedPtr<View> CoverFlowFileRecyclerAdapter::CreateView() const
{
return new CoverView(_vblankTextureLoader);
return CoverView::CreateShared(
std::make_unique<RomBrowserItemViewModel>(_romBrowserController), _vblankTextureLoader);
}
void CoverFlowFileRecyclerAdapter::DestroyView(View* view) const
{
auto coverView = static_cast<CoverView*>(view);
delete coverView;
}
TaskResult<void> CoverFlowFileRecyclerAdapter::BindView(View* view, int index,
TaskResult<void> CoverFlowFileRecyclerAdapter::BindView(SharedPtr<View> view, int index,
const InternalFileInfo* internalFileInfo, const vu8& cancelRequested) const
{
auto coverView = static_cast<CoverView*>(view);
auto coverView = static_cast<CoverView*>(view.GetPointer());
coverView->GetViewModel().SetIndex(index);
auto cover = _fileInfoManager->GetFileCover(index);
if (cancelRequested)
{
@@ -45,11 +41,19 @@ TaskResult<void> CoverFlowFileRecyclerAdapter::BindView(View* view, int index,
return TaskResult<void>::Completed();
}
void CoverFlowFileRecyclerAdapter::ReleaseView(View* view, int index) const
void CoverFlowFileRecyclerAdapter::SetQueueTask(const SharedPtr<View>& view, QueueTask<void> queueTask) const
{
auto coverView = static_cast<CoverView*>(view.GetPointer());
coverView->GetViewModel().SetQueueTask(std::move(queueTask));
}
void CoverFlowFileRecyclerAdapter::ReleaseView(SharedPtr<View> view, int index) const
{
LOG_DEBUG("Releasing %d\n", index);
auto coverView = static_cast<CoverView*>(view);
auto coverView = static_cast<CoverView*>(view.GetPointer());
coverView->ClearCover();
coverView->GetViewModel().SetIndex(-1);
coverView->GetViewModel().CancelQueueTask();
_fileInfoManager->ReleaseFileInfo(index);
}

View File

@@ -8,20 +8,19 @@ 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) { }
void GetViewSize(int& width, int& height) const override;
View* CreateView() const override;
void DestroyView(View* view) const override;
void ReleaseView(View* view, int index) const override;
SharedPtr<View> CreateView() const override;
void ReleaseView(SharedPtr<View> view, int index) const override;
void InitVram(const VramContext& vramContext) override;
@@ -30,6 +29,7 @@ private:
VBlankTextureLoader* _vblankTextureLoader;
const ICoverRepository* _coverRepository;
TaskResult<void> BindView(View* view, int index,
TaskResult<void> BindView(SharedPtr<View> view, int index,
const InternalFileInfo* internalFileInfo, const vu8& cancelRequested) const override;
void SetQueueTask(const SharedPtr<View>& view, QueueTask<void> queueTask) const override;
};

View File

@@ -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
@@ -11,27 +12,23 @@ void IconGridFileRecyclerAdapter::GetViewSize(int& width, int& height) const
height = 44;
}
View* IconGridFileRecyclerAdapter::CreateView() const
SharedPtr<View> IconGridFileRecyclerAdapter::CreateView() const
{
return _romBrowserViewFactory->CreateIconGridItemView();
return _romBrowserViewFactory->CreateIconGridItemView(std::make_unique<RomBrowserItemViewModel>(_romBrowserController));
}
void IconGridFileRecyclerAdapter::DestroyView(View* view) const
void IconGridFileRecyclerAdapter::BindView(SharedPtr<View> view, int index) const
{
delete static_cast<IconGridItemView*>(view);
}
void IconGridFileRecyclerAdapter::BindView(View* view, int index) const
{
auto iconGridItemView = static_cast<IconGridItemView*>(view);
auto iconGridItemView = static_cast<IconGridItemView*>(view.GetPointer());
iconGridItemView->SetGraphics(_iconGridItemViewGraphics);
FileRecyclerAdapter::BindView(view, index);
}
TaskResult<void> IconGridFileRecyclerAdapter::BindView(View* view, int index,
TaskResult<void> IconGridFileRecyclerAdapter::BindView(SharedPtr<View> view, int index,
const InternalFileInfo* internalFileInfo, const vu8& cancelRequested) const
{
auto iconGridItemView = static_cast<IconGridItemView*>(view);
auto iconGridItemView = static_cast<IconGridItemView*>(view.GetPointer());
iconGridItemView->GetViewModel().SetIndex(index);
auto icon = internalFileInfo ? internalFileInfo->CreateGameIcon() : nullptr;
if (!icon)
{
@@ -59,11 +56,19 @@ TaskResult<void> IconGridFileRecyclerAdapter::BindView(View* view, int index,
return TaskResult<void>::Completed();
}
void IconGridFileRecyclerAdapter::ReleaseView(View* view, int index) const
void IconGridFileRecyclerAdapter::SetQueueTask(const SharedPtr<View>& view, QueueTask<void> queueTask) const
{
auto iconGridItemView = static_cast<IconGridItemView*>(view.GetPointer());
iconGridItemView->GetViewModel().SetQueueTask(std::move(queueTask));
}
void IconGridFileRecyclerAdapter::ReleaseView(SharedPtr<View> view, int index) const
{
LOG_DEBUG("Releasing %d\n", index);
auto iconGridItemView = static_cast<IconGridItemView*>(view);
auto iconGridItemView = static_cast<IconGridItemView*>(view.GetPointer());
iconGridItemView->SetIcon(nullptr);
iconGridItemView->GetViewModel().SetIndex(-1);
iconGridItemView->GetViewModel().CancelQueueTask();
_fileInfoManager->ReleaseFileInfo(index);
}

View File

@@ -7,17 +7,16 @@ 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;
View* CreateView() const override;
void DestroyView(View* view) const override;
void BindView(View* view, int index) const override;
void ReleaseView(View* view, int index) const override;
SharedPtr<View> CreateView() const override;
void BindView(SharedPtr<View> view, int index) const override;
void ReleaseView(SharedPtr<View> view, int index) const override;
void InitVram(const VramContext& vramContext) override;
@@ -25,6 +24,7 @@ private:
const IRomBrowserViewFactory* _romBrowserViewFactory;
IconGridItemView::VramToken _iconGridItemViewGraphics;
TaskResult<void> BindView(View* view, int index,
TaskResult<void> BindView(SharedPtr<View> view, int index,
const InternalFileInfo* internalFileInfo, const vu8& cancelRequested) const override;
void SetQueueTask(const SharedPtr<View>& view, QueueTask<void> queueTask) const override;
};

View File

@@ -10,26 +10,26 @@ public:
bool IsVertical() const override { return true; }
std::unique_ptr<AppBarView> CreateAppBarView(const IRomBrowserViewFactory* romBrowserViewFactory,
SharedPtr<AppBarView> CreateAppBarView(const IRomBrowserViewFactory* romBrowserViewFactory,
int startButtonCount, int endButtonCount) const override
{
return romBrowserViewFactory->CreateAppBarView(0, 0,
AppBarView::Orientation::Vertical, startButtonCount, endButtonCount);
}
std::unique_ptr<RecyclerViewBase> CreateRecyclerView(const IRomBrowserViewFactory* romBrowserViewFactory) const override
SharedPtr<RecyclerViewBase> CreateRecyclerView(const IRomBrowserViewFactory* romBrowserViewFactory) const override
{
auto recyclerView = std::make_unique<RecyclerView>(42, 0, 256 - 42, 192, RecyclerView::Mode::VerticalList);
auto recyclerView = RecyclerView::CreateShared(42, 0, 256 - 42, 192, RecyclerView::Mode::VerticalList);
recyclerView->SetPadding(0, 3);
recyclerView->SetItemSpacing(0, 3);
return recyclerView;
}
FileRecyclerAdapter* CreateRecyclerAdapter(
SharedPtr<FileRecyclerAdapter> CreateRecyclerAdapter(
RomBrowserViewModel* viewModel, const IThemeFileIconFactory* themeFileIconFactory,
const IRomBrowserViewFactory* romBrowserViewFactory, VBlankTextureLoader* vblankTextureLoader) const override
{
return new BannerListFileRecyclerAdapter(
return SharedPtr<BannerListFileRecyclerAdapter>::MakeShared(viewModel->GetRomBrowserController(),
&viewModel->GetFileInfoManager(), viewModel->GetIoTaskQueue(), themeFileIconFactory,
romBrowserViewFactory, vblankTextureLoader);
}

View File

@@ -14,10 +14,10 @@ class RomBrowserDisplayMode
public:
virtual bool IsVertical() const = 0;
virtual bool ShowCoverOnTopScreen() const { return true; }
virtual std::unique_ptr<AppBarView> CreateAppBarView(const IRomBrowserViewFactory* romBrowserViewFactory,
virtual SharedPtr<AppBarView> CreateAppBarView(const IRomBrowserViewFactory* romBrowserViewFactory,
int startButtonCount, int endButtonCount) const = 0;
virtual std::unique_ptr<RecyclerViewBase> CreateRecyclerView(const IRomBrowserViewFactory* romBrowserViewFactory) const = 0;
virtual FileRecyclerAdapter* CreateRecyclerAdapter(
virtual SharedPtr<RecyclerViewBase> CreateRecyclerView(const IRomBrowserViewFactory* romBrowserViewFactory) const = 0;
virtual SharedPtr<FileRecyclerAdapter> CreateRecyclerAdapter(
RomBrowserViewModel* viewModel, const IThemeFileIconFactory* themeFileIconFactory,
const IRomBrowserViewFactory* romBrowserViewFactory, VBlankTextureLoader* vblankTextureLoader) const = 0;
};

View File

@@ -9,19 +9,19 @@ public:
bool IsVertical() const override { return false; }
bool ShowCoverOnTopScreen() const override { return false; }
std::unique_ptr<AppBarView> CreateAppBarView(const IRomBrowserViewFactory* romBrowserViewFactory,
SharedPtr<AppBarView> CreateAppBarView(const IRomBrowserViewFactory* romBrowserViewFactory,
int startButtonCount, int endButtonCount) const override
{
return romBrowserViewFactory->CreateAppBarView(0, 0,
AppBarView::Orientation::Horizontal, startButtonCount, endButtonCount);
}
std::unique_ptr<RecyclerViewBase> CreateRecyclerView(const IRomBrowserViewFactory* romBrowserViewFactory) const override
SharedPtr<RecyclerViewBase> CreateRecyclerView(const IRomBrowserViewFactory* romBrowserViewFactory) const override
{
return romBrowserViewFactory->CreateCoverFlowRecyclerView();
}
FileRecyclerAdapter* CreateRecyclerAdapter(
SharedPtr<FileRecyclerAdapter> CreateRecyclerAdapter(
RomBrowserViewModel* viewModel, const IThemeFileIconFactory* themeFileIconFactory,
const IRomBrowserViewFactory* romBrowserViewFactory, VBlankTextureLoader* vblankTextureLoader) const override
{

View File

@@ -10,26 +10,26 @@ public:
bool IsVertical() const override { return false; }
std::unique_ptr<AppBarView> CreateAppBarView(const IRomBrowserViewFactory* romBrowserViewFactory,
SharedPtr<AppBarView> CreateAppBarView(const IRomBrowserViewFactory* romBrowserViewFactory,
int startButtonCount, int endButtonCount) const override
{
return romBrowserViewFactory->CreateAppBarView(0, 0,
AppBarView::Orientation::Horizontal, startButtonCount, endButtonCount);
}
std::unique_ptr<RecyclerViewBase> CreateRecyclerView(const IRomBrowserViewFactory* romBrowserViewFactory) const override
SharedPtr<RecyclerViewBase> CreateRecyclerView(const IRomBrowserViewFactory* romBrowserViewFactory) const override
{
auto recyclerView = std::make_unique<RecyclerView>(0, 42, 256, 192 - 42, RecyclerView::Mode::HorizontalGrid);
auto recyclerView = RecyclerView::CreateShared(0, 42, 256, 192 - 42, RecyclerView::Mode::HorizontalGrid);
recyclerView->SetPadding(10, 0);
recyclerView->SetItemSpacing(4, 4);
return recyclerView;
}
FileRecyclerAdapter* CreateRecyclerAdapter(
SharedPtr<FileRecyclerAdapter> CreateRecyclerAdapter(
RomBrowserViewModel* viewModel, const IThemeFileIconFactory* themeFileIconFactory,
const IRomBrowserViewFactory* romBrowserViewFactory, VBlankTextureLoader* vblankTextureLoader) const override
{
return new IconGridFileRecyclerAdapter(
return SharedPtr<IconGridFileRecyclerAdapter>::MakeShared(viewModel->GetRomBrowserController(),
&viewModel->GetFileInfoManager(), viewModel->GetIoTaskQueue(),
themeFileIconFactory, romBrowserViewFactory);
}

View File

@@ -10,26 +10,26 @@ public:
bool IsVertical() const override { return true; }
std::unique_ptr<AppBarView> CreateAppBarView(const IRomBrowserViewFactory* romBrowserViewFactory,
SharedPtr<AppBarView> CreateAppBarView(const IRomBrowserViewFactory* romBrowserViewFactory,
int startButtonCount, int endButtonCount) const override
{
return romBrowserViewFactory->CreateAppBarView(0, 0,
AppBarView::Orientation::Vertical, startButtonCount, endButtonCount);
}
std::unique_ptr<RecyclerViewBase> CreateRecyclerView(const IRomBrowserViewFactory* romBrowserViewFactory) const override
SharedPtr<RecyclerViewBase> CreateRecyclerView(const IRomBrowserViewFactory* romBrowserViewFactory) const override
{
auto recyclerView = std::make_unique<RecyclerView>(42, 0, 256 - 42, 192, RecyclerView::Mode::VerticalGrid);
auto recyclerView = RecyclerView::CreateShared(42, 0, 256 - 42, 192, RecyclerView::Mode::VerticalGrid);
recyclerView->SetPadding(0, 3);
recyclerView->SetItemSpacing(9, 3);
return recyclerView;
}
FileRecyclerAdapter* CreateRecyclerAdapter(
SharedPtr<FileRecyclerAdapter> CreateRecyclerAdapter(
RomBrowserViewModel* viewModel, const IThemeFileIconFactory* themeFileIconFactory,
const IRomBrowserViewFactory* romBrowserViewFactory, VBlankTextureLoader* vblankTextureLoader) const override
{
return new IconGridFileRecyclerAdapter(
return SharedPtr<IconGridFileRecyclerAdapter>::MakeShared(viewModel->GetRomBrowserController(),
&viewModel->GetFileInfoManager(), viewModel->GetIoTaskQueue(),
themeFileIconFactory, romBrowserViewFactory);
}

View File

@@ -15,6 +15,34 @@ FileInfoManager::~FileInfoManager()
}
}
void FileInfoManager::LoadFileInfo(int index)
{
auto internalFileInfo = _extraFileInfo[index].internalFileInfo;
if (!internalFileInfo)
{
internalFileInfo = _items[index]->CreateInternalFileInfo();
}
if (!_extraFileInfo[index].fileCover.Lock())
{
_extraFileInfo[index].fileCover = SharedPtr(_coverRepository.GetCoverForFile(*_items[index], internalFileInfo));
}
_extraFileInfo[index].internalFileInfo = internalFileInfo;
}
void FileInfoManager::ReleaseFileInfo(int index)
{
auto internalFileInfo = _extraFileInfo[index].internalFileInfo;
if (internalFileInfo)
{
_extraFileInfo[index].internalFileInfo = nullptr;
delete internalFileInfo;
}
_extraFileInfo[index].fileCover.Reset();
}
int FileInfoManager::GetItemIndex(const char* fileName)
{
if (fileName == nullptr)

View File

@@ -4,7 +4,7 @@
#include "FileInfo.h"
#include "FileType/FileCover.h"
#include "ICoverRepository.h"
#include "core/SharedPtr.h"
#include "core/AtomicSharedPtr.h"
#include "FileType/InternalFileInfo.h"
class FileInfoManager
@@ -20,36 +20,12 @@ public:
SharedPtr<FileCover> GetFileCover(int index)
{
return _extraFileInfo[index].fileCover;
return _extraFileInfo[index].fileCover.Lock();
}
void LoadFileInfo(int index)
{
auto internalFileInfo = GetInternalFileInfo(index);
if (!internalFileInfo)
{
internalFileInfo = _items[index]->CreateInternalFileInfo();
}
void LoadFileInfo(int index);
if (!_extraFileInfo[index].fileCover.IsValid())
{
_extraFileInfo[index].fileCover = SharedPtr(_coverRepository.GetCoverForFile(*_items[index], internalFileInfo));
}
_extraFileInfo[index].internalFileInfo = internalFileInfo;
}
void ReleaseFileInfo(int index)
{
auto internalFileInfo = GetInternalFileInfo(index);
if (internalFileInfo)
{
delete internalFileInfo;
_extraFileInfo[index].internalFileInfo = nullptr;
}
_extraFileInfo[index].fileCover.Reset();
}
void ReleaseFileInfo(int index);
int GetItemIndex(const char* fileName);
@@ -60,7 +36,7 @@ private:
struct ExtraFileInfo
{
const InternalFileInfo* internalFileInfo;
SharedPtr<FileCover> fileCover;
AtomicSharedPtr<FileCover> fileCover;
};
std::unique_ptr<const FileInfo*[]> _items;

View File

@@ -8,11 +8,17 @@ u32 FileRecyclerAdapter::GetItemCount() const
return _fileInfoManager->GetItemCount();
}
void FileRecyclerAdapter::BindView(View* view, int index) const
void FileRecyclerAdapter::BindView(SharedPtr<View> 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<void>::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(View* view, int index) const
}
return BindView(view, index, internalFileInfo, cancelRequested);
});
SetQueueTask(view, std::move(queueTask));
}

View File

@@ -7,12 +7,13 @@ class IVramManager;
class InternalFileInfo;
class IThemeFileIconFactory;
class VramContext;
class IRomBrowserController;
class FileRecyclerAdapter : public RecyclerAdapter
{
public:
u32 GetItemCount() const override;
void BindView(View* view, int index) const override;
void BindView(SharedPtr<View> view, int index) const override;
void SetIconFrameCounter(u32 iconFrameCounter)
{
@@ -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<void> BindView(View* view, int index,
virtual TaskResult<void> BindView(SharedPtr<View> view, int index,
const InternalFileInfo* internalFileInfo, const vu8& cancelRequested) const = 0;
virtual void SetQueueTask(const SharedPtr<View>& view, QueueTask<void> queueTask) const = 0;
};

View File

@@ -182,7 +182,7 @@ void RomBrowserController::HandleFolderLoadDoneTrigger()
LOG_DEBUG("RomBrowserStateTrigger::FolderLoadDone\n");
_romBrowserViewModel.Reset();
_sdFolder = std::move(_newSdFolder);
_romBrowserViewModel = SharedPtr(new RomBrowserViewModel(this, _navigateFileName));
_romBrowserViewModel = SharedPtr<RomBrowserViewModel>::MakeShared(this, _navigateFileName);
}
void RomBrowserController::HandleLaunchTrigger()
@@ -200,7 +200,7 @@ void RomBrowserController::HandleLaunchTrigger()
void RomBrowserController::HandleChangeDisplayModeTrigger()
{
LOG_DEBUG("RomBrowserStateTrigger::ChangeDisplayMode\n");
_romBrowserViewModel = SharedPtr(new RomBrowserViewModel(this));
_romBrowserViewModel = SharedPtr<RomBrowserViewModel>::MakeShared(this);
}
void RomBrowserController::UpdateLastUsedFilepath()

View File

@@ -1,5 +1,6 @@
#pragma once
#include <memory>
#include "core/SharedPtr.h"
#include "../views/IconGridItemView.h"
#include "../views/BannerListItemView.h"
#include "../views/AppBarView.h"
@@ -11,30 +12,34 @@ class VBlankTextureLoader;
class RomBrowserViewModel;
class IThemeFileIconFactory;
class FileRecyclerAdapter;
class RomBrowserItemViewModel;
class IRomBrowserViewFactory
{
public:
virtual ~IRomBrowserViewFactory() = 0;
virtual IconGridItemView* CreateIconGridItemView() const = 0;
virtual SharedPtr<IconGridItemView> CreateIconGridItemView(std::unique_ptr<RomBrowserItemViewModel> viewModel) const = 0;
virtual IconGridItemView::VramToken UploadIconGridItemViewGraphics(
const VramContext& vramContext) const { return IconGridItemView::VramToken(0); }
virtual BannerListItemView* CreateBannerListItemView(VBlankTextureLoader* vblankTextureLoader) const = 0;
virtual SharedPtr<BannerListItemView> CreateBannerListItemView(std::unique_ptr<RomBrowserItemViewModel> viewModel,
VBlankTextureLoader* vblankTextureLoader) const = 0;
virtual BannerListItemView::VramToken UploadBannerListItemViewGraphics(
const VramContext& vramContext) const { return BannerListItemView::VramToken(0); }
virtual std::unique_ptr<AppBarView> CreateAppBarView(int x, int y, AppBarView::Orientation orientation,
virtual SharedPtr<AppBarView> CreateAppBarView(int x, int y, AppBarView::Orientation orientation,
int startButtonCount, int endButtonCount) const = 0;
virtual std::unique_ptr<BannerView> CreateFileInfoView() const = 0;
virtual SharedPtr<BannerView> CreateFileInfoView() const = 0;
virtual std::unique_ptr<RecyclerViewBase> CreateCoverFlowRecyclerView() const = 0;
virtual SharedPtr<RecyclerViewBase> CreateCoverFlowRecyclerView() const = 0;
virtual FileRecyclerAdapter* CreateCoverFlowRecyclerAdapter(
virtual SharedPtr<FileRecyclerAdapter> CreateCoverFlowRecyclerAdapter(
RomBrowserViewModel* viewModel, const IThemeFileIconFactory* themeFileIconFactory,
VBlankTextureLoader* vblankTextureLoader) const = 0;
virtual Point GetTopCoverPosition() const = 0;
};
inline IRomBrowserViewFactory::~IRomBrowserViewFactory() { }

View File

@@ -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<fix32<12>>(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<fix32<12>>(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<fix32<12>>(SELECTED_COVER_WIDTH, SMALL_COVER_WIDTH, initialOffsetFromCenter);
}
else if (initialOffsetFromCenter < 1)
{
// from selected to next
x = Interpolator::InterpolateLinear<fix32<12>>(SELECTED_COVER_X, NEXT_COVER_X, initialOffsetFromCenter);
width = Interpolator::InterpolateLinear<fix32<12>>(SELECTED_COVER_WIDTH, NEXT_COVER_WIDTH, initialOffsetFromCenter);
}
else
{
// everything after next
x = NEXT_COVER_X
+ Interpolator::InterpolateLinear<fix32<12>>(0, NEXT_COVER_WIDTH + COVER_SPACING, initialOffsetFromNext);
if (absOffsetFromCenter - 2 > 0)
{
x = x + (SMALL_COVER_WIDTH + COVER_SPACING) * (absOffsetFromCenter - 2);
}
width = Interpolator::InterpolateLinear<fix32<12>>(NEXT_COVER_WIDTH, SMALL_COVER_WIDTH, initialOffsetFromNext);
}
itemEx.xPosition = x;
itemEx.width = width;
}

View File

@@ -7,31 +7,44 @@ class MaterialColorScheme;
class CarouselRecyclerView : public CoverFlowRecyclerViewBase
{
public:
explicit CarouselRecyclerView(const MaterialColorScheme* materialColorScheme)
: _materialColorScheme(materialColorScheme) { }
SHARED_ONLY(CarouselRecyclerView)
public:
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<fix32<12>> xPositionAnimator;
Animator<fix32<12>> widthAnimator;
fix32<12> xPosition;
fix32<12> width;
};
std::array<ViewPoolEntryEx, 10> _viewPoolEx;
const MaterialColorScheme* _materialColorScheme;
Animator<fix32<12>> _scrollAnimator = Animator<fix32<12>>(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
{

View File

@@ -9,12 +9,12 @@ MaterialAppBarView::MaterialAppBarView(int x, int y, Orientation orientation,
{
for (int i = 0; i < _startButtonCount + _endButtonCount; i++)
{
_buttons[i] = new IconButton2DView(
_buttons[i] = IconButton2DView::CreateShared(
IconButtonView::Type::Standard,
IconButtonView::State::NoToggle,
md::sys::color::inverseOnSurface,
materialColorScheme);
AddChildTail(_buttons[i]);
AddChildTail(_buttons[i].GetPointer());
}
}
@@ -26,7 +26,7 @@ void MaterialAppBarView::InitVram(const VramContext& vramContext)
auto iconButtonVramToken = IconButton2DView::UploadGraphics(*objVramManager);
for (int i = 0; i < _startButtonCount + _endButtonCount; i++)
{
static_cast<IconButton2DView*>(_buttons[i])->SetGraphics(iconButtonVramToken);
static_cast<IconButton2DView*>(_buttons[i].GetPointer())->SetGraphics(iconButtonVramToken);
}
}
}

View File

@@ -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;
};

View File

@@ -18,12 +18,12 @@
#include "gui/views/Label2DView.h"
#include "MaterialBannerListItemView.h"
MaterialBannerListItemView::MaterialBannerListItemView(const MaterialColorScheme* materialColorScheme,
const IFontRepository* fontRepository)
: BannerListItemView(
std::make_unique<Label2DView>(160, 16, 50, fontRepository->GetFont(FontType::Medium10)),
std::make_unique<Label2DView>(160, 16, 50, fontRepository->GetFont(FontType::Regular10)),
std::make_unique<Label2DView>(160, 16, 50, fontRepository->GetFont(FontType::Regular10)))
MaterialBannerListItemView::MaterialBannerListItemView(std::unique_ptr<RomBrowserItemViewModel> 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)

View File

@@ -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<RomBrowserItemViewModel> viewModel,
const MaterialColorScheme* materialColorScheme, const IFontRepository* fontRepository);
};

View File

@@ -13,21 +13,17 @@ void MaterialCoverFlowFileRecyclerAdapter::GetViewSize(int& width, int& height)
height = COVER_HEIGHT;
}
View* MaterialCoverFlowFileRecyclerAdapter::CreateView() const
SharedPtr<View> MaterialCoverFlowFileRecyclerAdapter::CreateView() const
{
return new MaterialCoverView(_vblankTextureLoader);
return MaterialCoverView::CreateShared(
std::make_unique<RomBrowserItemViewModel>(_romBrowserController), _vblankTextureLoader);
}
void MaterialCoverFlowFileRecyclerAdapter::DestroyView(View* view) const
{
auto coverView = static_cast<MaterialCoverView*>(view);
delete coverView;
}
TaskResult<void> MaterialCoverFlowFileRecyclerAdapter::BindView(View* view, int index,
TaskResult<void> MaterialCoverFlowFileRecyclerAdapter::BindView(SharedPtr<View> view, int index,
const InternalFileInfo* internalFileInfo, const vu8& cancelRequested) const
{
auto coverView = static_cast<MaterialCoverView*>(view);
auto coverView = static_cast<MaterialCoverView*>(view.GetPointer());
coverView->GetViewModel().SetIndex(index);
auto cover = _fileInfoManager->GetFileCover(index);
if (cancelRequested)
{
@@ -45,10 +41,18 @@ TaskResult<void> MaterialCoverFlowFileRecyclerAdapter::BindView(View* view, int
return TaskResult<void>::Completed();
}
void MaterialCoverFlowFileRecyclerAdapter::ReleaseView(View* view, int index) const
void MaterialCoverFlowFileRecyclerAdapter::SetQueueTask(const SharedPtr<View>& view, QueueTask<void> queueTask) const
{
auto coverView = static_cast<MaterialCoverView*>(view.GetPointer());
coverView->GetViewModel().SetQueueTask(std::move(queueTask));
}
void MaterialCoverFlowFileRecyclerAdapter::ReleaseView(SharedPtr<View> view, int index) const
{
LOG_DEBUG("Releasing %d\n", index);
auto coverView = static_cast<MaterialCoverView*>(view);
auto coverView = static_cast<MaterialCoverView*>(view.GetPointer());
coverView->ClearCover();
coverView->GetViewModel().SetIndex(-1);
coverView->GetViewModel().CancelQueueTask();
_fileInfoManager->ReleaseFileInfo(index);
}

View File

@@ -8,26 +8,26 @@ 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) { }
void GetViewSize(int& width, int& height) const override;
View* CreateView() const override;
void DestroyView(View* view) const override;
void ReleaseView(View* view, int index) const override;
SharedPtr<View> CreateView() const override;
void ReleaseView(SharedPtr<View> view, int index) const override;
private:
const IRomBrowserViewFactory* _romBrowserViewFactory;
VBlankTextureLoader* _vblankTextureLoader;
const ICoverRepository* _coverRepository;
TaskResult<void> BindView(View* view, int index,
TaskResult<void> BindView(SharedPtr<View> view, int index,
const InternalFileInfo* internalFileInfo, const vu8& cancelRequested) const override;
void SetQueueTask(const SharedPtr<View>& view, QueueTask<void> queueTask) const override;
};

View File

@@ -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,9 +18,14 @@ void MaterialCoverView::InitVram(const VramContext& vramContext)
}
}
void MaterialCoverView::Update()
{
_viewModel->DisposeQueueTaskWhenComplete();
}
void MaterialCoverView::Draw(GraphicsContext& graphicsContext)
{
if (_cover.IsValid() && _textureLoadRequest.GetState() == VBlankTextureLoadRequestState::LoadComplete)
if (_cover.Lock() && _textureLoadRequest.GetState() == VBlankTextureLoadRequestState::LoadComplete)
{
Gx::TexImageParam(_texVramOffset >> 3, false, true, false, true, GX_TEXSIZE_128,
GX_TEXSIZE_128, GX_TEXFMT_PLTT256, false, GX_TEXGEN_NONE);
@@ -44,13 +50,34 @@ 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 (_cover.IsValid())
if (auto cover = _cover.Lock())
{
_cover->SetTexVramOffset(_texVramOffset, _plttVramOffset);
cover->SetTexVramOffset(_texVramOffset, _plttVramOffset);
_vblankTextureLoader->CancelLoad(_textureLoadRequest);
_textureLoadRequest = _cover->CreateTextureLoadRequest();
_textureLoadRequest = cover->CreateTextureLoadRequest();
_vblankTextureLoader->RequestLoad(_textureLoadRequest);
}
}

View File

@@ -1,16 +1,16 @@
#pragma once
#include <memory>
#include "core/SharedPtr.h"
#include "core/AtomicSharedPtr.h"
#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);
@@ -18,37 +18,48 @@ 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<FileCover> cover)
{
if (_cover.IsValid())
{
_vblankTextureLoader->CancelLoad(_textureLoadRequest);
}
_vblankTextureLoader->CancelLoad(_textureLoadRequest);
_cover = std::move(cover);
}
void ClearCover()
{
if (_cover.IsValid())
{
_vblankTextureLoader->CancelLoad(_textureLoadRequest);
}
_vblankTextureLoader->CancelLoad(_textureLoadRequest);
_cover.Reset();
}
void UploadCoverGraphics();
RomBrowserItemViewModel& GetViewModel() const
{
return *_viewModel;
}
private:
std::unique_ptr<RomBrowserItemViewModel> _viewModel;
VBlankTextureLoader* _vblankTextureLoader;
SharedPtr<FileCover> _cover;
AtomicSharedPtr<FileCover> _cover;
VBlankTextureLoadRequest _textureLoadRequest;
u32 _texVramOffset = 0;
u32 _plttVramOffset = 0;
RomBrowserItemInputHandler _inputHandler;
MaterialCoverView(std::unique_ptr<RomBrowserItemViewModel> viewModel, VBlankTextureLoader* vblankTextureLoader)
: _viewModel(std::move(viewModel)), _vblankTextureLoader(vblankTextureLoader)
, _inputHandler(this, _viewModel.get()) { }
};

View File

@@ -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);

View File

@@ -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<Label2DView> _firstLine;
SharedPtr<Label2DView> _secondLine;
SharedPtr<Label2DView> _thirdLine;
SharedPtr<Label2DView> _filenameLabelView;
u32 _iconCellVramOffset;
const MaterialColorScheme* _materialColorScheme;
MaterialFileInfoCardView(const MaterialColorScheme* materialColorScheme,
const IFontRepository* fontRepository);
};

View File

@@ -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];

View File

@@ -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;
MaterialIconGridItemView(std::unique_ptr<RomBrowserItemViewModel> viewModel, const MaterialColorScheme* materialColorScheme)
: IconGridItemView(std::move(viewModel)), _materialColorScheme(materialColorScheme) { }
};

View File

@@ -18,9 +18,9 @@ public:
const IFontRepository* fontRepository)
: _materialColorScheme(materialColorScheme), _fontRepository(fontRepository) { }
IconGridItemView* CreateIconGridItemView() const override
SharedPtr<IconGridItemView> CreateIconGridItemView(std::unique_ptr<RomBrowserItemViewModel> viewModel) const override
{
return new MaterialIconGridItemView(_materialColorScheme);
return MaterialIconGridItemView::CreateShared(std::move(viewModel), _materialColorScheme);
}
IconGridItemView::VramToken UploadIconGridItemViewGraphics(
@@ -29,9 +29,10 @@ public:
return MaterialIconGridItemView::UploadGraphics(vramContext);
}
BannerListItemView* CreateBannerListItemView(VBlankTextureLoader* vblankTextureLoader) const override
SharedPtr<BannerListItemView> CreateBannerListItemView(std::unique_ptr<RomBrowserItemViewModel> viewModel,
VBlankTextureLoader* vblankTextureLoader) const override
{
return new MaterialBannerListItemView(_materialColorScheme, _fontRepository);
return MaterialBannerListItemView::CreateShared(std::move(viewModel), _materialColorScheme, _fontRepository);
}
BannerListItemView::VramToken UploadBannerListItemViewGraphics(
@@ -40,31 +41,36 @@ public:
return MaterialBannerListItemView::UploadGraphics(vramContext);
}
std::unique_ptr<AppBarView> CreateAppBarView(int x, int y, AppBarView::Orientation orientation,
SharedPtr<AppBarView> CreateAppBarView(int x, int y, AppBarView::Orientation orientation,
int startButtonCount, int endButtonCount) const override
{
return std::make_unique<MaterialAppBarView>(x, y, orientation, startButtonCount, endButtonCount, _materialColorScheme);
return MaterialAppBarView::CreateShared(x, y, orientation, startButtonCount, endButtonCount, _materialColorScheme);
}
std::unique_ptr<BannerView> CreateFileInfoView() const override
SharedPtr<BannerView> CreateFileInfoView() const override
{
return std::make_unique<MaterialFileInfoCardView>(_materialColorScheme, _fontRepository);
return MaterialFileInfoCardView::CreateShared(_materialColorScheme, _fontRepository);
}
std::unique_ptr<RecyclerViewBase> CreateCoverFlowRecyclerView() const override
SharedPtr<RecyclerViewBase> CreateCoverFlowRecyclerView() const override
{
return std::make_unique<CarouselRecyclerView>(_materialColorScheme);
return CarouselRecyclerView::CreateShared(_materialColorScheme);
}
FileRecyclerAdapter* CreateCoverFlowRecyclerAdapter(
SharedPtr<FileRecyclerAdapter> CreateCoverFlowRecyclerAdapter(
RomBrowserViewModel* viewModel, const IThemeFileIconFactory* themeFileIconFactory,
VBlankTextureLoader* vblankTextureLoader) const override
{
return new MaterialCoverFlowFileRecyclerAdapter(
return SharedPtr<MaterialCoverFlowFileRecyclerAdapter>::MakeShared(viewModel->GetRomBrowserController(),
&viewModel->GetFileInfoManager(), viewModel->GetIoTaskQueue(),
themeFileIconFactory, this, vblankTextureLoader, &viewModel->GetCoverRepository());
}
Point GetTopCoverPosition() const override
{
return Point(75, 18);
}
private:
const MaterialColorScheme* _materialColorScheme;
const IFontRepository* _fontRepository;

View File

@@ -4,8 +4,6 @@
#include "romBrowser/views/IconButton3DView.h"
#include "CustomAppBarView.h"
#define BLOCK_VTX_PACK(x, y, z) (((x)&0x3FF) | ((((y) >> 3) & 0x3FF) << 10) | ((z) << 20))
CustomAppBarView::CustomAppBarView(int x, int y, Orientation orientation,
int startButtonCount, int endButtonCount, const MaterialColorScheme* materialColorScheme,
u32 scrimTexVramOffset, u32 scrimPlttVramOffset)
@@ -14,12 +12,12 @@ CustomAppBarView::CustomAppBarView(int x, int y, Orientation orientation,
{
for (int i = 0; i < _startButtonCount + _endButtonCount; i++)
{
_buttons[i] = new IconButton3DView(
_buttons[i] = IconButton3DView::CreateShared(
IconButtonView::Type::Tonal,
IconButtonView::State::NoToggle,
md::sys::color::inverseOnSurface,
materialColorScheme);
AddChildTail(_buttons[i]);
AddChildTail(_buttons[i].GetPointer());
}
}

View File

@@ -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);
};

View File

@@ -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<RomBrowserItemViewModel> viewModel,
const CustomThemeInfo* customThemeInfo, const MaterialColorScheme* materialColorScheme,
const IFontRepository* fontRepository, u32 texVramOffset, u32 plttVramOffset,
u32 selectedTexVramOffset, u32 selectedPlttVramOffset,
VBlankTextureLoader* vblankTextureLoader)
: BannerListItemView(
std::make_unique<Label3DView>(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<Label3DView>(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<Label3DView>(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)

View File

@@ -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<RomBrowserItemViewModel> viewModel, const CustomThemeInfo* customThemeInfo,
const MaterialColorScheme* materialColorScheme, const IFontRepository* fontRepository,
u32 texVramOffset, u32 plttVramOffset, u32 selectedTexVramOffset, u32 selectedPlttVramOffset,
VBlankTextureLoader* vblankTextureLoader);
};

View File

@@ -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);

View File

@@ -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<Label2DView> _firstLine;
SharedPtr<Label2DView> _secondLine;
SharedPtr<Label2DView> _thirdLine;
SharedPtr<Label2DView> _filenameLabelView;
const CustomThemeInfo* _customThemeInfo;
CustomFileInfoView(const CustomThemeInfo* customThemeInfo, const IFontRepository* fontRepository);
};

View File

@@ -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);

View File

@@ -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<RomBrowserItemViewModel> 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) { }
};

View File

@@ -7,12 +7,12 @@
#include "romBrowser/views/CoverFlowRecyclerView.h"
#include "romBrowser/viewModels/RomBrowserViewModel.h"
#include "romBrowser/DisplayMode/CoverFlowFileRecyclerAdapter.h"
#include "themes/custom/CustomThemeInfo.h"
class MaterialColorScheme;
class ITheme;
class VramContext;
class IFontRepository;
class CustomThemeInfo;
class CustomRomBrowserViewFactory : public IRomBrowserViewFactory
{
@@ -21,15 +21,16 @@ public:
const IFontRepository* fontRepository)
: _customThemeInfo(customThemeInfo), _materialColorScheme(materialColorScheme), _fontRepository(fontRepository) { }
IconGridItemView* CreateIconGridItemView() const override
SharedPtr<IconGridItemView> CreateIconGridItemView(std::unique_ptr<RomBrowserItemViewModel> viewModel) const override
{
return new CustomIconGridItemView(_customThemeInfo, _gridCellTexVramOffset, _gridCellPlttVramOffset,
return CustomIconGridItemView::CreateShared(std::move(viewModel), _customThemeInfo, _gridCellTexVramOffset, _gridCellPlttVramOffset,
_gridCellSelectedTexVramOffset, _gridCellSelectedPlttVramOffset);
}
BannerListItemView* CreateBannerListItemView(VBlankTextureLoader* vblankTextureLoader) const override
SharedPtr<BannerListItemView> CreateBannerListItemView(std::unique_ptr<RomBrowserItemViewModel> viewModel,
VBlankTextureLoader* vblankTextureLoader) const override
{
return new CustomBannerListItemView(_customThemeInfo, _materialColorScheme, _fontRepository,
return CustomBannerListItemView::CreateShared(std::move(viewModel), _customThemeInfo, _materialColorScheme, _fontRepository,
_bannerListCellTexVramOffset, _bannerListCellPlttVramOffset,
_bannerListCellSelectedTexVramOffset, _bannerListCellSelectedPlttVramOffset, vblankTextureLoader);
}
@@ -39,32 +40,37 @@ public:
return BannerListItemView::VramToken(0);
}
std::unique_ptr<AppBarView> CreateAppBarView(int x, int y, AppBarView::Orientation orientation,
SharedPtr<AppBarView> CreateAppBarView(int x, int y, AppBarView::Orientation orientation,
int startButtonCount, int endButtonCount) const override
{
return std::make_unique<CustomAppBarView>(x, y, orientation, startButtonCount, endButtonCount, _materialColorScheme,
return CustomAppBarView::CreateShared(x, y, orientation, startButtonCount, endButtonCount, _materialColorScheme,
_scrimTexVramOffset, _scrimPlttVramOffset);
}
std::unique_ptr<BannerView> CreateFileInfoView() const override
SharedPtr<BannerView> CreateFileInfoView() const override
{
return std::make_unique<CustomFileInfoView>(_customThemeInfo, _fontRepository);
return CustomFileInfoView::CreateShared(_customThemeInfo, _fontRepository);
}
std::unique_ptr<RecyclerViewBase> CreateCoverFlowRecyclerView() const override
SharedPtr<RecyclerViewBase> CreateCoverFlowRecyclerView() const override
{
return std::make_unique<CoverFlowRecyclerView>();
return CoverFlowRecyclerView::CreateShared();
}
FileRecyclerAdapter* CreateCoverFlowRecyclerAdapter(
SharedPtr<FileRecyclerAdapter> CreateCoverFlowRecyclerAdapter(
RomBrowserViewModel* viewModel, const IThemeFileIconFactory* themeFileIconFactory,
VBlankTextureLoader* vblankTextureLoader) const override
{
return new CoverFlowFileRecyclerAdapter(
return SharedPtr<CoverFlowFileRecyclerAdapter>::MakeShared(viewModel->GetRomBrowserController(),
&viewModel->GetFileInfoManager(), viewModel->GetIoTaskQueue(),
themeFileIconFactory, this, vblankTextureLoader, &viewModel->GetCoverRepository());
}
Point GetTopCoverPosition() const override
{
return _customThemeInfo->topCoverInfo.GetPosition();
}
void LoadResources(const ITheme& theme, const VramContext& mainVramContext);
private:

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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);
}
}
}

View File

@@ -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<void> queueTask)
{
_queueTask = std::move(queueTask);
}
void CancelQueueTask()
{
_queueTask.CancelTask();
}
void DisposeQueueTaskWhenComplete()
{
if (_queueTask.GetTask().IsCompleted())
{
_queueTask.Dispose();
}
}
private:
int _index = -1;
QueueTask<void> _queueTask;
IRomBrowserController* _romBrowserController;
};

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -6,21 +6,12 @@
AppBarView::AppBarView(int x, int y, Orientation orientation,
int startButtonCount, int endButtonCount, const MaterialColorScheme* materialColorScheme)
: _orientation(orientation)
, _buttons(std::make_unique<IconButtonView*[]>(startButtonCount + endButtonCount))
, _buttons(std::make_unique<SharedPtr<IconButtonView>[]>(startButtonCount + endButtonCount))
, _startButtonCount(startButtonCount), _endButtonCount(endButtonCount)
{
SetPosition(x, y);
}
AppBarView::~AppBarView()
{
for (int i = 0; i < _startButtonCount + _endButtonCount; i++)
{
delete _buttons[i];
_buttons[i] = nullptr;
}
}
Rectangle AppBarView::GetBounds() const
{
if (_orientation == Orientation::Horizontal)
@@ -39,9 +30,9 @@ void AppBarView::Update()
ViewContainer::Update();
}
View* AppBarView::MoveFocus(View* currentFocus, FocusMoveDirection direction, View* source)
SharedPtr<View> AppBarView::MoveFocus(const SharedPtr<View>& currentFocus, FocusMoveDirection direction, View* source)
{
int idx = FindButtonIndex(currentFocus);
int idx = FindButtonIndex(currentFocus.GetPointer());
if (idx >= 0)
{
if (_orientation == Orientation::Horizontal)
@@ -71,21 +62,28 @@ View* AppBarView::MoveFocus(View* currentFocus, FocusMoveDirection direction, Vi
else if ((_orientation == Orientation::Horizontal && (direction == FocusMoveDirection::Up || direction == FocusMoveDirection::Down)) ||
(_orientation == Orientation::Vertical && (direction == FocusMoveDirection::Left || direction == FocusMoveDirection::Right)))
{
if (currentFocus == nullptr)
if (!currentFocus)
return _buttons[0];
Point curFocusPoint = currentFocus->GetBounds().GetCenter();
s64 bestDistance = std::numeric_limits<s64>::max();
View* nearestButton = nullptr;
int nearestButton = -1;
for (int i = 0; i < _startButtonCount + _endButtonCount; i++)
{
s64 distance = curFocusPoint.DistanceSquaredTo(_buttons[i]->GetBounds().GetCenter());
if (distance < bestDistance)
{
bestDistance = distance;
nearestButton = _buttons[i];
nearestButton = i;
}
}
return nearestButton;
if (nearestButton >= 0)
{
return _buttons[nearestButton];
}
else
{
return nullptr;
}
}
else
return View::MoveFocus(currentFocus, direction, this);
@@ -126,7 +124,7 @@ int AppBarView::FindButtonIndex(const View* view)
{
for (int i = 0; i < _startButtonCount + _endButtonCount; i++)
{
if (_buttons[i] == view)
if (_buttons[i].GetPointer() == view)
{
return i;
}

View File

@@ -14,8 +14,6 @@ public:
Vertical
};
virtual ~AppBarView();
void SetButtonIcon(int button, u32 vramOffset)
{
_buttons[button]->SetIconVramOffset(vramOffset);
@@ -28,14 +26,14 @@ public:
Rectangle GetBounds() const override;
void Update() override;
View* MoveFocus(View* currentFocus, FocusMoveDirection direction, View* source) override;
SharedPtr<View> MoveFocus(const SharedPtr<View>& currentFocus, FocusMoveDirection direction, View* source) override;
void Focus(FocusManager& focusManager, int button);
constexpr Orientation GetOrientation() const { return _orientation; }
protected:
Orientation _orientation;
std::unique_ptr<IconButtonView*[]> _buttons;
std::unique_ptr<SharedPtr<IconButtonView>[]> _buttons;
int _startButtonCount;
int _endButtonCount;

View File

@@ -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<LabelView> firstLine,
std::unique_ptr<LabelView> secondLine, std::unique_ptr<LabelView> thirdLine)
: _firstLine(std::move(firstLine))
BannerListItemView::BannerListItemView(std::unique_ptr<RomBrowserItemViewModel> viewModel,
SharedPtr<LabelView> firstLine, SharedPtr<LabelView> secondLine, SharedPtr<LabelView> 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);
}

View File

@@ -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<LabelView> firstLine,
std::unique_ptr<LabelView> secondLine, std::unique_ptr<LabelView> 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<LabelView> _firstLine;
std::unique_ptr<LabelView> _secondLine;
std::unique_ptr<LabelView> _thirdLine;
std::unique_ptr<RomBrowserItemViewModel> _viewModel;
SharedPtr<LabelView> _firstLine;
SharedPtr<LabelView> _secondLine;
SharedPtr<LabelView> _thirdLine;
RomBrowserItemInputHandler _inputHandler;
BannerListItemView(std::unique_ptr<RomBrowserItemViewModel> viewModel, SharedPtr<LabelView> firstLine,
SharedPtr<LabelView> secondLine, SharedPtr<LabelView> thirdLine);
};

View File

@@ -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;
}

Some files were not shown because too many files have changed in this diff Show More