TextBox widget, justification and inheritance in TextConfig,

fix closing osk from InputHandler, make font text input const,
font-related miscellany
This commit is contained in:
zetaPRIME 2017-03-16 13:25:16 -04:00
parent 68042ed86d
commit e22c8995a6
20 changed files with 257 additions and 97 deletions

View File

@ -347,10 +347,27 @@ TextConfig::TextConfig(const std::string& fontName, Color text, Color border) {
textColor = text; borderColor = border;
}
void TextConfig::Print(Vector2 position, std::string& text, Vector2 justification)
{ font->Print(position, text, 1, textColor, justification, borderColor); }
void TextConfig::Print(VRect rect, std::string& text, Vector2 justification)
{ font->Print(rect, text, 1, textColor, justification, borderColor); }
void TextConfig::Print(Vector2 position, std::string& text, Vector2 justification) {
if (!justification) justification = this->justification;
font->Print(position, text, 1, textColor, justification, borderColor);
}
void TextConfig::Print(VRect rect, std::string& text, Vector2 justification) {
if (!justification) justification = this->justification;
font->Print(rect, text, 1, textColor, justification, borderColor);
}
Vector2 TextConfig::Measure(const std::string& text, float maxWidth) {
return font->Measure(text, 1, maxWidth);
}
Vector2 TextConfig::GetCursorPosition(VRect rect, const std::string& text, unsigned int end) {
if (borderColor != Color::transparent) rect = rect.Expand(-1); // sync with drawing where bordered
return font->GetCursorPosition(rect, text, end);
}
unsigned int TextConfig::GetCursorFromPoint(VRect rect, const std::string& text, Vector2 pt) {
if (borderColor != Color::transparent) rect = rect.Expand(-1); // sync with drawing where bordered
return font->GetCursorFromPoint(rect, text, pt);
}
namespace starlight { // todo: expose these in the header
void to_json(nlohmann::json& j, const TextConfig& tc) {
@ -358,9 +375,14 @@ namespace starlight { // todo: expose these in the header
}
void from_json(const nlohmann::json& j, TextConfig& tc) {
if (j.is_object()) {
tc.font = ThemeManager::GetFont(j.value("font", "default.12"));
tc.textColor = j.value("textColor", Color::white);
tc.borderColor = j.value("borderColor", Color::transparent);
std::string inh = j.value("_inherit", "");
if (inh != "") {
tc = ThemeManager::GetMetric<TextConfig>(inh);
}
tc.font = ThemeManager::GetFont(j.value("font", tc.font.GetName()));
tc.textColor = j.value("textColor", tc.textColor);
tc.borderColor = j.value("borderColor", tc.borderColor);
tc.justification = j.value("justification", tc.justification);
}
//
}

View File

@ -79,12 +79,18 @@ namespace starlight {
gfx::ThemeRef<gfx::Font> font = ThemeManager::GetFont("default.12");
Color textColor = Color::white;
Color borderColor = Color::transparent;
Vector2 justification = Vector2::zero;
TextConfig() = default;
TextConfig(const std::string& fontName, Color text, Color border = Color::transparent);
~TextConfig() = default;
void Print(Vector2 position, std::string& text, Vector2 justification = Vector2::zero);
void Print(VRect rect, std::string& text, Vector2 justification = Vector2::zero);
void Print(Vector2 position, std::string& text, Vector2 justification = Vector2::invalid);
void Print(VRect rect, std::string& text, Vector2 justification = Vector2::invalid);
Vector2 Measure(const std::string& text, float maxWidth = 65536*64);
Vector2 GetCursorPosition(VRect rect, const std::string& text, unsigned int end);
unsigned int GetCursorFromPoint(VRect rect, const std::string& text, Vector2 pt);
};
}

View File

@ -112,6 +112,9 @@ OSK::OSK(osk::InputHandler* handler) : Form(true), handler(handler) {
}
void OSK::Update(bool focused) {
if (handler->done) {
Close();
}
if (focused) {
if (InputManager::Pressed(Keys::B)) handler->Done();
if (true || handler->showPreview) {
@ -126,17 +129,17 @@ void OSK::Update(bool focused) {
auto& tc = PreviewTC();
if (InputManager::Pressed(Keys::DPadUp)) {
Vector2 pt = tc.font->GetCursorPosition(preview->rect, handler->GetPreviewText(), handler->GetCursor());
Vector2 pt = tc.GetCursorPosition(preview->rect, handler->GetPreviewText(), handler->GetCursor());
string msr = "|";
pt.y -= tc.font->Measure(msr).y * 0.5f;
handler->SetCursor(tc.font->GetCursorFromPoint(preview->rect, handler->GetPreviewText(), pt));
pt.y -= tc.Measure(msr).y * 0.5f;
handler->SetCursor(tc.GetCursorFromPoint(preview->rect, handler->GetPreviewText(), pt));
preview->Refresh();
}
if (InputManager::Pressed(Keys::DPadDown)) {
Vector2 pt = tc.font->GetCursorPosition(preview->rect, handler->GetPreviewText(), handler->GetCursor());
Vector2 pt = tc.GetCursorPosition(preview->rect, handler->GetPreviewText(), handler->GetCursor());
string msr = "|";
pt.y += tc.font->Measure(msr).y * 1.5f;
handler->SetCursor(tc.font->GetCursorFromPoint(preview->rect, handler->GetPreviewText(), pt));
pt.y += tc.Measure(msr).y * 1.5f;
handler->SetCursor(tc.GetCursorFromPoint(preview->rect, handler->GetPreviewText(), pt));
preview->Refresh();
}
}
@ -162,7 +165,7 @@ void OSK::DrawPreview(DrawLayerProxy& layer) {
auto& tc = PreviewTC();
tc.Print(layer.rect, handler->GetPreviewText(), Vector2::zero);
Vector2 cp = tc.font->GetCursorPosition(layer.rect, handler->GetPreviewText(), handler->GetCursor());
Vector2 cp = tc.GetCursorPosition(layer.rect, handler->GetPreviewText(), handler->GetCursor());
string cc = "|";
tc.Print(cp, cc, Vector2::zero);
}
@ -171,6 +174,6 @@ void OSK::DrawPreview(DrawLayerProxy& layer) {
void OSK::OnPreviewTap(DrawLayerProxy& layer) {
Vector2 tpos = InputManager::TouchPos() - layer.ScreenRect().pos;
auto& tc = PreviewTC();
handler->SetCursor(tc.font->GetCursorFromPoint(layer.rect, handler->GetPreviewText(), tpos));
handler->SetCursor(tc.GetCursorFromPoint(layer.rect, handler->GetPreviewText(), tpos));
preview->Refresh();
}

View File

@ -40,7 +40,7 @@ void InputHandlerDirectEdit::Enter() {
void InputHandlerDirectEdit::Done() {
if (eOnFinalize) eOnFinalize();
parent->Close();
done = true;
}
// Buffered
@ -66,5 +66,5 @@ void InputHandlerBuffered::Enter() {
void InputHandlerBuffered::Done() {
if (eOnFinalize) eOnFinalize(buffer);
parent->Close();
done = true;
}

View File

@ -18,6 +18,8 @@ namespace starlight {
bool showPreview = false;
ui::Form* parent;
bool done = false;
InputHandler() = default;
virtual ~InputHandler() = default;

View File

@ -63,7 +63,7 @@ BitmapFont::CharInfo& BitmapFont::Char(char c) {
return cdefault;
}
Vector2 BitmapFont::MeasureTo(std::string& msg, bool total, unsigned int end, float maxWidth) {
Vector2 BitmapFont::MeasureTo(const std::string& msg, bool total, unsigned int end, float maxWidth) {
if (total) {
Vector2 measure = Vector2::zero;
@ -100,7 +100,7 @@ Vector2 BitmapFont::MeasureTo(std::string& msg, bool total, unsigned int end, fl
return measure;
}
unsigned int BitmapFont::PointToIndex(std::string& msg, Vector2 pt, float maxWidth) {
unsigned int BitmapFont::PointToIndex(const std::string& msg, Vector2 pt, float maxWidth) {
//pt -= Vector2(padX, 0*padY);
if (pt.y < 0) return 0;
unsigned int tl = std::floor(pt.y / lineHeight);

View File

@ -62,8 +62,8 @@ namespace starlight {
void ForChar(const std::string& msg, std::function<bool(CharLoopState&)> func, float maxWidth = 65536*64);
Vector2 MeasureTo(std::string& msg, bool total = true, unsigned int end = 4294967295, float maxWidth = 65536*64);
unsigned int PointToIndex(std::string& msg, Vector2 pt, float maxWidth = 65536*64);
Vector2 MeasureTo(const std::string& msg, bool total = true, unsigned int end = 4294967295, float maxWidth = 65536*64);
unsigned int PointToIndex(const std::string& msg, Vector2 pt, float maxWidth = 65536*64);
static inline constexpr unsigned int KerningKey(char cl, char cr) {
return (static_cast<unsigned int>(cl) | (static_cast<unsigned int>(cr) << 8));

View File

@ -19,14 +19,15 @@ namespace starlight {
Font() { }
virtual ~Font() { }
virtual Vector2 Measure(std::string& text, float scale = 1, float maxWidth = 400) = 0;
virtual void Print(Vector2 position, std::string& text, float scale = 1, Color color = Color::white, Vector2 justification = Vector2::zero, OptRef<Color> borderColor = nullptr) = 0;
virtual void Print(VRect rect, std::string& text, float scale = 1, Color color = Color::white, Vector2 justification = Vector2::zero, OptRef<Color> borderColor = nullptr) = 0;
virtual void Print(Vector2 position, const std::string& text, float scale = 1, Color color = Color::white, Vector2 justification = Vector2::zero, OptRef<Color> borderColor = nullptr) = 0;
virtual void Print(VRect rect, const std::string& text, float scale = 1, Color color = Color::white, Vector2 justification = Vector2::zero, OptRef<Color> borderColor = nullptr) = 0;
//virtual void PrintDisplayList(DisplayList* dl, Vector2 position, std::string& text, float scale = 1, Color color = Color::white, Vector2 justification = Vector2::zero, OptRef<Color> borderColor = nullptr) = 0;
//virtual void PrintDisplayList(DisplayList* dl, VRect rect, std::string& text, float scale = 1, Color color = Color::white, Vector2 justification = Vector2::zero, OptRef<Color> borderColor = nullptr) = 0;
virtual Vector2 GetCursorPosition(VRect rect, std::string& text, unsigned int end, float scale = 1) = 0;
virtual unsigned int GetCursorFromPoint(VRect rect, std::string& text, Vector2 pt, float scale = 1) = 0;
virtual Vector2 Measure(const std::string& text, float scale = 1, float maxWidth = 400) = 0;
virtual Vector2 GetCursorPosition(VRect rect, const std::string& text, unsigned int end, float scale = 1) = 0;
virtual unsigned int GetCursorFromPoint(VRect rect, const std::string& text, Vector2 pt, float scale = 1) = 0;
};
}

View File

@ -16,12 +16,12 @@ using starlight::gfx::FontBMF;
//#define err(nth, wat) *((unsigned int*)0x00100000+(nth))=wat;
//#define ded(wat) err(0,wat)
Vector2 FontBMF::Measure(std::string& text, float scale, float maxWidth) {
Vector2 FontBMF::Measure(const std::string& text, float scale, float maxWidth) {
if (text == "") return Vector2::zero;
return font->MeasureTo(text, true, text.length(), maxWidth) * scale;
}
void FontBMF::Print(Vector2 position, std::string& text, float scale, Color color, Vector2 justification, OptRef<Color> borderColor) {
void FontBMF::Print(Vector2 position, const std::string& text, float scale, Color color, Vector2 justification, OptRef<Color> borderColor) {
if (text == "") return;
if (GFXManager::PrepareForDrawing()) {
DisplayList dl = DisplayList();
@ -48,10 +48,10 @@ void FontBMF::Print(Vector2 position, std::string& text, float scale, Color colo
}
}
void FontBMF::Print(VRect rect, std::string& text, float scale, Color color, Vector2 justification, OptRef<Color> borderColor) {
void FontBMF::Print(VRect rect, const std::string& text, float scale, Color color, Vector2 justification, OptRef<Color> borderColor) {
if (text == "") return;
if (GFXManager::PrepareForDrawing()) {
if (borderColor && borderColor.get() != Color::transparent) rect = rect.Expand(-1, -1);
if (borderColor && borderColor.get() != Color::transparent) rect = rect.Expand(-1);
Vector2 position = rect.pos + rect.size * justification;
DisplayList dl = DisplayList();
{
@ -78,10 +78,10 @@ void FontBMF::Print(VRect rect, std::string& text, float scale, Color color, Vec
}
}
Vector2 FontBMF::GetCursorPosition(VRect rect, std::string& text, unsigned int end, float scale) {
Vector2 FontBMF::GetCursorPosition(VRect rect, const std::string& text, unsigned int end, float scale) {
return rect.pos + (font->MeasureTo(text, false, end, rect.size.x / scale)* scale);
}
unsigned int FontBMF::GetCursorFromPoint(VRect rect, std::string& text, Vector2 pt, float scale) {
unsigned int FontBMF::GetCursorFromPoint(VRect rect, const std::string& text, Vector2 pt, float scale) {
return font->PointToIndex(text, pt*scale - rect.pos, rect.size.x / scale);
}

View File

@ -18,14 +18,14 @@ namespace starlight {
FontBMF() { }
~FontBMF() { }
Vector2 Measure(std::string& text, float scale = 1, float maxWidth = 400) override;
void Print(Vector2 position, std::string& text, float scale = 1, Color color = Color::white, Vector2 justification = Vector2::zero, OptRef<Color> borderColor = nullptr) override;
void Print(VRect rect, std::string& text, float scale = 1, Color color = Color::white, Vector2 justification = Vector2::zero, OptRef<Color> borderColor = nullptr) override;
Vector2 Measure(const std::string& text, float scale = 1, float maxWidth = 400) override;
void Print(Vector2 position, const std::string& text, float scale = 1, Color color = Color::white, Vector2 justification = Vector2::zero, OptRef<Color> borderColor = nullptr) override;
void Print(VRect rect, const std::string& text, float scale = 1, Color color = Color::white, Vector2 justification = Vector2::zero, OptRef<Color> borderColor = nullptr) override;
//void PrintDisplayList(DisplayList* dl, Vector2 position, std::string& text, float scale = 1, Color color = Color::white, Vector2 justification = Vector2::zero, OptRef<Color> borderColor = nullptr) override;
//void PrintDisplayList(DisplayList* dl, VRect rect, std::string& text, float scale = 1, Color color = Color::white, Vector2 justification = Vector2::zero, OptRef<Color> borderColor = nullptr) override;
Vector2 GetCursorPosition(VRect rect, std::string& text, unsigned int end, float scale) override;
unsigned int GetCursorFromPoint(VRect rect, std::string& text, Vector2 pt, float scale) override;
Vector2 GetCursorPosition(VRect rect, const std::string& text, unsigned int end, float scale) override;
unsigned int GetCursorFromPoint(VRect rect, const std::string& text, Vector2 pt, float scale) override;
};
}
}

View File

@ -53,6 +53,7 @@ namespace starlight {
inline const ThemeRefContainer<T>& operator ->() const { return *cptr; }
inline explicit operator bool() const { return cptr != nullptr; }
inline std::shared_ptr<T> GetShared() const { return (*cptr).ptr; }
inline const std::string& GetName() const { return (*cptr).name; }
};
}
}

View File

@ -28,7 +28,7 @@ void Button::Draw() {
static auto idle = ThemeManager::GetAsset("controls/button.idle");
static auto press = ThemeManager::GetAsset("controls/button.press");
static TextConfig tc = ThemeManager::GetMetric<TextConfig>("/controls/button/text", TextConfig());
static TextConfig tc = ThemeManager::GetMetric("/controls/button/text", TextConfig());
auto rect = (this->rect + GFXManager::GetOffset()).IntSnap();
@ -39,7 +39,7 @@ void Button::Draw() {
}
//font->Print(rect, label, 1, cl/*Color::white*/, Vector2(0.5f, 0.5f), Color::black);
tc.Print(rect, label, Vector2::half);
tc.Print(rect, label);
}
void Button::OnTouchOn() {

View File

@ -0,0 +1,103 @@
#include "TextBox.h"
#include <cmath>
#include "starlight/_incLib/json.hpp"
#include "starlight/InputManager.h"
#include "starlight/GFXManager.h"
#include "starlight/ThemeManager.h"
#include "starlight/dialog/OSK.h"
using starlight::Vector2;
using starlight::Color;
using starlight::gfx::Font;
using starlight::InputManager;
using starlight::GFXManager;
using starlight::ThemeManager;
using starlight::TextConfig;
using starlight::dialog::OSK;
using starlight::dialog::osk::InputHandlerBuffered;
using starlight::ui::TextBox;
void TextBox::SetText(const std::string& text) {
this->text = text;
textView.reset();
MarkForRedraw();
}
void TextBox::PreDraw() {
if (!textView) {
static Vector2 margin = ThemeManager::GetMetric("/controls/textBox/margin", Vector2::zero);
textView = std::make_unique<gfx::DrawContextCanvas>(rect.size - margin*2);
textView->Clear();
GFXManager::PushContext(textView.get());
static TextConfig tc = ThemeManager::GetMetric("/controls/textBox/text", TextConfig());
if (multiLine) {
// for now I guess just flat top-left
tc.Print(textView->rect, text, Vector2::zero);
} else {
Vector2 sz = tc.Measure(text);
Vector2 justification = Vector2(tc.justification.x, 0.5f);
tc.Print(textView->rect.RightEdge(std::max(textView->rect.size.x, sz.x)), text, justification);
}
GFXManager::PopContext();
}
}
void TextBox::PreDrawOffscreen() { textView.reset(); } // discard on offscreen
void TextBox::Draw() {
static auto bg = ThemeManager::GetAsset("controls/textBox");
static Vector2 margin = ThemeManager::GetMetric("/controls/textBox/margin", Vector2::zero);
auto rect = (this->rect + GFXManager::GetOffset()).IntSnap();
bg->Draw(rect);
//tc.Print(rect.Expand(-margin), text);
if (textView) textView->Draw(rect.Expand(-margin));
}
void TextBox::OnResize() {
textView.reset();
MarkForRedraw();
}
void TextBox::OnTouchOn() {
if (InputManager::Pressed(Keys::Touch)) {
InputManager::GetDragHandle().Grab(this);
MarkForRedraw();
}
}
void TextBox::OnTouchOff() {
auto& drag = InputManager::GetDragHandle();
if (drag == this) drag.Release();
}
void TextBox::OnDragStart() {
// do we need to do anything here?
}
void TextBox::OnDragHold() {
if (InputManager::TouchDragDist().Length() > InputManager::dragThreshold) {
InputManager::GetDragHandle().PassUp();
}
}
void TextBox::OnDragRelease() {
if (InputManager::Released(Keys::Touch)) {
// pop up osk
OSK::New(new InputHandlerBuffered(text, multiLine, [this](auto& str){ this->SetText(str); }))->Open();
}
MarkForRedraw();
}

View File

@ -0,0 +1,44 @@
#pragma once
#include "starlight/_global.h"
#include <string>
#include "starlight/gfx/DrawContextCanvas.h"
#include "starlight/ui/UIElement.h"
namespace starlight {
namespace ui {
class TextBox : public UIElement {
private:
//
public:
std::string text = "";
bool multiLine = false;
std::unique_ptr<gfx::DrawContextCanvas> textView;
TextBox(VRect rect) { this->rect = rect; }
TextBox(Vector2 pos) { this->rect = VRect(pos, Vector2(128, 24)); }
~TextBox() { }
void SetText(const std::string& text);
void PreDraw() override;
void PreDrawOffscreen() override;
void Draw() override;
// events
void OnResize() override;
void OnTouchOn() override;
void OnTouchOff() override;
void OnDragStart() override;
void OnDragRelease() override;
void OnDragHold() override;
};
}
}

View File

@ -2,41 +2,28 @@
roadmap to first release, in no particular order {
- implement app:/ asset loading
finish implementing OSK! {
- make backspace and enter actually do something
- abstract osk input actions into a separate object/class heirarchy
- preview where applicable
fix font glyph padding to eliminate slight "crosstalk" in bordered variants
fix lowercase j running into things
adjust monospace line height (and maybe offset) to closer match the vwf of the same size
add justification to TextConfig as a default
- MAKE IT NOT CRASH ON BEING CLOSED FROM INPUTHANDLER
enable scrolling preview (and scroll to cursor where applicable)
polish!
InputManager::OpenKeyboard
}
textbox widget
- "draw proxy" UIElement (takes a std::function for draw operation)
- textbox widget
add generic backdrop assets (and form)
fix font glyph padding to eliminate slight "crosstalk" in bordered variants
fix lowercase j running into things
adjust monospace line height (and maybe offset) to closer match the vwf of the same size
add license!! (MIT?)
ADD README.MD PLS
} and some lesser priority things {
add language config and atlas support
} then consider these before 1.0 "gold" {
should form priority be a float?
language config and atlas support
maybe implement some way of "knocking out" and replacing metrics during runtime for theme switching
}
form system { framework done apart from some small api changes
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
}
meaningful state change signals current Application to resort and rebuild draw list during next update
}
today's agenda {
...
} then {
@ -53,18 +40,15 @@ unordered_roadmap {
radio box
tabs?
auto-layout/list boxes
text/combo box
combo box
slider
progress bar
}
maybe switch drawoffset system from a stack to a pass-in
moar utility stuff in Vector2 and VRect {
-
}
moar utility stuff in basic types
make textbox scrollable when text is larger than container
tween system
figure out theme layout and fallback system
maybe a few further refinements to bitmap fonts
...
use ctrulib sync features for WorkerThread instead of spinlocks at some point
- http://smealum.github.io/ctrulib/synchronization_8h.html#a9fe83ca3ec3c6ae269203acf367ad5a9
@ -74,28 +58,6 @@ unordered_roadmap {
figure out the whole font y offset deal
}
theme layout {
sdmc:/.starlight/themes/<name>/ {
fonts {
default.12.json/png/border.png
default.16
mono.12/16
}
controls {
button.idle/pressed
...
}
}
}
drawable, drawcontext, gfxmanager (pushContext, popContext) (done mostly)
ThemeRef (done) {
theme-asset-specific reference so themes can be reloaded
-> operator overloaded etc.
}
T H E M E S
configurator for ui elements? maybe crtp after all
noap, macro/include shenanigans
new Button().at(40, 40).within(container).ofSize(64, 32).withText("Popsicles!");
@ -109,4 +71,5 @@ maybe implement this: https://probablydance.com/2013/01/13/a-faster-implementati
// notes {
bitmap font converter - https://github.com/playcanvas/fonts/blob/master/fnt_to_json.py
pretty print - jsonprettyprint.com
}

View File

@ -15,6 +15,7 @@
#include "starlight/ui/ParallaxLayer.h"
#include "starlight/ui/ScrollField.h"
#include "starlight/ui/Button.h"
#include "starlight/ui/TextBox.h"
#include "starlight/ui/Label.h"
#include "starlight/dialog/MessageBox.h"
@ -72,9 +73,12 @@ void Core::Init() {
tlbl->textConfig.borderColor = Color::black;
tlbl->SetText("3DS:~# ");
form->topScreen->Add(tlbl);
auto kb = sl::dialog::OSK::New(new sl::dialog::osk::InputHandlerDirectEdit(&(tlbl->text), true, 7, [tlbl](){tlbl->Refresh();}));
//&(tlbl->text), [tlbl](){tlbl->Refresh();});
kb->Open();
//auto kb = sl::dialog::OSK::New(new sl::dialog::osk::InputHandlerDirectEdit(&(tlbl->text), true, 7, [tlbl](){tlbl->Refresh();}));
//kb->Open();
auto tb = std::make_shared<sl::ui::TextBox>(VRect(0, 64, 320, 24).Expand(-16, 0));
tb->text = "TextBox testing in progress.";
form->touchScreen->Add(tb);
/*label->SetFont("default.16");
btn.SetText("I was pressed!");

View File

@ -0,0 +1,4 @@
{
"assetType" : "ninepatch",
"margin" : [3, 3]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 418 B

Binary file not shown.

View File

@ -25,6 +25,13 @@
"controls" : {
"button" : {
"text" : {
"_inherit" : "/textPresets/normal.12",
"justification" : [0.5, 0.5]
}
},
"textBox" : {
"margin" : [2, 2],
"text" : { "_redir" : "/textPresets/normal.12" }
}
},