From 36960effa4cd613db30cedd13ad7f2a0fc48f109 Mon Sep 17 00:00:00 2001 From: zetaPRIME Date: Tue, 14 Mar 2017 14:40:40 -0400 Subject: [PATCH] tap action for drawlayerproxy, text cursor for osk! --- libstarlight/source/starlight/dialog/OSK.cpp | 38 ++++++ libstarlight/source/starlight/dialog/OSK.h | 1 + .../starlight/dialog/osk/InputHandler.cpp | 14 +- .../starlight/dialog/osk/InputHandler.h | 3 +- .../source/starlight/gfx/BitmapFont.cpp | 120 +++++++++++++++++- .../source/starlight/gfx/BitmapFont.h | 4 +- libstarlight/source/starlight/gfx/Font.h | 3 + libstarlight/source/starlight/gfx/FontBMF.cpp | 13 +- libstarlight/source/starlight/gfx/FontBMF.h | 3 + .../source/starlight/ui/DrawLayerProxy.cpp | 29 +++++ .../source/starlight/ui/DrawLayerProxy.h | 6 + libstarlight/todo.txt | 4 +- 12 files changed, 221 insertions(+), 17 deletions(-) diff --git a/libstarlight/source/starlight/dialog/OSK.cpp b/libstarlight/source/starlight/dialog/OSK.cpp index 7c3c1f8..99b9ca7 100644 --- a/libstarlight/source/starlight/dialog/OSK.cpp +++ b/libstarlight/source/starlight/dialog/OSK.cpp @@ -100,12 +100,39 @@ OSK::OSK(osk::InputHandler* handler) : Form(true), handler(handler) { touchScreen->Add(key); preview = std::make_shared(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("/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("/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("/dialogs/OSK/preview"); + handler->SetCursor(tc.font->GetCursorFromPoint(layer.rect, handler->GetPreviewText(), tpos + layer.rect.pos)); + preview->Refresh(); +} diff --git a/libstarlight/source/starlight/dialog/OSK.h b/libstarlight/source/starlight/dialog/OSK.h index fd7630d..e2c88cc 100644 --- a/libstarlight/source/starlight/dialog/OSK.h +++ b/libstarlight/source/starlight/dialog/OSK.h @@ -28,6 +28,7 @@ namespace starlight { void OnKey(); void DrawPreview(ui::DrawLayerProxy& layer); + void OnPreviewTap(ui::DrawLayerProxy& layer); }; } } diff --git a/libstarlight/source/starlight/dialog/osk/InputHandler.cpp b/libstarlight/source/starlight/dialog/osk/InputHandler.cpp index 8c06136..d7dc062 100644 --- a/libstarlight/source/starlight/dialog/osk/InputHandler.cpp +++ b/libstarlight/source/starlight/dialog/osk/InputHandler.cpp @@ -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(); } } diff --git a/libstarlight/source/starlight/dialog/osk/InputHandler.h b/libstarlight/source/starlight/dialog/osk/InputHandler.h index 40d8e83..95d8c84 100644 --- a/libstarlight/source/starlight/dialog/osk/InputHandler.h +++ b/libstarlight/source/starlight/dialog/osk/InputHandler.h @@ -39,12 +39,13 @@ namespace starlight { std::string* pText; unsigned int minIndex = 0; + unsigned int cursor = 0; std::function eOnModify = {}; std::function eOnFinalize = {}; InputHandlerDirectEdit(std::string* textptr, bool multiLine = false, unsigned int minIndex = 0, std::function onModify = {}, std::function 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; diff --git a/libstarlight/source/starlight/gfx/BitmapFont.cpp b/libstarlight/source/starlight/gfx/BitmapFont.cpp index d63b1f1..52593c6 100644 --- a/libstarlight/source/starlight/gfx/BitmapFont.cpp +++ b/libstarlight/source/starlight/gfx/BitmapFont.cpp @@ -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 - - - - - - - +// diff --git a/libstarlight/source/starlight/gfx/BitmapFont.h b/libstarlight/source/starlight/gfx/BitmapFont.h index b991ae3..015e03a 100644 --- a/libstarlight/source/starlight/gfx/BitmapFont.h +++ b/libstarlight/source/starlight/gfx/BitmapFont.h @@ -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(cl) | (static_cast(cr) << 8)); } }; } -} \ No newline at end of file +} diff --git a/libstarlight/source/starlight/gfx/Font.h b/libstarlight/source/starlight/gfx/Font.h index 5008520..88d2ac8 100644 --- a/libstarlight/source/starlight/gfx/Font.h +++ b/libstarlight/source/starlight/gfx/Font.h @@ -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 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 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 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; }; } diff --git a/libstarlight/source/starlight/gfx/FontBMF.cpp b/libstarlight/source/starlight/gfx/FontBMF.cpp index 7368d72..02b38f4 100644 --- a/libstarlight/source/starlight/gfx/FontBMF.cpp +++ b/libstarlight/source/starlight/gfx/FontBMF.cpp @@ -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(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 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); +} diff --git a/libstarlight/source/starlight/gfx/FontBMF.h b/libstarlight/source/starlight/gfx/FontBMF.h index 02de524..187d734 100644 --- a/libstarlight/source/starlight/gfx/FontBMF.h +++ b/libstarlight/source/starlight/gfx/FontBMF.h @@ -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 borderColor = nullptr) override; void PrintDisplayList(DisplayList* dl, Vector2 position, std::string& text, float scale = 1, Color color = Color::white, Vector2 justification = Vector2::zero, OptRef borderColor = nullptr) override; void PrintDisplayList(DisplayList* dl, VRect rect, std::string& text, float scale = 1, Color color = Color::white, Vector2 justification = Vector2::zero, OptRef 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; }; } } diff --git a/libstarlight/source/starlight/ui/DrawLayerProxy.cpp b/libstarlight/source/starlight/ui/DrawLayerProxy.cpp index 9a1ce0f..5ba4e6e 100644 --- a/libstarlight/source/starlight/ui/DrawLayerProxy.cpp +++ b/libstarlight/source/starlight/ui/DrawLayerProxy.cpp @@ -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(); +} diff --git a/libstarlight/source/starlight/ui/DrawLayerProxy.h b/libstarlight/source/starlight/ui/DrawLayerProxy.h index 88235b7..6a25a81 100644 --- a/libstarlight/source/starlight/ui/DrawLayerProxy.h +++ b/libstarlight/source/starlight/ui/DrawLayerProxy.h @@ -24,6 +24,7 @@ namespace starlight { std::unique_ptr canvas; std::function eDraw; + std::function eOnTap; DrawLayerProxy(VRect rect, std::function 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; + // }; } diff --git a/libstarlight/todo.txt b/libstarlight/todo.txt index 5e3b8e5..aa1419b 100644 --- a/libstarlight/todo.txt +++ b/libstarlight/todo.txt @@ -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 }