From 151bc4c9cd6c6586f30189c06b5a00d425255b63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20B=C3=A1lint=20Misius?= Date: Fri, 15 Dec 2023 22:27:12 +0100 Subject: [PATCH] Fix Textbox width limiting content length --- src/gui/interface/Label.cpp | 25 +++++++--- src/gui/interface/Label.h | 1 + src/gui/interface/TextWrapper.cpp | 16 ++++-- src/gui/interface/TextWrapper.h | 6 +++ src/gui/interface/Textbox.cpp | 81 ++++++++++++++++--------------- 5 files changed, 77 insertions(+), 52 deletions(-) diff --git a/src/gui/interface/Label.cpp b/src/gui/interface/Label.cpp index b7d767f14..dfd72cd1f 100644 --- a/src/gui/interface/Label.cpp +++ b/src/gui/interface/Label.cpp @@ -97,7 +97,8 @@ void Label::OnMouseClick(int x, int y, unsigned button) else { selecting = true; - selectionIndex0 = textWrapper.Point2Index(x - textPosition.X, y - textPosition.Y); + auto tp = textPosition - Vec2{ scrollX, 0 }; + selectionIndex0 = textWrapper.Point2Index(x - tp.X, y - tp.Y); selectionIndexL = selectionIndex0; selectionIndexH = selectionIndex0; @@ -143,7 +144,8 @@ void Label::OnMouseMoved(int localx, int localy, int dx, int dy) { if (selecting) { - selectionIndex1 = textWrapper.Point2Index(localx - textPosition.X, localy - textPosition.Y); + auto tp = textPosition - Vec2{ scrollX, 0 }; + selectionIndex1 = textWrapper.Point2Index(localx - tp.X, localy - tp.Y); if (selectionIndex1.raw_index < selectionIndex0.raw_index) { selectionIndexL = selectionIndex1; @@ -160,6 +162,10 @@ void Label::OnMouseMoved(int localx, int localy, int dx, int dy) void Label::Tick(float dt) { + if (multiline) + { + scrollX = 0; + } if (!this->IsFocused() && (HasSelection() || selecting)) { ClearSelection(); @@ -244,13 +250,16 @@ void Label::Draw(const Point& screenPos) int selectionYH; int selectionLineH = displayTextWrapper.Index2Point(indexH, selectionXH, selectionYH); + auto clip = RectSized(screenPos + Vec2{ 1, 1 }, Size - Vec2{ 2, 2 }) & g->GetClipRect(); + g->SwapClipRect(clip); + auto tp = textPosition - Vec2{ scrollX, 0 }; if (HasSelection()) { if (selectionLineH == selectionLineL) { g->DrawFilledRect( RectSized( - screenPos + textPosition + Vec2{ selectionXL - 1, selectionYL - 2 }, + screenPos + tp + Vec2{ selectionXL - 1, selectionYL - 2 }, Vec2{ selectionXH - selectionXL + 1, FONT_H } ), 0xFFFFFF_rgb @@ -260,7 +269,7 @@ void Label::Draw(const Point& screenPos) { g->DrawFilledRect( RectSized( - screenPos + textPosition + Vec2{ selectionXL - 1, selectionYL - 2 }, + screenPos + tp + Vec2{ selectionXL - 1, selectionYL - 2 }, Vec2{ textSize.X - selectionXL + 1, FONT_H } ), 0xFFFFFF_rgb @@ -269,7 +278,7 @@ void Label::Draw(const Point& screenPos) { g->DrawFilledRect( RectSized( - screenPos + textPosition + Vec2{ -1, selectionYL - 2 + i * FONT_H }, + screenPos + tp + Vec2{ -1, selectionYL - 2 + i * FONT_H }, Vec2{ textSize.X + 1, FONT_H } ), 0xFFFFFF_rgb @@ -277,18 +286,18 @@ void Label::Draw(const Point& screenPos) } g->DrawFilledRect( RectSized( - screenPos + textPosition + Vec2{ -1, selectionYH - 2 }, + screenPos + tp + Vec2{ -1, selectionYH - 2 }, Vec2{ selectionXH + 1, FONT_H } ), 0xFFFFFF_rgb ); } } - g->BlendText( - screenPos + textPosition, + screenPos + tp, displayTextWithSelection, textColour.NoAlpha().WithAlpha(255) ); + g->SwapClipRect(clip); } diff --git a/src/gui/interface/Label.h b/src/gui/interface/Label.h index 17891bcd5..3dfa6ae92 100644 --- a/src/gui/interface/Label.h +++ b/src/gui/interface/Label.h @@ -35,6 +35,7 @@ namespace ui int getLowerSelectionBound(); int getHigherSelectionBound(); + int scrollX = 0; void copySelection(); public: diff --git a/src/gui/interface/TextWrapper.cpp b/src/gui/interface/TextWrapper.cpp index 394f2c581..0a4575e9b 100644 --- a/src/gui/interface/TextWrapper.cpp +++ b/src/gui/interface/TextWrapper.cpp @@ -27,10 +27,17 @@ namespace ui int word_begins_at = -1; // this is a pointer into records; we're not currently in a word int word_width = 0; - int lines = 1; + int lines = 0; int char_width; int clear_count = 0; + wrappedWidth = 0; + auto resetLine = [&]() { + wrappedWidth = std::max(wrappedWidth, line_width); + line_width = 0; + lines += 1; + }; + auto wrap_if_needed = [&](int width_to_consider) -> bool { if (do_wrapping && width_to_consider + char_width > max_width) { @@ -42,8 +49,7 @@ namespace ui true, // signal the end of the line to the clickmap generator true // allow record to eat the following space }); - line_width = 0; - lines += 1; + resetLine(); return true; } return false; @@ -98,8 +104,7 @@ namespace ui true, // signal the end of the line to the clickmap generator false }); - lines += 1; - line_width = 0; + resetLine(); word_begins_at = -1; // reset word state ++clear_count; break; @@ -206,6 +211,7 @@ namespace ui wrapped_text.append(1, record.character); } + resetLine(); clear_text_size = clear_count; wrapped_lines = lines; return lines; diff --git a/src/gui/interface/TextWrapper.h b/src/gui/interface/TextWrapper.h index 2c519809c..05c7d5e1d 100644 --- a/src/gui/interface/TextWrapper.h +++ b/src/gui/interface/TextWrapper.h @@ -27,6 +27,7 @@ namespace ui Index index; }; int wrapped_lines; + int wrappedWidth; std::vector regions; public: @@ -54,5 +55,10 @@ namespace ui { return Index{ raw_text_size, (int)wrapped_text.size(), clear_text_size }; } + + int WrappedWidth() const + { + return wrappedWidth; + } }; } diff --git a/src/gui/interface/Textbox.cpp b/src/gui/interface/Textbox.cpp index 1b44f2cc1..3b95a2b2a 100644 --- a/src/gui/interface/Textbox.cpp +++ b/src/gui/interface/Textbox.cpp @@ -190,33 +190,10 @@ void Textbox::pasteIntoSelection() cursor = getLowerSelectionBound(); } - int regionWidth = Size.X; - if (Appearance.icon) - regionWidth -= 13; - regionWidth -= Appearance.Margin.Left; - regionWidth -= Appearance.Margin.Right; - if (limit != String::npos) { newText = newText.Substr(0, limit-backingText.length()); } - if (!multiline && Graphics::TextSize(backingText + newText).X - 1 > regionWidth) - { - int pLimit = regionWidth - (Graphics::TextSize(backingText).X - 1); - int pWidth = 0; - auto it = newText.begin(); - while (it != newText.end()) - { - auto w = Graphics::CharWidth(*it); - if (pWidth + w > pLimit) - { - break; - } - pWidth += w; - ++it; - } - newText = String(newText.begin(), it); - } backingText.Insert(cursor, newText); cursor = cursor+newText.length(); @@ -273,9 +250,10 @@ bool Textbox::StringValid(String text) void Textbox::Tick(float dt) { Label::Tick(dt); + auto tp = textPosition - Vec2{ scrollX, 0 }; if (GetParentWindow() && Visible && Enabled && IsFocused()) { - ui::Engine::Ref().TextInputRect(GetScreenPos() + textPosition + inputRectPosition - Point(1, 3), Point(Size.X - textPosition.X - inputRectPosition.X, FONT_H + 2)); + ui::Engine::Ref().TextInputRect(GetScreenPos() + tp + inputRectPosition - Point(1, 3), Point(Size.X - tp.X - inputRectPosition.X, FONT_H + 2)); } if (!IsFocused()) { @@ -288,6 +266,32 @@ void Textbox::Tick(float dt) //OnVKeyPress(keyDown, characterDown, false, false, false); repeatTime = Platform::GetTime()+30; } + if (!multiline) + { + int regionWidth = Size.X; + if (Appearance.icon) + { + regionWidth -= 13; + } + regionWidth -= Appearance.Margin.Left; + regionWidth -= Appearance.Margin.Right; + if (scrollX > displayTextWrapper.WrappedWidth() - regionWidth) + { + scrollX = displayTextWrapper.WrappedWidth() - regionWidth; + } + if (scrollX < cursorPositionX - regionWidth) + { + scrollX = cursorPositionX - regionWidth; + } + if (scrollX > cursorPositionX) + { + scrollX = cursorPositionX; + } + if (scrollX < 0) + { + scrollX = 0; + } + } } void Textbox::OnKeyRelease(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt) @@ -483,12 +487,7 @@ void Textbox::InsertText(String text) cursor = getLowerSelectionBound(); } - int regionWidth = Size.X; - if (Appearance.icon) - regionWidth -= 13; - regionWidth -= Appearance.Margin.Left; - regionWidth -= Appearance.Margin.Right; - if ((limit==String::npos || backingText.length() < limit) && (Graphics::TextSize(backingText + text).X - 1 <= regionWidth || multiline)) + if (limit==String::npos || backingText.length() < limit) { if (cursor == (int)backingText.length()) { @@ -576,7 +575,8 @@ void Textbox::OnMouseClick(int x, int y, unsigned button) { StopTextEditing(); mouseDown = true; - auto index = textWrapper.Point2Index(x-textPosition.X, y-textPosition.Y); + auto tp = textPosition - Vec2{ scrollX, 0 }; + auto index = textWrapper.Point2Index(x-tp.X, y-tp.Y); cursor = index.raw_index; resetCursorPosition(); } @@ -593,7 +593,8 @@ void Textbox::OnMouseMoved(int localx, int localy, int dx, int dy) { if(mouseDown) { - auto index = textWrapper.Point2Index(localx-textPosition.X, localy-textPosition.Y); + auto tp = textPosition - Vec2{ scrollX, 0 }; + auto index = textWrapper.Point2Index(localx-tp.X, localy-tp.Y); cursor = index.raw_index; resetCursorPosition(); } @@ -611,24 +612,26 @@ void Textbox::Draw(const Point& screenPos) Label::Draw(screenPos); Graphics * g = GetGraphics(); + auto clip = RectSized(screenPos + Vec2{ 1, 1 }, Size - Vec2{ 2, 2 }) & g->GetClipRect(); + g->SwapClipRect(clip); + auto tp = textPosition - Vec2{ scrollX, 0 }; if(IsFocused()) { - if(border) - g->DrawRect(RectSized(screenPos, Size), 0xFFFFFF_rgb); g->DrawLine( - screenPos + textPosition + Vec2{ cursorPositionX, cursorPositionY-2 }, - screenPos + textPosition + Vec2{ cursorPositionX, cursorPositionY+9 }, + screenPos + tp + Vec2{ cursorPositionX, cursorPositionY-2 }, + screenPos + tp + Vec2{ cursorPositionX, cursorPositionY+9 }, 0xFFFFFF_rgb); } else { if(!text.length()) { - g->BlendText(screenPos + textPosition, placeHolder, textColour.NoAlpha().WithAlpha(170)); + g->BlendText(screenPos + tp, placeHolder, textColour.NoAlpha().WithAlpha(170)); } - if(border) - g->DrawRect(RectSized(screenPos, Size), 0xA0A0A0_rgb); } if(Appearance.icon) g->draw_icon(screenPos.X+iconPosition.X, screenPos.Y+iconPosition.Y, Appearance.icon); + g->SwapClipRect(clip); + if(border) + g->DrawRect(RectSized(screenPos, Size), IsFocused() ? 0xFFFFFF_rgb : 0xA0A0A0_rgb); }