forked from Mirror/libstarlight
tap action for drawlayerproxy, text cursor for osk!
This commit is contained in:
parent
92467e21c6
commit
36960effa4
@ -100,12 +100,39 @@ OSK::OSK(osk::InputHandler* handler) : Form(true), handler(handler) {
|
||||
touchScreen->Add(key);
|
||||
|
||||
preview = std::make_shared<DrawLayerProxy>(VRect::touchScreen.TopEdge(68).Expand(-2), [this](auto& layer){ this->DrawPreview(layer); }, true);
|
||||
preview->eOnTap = [this](auto& layer){ this->OnPreviewTap(layer); };
|
||||
touchScreen->Add(preview);
|
||||
}
|
||||
|
||||
void OSK::Update(bool focused) {
|
||||
if (focused) {
|
||||
if (InputManager::Pressed(Keys::B)) handler->Done();
|
||||
if (true || handler->showPreview) {
|
||||
if (InputManager::Pressed(Keys::DPadLeft)) {
|
||||
handler->SetCursor(handler->GetCursor() - 1);
|
||||
preview->Refresh();
|
||||
}
|
||||
if (InputManager::Pressed(Keys::DPadRight)) {
|
||||
handler->SetCursor(handler->GetCursor() + 1);
|
||||
preview->Refresh();
|
||||
}
|
||||
|
||||
static auto tc = ThemeManager::GetMetric<TextConfig>("/dialogs/OSK/preview");
|
||||
if (InputManager::Pressed(Keys::DPadUp)) {
|
||||
Vector2 pt = tc.font->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));
|
||||
preview->Refresh();
|
||||
}
|
||||
if (InputManager::Pressed(Keys::DPadDown)) {
|
||||
Vector2 pt = tc.font->GetCursorPosition(preview->rect, handler->GetPreviewText(), handler->GetCursor());
|
||||
string msr = "|";
|
||||
pt.y += tc.font->Measure(msr).y;
|
||||
handler->SetCursor(tc.font->GetCursorFromPoint(preview->rect, handler->GetPreviewText(), pt));
|
||||
preview->Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
float& s = setContainer->scrollOffset.y;
|
||||
float ts = 0;
|
||||
@ -127,5 +154,16 @@ void OSK::DrawPreview(DrawLayerProxy& layer) {
|
||||
if (true || handler->showPreview) {
|
||||
static auto tc = ThemeManager::GetMetric<TextConfig>("/dialogs/OSK/preview");
|
||||
tc.Print(layer.rect, handler->GetPreviewText(), Vector2::zero);
|
||||
|
||||
Vector2 cp = tc.font->GetCursorPosition(layer.rect, handler->GetPreviewText(), handler->GetCursor());
|
||||
string cc = "|";
|
||||
tc.Print(cp, cc, Vector2::zero);
|
||||
}
|
||||
}
|
||||
|
||||
void OSK::OnPreviewTap(DrawLayerProxy& layer) {
|
||||
Vector2 tpos = InputManager::TouchPos() - layer.ScreenRect().pos;
|
||||
static auto tc = ThemeManager::GetMetric<TextConfig>("/dialogs/OSK/preview");
|
||||
handler->SetCursor(tc.font->GetCursorFromPoint(layer.rect, handler->GetPreviewText(), tpos + layer.rect.pos));
|
||||
preview->Refresh();
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ namespace starlight {
|
||||
void OnKey();
|
||||
|
||||
void DrawPreview(ui::DrawLayerProxy& layer);
|
||||
void OnPreviewTap(ui::DrawLayerProxy& layer);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -12,17 +12,21 @@ using starlight::dialog::osk::InputHandlerBuffered;
|
||||
|
||||
std::string& InputHandlerDirectEdit::GetPreviewText() { return *pText; }
|
||||
|
||||
unsigned int InputHandlerDirectEdit::GetCursor() { return pText->length(); }
|
||||
void InputHandlerDirectEdit::SetCursor(unsigned int index) { }
|
||||
unsigned int InputHandlerDirectEdit::GetCursor() { return cursor; }
|
||||
void InputHandlerDirectEdit::SetCursor(unsigned int index) { cursor = index; if (cursor < minIndex) cursor = minIndex; auto len = pText->length(); if (cursor > len) cursor = len; }
|
||||
|
||||
void InputHandlerDirectEdit::InputSymbol(const string& sym) {
|
||||
pText->append(sym);
|
||||
//pText->append(sym);
|
||||
pText->insert(cursor, sym);
|
||||
cursor += sym.length();
|
||||
if (eOnModify) eOnModify();
|
||||
}
|
||||
|
||||
void InputHandlerDirectEdit::Backspace() {
|
||||
if (pText->length() > minIndex) {
|
||||
pText->pop_back();
|
||||
if (cursor > minIndex) {
|
||||
//pText->pop_back();
|
||||
pText->erase(cursor-1, 1);
|
||||
cursor -= 1;
|
||||
if (eOnModify) eOnModify();
|
||||
}
|
||||
}
|
||||
|
@ -39,12 +39,13 @@ namespace starlight {
|
||||
|
||||
std::string* pText;
|
||||
unsigned int minIndex = 0;
|
||||
unsigned int cursor = 0;
|
||||
|
||||
std::function<void()> eOnModify = {};
|
||||
std::function<void()> eOnFinalize = {};
|
||||
|
||||
InputHandlerDirectEdit(std::string* textptr, bool multiLine = false, unsigned int minIndex = 0, std::function<void()> onModify = {}, std::function<void()> onFinalize = {})
|
||||
: multiLine(multiLine), pText(textptr), minIndex(minIndex), eOnModify(onModify), eOnFinalize(onFinalize) { }
|
||||
: multiLine(multiLine), pText(textptr), minIndex(minIndex), cursor(textptr->length()), eOnModify(onModify), eOnFinalize(onFinalize) { }
|
||||
~InputHandlerDirectEdit() override { }
|
||||
|
||||
std::string& GetPreviewText() override;
|
||||
|
@ -86,6 +86,118 @@ float BitmapFont::DrawText(const Vector2& penStart, std::string& msg, float scal
|
||||
return pen.x - penStart.x;
|
||||
}
|
||||
|
||||
Vector2 BitmapFont::MeasureTo(std::string& msg, bool total, unsigned int end, float maxWidth) {
|
||||
auto len = msg.length();
|
||||
if (end > len) end = len;
|
||||
|
||||
Vector2 pen = Vector2::zero;
|
||||
Vector2 oPen = pen;
|
||||
float longest = 0;
|
||||
float wordlen = 0;
|
||||
float plen = 0;
|
||||
|
||||
float space = Char(' ').advX;
|
||||
|
||||
for (unsigned int i = 0; i < len; i++) {
|
||||
char& c = msg[i];
|
||||
if (c == ' ' || c == '\n') {
|
||||
bool alb = false; // already linebreak
|
||||
oPen = pen;
|
||||
if (pen.x > longest) longest = pen.x;
|
||||
if (pen.x + wordlen > maxWidth) {
|
||||
pen.x = 0; pen.y += lineHeight;
|
||||
alb = true;
|
||||
}
|
||||
pen.x += wordlen;
|
||||
pen.x += space;
|
||||
|
||||
if (c == '\n' && !alb) {
|
||||
if (pen.x > longest) longest = pen.x;
|
||||
pen.x = 0; pen.y += lineHeight;
|
||||
}
|
||||
|
||||
if (!total && i >= end) {
|
||||
//if (c == ' ') pen.x -= space; // I think this needs to be undone too?
|
||||
return Vector2(oPen.x + plen, oPen.y); // return cursor position
|
||||
}
|
||||
wordlen = plen = 0;
|
||||
} else {
|
||||
float adv = Char(c).advX;
|
||||
wordlen += adv;
|
||||
if (i < end) plen += adv;
|
||||
}
|
||||
}
|
||||
|
||||
{ // oh right, this check kind of needs to happen at the end too
|
||||
if (pen.x > longest) longest = pen.x;
|
||||
if (pen.x + wordlen > maxWidth) {
|
||||
pen.x = 0; pen.y += lineHeight;
|
||||
}
|
||||
pen.x += wordlen;
|
||||
|
||||
if (!total) {
|
||||
//if (c == ' ') pen.x -= space; // I think this needs to be undone too?
|
||||
return Vector2(pen.x - (wordlen - plen), pen.y); // return cursor position
|
||||
}
|
||||
}
|
||||
|
||||
//if (msg.back() != '\n') pen.y += lineHeight; // trim trailing newline (todo: make this recursive...?)
|
||||
pen.y += lineHeight;
|
||||
return Vector2(longest, pen.y); // total size
|
||||
}
|
||||
|
||||
unsigned int BitmapFont::PointToIndex(std::string& msg, Vector2 pt, float maxWidth) {
|
||||
if (pt.y < 0) return 0;
|
||||
auto len = msg.length();
|
||||
|
||||
unsigned int line = 0;
|
||||
unsigned int tLine = std::max(0.0f, std::floor(pt.y / lineHeight));
|
||||
|
||||
unsigned int le = 0; // line end
|
||||
unsigned int ti = 4294967295; // target index
|
||||
|
||||
Vector2 pen = Vector2::zero;
|
||||
float wordlen = 0;
|
||||
|
||||
float space = Char(' ').advX;
|
||||
|
||||
for (unsigned int i = 0; i < len; i++) {
|
||||
char& c = msg[i];
|
||||
if (c == ' ' || c == '\n') {
|
||||
// linebreak on newline or wrap needed
|
||||
bool lb = (c == '\n' || pen.x + space + wordlen > maxWidth);
|
||||
|
||||
if (lb) {
|
||||
if (c == '\n') le = i; // not wrapped
|
||||
if (line == tLine) return std::min(le, ti);
|
||||
pen.x = (c == ' ') ? wordlen : 0;
|
||||
line++;
|
||||
} else {
|
||||
pen.x += wordlen + space;
|
||||
if (line == tLine && ti == 4294967295 && pen.x - space*0.5f >= pt.x) ti = i;
|
||||
le = i;
|
||||
}
|
||||
|
||||
wordlen = 0; // HERP DERP.
|
||||
} else {
|
||||
float cw = Char(c).advX;
|
||||
wordlen += cw;
|
||||
if (line == tLine && ti == 4294967295 && pen.x + wordlen - cw*0.5f >= pt.x) ti = i;
|
||||
}
|
||||
}
|
||||
// oh right, process last word
|
||||
if (pen.x + space + wordlen > maxWidth) {
|
||||
if (line == tLine) return std::min(le, ti);
|
||||
pen.x = wordlen;
|
||||
line++;
|
||||
} else {
|
||||
le = len;
|
||||
}
|
||||
|
||||
if (line == tLine) return std::min(le, ti);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -107,10 +219,4 @@ float BitmapFont::DrawText(const Vector2& penStart, std::string& msg, float scal
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
|
@ -49,10 +49,12 @@ namespace starlight {
|
||||
CharInfo& Char(char c);
|
||||
float DrawText(const Vector2& penStart, std::string& msg, float scale = 1, DisplayList* dl = nullptr);
|
||||
// what to put in the bitmapfont class itself?
|
||||
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);
|
||||
|
||||
static inline constexpr unsigned int KerningKey(char cl, char cr) {
|
||||
return (static_cast<unsigned int>(cl) | (static_cast<unsigned int>(cr) << 8));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,9 @@ namespace starlight {
|
||||
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 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;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -18,9 +18,10 @@ using starlight::gfx::FontBMF;
|
||||
#define ded(wat) err(0,wat)
|
||||
Vector2 FontBMF::Measure(std::string& text, float scale, float maxWidth) {
|
||||
if (text == "") return Vector2::zero;
|
||||
Vector2 v;
|
||||
/*Vector2 v;
|
||||
PrintOp(Vector2(), text, scale, Color(), Vector2(), nullptr, maxWidth, &v, static_cast<DisplayList*>(nullptr));
|
||||
return v;
|
||||
return v;*/
|
||||
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) {
|
||||
@ -139,3 +140,11 @@ void FontBMF::PrintOp(Vector2 position, std::string& text, float scale, const Co
|
||||
li++;
|
||||
}
|
||||
}
|
||||
|
||||
Vector2 FontBMF::GetCursorPosition(VRect rect, 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) {
|
||||
return font->PointToIndex(text, pt*scale - rect.pos, rect.size.x / scale);
|
||||
}
|
||||
|
@ -23,6 +23,9 @@ namespace starlight {
|
||||
void Print(VRect rect, 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;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,13 @@
|
||||
#include "DrawLayerProxy.h"
|
||||
|
||||
#include "starlight/GFXManager.h"
|
||||
#include "starlight/InputManager.h"
|
||||
|
||||
using starlight::GFXManager;
|
||||
using starlight::gfx::DrawContextCanvas;
|
||||
|
||||
using starlight::InputManager;
|
||||
|
||||
using starlight::ui::DrawLayerProxy;
|
||||
|
||||
void DrawLayerProxy::Refresh() {
|
||||
@ -31,3 +34,29 @@ void DrawLayerProxy::Draw() {
|
||||
if (eDraw) eDraw(*this);
|
||||
}
|
||||
}
|
||||
|
||||
void DrawLayerProxy::OnTouchOn() {
|
||||
if (!eOnTap) return;
|
||||
if (InputManager::Pressed(Keys::Touch)) {
|
||||
InputManager::GetDragHandle().Grab(this);
|
||||
MarkForRedraw();
|
||||
}
|
||||
}
|
||||
|
||||
void DrawLayerProxy::OnTouchOff() {
|
||||
auto& drag = InputManager::GetDragHandle();
|
||||
if (drag == this) drag.Release();
|
||||
}
|
||||
|
||||
void DrawLayerProxy::OnDragHold() {
|
||||
if (InputManager::TouchDragDist().Length() > InputManager::dragThreshold) {
|
||||
InputManager::GetDragHandle().PassUp();
|
||||
}
|
||||
}
|
||||
|
||||
void DrawLayerProxy::OnDragRelease() {
|
||||
if (InputManager::Released(Keys::Touch)) {
|
||||
if (eOnTap) eOnTap(*this);
|
||||
}
|
||||
MarkForRedraw();
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ namespace starlight {
|
||||
std::unique_ptr<gfx::DrawContextCanvas> canvas;
|
||||
|
||||
std::function<void(DrawLayerProxy&)> eDraw;
|
||||
std::function<void(DrawLayerProxy&)> eOnTap;
|
||||
|
||||
DrawLayerProxy(VRect rect, std::function<void(DrawLayerProxy&)> drawFunc, bool useCanvas = false) : useCanvas(useCanvas), eDraw(drawFunc) { this->rect = rect; }
|
||||
~DrawLayerProxy() override { }
|
||||
@ -34,6 +35,11 @@ namespace starlight {
|
||||
void PreDraw() override;
|
||||
void Draw() override;
|
||||
|
||||
void OnTouchOn() override;
|
||||
void OnTouchOff() override;
|
||||
void OnDragHold() override;
|
||||
void OnDragRelease() override;
|
||||
|
||||
//
|
||||
};
|
||||
}
|
||||
|
@ -6,7 +6,9 @@ roadmap to first release, in no particular order {
|
||||
finish implementing OSK! {
|
||||
- make backspace and enter actually do something
|
||||
- abstract osk input actions into a separate object/class heirarchy
|
||||
preview where applicable
|
||||
- preview where applicable
|
||||
fix desync between cursor position, tap-cursor and display when a single word overflows a line
|
||||
(cursor doesn't wrap until the next word!?)
|
||||
polish!
|
||||
InputManager::OpenKeyboard
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user