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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

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.