partially-implemented OSK! more metrics implementation,

a few constants, Image::blockTouch and modal cover
This commit is contained in:
zetaPRIME 2017-03-05 09:12:17 -05:00
parent 01580c8dda
commit abc3eac3e1
16 changed files with 234 additions and 32 deletions

View File

@ -140,7 +140,7 @@ ThemeInfo::ThemeInfo(const Path& path, const std::string& name) {
basePath = path;
meta = std::make_shared<nlohmann::json>();
metrics = std::make_shared<nlohmann::json>();
if (!basePath.IsDirectory()) return; // don't bother trying to load stuff
//if (!basePath.IsDirectory() && std::string(basePath).find("romfs:") != std::string::npos) return; // don't bother trying to load stuff
{ // using...
std::ifstream load = basePath.Combine("meta.json").OpenI();
if (load.good()) load >> *meta;
@ -163,6 +163,7 @@ void ThemeManager::Init() {
if (!thm.basePath.IsDirectory()) thm = ThemeInfo("default"); // fall back on default if not found
// ...and if "default" doesn't exist, fall back on a standard location in romfs:
if (!thm.basePath.IsDirectory()) thm = ThemeInfo(Path("romfs:/.fallback_theme", "FALLBACK"));
if (!thm.basePath.IsDirectory()) thm = ThemeInfo(Path("romfs:/", "FALLBACK")); // fall back on root of romfs for testbed I guess
themeData.push_back(thm);
while (!(*thm.meta)["fallback"].is_null()) { // follow fallback chain
@ -319,6 +320,13 @@ T ThemeManager::GetMetric(const std::string& path, const T& defaultValue) {
}//*/
}
template <typename T>
T ThemeManager::GetMetric(const std::string& path) {
json& j = GetMetric(path);
if (j.is_null()) return T();
return j;
}
TextConfig::TextConfig(const std::string& fontName, Color text, Color border) {
font = ThemeManager::GetFont(fontName);
textColor = text; borderColor = border;
@ -343,8 +351,13 @@ namespace starlight { // todo: expose these in the header
}
}
template Vector2 ThemeManager::GetMetric(const std::string&, const Vector2&);
template VRect ThemeManager::GetMetric(const std::string&, const VRect&);
template Color ThemeManager::GetMetric(const std::string&, const Color&);
// explicit type conversions for metrics
#define typeconv(t) \
template t ThemeManager::GetMetric(const std::string&, const t &); \
template t ThemeManager::GetMetric(const std::string&);
template starlight::TextConfig ThemeManager::GetMetric(const std::string&, const TextConfig&);
typeconv(Vector2);
typeconv(VRect);
typeconv(Color);
typeconv(TextConfig);

View File

@ -66,6 +66,7 @@ namespace starlight {
static inline std::string GetThemeName() { return themeData.front().name; }
static nlohmann::json& GetMetric(const std::string& path);
template <typename T> static T GetMetric(const std::string& path, const T& defaultValue);
template <typename T> static T GetMetric(const std::string& path);
};
}

View File

@ -58,3 +58,6 @@ VRect VRect::RightEdge(float width) const { return VRect(pos.x + size.x - widt
const VRect VRect::invalid = VRect(Vector2::invalid, Vector2::invalid);
const VRect VRect::zero = VRect(); // should initialize to 0,0,0,0
const VRect VRect::touchScreen = VRect(0, 0, 320, 240);
const VRect VRect::topScreen = VRect(0, 0, 400, 240);

View File

@ -58,5 +58,8 @@ namespace starlight {
static const VRect invalid;
static const VRect zero;
static const VRect touchScreen;
static const VRect topScreen;
};
}

View File

@ -1,5 +1,6 @@
#include "MessageBox.h"
#include "starlight/ThemeManager.h"
#include "starlight/InputManager.h"
#include "starlight/ui/Image.h"
@ -22,7 +23,11 @@ MessageBox::MessageBox(Mode m, const std::string& msg, std::function<void(int)>
priority = 10;
eOnSelect = onSelect;
VRect boxArea = VRect(160, 120, 0, 0).Expand(Vector2(240, 160)*.5);
VRect boxArea = VRect(160, 120, 0, 0).Expand(ThemeManager::GetMetric<Vector2>("/dialogs/messageBox/size")*.5);
auto cover = std::make_shared<Image>(touchScreen->rect.Expand(4), "decorations/dialog.modal-cover");
cover->blockTouch = true;
touchScreen->Add(cover);
auto bg = std::make_shared<Image>(boxArea, "decorations/panel.bg");
touchScreen->Add(bg);
@ -30,7 +35,7 @@ MessageBox::MessageBox(Mode m, const std::string& msg, std::function<void(int)>
touchScreen->Add(scroll);
auto label = std::make_shared<Label>(VRect(0, 0, scroll->rect.size.x, 0));
label->autoSizeV = true;
label->SetFont("default.16");
label->SetPreset("normal.16");
label->SetText(msg);
scroll->Add(label);

View File

@ -0,0 +1,116 @@
#include "OSK.h"
#include "starlight/ThemeManager.h"
#include "starlight/InputManager.h"
#include "starlight/ui/Image.h"
#include "starlight/ui/Button.h"
#include "starlight/ui/Label.h"
#include "starlight/ui/ScrollField.h"
#include "starlight/ConfigManager.h"
using std::string;
using starlight::InputManager;
using starlight::ui::Image;
using starlight::ui::Button;
using starlight::ui::Label;
using starlight::ui::ScrollField;
using starlight::ui::Form;
using starlight::dialog::OSK;
OSK::OSK(std::string* textptr, std::function<void()> onModify) : Form(true) {
priority = 1000; // probably don't want all that much displaying above the keyboard
eOnModify = onModify;
pText = textptr;
auto cover = std::make_shared<Image>(touchScreen->rect.Expand(4), "decorations/dialog.modal-cover");
cover->blockTouch = true;
touchScreen->Add(cover);
// wip
setContainer = std::make_shared<ui::UIContainer>(VRect::touchScreen);
touchScreen->Add(setContainer);
auto actSym = [this](Button& key){
this->OnSymKey(key.label);
};
Vector2 bs(24, 32);
Vector2 bpen;
Vector2 bpstart(160-bs.x*(12.5/2), 68);
int line = -1;
float linestart [] = {0, .5, .75, 1.25, 2.75-1};
string chr = "\n1234567890-=\nqwertyuiop[]\nasdfghjkl;\'\nzxcvbnm,./\n` \\";
string Chr = "\n!@#$%^&*()_+\nQWERTYUIOP{}\nASDFGHJKL:\"\nZXCVBNM<>?\n~ |";
for (unsigned int ic = 0; ic < chr.length(); ic++) {
char& c = chr[ic];
char& C = Chr[ic];
if (c == '\n') {
line++;
bpen = bpstart + Vector2(linestart[line] * bs.x, bs.y * line);
} else {
// lower
auto key = std::make_shared<Button>(VRect(bpen, bs));
if (c == ' ') key->rect.size.x *= 6;
key->SetText(string(1, c));
key->eOnTap = actSym;
setContainer->Add(key);
// upper
key = std::make_shared<Button>(VRect(bpen + Vector2(0, 1000), bs));
if (C == ' ') key->rect.size.x *= 6;
key->SetText(string(1, C));
key->eOnTap = actSym;
setContainer->Add(key);
// and after
bpen.x += key->rect.size.x;
}
}
// backspace
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("< <");
touchScreen->Add(key);
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");
touchScreen->Add(key);
}
void OSK::Update(bool focused) {
if (focused) {
if (InputManager::Pressed(Keys::B)) Close();
float& s = setContainer->scrollOffset.y;
float ts = 0;
if (InputManager::Held(Keys::L) || InputManager::Held(Keys::R)) {
ts = 1000;
}
if (s != ts) {
s = ts;
setContainer->MarkForRedraw();
}
}
}
void OSK::OnSymKey(const string& chr) {
pText->append(chr);
//pText->append("sackboy ");
//auto& tx = *pText;
//ConfigManager::Get("user").Json()["log"].push_back(*pText);
//tx.assign("shickaxe");
if (eOnModify) eOnModify();
}

View File

@ -0,0 +1,28 @@
#pragma once
#include "starlight/_global.h"
#include <string>
#include <functional>
#include "starlight/ui/Form.h"
namespace starlight {
namespace dialog {
class OSK : public ui::Form, public ui::FormCreator<OSK> {
private:
std::shared_ptr<ui::UIContainer> setContainer;
public:
std::string* pText = nullptr;
std::function<void()> eOnModify;
OSK(std::string* textptr, std::function<void()> onModify = {});
~OSK() override { };
void Update(bool focused) override;
void OnSymKey(const std::string& chr);
};
}
}

View File

@ -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(0.5f, 0.5f));
tc.Print(rect, label, Vector2::half);
}
void Button::OnTouchOn() {

View File

@ -19,6 +19,7 @@ namespace starlight {
public:
gfx::ThemeRef<gfx::Drawable> image;
Color tint = Color::white;
bool blockTouch = false;
Image(VRect rect, const std::string& imgPath);
Image(Vector2 pos, const std::string& imgPath);
@ -27,6 +28,8 @@ namespace starlight {
void SetImage(const std::string& imgPath, bool resize = true);
void Draw() override;
bool InterceptsTouch(Vector2 where) override { return blockTouch; }
};
}
}

View File

@ -8,12 +8,12 @@ using starlight::ui::Label;
Label::Label(VRect rect) {
this->rect = rect;
font = ThemeManager::GetFont("default.12");
textConfig = ThemeManager::GetMetric<TextConfig>("/textPresets/normal.12", TextConfig());
}
void Label::AutoSize() {
if (autoSizeV) {
float h = font->Measure(text, 1, rect.size.x).y;
float h = textConfig.font->Measure(text, 1, rect.size.x).y;
Resize(rect.size.x, h);
}
@ -28,10 +28,17 @@ void Label::SetText(const std::string& text) {
}
void Label::SetFont(const std::string& fontName) {
font = ThemeManager::GetFont(fontName);
textConfig.font = ThemeManager::GetFont(fontName);
AutoSize();
}
void Label::SetPreset(const std::string& name) {
textConfig = ThemeManager::GetMetric<TextConfig>("/textPresets/" + name, textConfig);
AutoSize();
}
void Label::Refresh() { AutoSize(); }
void Label::PreDrawOffscreen() {
buffer.reset(); // I guess?
}
@ -41,7 +48,7 @@ void Label::PreDraw() {
buffer = std::make_unique<gfx::DrawContextCanvas>(rect.size + Vector2(0, 8));
buffer->Clear();
GFXManager::PushContext(buffer.get());
font->Print(buffer->rect, text, 1, color, justification, borderColor);
textConfig.Print(buffer->rect, text, justification);
GFXManager::PopContext();
}
}
@ -51,7 +58,6 @@ void Label::Draw() {
if (buffer) {
buffer->Draw(VRect(rect.pos, buffer->rect.size));
} else {
font->Print(rect, text, 1, color, justification, borderColor);
textConfig.Print(rect, text, justification);
}
}

View File

@ -19,13 +19,10 @@ namespace starlight {
public:
std::string text = "";
gfx::ThemeRef<gfx::Font> font;
TextConfig textConfig;
std::unique_ptr<gfx::DrawContextCanvas> buffer;
Color color = Color::white;
Color borderColor = Color::transparent;
bool autoSizeV = false;
Vector2 justification = Vector2::half;
@ -34,6 +31,9 @@ namespace starlight {
void SetText(const std::string& text);
void SetFont(const std::string& fontName);
void SetPreset(const std::string& name);
void Refresh();
void PreDrawOffscreen() override;
void PreDraw() override;

View File

@ -2,13 +2,18 @@
roadmap to first release, in no particular order {
add touch interceptor (and possibly dimming "shroud") to modal box
make more stuff use theme metrics (particularly default text configs) {
label defaults
make more stuff use theme metrics {
dialog layouts(...?)
}
finish implementing OSK! {
make backspace and enter actually do something
abstract osk input actions into a separate object/class heirarchy
polish!
InputManager::OpenKeyboard
}
implement OSK!
add license!! (MIT?)
ADD README.MD PLS
} and some lesser priority things {
add language config and atlas support
maybe implement some way of "knocking out" and replacing metrics during runtime for theme switching
@ -28,7 +33,7 @@ form system { framework done apart from some small api changes
today's agenda {
FSHelper, recursive directory assertion etc.
...
} then {
change Label to move the rect instead of resizing to accomodate drops (add an offset thing to Font)
kill scroll velocity when hitting the edge (or rapid decel)

View File

@ -18,6 +18,7 @@
#include "starlight/ui/Label.h"
#include "starlight/dialog/MessageBox.h"
#include "starlight/dialog/OSK.h"
using starlight::Vector2;
using starlight::VRect;
@ -49,20 +50,32 @@ void Core::Init() {
auto button = std::make_shared<sl::ui::Button>(VRect(64,80,128,32));
button->SetText("I'm a button.");
button->eOnTap = [label](auto& btn){
button->eOnTap = [](auto& btn){
auto form = std::make_shared<sl::ui::Form>(true);
auto label = std::make_shared<sl::ui::Label>(VRect(0,0,320,0));
label->autoSizeV = true;
label->SetText("This is a form, coming in and nuking the non-form UI elements. Whoops.");
form->touchScreen->Add(label);
auto xbtn = std::make_shared<sl::ui::Button>(VRect(0,0,32,32));
xbtn->SetText(" ");
auto xbtn = std::make_shared<sl::ui::Button>(VRect(4,24,32,32));
//xbtn->SetText(" ");
xbtn->eOnTap = [](auto& btn){
Application::Quit();
};
form->touchScreen->Add(xbtn);
form->Open();
auto msg = sl::dialog::MessageBox::New(sl::dialog::MessageBox::OkCancel, "This is a modal dialog!\n\n\n\nScrolly\n\n\n\nscrolly\n\n\n\nscrolly\n\n\n\nscrolly\n\n\n\nscroll!");
msg->Open();
//auto msg = sl::dialog::MessageBox::New(sl::dialog::MessageBox::OkCancel, "This is a modal dialog!\n\n\n\nScrolly\n\n\n\nscrolly\n\n\n\nscrolly\n\n\n\nscrolly\n\n\n\nscroll!");
//msg->Open();
auto tlbl = std::make_shared<sl::ui::Label>(VRect(2, 2, 396, 0));
tlbl->autoSizeV = true;
tlbl->SetPreset("normal.16");
tlbl->justification = Vector2::zero;
tlbl->textConfig.borderColor = Color::black;
tlbl->SetText("3DS:~# ");
form->topScreen->Add(tlbl);
auto kb = sl::dialog::OSK::New(&(tlbl->text), [tlbl](){tlbl->Refresh();});
kb->Open();
label->SetFont("default.16");
/*label->SetFont("default.16");
btn.SetText("I was pressed!");
btn.eOnTap = [label](auto& btn){
label->borderColor = Color::black;
@ -89,7 +102,7 @@ void Core::Init() {
msg->Open();
};
};
};
};*/
};
container->Add(button);
@ -100,7 +113,7 @@ void Core::Init() {
topScreen->Add(parallax);
auto pipf = std::make_shared<sl::ui::Label>(VRect(0,0,400,240));
pipf->SetFont("default.16"); pipf->borderColor = Color::black;
pipf->SetPreset("normal.16"); pipf->textConfig.borderColor = Color::black;
//pipf->SetText("I am the very model of something on the top screen. :D\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.");
std::stringstream st;
//st << "dir: " << Path("sdmc:/.starlight").IsDirectory() << "\nfile: " << Path("sdmc:/arm9loaderhax.bin").IsFile();

Binary file not shown.

After

Width:  |  Height:  |  Size: 794 B

Binary file not shown.

View File

@ -29,5 +29,11 @@
}
},
"dialogs" : {
"messageBox" : {
"size" : [240, 160]
}
},
"":""
}