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:
zetaPRIME 2017-03-18 19:29:32 -04:00
parent ecf47db716
commit 7f27018808
17 changed files with 146 additions and 28 deletions

View 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)
}
//
};
}

View File

@ -96,7 +96,8 @@ OSK::OSK(osk::InputHandler* handler) : Form(true), handler(handler) {
bpen = bpstart + bs * Vector2(linestart[3] + 10, 3); bpen = bpstart + bs * Vector2(linestart[3] + 10, 3);
auto key = std::make_shared<Button>(VRect(bpen, bs)); auto key = std::make_shared<Button>(VRect(bpen, bs));
key->rect.size.x *= 1.25; 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(); }; key->eOnTap = [this](auto& btn){ this->handler->Backspace(); this->OnKey(); };
touchScreen->Add(key); touchScreen->Add(key);
@ -104,7 +105,8 @@ OSK::OSK(osk::InputHandler* handler) : Form(true), handler(handler) {
bpen = bpstart + bs * Vector2(linestart[4] + 8, 4); bpen = bpstart + bs * Vector2(linestart[4] + 8, 4);
key = std::make_shared<Button>(VRect(bpen, bs)); key = std::make_shared<Button>(VRect(bpen, bs));
key->rect.size.x *= 2.5; 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(); }; key->eOnTap = [this](auto& btn){ this->handler->Enter(); this->OnKey(); };
touchScreen->Add(key); touchScreen->Add(key);

View File

@ -19,7 +19,7 @@ void DrawableImage::Draw(const Vector2& position, const Vector2& origin, OptRef<
if (GFXManager::PrepareForDrawing()) { if (GFXManager::PrepareForDrawing()) {
texture->Bind(color ? color.get() : Color(1,1,1,1)); texture->Bind(color ? color.get() : Color(1,1,1,1));
const VRect& sr = sampleRect ? sampleRect.get() : VRect(Vector2::zero, texture->size); 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); RenderCore::DrawQuad(rect, position, rotation, sr / texture->txSize);
} }
} }

View File

@ -15,8 +15,15 @@ using starlight::InputManager;
using starlight::GFXManager; using starlight::GFXManager;
using starlight::ThemeManager; using starlight::ThemeManager;
using starlight::TextConfig;
using starlight::ui::Button; 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) { void Button::SetText(const std::string& text) {
label = text; label = text;
MarkForRedraw(); MarkForRedraw();
@ -28,18 +35,18 @@ void Button::Draw() {
static auto idle = ThemeManager::GetAsset("controls/button.idle"); static auto idle = ThemeManager::GetAsset("controls/button.idle");
static auto press = ThemeManager::GetAsset("controls/button.press"); 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(); auto rect = (this->rect + GFXManager::GetOffset()).IntSnap();
if (InputManager::GetDragHandle() == this) { if (InputManager::GetDragHandle() == this) {
press->Draw(rect); (style.press ? style.press : press)->Draw(rect);
} else { } 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); tc.Print(rect, label);
if (style.glyph) style.glyph->Draw(rect.Center(), Vector2::half, nullptr, tc.textColor);
} }
void Button::OnTouchOn() { void Button::OnTouchOn() {

View File

@ -4,15 +4,30 @@
#include <string> #include <string>
#include <functional> #include <functional>
#include "starlight/datatypes/Optional.h"
#include "starlight/ThemeManager.h"
#include "starlight/gfx/ThemeRef.h"
#include "starlight/ui/UIElement.h" #include "starlight/ui/UIElement.h"
namespace starlight { namespace starlight {
namespace ui { namespace ui {
class Button : public UIElement { class Button : public UIElement {
public:
struct Style {
gfx::ThemeRef<gfx::Drawable>
idle = nullptr,
press = nullptr,
glyph = nullptr;
Optional<TextConfig> textConfig = &Button::defCfg;
};
private: private:
// static std::function<TextConfig&()> defCfg;
public: public:
Style style;
std::string label = ""; std::string label = "";
std::function<void(Button&)> eOnTap; std::function<void(Button&)> eOnTap;

View File

@ -3,17 +3,22 @@
#include "starlight/GFXManager.h" #include "starlight/GFXManager.h"
using starlight::GFXManager; using starlight::GFXManager;
using starlight::TextConfig;
using starlight::ui::Label; 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) { Label::Label(VRect rect) {
this->rect = rect; this->rect = rect;
textConfig = ThemeManager::GetMetric<TextConfig>("/textPresets/normal.12", TextConfig());
} }
void Label::AutoSize() { void Label::AutoSize() {
if (autoSizeV) { 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); Resize(rect.size.x, h);
} }
@ -28,12 +33,12 @@ void Label::SetText(const std::string& text) {
} }
void Label::SetFont(const std::string& fontName) { void Label::SetFont(const std::string& fontName) {
textConfig.font = ThemeManager::GetFont(fontName); textConfig->font = ThemeManager::GetFont(fontName);
AutoSize(); AutoSize();
} }
void Label::SetPreset(const std::string& name) { void Label::SetPreset(const std::string& name) {
textConfig = ThemeManager::GetMetric<TextConfig>("/textPresets/" + name, textConfig); textConfig = ThemeManager::GetMetric<TextConfig>("/textPresets/" + name, textConfig.ROGet());
AutoSize(); AutoSize();
} }
@ -48,7 +53,7 @@ void Label::PreDraw() {
buffer = std::make_unique<gfx::DrawContextCanvas>(rect.size + Vector2(0, 8)); buffer = std::make_unique<gfx::DrawContextCanvas>(rect.size + Vector2(0, 8));
buffer->Clear(); buffer->Clear();
GFXManager::PushContext(buffer.get()); GFXManager::PushContext(buffer.get());
textConfig.Print(buffer->rect, text); textConfig.ROGet().Print(buffer->rect, text);
GFXManager::PopContext(); GFXManager::PopContext();
} }
} }
@ -58,6 +63,6 @@ void Label::Draw() {
if (buffer) { if (buffer) {
buffer->Draw(VRect(rect.pos, buffer->rect.size)); buffer->Draw(VRect(rect.pos, buffer->rect.size));
} else { } else {
textConfig.Print(rect, text); textConfig.ROGet().Print(rect, text);
} }
} }

View File

@ -4,6 +4,8 @@
#include <string> #include <string>
#include <memory> #include <memory>
#include "starlight/datatypes/Optional.h"
#include "starlight/ThemeManager.h" #include "starlight/ThemeManager.h"
#include "starlight/gfx/ThemeRef.h" #include "starlight/gfx/ThemeRef.h"
@ -15,11 +17,13 @@ namespace starlight {
namespace ui { namespace ui {
class Label : public UIElement { class Label : public UIElement {
private: private:
static std::function<TextConfig&()> defCfg;
void AutoSize(); void AutoSize();
public: public:
std::string text = ""; std::string text = "";
TextConfig textConfig; Optional<TextConfig> textConfig = &defCfg;
std::unique_ptr<gfx::DrawContextCanvas> buffer; std::unique_ptr<gfx::DrawContextCanvas> buffer;

View File

@ -47,9 +47,9 @@ void UIContainer::_Dive(std::function<bool(UIElement*)>& func, bool consumable,
} }
void UIContainer::Add(std::shared_ptr<UIElement> elem, bool front) { 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())); 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(); MarkForRedraw();
} }
//void UIContainer::Add(UIElement* elem) { //void UIContainer::Add(UIElement* elem) {

View File

@ -35,6 +35,11 @@ namespace starlight {
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, bool front = false); 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 Add(UIElement* elem);
void Remove(std::shared_ptr<UIElement> elem); void Remove(std::shared_ptr<UIElement> elem);
void RemoveAll(); void RemoveAll();

View File

@ -1,12 +1,29 @@
roadmap to first release, in no particular order { roadmap to v0.5.1 {
- ding! - 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" { } 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) 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) garbage collection for not-recently-used theme assets {
^ use that to spice up the OSK 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 actual cursor image for OSK instead of just using a | glypyh
input prompt dialog input prompt dialog
"shortcut" overloads for InputManager::OpenKeyboard "shortcut" overloads for InputManager::OpenKeyboard

View File

@ -42,9 +42,9 @@ void Core::Init() {
touchScreen->Add(container); touchScreen->Add(container);
auto label = std::make_shared<sl::ui::Label>(VRect(0,0,320,0)); 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->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); container->Add(label);
auto button = std::make_shared<sl::ui::Button>(VRect(64,80,128,32)); 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 form = std::make_shared<sl::ui::Form>(true);
auto label = std::make_shared<sl::ui::Label>(VRect(0,0,320,0)); 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->autoSizeV = true;
label->SetText("This is a form, coming in and nuking the non-form UI elements. Whoops."); label->SetText("This is a form, coming in and nuking the non-form UI elements. Whoops.");
form->touchScreen->Add(label); form->touchScreen->Add(label);
@ -69,8 +69,8 @@ void Core::Init() {
auto tlbl = std::make_shared<sl::ui::Label>(VRect(2, 2, 396, 0)); auto tlbl = std::make_shared<sl::ui::Label>(VRect(2, 2, 396, 0));
tlbl->autoSizeV = true; tlbl->autoSizeV = true;
tlbl->SetPreset("normal.16"); tlbl->SetPreset("normal.16");
tlbl->textConfig.justification = Vector2::zero; tlbl->textConfig->justification = Vector2::zero;
tlbl->textConfig.borderColor = Color::black; tlbl->textConfig->borderColor = Color::black;
tlbl->SetText("3DS:~# sudo make me a sandwich_"); tlbl->SetText("3DS:~# sudo make me a sandwich_");
form->topScreen->Add(tlbl); form->topScreen->Add(tlbl);
@ -100,8 +100,8 @@ void Core::Init() {
auto pipf = std::make_shared<sl::ui::Label>(VRect(0,0,400,240)); auto pipf = std::make_shared<sl::ui::Label>(VRect(0,0,400,240));
pipf->SetPreset("normal.16"); pipf->SetPreset("normal.16");
pipf->textConfig.borderColor = Color::black; pipf->textConfig->borderColor = Color::black;
pipf->textConfig.justification = Vector2::half; 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."); 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); parallax->Add(pipf);

Binary file not shown.

After

Width:  |  Height:  |  Size: 309 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 B

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 267 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 B

Binary file not shown.