forked from Mirror/libstarlight
UIContainer::AddNew, Add uses std::move, Optional type,
button styles and glyphs, lower memory footprint for default text style on Label
This commit is contained in:
parent
ecf47db716
commit
7f27018808
63
libstarlight/source/starlight/datatypes/Optional.h
Normal file
63
libstarlight/source/starlight/datatypes/Optional.h
Normal file
@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
#include "starlight/_global.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace starlight {
|
||||
template<typename T>
|
||||
class Optional {
|
||||
private:
|
||||
std::unique_ptr<T> p = nullptr;
|
||||
std::function<T&()>* getdef = nullptr;
|
||||
|
||||
inline void initp() {
|
||||
if (!p) {
|
||||
p = std::make_unique<T>();
|
||||
if (getdef) *p = (*getdef)();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
Optional<T>() = default;
|
||||
Optional<T>(std::function<T&()>* getDefault) : getdef(getDefault) { }
|
||||
Optional<T>(nullptr_t) : p(nullptr) { }
|
||||
Optional<T>(const Optional<T>& o) { // copy operator *actually copies the inner object*
|
||||
if (o.p) {
|
||||
p = std::make_unique<T>();
|
||||
*p = *o.p;
|
||||
}
|
||||
getdef = o.getdef;
|
||||
}
|
||||
|
||||
Optional<T>& operator=(const nullptr_t&) { p.reset(); }
|
||||
Optional<T>& operator=(const T& o) { // assign by type's assignment operator if passed a "value"
|
||||
if (!p) p = std::make_unique<T>();
|
||||
*p = o;
|
||||
return *this;
|
||||
}
|
||||
|
||||
T& operator *() {
|
||||
initp();
|
||||
return *p;
|
||||
}
|
||||
|
||||
T* operator ->() {
|
||||
initp();
|
||||
return &*p;
|
||||
}
|
||||
|
||||
inline T& Get(T& defaultRef) {
|
||||
if (p) return *p;
|
||||
return defaultRef;
|
||||
}
|
||||
|
||||
inline T& ROGet() {
|
||||
if (p) return *p;
|
||||
if (getdef) return (*getdef)();
|
||||
static T fb; return fb; // meh, hackish but you shouldn't do this without a getdef anyway
|
||||
// todo: clean this up somehow ^ (throw instead? or maybe have a static unique_ptr instead so we save memory when this is never called for a type)
|
||||
}
|
||||
|
||||
//
|
||||
};
|
||||
}
|
@ -96,7 +96,8 @@ OSK::OSK(osk::InputHandler* handler) : Form(true), handler(handler) {
|
||||
bpen = bpstart + bs * Vector2(linestart[3] + 10, 3);
|
||||
auto key = std::make_shared<Button>(VRect(bpen, bs));
|
||||
key->rect.size.x *= 1.25;
|
||||
key->SetText("< <");
|
||||
//key->SetText("< <");
|
||||
key->style.glyph = ThemeManager::GetAsset("glyphs/backspace.small");
|
||||
key->eOnTap = [this](auto& btn){ this->handler->Backspace(); this->OnKey(); };
|
||||
touchScreen->Add(key);
|
||||
|
||||
@ -104,7 +105,8 @@ OSK::OSK(osk::InputHandler* handler) : Form(true), handler(handler) {
|
||||
bpen = bpstart + bs * Vector2(linestart[4] + 8, 4);
|
||||
key = std::make_shared<Button>(VRect(bpen, bs));
|
||||
key->rect.size.x *= 2.5;
|
||||
key->SetText("Enter");
|
||||
//key->SetText("Enter");
|
||||
key->style.glyph = ThemeManager::GetAsset("glyphs/enter.large");
|
||||
key->eOnTap = [this](auto& btn){ this->handler->Enter(); this->OnKey(); };
|
||||
touchScreen->Add(key);
|
||||
|
||||
|
@ -19,7 +19,7 @@ void DrawableImage::Draw(const Vector2& position, const Vector2& origin, OptRef<
|
||||
if (GFXManager::PrepareForDrawing()) {
|
||||
texture->Bind(color ? color.get() : Color(1,1,1,1));
|
||||
const VRect& sr = sampleRect ? sampleRect.get() : VRect(Vector2::zero, texture->size);
|
||||
VRect rect(position - origin * scale, sr.size * scale);
|
||||
VRect rect(position - (texture->size * origin) * scale, sr.size * scale);
|
||||
RenderCore::DrawQuad(rect, position, rotation, sr / texture->txSize);
|
||||
}
|
||||
}
|
||||
|
@ -15,8 +15,15 @@ using starlight::InputManager;
|
||||
using starlight::GFXManager;
|
||||
using starlight::ThemeManager;
|
||||
|
||||
using starlight::TextConfig;
|
||||
|
||||
using starlight::ui::Button;
|
||||
|
||||
std::function<TextConfig&()> Button::defCfg = []() -> TextConfig& {
|
||||
static TextConfig _tc = ThemeManager::GetMetric("/controls/button/text", TextConfig());
|
||||
return _tc;
|
||||
};
|
||||
|
||||
void Button::SetText(const std::string& text) {
|
||||
label = text;
|
||||
MarkForRedraw();
|
||||
@ -28,18 +35,18 @@ void Button::Draw() {
|
||||
static auto idle = ThemeManager::GetAsset("controls/button.idle");
|
||||
static auto press = ThemeManager::GetAsset("controls/button.press");
|
||||
|
||||
static TextConfig tc = ThemeManager::GetMetric("/controls/button/text", TextConfig());
|
||||
TextConfig& tc = style.textConfig.ROGet();
|
||||
|
||||
auto rect = (this->rect + GFXManager::GetOffset()).IntSnap();
|
||||
|
||||
if (InputManager::GetDragHandle() == this) {
|
||||
press->Draw(rect);
|
||||
(style.press ? style.press : press)->Draw(rect);
|
||||
} else {
|
||||
idle->Draw(rect);
|
||||
(style.idle ? style.idle : idle)->Draw(rect);
|
||||
}
|
||||
|
||||
//font->Print(rect, label, 1, cl/*Color::white*/, Vector2(0.5f, 0.5f), Color::black);
|
||||
tc.Print(rect, label);
|
||||
if (style.glyph) style.glyph->Draw(rect.Center(), Vector2::half, nullptr, tc.textColor);
|
||||
}
|
||||
|
||||
void Button::OnTouchOn() {
|
||||
|
@ -4,15 +4,30 @@
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
#include "starlight/datatypes/Optional.h"
|
||||
|
||||
#include "starlight/ThemeManager.h"
|
||||
#include "starlight/gfx/ThemeRef.h"
|
||||
|
||||
#include "starlight/ui/UIElement.h"
|
||||
|
||||
namespace starlight {
|
||||
namespace ui {
|
||||
class Button : public UIElement {
|
||||
public:
|
||||
struct Style {
|
||||
gfx::ThemeRef<gfx::Drawable>
|
||||
idle = nullptr,
|
||||
press = nullptr,
|
||||
glyph = nullptr;
|
||||
Optional<TextConfig> textConfig = &Button::defCfg;
|
||||
};
|
||||
private:
|
||||
//
|
||||
static std::function<TextConfig&()> defCfg;
|
||||
|
||||
public:
|
||||
Style style;
|
||||
|
||||
std::string label = "";
|
||||
std::function<void(Button&)> eOnTap;
|
||||
|
||||
|
@ -3,17 +3,22 @@
|
||||
#include "starlight/GFXManager.h"
|
||||
|
||||
using starlight::GFXManager;
|
||||
using starlight::TextConfig;
|
||||
|
||||
using starlight::ui::Label;
|
||||
|
||||
std::function<TextConfig&()> Label::defCfg = []() -> TextConfig& {
|
||||
static TextConfig _tc = ThemeManager::GetMetric<TextConfig>("/textPresets/normal.12", TextConfig());
|
||||
return _tc;
|
||||
};
|
||||
|
||||
Label::Label(VRect rect) {
|
||||
this->rect = rect;
|
||||
textConfig = ThemeManager::GetMetric<TextConfig>("/textPresets/normal.12", TextConfig());
|
||||
}
|
||||
|
||||
void Label::AutoSize() {
|
||||
if (autoSizeV) {
|
||||
float h = textConfig.font->Measure(text, 1, rect.size.x).y;
|
||||
float h = textConfig.ROGet().font->Measure(text, 1, rect.size.x).y;
|
||||
Resize(rect.size.x, h);
|
||||
}
|
||||
|
||||
@ -28,12 +33,12 @@ void Label::SetText(const std::string& text) {
|
||||
}
|
||||
|
||||
void Label::SetFont(const std::string& fontName) {
|
||||
textConfig.font = ThemeManager::GetFont(fontName);
|
||||
textConfig->font = ThemeManager::GetFont(fontName);
|
||||
AutoSize();
|
||||
}
|
||||
|
||||
void Label::SetPreset(const std::string& name) {
|
||||
textConfig = ThemeManager::GetMetric<TextConfig>("/textPresets/" + name, textConfig);
|
||||
textConfig = ThemeManager::GetMetric<TextConfig>("/textPresets/" + name, textConfig.ROGet());
|
||||
AutoSize();
|
||||
}
|
||||
|
||||
@ -48,7 +53,7 @@ void Label::PreDraw() {
|
||||
buffer = std::make_unique<gfx::DrawContextCanvas>(rect.size + Vector2(0, 8));
|
||||
buffer->Clear();
|
||||
GFXManager::PushContext(buffer.get());
|
||||
textConfig.Print(buffer->rect, text);
|
||||
textConfig.ROGet().Print(buffer->rect, text);
|
||||
GFXManager::PopContext();
|
||||
}
|
||||
}
|
||||
@ -58,6 +63,6 @@ void Label::Draw() {
|
||||
if (buffer) {
|
||||
buffer->Draw(VRect(rect.pos, buffer->rect.size));
|
||||
} else {
|
||||
textConfig.Print(rect, text);
|
||||
textConfig.ROGet().Print(rect, text);
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,8 @@
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
#include "starlight/datatypes/Optional.h"
|
||||
|
||||
#include "starlight/ThemeManager.h"
|
||||
#include "starlight/gfx/ThemeRef.h"
|
||||
|
||||
@ -15,11 +17,13 @@ namespace starlight {
|
||||
namespace ui {
|
||||
class Label : public UIElement {
|
||||
private:
|
||||
static std::function<TextConfig&()> defCfg;
|
||||
|
||||
void AutoSize();
|
||||
|
||||
public:
|
||||
std::string text = "";
|
||||
TextConfig textConfig;
|
||||
Optional<TextConfig> textConfig = &defCfg;
|
||||
|
||||
std::unique_ptr<gfx::DrawContextCanvas> buffer;
|
||||
|
||||
|
@ -47,9 +47,9 @@ void UIContainer::_Dive(std::function<bool(UIElement*)>& func, bool consumable,
|
||||
}
|
||||
|
||||
void UIContainer::Add(std::shared_ptr<UIElement> elem, bool front) {
|
||||
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()));
|
||||
if (front) children.push_front(std::move(elem));
|
||||
else children.push_back(std::move(elem));
|
||||
MarkForRedraw();
|
||||
}
|
||||
//void UIContainer::Add(UIElement* elem) {
|
||||
|
@ -35,6 +35,11 @@ namespace starlight {
|
||||
void Dive(std::function<bool(UIElement*)> func, bool consumable = true, bool frontFirst = true);
|
||||
|
||||
void Add(std::shared_ptr<UIElement> elem, bool front = false);
|
||||
template<class E, typename ... Args>
|
||||
inline std::shared_ptr<E> AddNew(Args... args) {
|
||||
auto n = std::make_shared<E>(args...);
|
||||
Add(n); return n;
|
||||
}
|
||||
//void Add(UIElement* elem);
|
||||
void Remove(std::shared_ptr<UIElement> elem);
|
||||
void RemoveAll();
|
||||
|
@ -1,12 +1,29 @@
|
||||
|
||||
|
||||
|
||||
roadmap to first release, in no particular order {
|
||||
- ding!
|
||||
roadmap to v0.5.1 {
|
||||
- add customization for Button (alternate idle/press images, optional glyph drawable) {
|
||||
- also add (optional) TextConfig
|
||||
- use that to spice up the OSK
|
||||
}
|
||||
figure out what to put on the left side of the keyboard (opposite backspace and enter)
|
||||
temporary drawable loading, local themeref, discard etc.
|
||||
^ both png and raw load
|
||||
maybe rgb565 for smdh icon loading?
|
||||
some examples (minesweeper?)
|
||||
proper thread dispatch?
|
||||
} then consider these before 1.0 "gold" {
|
||||
make closing forms a bit less finicky (add them to a separate list and let the Application remove them from the list)
|
||||
add customization for Button (alternate idle/press images, optional glyph drawable)
|
||||
^ use that to spice up the OSK
|
||||
garbage collection for not-recently-used theme assets {
|
||||
keep track of last-use in ThemeRefContainer
|
||||
have ThemeManager sweep gc every so often
|
||||
rework redirects (proxy drawable I guess...?)
|
||||
}
|
||||
HANDLE CANVAS OVERRUNS FOR LABELS AND OSK PREVIEW {
|
||||
- well, it doesn't actually *crash* anymore... or at least nowhere near as fast
|
||||
use a "windowed" approach; only cache a bit more than is visible and redraw when the viewport changes enough
|
||||
have a way for text rendering to skip lines that won't be visible, and use that with windowing to cut down render times further
|
||||
}
|
||||
actual cursor image for OSK instead of just using a | glypyh
|
||||
input prompt dialog
|
||||
"shortcut" overloads for InputManager::OpenKeyboard
|
||||
|
@ -42,9 +42,9 @@ void Core::Init() {
|
||||
touchScreen->Add(container);
|
||||
|
||||
auto label = std::make_shared<sl::ui::Label>(VRect(0,0,320,0));
|
||||
label->textConfig.justification = Vector2::half;
|
||||
label->textConfig->justification = Vector2::half;
|
||||
label->autoSizeV = true;
|
||||
label->SetText("~libstarlight UI test~\n\nHello. I'm a label.\nI have multiple lines and can resize to fit my content. Did you know that miles per gallon is actually a measure of volume?");
|
||||
label->SetText("~libstarlight UI test~\n\nHello. I'm a label.\nI have multiple lines and can resize to fit my content. Did you know that miles per gallon is actually a measure of volume? " + std::to_string(sizeof(std::unique_ptr<sl::ui::Label>)));
|
||||
container->Add(label);
|
||||
|
||||
auto button = std::make_shared<sl::ui::Button>(VRect(64,80,128,32));
|
||||
@ -54,7 +54,7 @@ void Core::Init() {
|
||||
auto form = std::make_shared<sl::ui::Form>(true);
|
||||
|
||||
auto label = std::make_shared<sl::ui::Label>(VRect(0,0,320,0));
|
||||
label->textConfig.justification = Vector2::half;
|
||||
label->textConfig->justification = Vector2::half;
|
||||
label->autoSizeV = true;
|
||||
label->SetText("This is a form, coming in and nuking the non-form UI elements. Whoops.");
|
||||
form->touchScreen->Add(label);
|
||||
@ -69,8 +69,8 @@ void Core::Init() {
|
||||
auto tlbl = std::make_shared<sl::ui::Label>(VRect(2, 2, 396, 0));
|
||||
tlbl->autoSizeV = true;
|
||||
tlbl->SetPreset("normal.16");
|
||||
tlbl->textConfig.justification = Vector2::zero;
|
||||
tlbl->textConfig.borderColor = Color::black;
|
||||
tlbl->textConfig->justification = Vector2::zero;
|
||||
tlbl->textConfig->borderColor = Color::black;
|
||||
tlbl->SetText("3DS:~# sudo make me a sandwich_");
|
||||
form->topScreen->Add(tlbl);
|
||||
|
||||
@ -100,8 +100,8 @@ void Core::Init() {
|
||||
|
||||
auto pipf = std::make_shared<sl::ui::Label>(VRect(0,0,400,240));
|
||||
pipf->SetPreset("normal.16");
|
||||
pipf->textConfig.borderColor = Color::black;
|
||||
pipf->textConfig.justification = Vector2::half;
|
||||
pipf->textConfig->borderColor = Color::black;
|
||||
pipf->textConfig->justification = Vector2::half;
|
||||
pipf->SetText("This label is on a parallax layer. Try moving the 3D slider.\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.");
|
||||
parallax->Add(pipf);
|
||||
|
||||
|
BIN
themes/default/glyphs/backspace.large.png
Normal file
BIN
themes/default/glyphs/backspace.large.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 309 B |
BIN
themes/default/glyphs/backspace.small.png
Normal file
BIN
themes/default/glyphs/backspace.small.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 295 B |
BIN
themes/default/glyphs/backspace.xcf
Normal file
BIN
themes/default/glyphs/backspace.xcf
Normal file
Binary file not shown.
BIN
themes/default/glyphs/enter.large.png
Normal file
BIN
themes/default/glyphs/enter.large.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 267 B |
BIN
themes/default/glyphs/enter.small.png
Normal file
BIN
themes/default/glyphs/enter.small.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 237 B |
BIN
themes/default/glyphs/enter.xcf
Normal file
BIN
themes/default/glyphs/enter.xcf
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user