Add new shared pointer and make use of it

This commit is contained in:
Gericom
2026-03-28 12:03:06 +01:00
parent bec797ffe7
commit 21a8790ebc
66 changed files with 1098 additions and 523 deletions

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

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

@@ -4,7 +4,7 @@
#include "gui/input/InputProvider.h"
#include "RecyclerView.h"
RecyclerView::RecyclerView(int x, int y, int width, int height, Mode mode)
RecyclerView::RecyclerView(Private, int x, int y, int width, int height, Mode mode)
: _width(width), _height(height), _mode(mode), _rows(0), _columns(0)
, _viewPoolFreeCount(0), _viewPoolTotalCount(0)
, _xOffset(0), _yOffset(0), _xPadding(0), _yPadding(0)
@@ -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,12 +248,12 @@ 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)
@@ -263,7 +263,7 @@ View* RecyclerView::MoveFocusVertical(View* currentFocus, FocusMoveDirection dir
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 _selectedItem != nullptr ? _selectedItem->view : SharedFromThis();
}
int column = _selectedItem->itemIdx % _columns;
@@ -304,7 +304,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)

View File

@@ -1,13 +1,16 @@
#pragma once
#include <memory>
#include "core/EnableSharedFromThis.h"
#include "View.h"
#include "RecyclerAdapter.h"
#include "gui/FocusManager.h"
#include "animation/Animator.h"
#include "RecyclerViewBase.h"
class RecyclerView : public RecyclerViewBase
class RecyclerView : public RecyclerViewBase, public EnableSharedFromThis<RecyclerView>
{
struct Private { explicit Private() = default; };
public:
enum class Mode
{
@@ -21,10 +24,16 @@ public:
VerticalGrid
};
RecyclerView(int x, int y, int width, int height, Mode mode);
RecyclerView(Private, int x, int y, int width, int height, Mode mode);
static SharedPtr<RecyclerView> CreateShared(int x, int y, int width, int height, Mode mode)
{
return SharedPtr<RecyclerView>::MakeShared(Private(), x, y, width, height, 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 +44,20 @@ 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 Focus(FocusManager& focusManager) override
{
if (_selectedItem)
{
focusManager.Focus(_selectedItem->view);
}
else
focusManager.Focus(this);
{
focusManager.Focus(SharedFromThis());
}
}
int GetSelectedItem() const override
@@ -69,7 +82,7 @@ public:
private:
struct ViewPoolEntry
{
View* view;
SharedPtr<View> view;
int itemIdx;
};
@@ -107,6 +120,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,7 @@
#include "core/LinkedListLink.h"
#include "core/math/Point.h"
#include "core/math/Rectangle.h"
#include "core/SharedPtr.h"
#include "../FocusManager.h"
#include "../FocusMoveDirection.h"
@@ -37,7 +38,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);