mirror of
https://github.com/zetaPRIME/libstarlight.git
synced 2025-06-26 13:42:46 +00:00
add OSK preview scrolling, background, fix DrawLayerProxy,
make TextConfig.Print string ref const, make form priority float, ScrollField::ScrollIntoView, minor BitmapFont fix
This commit is contained in:
parent
5d7fd4d802
commit
5954dc5768
@ -347,11 +347,11 @@ TextConfig::TextConfig(const std::string& fontName, Color text, Color border) {
|
||||
textColor = text; borderColor = border;
|
||||
}
|
||||
|
||||
void TextConfig::Print(Vector2 position, std::string& text, Vector2 justification) {
|
||||
void TextConfig::Print(Vector2 position, const 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) {
|
||||
void TextConfig::Print(VRect rect, const std::string& text, Vector2 justification) {
|
||||
if (!justification) justification = this->justification;
|
||||
font->Print(rect, text, 1, textColor, justification, borderColor);
|
||||
}
|
||||
|
@ -85,8 +85,8 @@ namespace starlight {
|
||||
TextConfig(const std::string& fontName, Color text, Color border = Color::transparent);
|
||||
~TextConfig() = default;
|
||||
|
||||
void Print(Vector2 position, std::string& text, Vector2 justification = Vector2::invalid);
|
||||
void Print(VRect rect, std::string& text, Vector2 justification = Vector2::invalid);
|
||||
void Print(Vector2 position, const std::string& text, Vector2 justification = Vector2::invalid);
|
||||
void Print(VRect rect, const std::string& text, Vector2 justification = Vector2::invalid);
|
||||
|
||||
Vector2 Measure(const std::string& text, float maxWidth = 65536*64);
|
||||
|
||||
|
@ -36,13 +36,15 @@ namespace {
|
||||
static auto tc = ThemeManager::GetMetric<starlight::TextConfig>("/dialogs/OSK/preview");
|
||||
return tc;
|
||||
}
|
||||
|
||||
const constexpr float textHang = 4;
|
||||
}
|
||||
|
||||
OSK::OSK(osk::InputHandler* handler) : Form(true), handler(handler) {
|
||||
priority = 1000; // probably don't want all that much displaying above the keyboard
|
||||
handler->parent = this;
|
||||
|
||||
auto cover = std::make_shared<Image>(touchScreen->rect.Expand(4), "decorations/dialog.modal-cover");
|
||||
auto cover = std::make_shared<Image>(touchScreen->rect, "decorations/osk.background");
|
||||
cover->blockTouch = true;
|
||||
touchScreen->Add(cover);
|
||||
|
||||
@ -58,7 +60,7 @@ OSK::OSK(osk::InputHandler* handler) : Form(true), handler(handler) {
|
||||
|
||||
Vector2 bs(24, 32);
|
||||
Vector2 bpen;
|
||||
Vector2 bpstart(160-bs.x*(12.5/2), 68);
|
||||
Vector2 bpstart(160-bs.x*(12.5/2), 68+5);
|
||||
int line = -1;
|
||||
float linestart [] = {0, .5, .75, 1.25, 2.75-1};
|
||||
string chr = "\n1234567890-=\nqwertyuiop[]\nasdfghjkl;\'\nzxcvbnm,./\n` \\";
|
||||
@ -106,9 +108,14 @@ OSK::OSK(osk::InputHandler* handler) : Form(true), handler(handler) {
|
||||
key->eOnTap = [this](auto& btn){ this->handler->Enter(); this->OnKey(); };
|
||||
touchScreen->Add(key);
|
||||
|
||||
preview = std::make_shared<DrawLayerProxy>(VRect::touchScreen.TopEdge(68).Expand(-2), [this](auto& layer){ this->DrawPreview(layer); }, true);
|
||||
previewSc = std::make_shared<ScrollField>(VRect(VRect::touchScreen.TopEdge(66)));
|
||||
touchScreen->Add(previewSc);
|
||||
|
||||
preview = std::make_shared<DrawLayerProxy>(VRect::touchScreen.TopEdge(66).Expand(-2, 0), [this](auto& layer){ this->DrawPreview(layer); }, true);
|
||||
preview->eOnTap = [this](auto& layer){ this->OnPreviewTap(layer); };
|
||||
touchScreen->Add(preview);
|
||||
previewSc->Add(preview);
|
||||
|
||||
RefreshPreview();
|
||||
}
|
||||
|
||||
void OSK::Update(bool focused) {
|
||||
@ -117,30 +124,29 @@ void OSK::Update(bool focused) {
|
||||
}
|
||||
if (focused) {
|
||||
if (InputManager::Pressed(Keys::B)) handler->Done();
|
||||
if (true || handler->showPreview) {
|
||||
if (handler->showPreview) {
|
||||
if (InputManager::Pressed(Keys::DPadLeft)) {
|
||||
handler->SetCursor(handler->GetCursor() - 1);
|
||||
preview->Refresh();
|
||||
auto c = handler->GetCursor();
|
||||
if (c > 0) handler->SetCursor(c - 1);
|
||||
RefreshPreview();
|
||||
}
|
||||
if (InputManager::Pressed(Keys::DPadRight)) {
|
||||
handler->SetCursor(handler->GetCursor() + 1);
|
||||
preview->Refresh();
|
||||
RefreshPreview();
|
||||
}
|
||||
|
||||
auto& tc = PreviewTC();
|
||||
if (InputManager::Pressed(Keys::DPadUp)) {
|
||||
Vector2 pt = tc.GetCursorPosition(preview->rect, handler->GetPreviewText(), handler->GetCursor());
|
||||
string msr = "|";
|
||||
pt.y -= tc.Measure(msr).y * 0.5f;
|
||||
pt.y -= tc.Measure("|").y * 0.5f;
|
||||
handler->SetCursor(tc.GetCursorFromPoint(preview->rect, handler->GetPreviewText(), pt));
|
||||
preview->Refresh();
|
||||
RefreshPreview();
|
||||
}
|
||||
if (InputManager::Pressed(Keys::DPadDown)) {
|
||||
Vector2 pt = tc.GetCursorPosition(preview->rect, handler->GetPreviewText(), handler->GetCursor());
|
||||
string msr = "|";
|
||||
pt.y += tc.Measure(msr).y * 1.5f;
|
||||
pt.y += tc.Measure("|").y * 1.5f;
|
||||
handler->SetCursor(tc.GetCursorFromPoint(preview->rect, handler->GetPreviewText(), pt));
|
||||
preview->Refresh();
|
||||
RefreshPreview();
|
||||
}
|
||||
}
|
||||
|
||||
@ -157,23 +163,47 @@ void OSK::Update(bool focused) {
|
||||
}
|
||||
|
||||
void OSK::OnKey() {
|
||||
RefreshPreview();
|
||||
}
|
||||
|
||||
void OSK::RefreshPreview() {
|
||||
auto& tc = PreviewTC();
|
||||
if (handler->showPreview) {
|
||||
Vector2 sz = tc.Measure(handler->GetPreviewText(), preview->rect.size.x);
|
||||
preview->Resize(Vector2(preview->rect.size.x, std::max(sz.y + textHang, previewSc->rect.size.y))); // I guess a magic four will do
|
||||
|
||||
Vector2 cp = tc.GetCursorPosition(preview->rect, handler->GetPreviewText(), handler->GetCursor());
|
||||
Vector2 cs = tc.Measure("|") + Vector2(0, textHang);
|
||||
previewSc->ScrollIntoView(VRect(cp, cs));//*/
|
||||
|
||||
} else {
|
||||
preview->Resize(Vector2(preview->rect.size.x, 66));
|
||||
}
|
||||
preview->Refresh();
|
||||
}
|
||||
|
||||
void OSK::DrawPreview(DrawLayerProxy& layer) {
|
||||
if (true || handler->showPreview) {
|
||||
if (handler->showPreview) {
|
||||
auto& tc = PreviewTC();
|
||||
tc.Print(layer.rect, handler->GetPreviewText(), Vector2::zero);
|
||||
|
||||
Vector2 cp = tc.GetCursorPosition(layer.rect, handler->GetPreviewText(), handler->GetCursor());
|
||||
string cc = "|";
|
||||
tc.Print(cp, cc, Vector2::zero);
|
||||
tc.Print(cp, cc);
|
||||
|
||||
//Vector2 cs = tc.Measure("|") + Vector2(0, textHang);
|
||||
//previewSc->ScrollIntoView(VRect(cp, cs));
|
||||
} else {
|
||||
static auto tc = ThemeManager::GetMetric<starlight::TextConfig>("/dialogs/OSK/noPreview");
|
||||
tc.Print(layer.rect, "(no preview available)");
|
||||
}
|
||||
}
|
||||
|
||||
void OSK::OnPreviewTap(DrawLayerProxy& layer) {
|
||||
if (handler->showPreview) {
|
||||
Vector2 tpos = InputManager::TouchPos() - layer.ScreenRect().pos;
|
||||
auto& tc = PreviewTC();
|
||||
handler->SetCursor(tc.GetCursorFromPoint(layer.rect, handler->GetPreviewText(), tpos));
|
||||
preview->Refresh();
|
||||
RefreshPreview();
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <memory>
|
||||
|
||||
#include "starlight/ui/Form.h"
|
||||
#include "starlight/ui/ScrollField.h"
|
||||
#include "starlight/ui/DrawLayerProxy.h"
|
||||
|
||||
#include "starlight/dialog/osk/InputHandler.h"
|
||||
@ -15,8 +16,11 @@ namespace starlight {
|
||||
class OSK : public ui::Form, public ui::FormCreator<OSK> {
|
||||
private:
|
||||
std::shared_ptr<ui::UIContainer> setContainer;
|
||||
std::shared_ptr<ui::ScrollField> previewSc;
|
||||
std::shared_ptr<ui::DrawLayerProxy> preview;
|
||||
|
||||
//Vector2 cursorPos;
|
||||
|
||||
public:
|
||||
std::unique_ptr<osk::InputHandler> handler;
|
||||
|
||||
@ -27,6 +31,7 @@ namespace starlight {
|
||||
|
||||
void OnKey();
|
||||
|
||||
void RefreshPreview();
|
||||
void DrawPreview(ui::DrawLayerProxy& layer);
|
||||
void OnPreviewTap(ui::DrawLayerProxy& layer);
|
||||
};
|
||||
|
@ -64,7 +64,9 @@ BitmapFont::CharInfo& BitmapFont::Char(char c) {
|
||||
}
|
||||
|
||||
Vector2 BitmapFont::MeasureTo(const std::string& msg, bool total, unsigned int end, float maxWidth) {
|
||||
if (msg == "") return Vector2::zero;
|
||||
if (total) {
|
||||
if (end == 0) return Vector2(0, lineHeight);
|
||||
Vector2 measure = Vector2::zero;
|
||||
|
||||
ForChar(msg, [&, this](auto& s){
|
||||
@ -81,11 +83,14 @@ Vector2 BitmapFont::MeasureTo(const std::string& msg, bool total, unsigned int e
|
||||
Vector2 measure;
|
||||
bool found = false;
|
||||
|
||||
ForChar(msg, [&, this, total, end](auto& s){
|
||||
unsigned int et = end - 1;
|
||||
if (end == 0) et = 0;
|
||||
ForChar(msg, [&, this, total, end, et](auto& s){
|
||||
measure = Vector2(s.lineAcc + s.cc->advX, lineHeight * s.lineNum);
|
||||
if (s.i == end-1) {
|
||||
if (s.i >= et) {
|
||||
found = true;
|
||||
if (s.i == s.lineEnd) measure = Vector2(0, lineHeight * (s.lineNum + 1)); // linebreak == next line
|
||||
if (end == 0) measure = Vector2(0, lineHeight * s.lineNum);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,7 @@ void DrawLayerProxy::PreDraw() {
|
||||
|
||||
void DrawLayerProxy::Draw() {
|
||||
if (canvas) {
|
||||
auto rect = (this->rect + GFXManager::GetOffset()).IntSnap();
|
||||
canvas->Draw(VRect(rect.pos, canvas->rect.size));
|
||||
} else {
|
||||
if (eDraw) eDraw(*this);
|
||||
|
@ -58,7 +58,7 @@ namespace starlight {
|
||||
//
|
||||
|
||||
public:
|
||||
int priority = 0;
|
||||
float priority = 0;
|
||||
unsigned int flags = 0;
|
||||
|
||||
std::shared_ptr<UIContainer> touchScreen = nullptr;
|
||||
|
@ -38,6 +38,18 @@ void ScrollField::Update() {
|
||||
scrollOffset.y = std::max(0.0f, std::min(scrollOffset.y, scrollMax.y));
|
||||
}
|
||||
|
||||
void ScrollField::ScrollIntoView(Vector2 pt) {
|
||||
Vector2 sm = pt - rect.size;
|
||||
|
||||
scrollOffset.x = std::max(sm.x, std::min(scrollOffset.x, pt.x));
|
||||
scrollOffset.y = std::max(sm.y, std::min(scrollOffset.y, pt.y));
|
||||
|
||||
// hmm. doesn't play well with pending resizes
|
||||
//scrollOffset.x = std::max(0.0f, std::min(scrollOffset.x, scrollMax.x));
|
||||
//scrollOffset.y = std::max(0.0f, std::min(scrollOffset.y, scrollMax.y));
|
||||
}
|
||||
void ScrollField::ScrollIntoView(VRect box) { ScrollIntoView(box.BottomRight()); ScrollIntoView(box.pos); }
|
||||
|
||||
void ScrollField::OnProcessTouchEvent() { // stop when child element touched
|
||||
if (InputManager::Pressed(Keys::Touch)) scrollVel = Vector2::zero;
|
||||
}
|
||||
|
@ -16,6 +16,9 @@ namespace starlight {
|
||||
|
||||
void Update() override;
|
||||
|
||||
void ScrollIntoView(Vector2 pt);
|
||||
void ScrollIntoView(VRect box);
|
||||
|
||||
// events
|
||||
void OnTouchOn() override;
|
||||
void OnTouchOff() override { }
|
||||
@ -33,4 +36,3 @@ namespace starlight {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,20 +3,21 @@
|
||||
|
||||
roadmap to first release, in no particular order {
|
||||
finish implementing OSK! {
|
||||
enable scrolling preview (and scroll to cursor where applicable)
|
||||
polish!
|
||||
- fix cursor-down
|
||||
polish! {
|
||||
- background
|
||||
actual cursor image?
|
||||
}
|
||||
InputManager::OpenKeyboard
|
||||
}
|
||||
fix [ offset (-1 it)
|
||||
|
||||
add generic backdrop assets (and form)
|
||||
|
||||
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
|
||||
} then consider these before 1.0 "gold" {
|
||||
should form priority be a float?
|
||||
- should form priority be a float?
|
||||
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
|
||||
|
@ -78,6 +78,7 @@ void Core::Init() {
|
||||
|
||||
auto tb = std::make_shared<sl::ui::TextBox>(VRect(0, 64, 320, 24).Expand(-16, 0));
|
||||
tb->text = "TextBox testing in progress. ij ji lj jl";
|
||||
tb->multiLine = true;
|
||||
form->touchScreen->Add(tb);
|
||||
|
||||
/*label->SetFont("default.16");
|
||||
|
BIN
themes/default/decorations/osk.background.png
Normal file
BIN
themes/default/decorations/osk.background.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.8 KiB |
BIN
themes/default/decorations/osk.background.xcf
Normal file
BIN
themes/default/decorations/osk.background.xcf
Normal file
Binary file not shown.
@ -45,6 +45,12 @@
|
||||
"font" : "default.16",
|
||||
"textColor" : "white",
|
||||
"borderColor" : "black"
|
||||
},
|
||||
"noPreview" : {
|
||||
"font" : "default.16",
|
||||
"textColor" : "midGray",
|
||||
"borderColor" : "darkGray",
|
||||
"justification" : [0.5, 0.5]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
Loading…
x
Reference in New Issue
Block a user