mirror of
https://github.com/zetaPRIME/libstarlight.git
synced 2025-06-26 05:32:46 +00:00
basis/framework of form system
This commit is contained in:
parent
942732522b
commit
6ade2e8081
@ -20,6 +20,9 @@ using starlight::gfx::RenderCore;
|
|||||||
using starlight::ui::TouchScreenCanvas;
|
using starlight::ui::TouchScreenCanvas;
|
||||||
using starlight::ui::TopScreenCanvas;
|
using starlight::ui::TopScreenCanvas;
|
||||||
|
|
||||||
|
using starlight::ui::Form;
|
||||||
|
using starlight::ui::FormFlags;
|
||||||
|
|
||||||
using starlight::Application;
|
using starlight::Application;
|
||||||
|
|
||||||
////////////////////
|
////////////////////
|
||||||
@ -69,6 +72,8 @@ void Application::_init() {
|
|||||||
|
|
||||||
touchScreen = std::make_shared<TouchScreenCanvas>();
|
touchScreen = std::make_shared<TouchScreenCanvas>();
|
||||||
topScreen = std::make_shared<TopScreenCanvas>();
|
topScreen = std::make_shared<TopScreenCanvas>();
|
||||||
|
formTouchScreen = touchScreen.get();
|
||||||
|
formTopScreen = topScreen.get();
|
||||||
|
|
||||||
Init();
|
Init();
|
||||||
}
|
}
|
||||||
@ -81,9 +86,38 @@ void Application::_end() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Application::_mainLoop() {
|
void Application::_mainLoop() {
|
||||||
|
if (!forms.empty()) {
|
||||||
|
if (_sFormState) {
|
||||||
|
_sFormState = false;
|
||||||
|
|
||||||
|
// sort open forms
|
||||||
|
forms.sort(Form::OrderedCompare);
|
||||||
|
|
||||||
|
// reconstruct ui container heirarchy
|
||||||
|
bool otouch, otop;
|
||||||
|
formTouchScreen->RemoveAll();
|
||||||
|
formTopScreen->RemoveAll();
|
||||||
|
|
||||||
|
for (auto it = forms.rbegin(); it != forms.rend(); ++it) {
|
||||||
|
if ((*it)->IsVisible()) {
|
||||||
|
if (!otouch) formTouchScreen->Add((*it)->touchScreen, true);
|
||||||
|
if (!otop) formTopScreen->Add((*it)->topScreen, true);
|
||||||
|
if ((*it)->GetFlag(FormFlags::canOcclude)) {
|
||||||
|
if ((*it)->GetFlag(FormFlags::occludeTouch)) otouch = true;
|
||||||
|
if ((*it)->GetFlag(FormFlags::occludeTop)) otop = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// update step
|
// update step
|
||||||
InputManager::Update();
|
InputManager::Update();
|
||||||
Update();
|
Update();
|
||||||
|
for (auto it : forms) { // update loop for forms
|
||||||
|
it->Update(it == forms.back());
|
||||||
|
}
|
||||||
touchScreen->Update();
|
touchScreen->Update();
|
||||||
topScreen->Update();
|
topScreen->Update();
|
||||||
PostUpdate();
|
PostUpdate();
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
#include "starlight/ui/TouchScreenCanvas.h"
|
#include "starlight/ui/TouchScreenCanvas.h"
|
||||||
#include "starlight/ui/TopScreenCanvas.h"
|
#include "starlight/ui/TopScreenCanvas.h"
|
||||||
|
|
||||||
|
#include "starlight/ui/Form.h"
|
||||||
|
|
||||||
#include "starlight/ConfigManager.h"
|
#include "starlight/ConfigManager.h"
|
||||||
|
|
||||||
namespace starlight {
|
namespace starlight {
|
||||||
@ -25,12 +27,14 @@ namespace starlight {
|
|||||||
static bool Quit();
|
static bool Quit();
|
||||||
static Config& GetConfig(const std::string& path);
|
static Config& GetConfig(const std::string& path);
|
||||||
static std::string AppName();
|
static std::string AppName();
|
||||||
|
static inline Application* Current() { return _currentApp; }
|
||||||
|
|
||||||
//////////////////////
|
//////////////////////
|
||||||
// INSTANCE MEMBERS //
|
// INSTANCE MEMBERS //
|
||||||
//////////////////////
|
//////////////////////
|
||||||
private:
|
private:
|
||||||
bool _appQuit = false;
|
bool _appQuit = false;
|
||||||
|
bool _sFormState = false;
|
||||||
void _init();
|
void _init();
|
||||||
void _mainLoop();
|
void _mainLoop();
|
||||||
void _end();
|
void _end();
|
||||||
@ -43,6 +47,10 @@ namespace starlight {
|
|||||||
std::shared_ptr<ui::TouchScreenCanvas> touchScreen = nullptr;
|
std::shared_ptr<ui::TouchScreenCanvas> touchScreen = nullptr;
|
||||||
std::shared_ptr<ui::TopScreenCanvas> topScreen = nullptr;
|
std::shared_ptr<ui::TopScreenCanvas> topScreen = nullptr;
|
||||||
|
|
||||||
|
std::list<std::shared_ptr<ui::Form>> forms;
|
||||||
|
ui::UIContainer* formTouchScreen = nullptr;
|
||||||
|
ui::UIContainer* formTopScreen = nullptr;
|
||||||
|
|
||||||
Application() = delete;
|
Application() = delete;
|
||||||
Application(std::string id) : appId(id) { }
|
Application(std::string id) : appId(id) { }
|
||||||
virtual ~Application() = default;
|
virtual ~Application() = default;
|
||||||
@ -55,5 +63,7 @@ namespace starlight {
|
|||||||
virtual void Draw() { }
|
virtual void Draw() { }
|
||||||
virtual void PostDraw() { }
|
virtual void PostDraw() { }
|
||||||
virtual void End() { }
|
virtual void End() { }
|
||||||
|
|
||||||
|
inline void SignalFormState() { _sFormState = true; }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
77
libstarlight/source/starlight/ui/Form.cpp
Normal file
77
libstarlight/source/starlight/ui/Form.cpp
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
#include "Form.h"
|
||||||
|
|
||||||
|
#include <3ds.h>
|
||||||
|
|
||||||
|
#include "starlight/GFXManager.h"
|
||||||
|
#include "starlight/ConfigManager.h"
|
||||||
|
#include "starlight/ThemeManager.h"
|
||||||
|
#include "starlight/InputManager.h"
|
||||||
|
#include "starlight/gfx/RenderCore.h"
|
||||||
|
|
||||||
|
#include "starlight/Application.h"
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
using starlight::GFXManager;
|
||||||
|
using starlight::ConfigManager;
|
||||||
|
using starlight::Config;
|
||||||
|
using starlight::ThemeManager;
|
||||||
|
using starlight::InputManager;
|
||||||
|
using starlight::gfx::RenderCore;
|
||||||
|
|
||||||
|
using starlight::ui::TouchScreenCanvas;
|
||||||
|
using starlight::ui::TopScreenCanvas;
|
||||||
|
|
||||||
|
using starlight::Application;
|
||||||
|
|
||||||
|
using starlight::ui::Form;
|
||||||
|
|
||||||
|
////////////////////
|
||||||
|
// STATIC MEMBERS //
|
||||||
|
////////////////////
|
||||||
|
|
||||||
|
bool Form::OrderedCompare(std::shared_ptr<Form>& f1, std::shared_ptr<Form>& f2) { // acts as < operator
|
||||||
|
if (!f1->IsVisible()) return true;
|
||||||
|
if (f1->priority < f2->priority) return true;
|
||||||
|
if (f1->priority > f2->priority) return false;
|
||||||
|
return f1->showCounter < f2->showCounter;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////
|
||||||
|
// INSTANCE MEMBERS //
|
||||||
|
//////////////////////
|
||||||
|
|
||||||
|
void Form::Open() {
|
||||||
|
auto app = Application::Current();
|
||||||
|
if (app == nullptr) return;
|
||||||
|
if (GetFlag(FormFlags::open)) return;
|
||||||
|
app->forms.push_back(shared_from_this());
|
||||||
|
SetFlag(FormFlags::open, true);
|
||||||
|
app->SignalFormState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Form::Close() {
|
||||||
|
auto app = Application::Current();
|
||||||
|
if (app == nullptr) return;
|
||||||
|
app->forms.remove(shared_from_this());
|
||||||
|
SetFlag(FormFlags::open, false);
|
||||||
|
app->SignalFormState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Form::Show() {
|
||||||
|
auto app = Application::Current();
|
||||||
|
if (app == nullptr) return;
|
||||||
|
showCounter = nextShowCounter++;
|
||||||
|
SetFlag(FormFlags::visible, true);
|
||||||
|
app->SignalFormState();
|
||||||
|
OnShow();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Form::Hide() {
|
||||||
|
auto app = Application::Current();
|
||||||
|
if (app == nullptr) return;
|
||||||
|
if (!GetFlag(FormFlags::visible)) return; // don't signal if already hidden
|
||||||
|
SetFlag(FormFlags::visible, false);
|
||||||
|
app->SignalFormState();
|
||||||
|
OnHide(); // todo: make this interceptable
|
||||||
|
}
|
95
libstarlight/source/starlight/ui/Form.h
Normal file
95
libstarlight/source/starlight/ui/Form.h
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "starlight/_global.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <list>
|
||||||
|
#include <functional>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include "starlight/datatypes/Vector2.h"
|
||||||
|
#include "starlight/datatypes/VRect.h"
|
||||||
|
|
||||||
|
#include "starlight/ui/UIContainer.h"
|
||||||
|
|
||||||
|
// Form subclasses should also derive from FormCreator, with their own typename as the template argument
|
||||||
|
// class WhateverForm : public Form, public FormCreator<WhateverForm>
|
||||||
|
|
||||||
|
namespace starlight {
|
||||||
|
namespace ui {
|
||||||
|
enum class FormFlags : unsigned int {
|
||||||
|
visible = 1 << 0,
|
||||||
|
canOcclude = 1 << 1,
|
||||||
|
occludeTouch = 1 << 2,
|
||||||
|
occludeTop = 1 << 3,
|
||||||
|
|
||||||
|
open = 1 << 30
|
||||||
|
};
|
||||||
|
typedef std::underlying_type<FormFlags>::type FormFlags_t;
|
||||||
|
|
||||||
|
class Form;
|
||||||
|
template<class F>
|
||||||
|
class FormCreator {
|
||||||
|
public:
|
||||||
|
template<typename ... Args>
|
||||||
|
static std::shared_ptr<F> New(Args... args) {
|
||||||
|
auto f = std::make_shared<F>(args...);
|
||||||
|
// ... hmm. do I "make live" here, or have a distinct Open call to insert it into the Application's list?
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Form : public std::enable_shared_from_this<Form> {
|
||||||
|
////////////////////
|
||||||
|
// STATIC MEMBERS //
|
||||||
|
////////////////////
|
||||||
|
private:
|
||||||
|
static unsigned int nextShowCounter; // you're not going to end up showing forms 4.3 billion times in a single session
|
||||||
|
|
||||||
|
public:
|
||||||
|
static bool OrderedCompare(std::shared_ptr<Form>& f1, std::shared_ptr<Form>& f2);
|
||||||
|
|
||||||
|
//////////////////////
|
||||||
|
// INSTANCE MEMBERS //
|
||||||
|
//////////////////////
|
||||||
|
private:
|
||||||
|
unsigned int showCounter;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
//
|
||||||
|
|
||||||
|
public:
|
||||||
|
int priority;
|
||||||
|
unsigned int flags;
|
||||||
|
|
||||||
|
std::shared_ptr<UIContainer> touchScreen = nullptr;
|
||||||
|
std::shared_ptr<UIContainer> topScreen = nullptr;
|
||||||
|
|
||||||
|
Form() { }
|
||||||
|
virtual ~Form() { }
|
||||||
|
|
||||||
|
void Open();
|
||||||
|
void Close();
|
||||||
|
void Show();
|
||||||
|
void Hide();
|
||||||
|
|
||||||
|
//virtual void Init() { }
|
||||||
|
virtual void Update(bool focused) { }
|
||||||
|
//virtual void PostUpdate(bool focused) { }
|
||||||
|
//virtual void Draw() { }
|
||||||
|
//virtual void PostDraw() { }
|
||||||
|
//virtual void End() { }
|
||||||
|
virtual void OnShow() { }
|
||||||
|
virtual void OnHide() { }
|
||||||
|
|
||||||
|
// convenience
|
||||||
|
inline bool GetFlag(FormFlags f) { return flags & static_cast<unsigned int>(f); }
|
||||||
|
inline void SetFlag(FormFlags f, bool b) {
|
||||||
|
auto ff = static_cast<unsigned int>(f);
|
||||||
|
flags &= ~ff; if (b) flags |= ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool IsVisible() { return GetFlag(FormFlags::visible); }
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -47,8 +47,9 @@ void UIContainer::_Dive(std::function<bool(UIElement*)>& func, bool consumable,
|
|||||||
finished = func(this) && consumable;
|
finished = func(this) && consumable;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UIContainer::Add(std::shared_ptr<UIElement> elem) {
|
void UIContainer::Add(std::shared_ptr<UIElement> elem, bool front) {
|
||||||
children.push_back(elem);
|
if (front) children.push_front(elem);
|
||||||
|
else children.push_back(elem);
|
||||||
elem->parent = std::weak_ptr<UIContainer>(std::static_pointer_cast<UIContainer>(this->shared_from_this()));
|
elem->parent = std::weak_ptr<UIContainer>(std::static_pointer_cast<UIContainer>(this->shared_from_this()));
|
||||||
MarkForRedraw();
|
MarkForRedraw();
|
||||||
}
|
}
|
||||||
@ -66,6 +67,13 @@ void UIContainer::Remove(std::shared_ptr<UIElement> elem) {
|
|||||||
MarkForRedraw();
|
MarkForRedraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UIContainer::RemoveAll() {
|
||||||
|
for (auto it : children) {
|
||||||
|
it->parent = std::weak_ptr<UIContainer>(); // clear parent
|
||||||
|
}
|
||||||
|
children.clear();
|
||||||
|
}
|
||||||
|
|
||||||
void UIContainer::Update() {
|
void UIContainer::Update() {
|
||||||
for (auto& it : children) { it->Update(); }
|
for (auto& it : children) { it->Update(); }
|
||||||
}
|
}
|
||||||
@ -81,5 +89,3 @@ void UIContainer::Draw() {
|
|||||||
for (auto& it : children) { if (it->rect.Overlaps(vr)) it->Draw(); }
|
for (auto& it : children) { if (it->rect.Overlaps(vr)) it->Draw(); }
|
||||||
GFXManager::PopOffset();
|
GFXManager::PopOffset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -34,9 +34,10 @@ namespace starlight {
|
|||||||
void Dive(std::function<bool(UIElement*)> check, std::function<bool(UIElement*)> func, bool consumable = true, bool frontFirst = true);
|
void Dive(std::function<bool(UIElement*)> check, std::function<bool(UIElement*)> func, bool consumable = true, bool frontFirst = true);
|
||||||
void Dive(std::function<bool(UIElement*)> func, bool consumable = true, bool frontFirst = true);
|
void Dive(std::function<bool(UIElement*)> func, bool consumable = true, bool frontFirst = true);
|
||||||
|
|
||||||
void Add(std::shared_ptr<UIElement> elem);
|
void Add(std::shared_ptr<UIElement> elem, bool front = false);
|
||||||
//void Add(UIElement* elem);
|
//void Add(UIElement* elem);
|
||||||
void Remove(std::shared_ptr<UIElement> elem);
|
void Remove(std::shared_ptr<UIElement> elem);
|
||||||
|
void RemoveAll();
|
||||||
|
|
||||||
void Update() override;
|
void Update() override;
|
||||||
void PreDraw() override;
|
void PreDraw() override;
|
||||||
|
@ -1,6 +1,20 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
form system {
|
||||||
|
capabilities {
|
||||||
|
updates, recieves events etc. as if it were a stackable Application
|
||||||
|
priority level (modals etc.)
|
||||||
|
can be stacked, reordered etc. via order shown
|
||||||
|
can occlude independently on top and bottom screen, causing lower-ordered things on that screen to not even render
|
||||||
|
can tell if it's the focused (topmost) form and use that to determine whether to accept button input
|
||||||
|
|
||||||
|
}
|
||||||
|
hmm. implement as direct replacement of Application UI contents, or implement as its own container...?
|
||||||
|
meaningful state change signals current Application to resort and rebuild draw list during next update
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
today's agenda {
|
today's agenda {
|
||||||
FSHelper, recursive directory assertion etc.
|
FSHelper, recursive directory assertion etc.
|
||||||
} then {
|
} then {
|
||||||
|
1
themes/default/about.txt
Normal file
1
themes/default/about.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
loosely styled after Vertex - https://www.gnome-look.org/p/1013757/
|
Loading…
x
Reference in New Issue
Block a user