diff --git a/src/console_gui.cpp b/src/console_gui.cpp index 15d66d6264..b383232476 100644 --- a/src/console_gui.cpp +++ b/src/console_gui.cpp @@ -317,7 +317,7 @@ struct IConsoleWindow : Window return ES_HANDLED; } - void InsertTextString(WidgetID, const char *str, bool marked, const char *caret, const char *insert_location, const char *replacement_end) override + void InsertTextString(WidgetID, std::string_view str, bool marked, std::optional caret, std::optional insert_location, std::optional replacement_end) override { if (_iconsole_cmdline.InsertString(str, marked, caret, insert_location, replacement_end)) { _iconsole_tab_completion.Reset(); @@ -340,7 +340,7 @@ struct IConsoleWindow : Window return pt; } - Rect GetTextBoundingRect(const char *from, const char *to) const override + Rect GetTextBoundingRect(size_t from, size_t to) const override { int delta = std::min(this->width - this->line_offset - _iconsole_cmdline.pixels - ICON_RIGHT_BORDERWIDTH, 0); diff --git a/src/gfx_func.h b/src/gfx_func.h index 72654a7b8c..0a3ab5b5c2 100644 --- a/src/gfx_func.h +++ b/src/gfx_func.h @@ -70,7 +70,9 @@ extern Palette _cur_palette; ///< Current palette void HandleToolbarHotkey(int hotkey); void HandleKeypress(uint keycode, char32_t key); -void HandleTextInput(const char *str, bool marked = false, const char *caret = nullptr, const char *insert_location = nullptr, const char *replacement_end = nullptr); +void HandleTextInput(std::string_view str, bool marked = false, + std::optional caret = std::nullopt, + std::optional insert_location = std::nullopt, std::optional replacement_end = std::nullopt); void HandleCtrlChanged(); void HandleMouseEvents(); void UpdateWindows(); diff --git a/src/gfx_layout.cpp b/src/gfx_layout.cpp index c1b2b6c4ae..8642e6b416 100644 --- a/src/gfx_layout.cpp +++ b/src/gfx_layout.cpp @@ -418,15 +418,14 @@ void Layouter::ReduceLineCache() * Get the leading corner of a character in a single-line string relative * to the start of the string. * @param str String containing the character. - * @param ch Pointer to the character in the string. + * @param pos Index to the character in the string. * @param start_fontsize Font size to start the text with. * @return Upper left corner of the glyph associated with the character. */ -ParagraphLayouter::Position GetCharPosInString(std::string_view str, const char *ch, FontSize start_fontsize) +ParagraphLayouter::Position GetCharPosInString(std::string_view str, size_t pos, FontSize start_fontsize) { - /* Ensure "ch" is inside "str" or at the exact end. */ - assert(ch >= str.data() && (ch - str.data()) <= static_cast(str.size())); - auto it_ch = str.begin() + (ch - str.data()); + assert(pos <= str.size()); + auto it_ch = str.begin() + pos; Layouter layout(str, INT32_MAX, start_fontsize); return layout.GetCharPosition(it_ch); diff --git a/src/gfx_layout.h b/src/gfx_layout.h index e6f91e4d7f..ecf5d5fb65 100644 --- a/src/gfx_layout.h +++ b/src/gfx_layout.h @@ -197,7 +197,7 @@ public: static void ReduceLineCache(); }; -ParagraphLayouter::Position GetCharPosInString(std::string_view str, const char *ch, FontSize start_fontsize = FS_NORMAL); +ParagraphLayouter::Position GetCharPosInString(std::string_view str, size_t pos, FontSize start_fontsize = FS_NORMAL); ptrdiff_t GetCharAtPosition(std::string_view str, int x, FontSize start_fontsize = FS_NORMAL); #endif /* GFX_LAYOUT_H */ diff --git a/src/misc_gui.cpp b/src/misc_gui.cpp index 249d43f1c1..8317ff3c57 100644 --- a/src/misc_gui.cpp +++ b/src/misc_gui.cpp @@ -813,7 +813,7 @@ Point QueryString::GetCaretPosition(const Window *w, WidgetID wid) const * @param to End of the string range. * @return Rectangle encompassing the string range, relative to the window. */ -Rect QueryString::GetBoundingRect(const Window *w, WidgetID wid, const char *from, const char *to) const +Rect QueryString::GetBoundingRect(const Window *w, WidgetID wid, size_t from, size_t to) const { const NWidgetLeaf *wi = w->GetWidget(wid); diff --git a/src/querystring_gui.h b/src/querystring_gui.h index 52febfbb91..07df9255f4 100644 --- a/src/querystring_gui.h +++ b/src/querystring_gui.h @@ -45,7 +45,7 @@ public: void HandleEditBox(Window *w, WidgetID wid); Point GetCaretPosition(const Window *w, WidgetID wid) const; - Rect GetBoundingRect(const Window *w, WidgetID wid, const char *from, const char *to) const; + Rect GetBoundingRect(const Window *w, WidgetID wid, size_t from, size_t to) const; ptrdiff_t GetCharAtPosition(const Window *w, WidgetID wid, const Point &pt) const; }; diff --git a/src/textbuf.cpp b/src/textbuf.cpp index fb59136582..eabeac919d 100644 --- a/src/textbuf.cpp +++ b/src/textbuf.cpp @@ -154,21 +154,21 @@ bool Textbuf::InsertChar(char32_t key) * @param replacement_end Replace all characters from #insert_location up to this location with the new string. * @return True on successful change of Textbuf, or false otherwise. */ -bool Textbuf::InsertString(const char *str, bool marked, const char *caret, const char *insert_location, const char *replacement_end) +bool Textbuf::InsertString(std::string_view str, bool marked, std::optional caret, std::optional insert_location, std::optional replacement_end) { uint16_t insertpos = (marked && this->marklength != 0) ? this->markpos : this->caretpos; - if (insert_location != nullptr) { - insertpos = insert_location - this->buf.data(); + if (insert_location.has_value()) { + insertpos = static_cast(*insert_location); if (insertpos >= this->buf.size()) return false; - if (replacement_end != nullptr) { - this->DeleteText(insertpos, replacement_end - this->buf.data(), str == nullptr); + if (replacement_end.has_value()) { + this->DeleteText(insertpos, static_cast(*replacement_end), str.empty()); } } else { - if (marked) this->DiscardMarkedText(str == nullptr); + if (marked) this->DiscardMarkedText(str.empty()); } - if (str == nullptr) return false; + if (str.empty()) return false; uint16_t chars = 0; uint16_t bytes; @@ -192,7 +192,7 @@ bool Textbuf::InsertString(const char *str, bool marked, const char *caret, cons if (bytes == 0) return false; /* Move caret if needed. */ - if (str <= caret && caret <= str + bytes) this->caretpos = insertpos + (caret - str); + if (caret.has_value()) this->caretpos = insertpos + static_cast(*caret); if (marked) { this->markpos = insertpos; @@ -202,7 +202,7 @@ bool Textbuf::InsertString(const char *str, bool marked, const char *caret, cons this->buf.insert(insertpos, str, bytes); this->chars += chars; - if (!marked && caret == nullptr) this->caretpos += bytes; + if (!marked && !caret.has_value()) this->caretpos += bytes; assert(this->buf.size() < this->max_bytes); assert(this->chars <= this->max_chars); @@ -225,7 +225,7 @@ bool Textbuf::InsertClipboard() auto contents = GetClipboardContents(); if (!contents.has_value()) return false; - return this->InsertString(contents.value().c_str(), false); + return this->InsertString(contents.value(), false); } /** @@ -303,7 +303,7 @@ void Textbuf::UpdateWidth() /** Update pixel position of the caret. */ void Textbuf::UpdateCaretPosition() { - const auto pos = GetCharPosInString(this->buf, &this->buf[this->caretpos], FS_NORMAL); + const auto pos = GetCharPosInString(this->buf, this->caretpos, FS_NORMAL); this->caretxoffs = _current_text_dir == TD_LTR ? pos.left : pos.right; } @@ -311,8 +311,8 @@ void Textbuf::UpdateCaretPosition() void Textbuf::UpdateMarkedText() { if (this->markend != 0) { - const auto pos = GetCharPosInString(this->buf, &this->buf[this->markpos], FS_NORMAL); - const auto end = GetCharPosInString(this->buf, &this->buf[this->markend], FS_NORMAL); + const auto pos = GetCharPosInString(this->buf, this->markpos, FS_NORMAL); + const auto end = GetCharPosInString(this->buf, this->markend, FS_NORMAL); this->markxoffs = std::min(pos.left, end.left); this->marklength = std::max(pos.right, end.right) - this->markxoffs; } else { diff --git a/src/textbuf_type.h b/src/textbuf_type.h index 01c6d46d8e..99b8353d5b 100644 --- a/src/textbuf_type.h +++ b/src/textbuf_type.h @@ -49,7 +49,9 @@ struct Textbuf { bool InsertClipboard(); bool InsertChar(char32_t key); - bool InsertString(const char *str, bool marked, const char *caret = nullptr, const char *insert_location = nullptr, const char *replacement_end = nullptr); + bool InsertString(std::string_view str, bool marked, + std::optional caret = std::nullopt, + std::optional insert_location = std::nullopt, std::optional replacement_end = std::nullopt); bool DeleteChar(uint16_t keycode); bool MovePos(uint16_t keycode); diff --git a/src/video/cocoa/cocoa_v.mm b/src/video/cocoa/cocoa_v.mm index 48f175921b..d01733f12d 100644 --- a/src/video/cocoa/cocoa_v.mm +++ b/src/video/cocoa/cocoa_v.mm @@ -247,7 +247,7 @@ void VideoDriver_Cocoa::EditBoxLostFocus() { [ [ this->cocoaview inputContext ] performSelectorOnMainThread:@selector(discardMarkedText) withObject:nil waitUntilDone:[ NSThread isMainThread ] ]; /* Clear any marked string from the current edit box. */ - HandleTextInput(nullptr, true); + HandleTextInput({}, true); } /** diff --git a/src/video/cocoa/cocoa_wnd.mm b/src/video/cocoa/cocoa_wnd.mm index 067c56d152..99e3dc3f3b 100644 --- a/src/video/cocoa/cocoa_wnd.mm +++ b/src/video/cocoa/cocoa_wnd.mm @@ -115,9 +115,9 @@ static NSUInteger CountUtf16Units(std::string_view str) * Advance an UTF-8 string by a number of equivalent UTF-16 code points. * @param str UTF-8 string. * @param count Number of UTF-16 code points to advance the string by. - * @return Advanced string pointer. + * @return Position inside str. */ -static const char *Utf8AdvanceByUtf16Units(std::string_view str, NSUInteger count) +static size_t Utf8AdvanceByUtf16Units(std::string_view str, NSUInteger count) { Utf8View view(str); auto it = view.begin(); @@ -125,7 +125,7 @@ static const char *Utf8AdvanceByUtf16Units(std::string_view str, NSUInteger coun for (NSUInteger i = 0; it != end && i < count; ++it) { i += *it < 0x10000 ? 1 : 2; // Watch for surrogate pairs. } - return str.data() + it.GetByteOffset(); + return it.GetByteOffset(); } /** @@ -940,16 +940,17 @@ void CocoaDialog(std::string_view title, std::string_view message, std::string_v NSString *s = [ aString isKindOfClass:[ NSAttributedString class ] ] ? [ aString string ] : (NSString *)aString; - const char *insert_point = nullptr; - const char *replace_range = nullptr; + std::optional insert_point; + std::optional replace_range; if (replacementRange.location != NSNotFound) { /* Calculate the part to be replaced. */ - insert_point = Utf8AdvanceByUtf16Units(_focused_window->GetFocusedTextbuf()->GetText(), replacementRange.location); - replace_range = Utf8AdvanceByUtf16Units(insert_point, replacementRange.length); + std::string_view focused_text{_focused_window->GetFocusedTextbuf()->GetText()}; + insert_point = Utf8AdvanceByUtf16Units(focused_text, replacementRange.location); + replace_range = *insert_point + Utf8AdvanceByUtf16Units(focused_text.substr(*insert_point), replacementRange.length); } - HandleTextInput(nullptr, true); - HandleTextInput([ s UTF8String ], false, nullptr, insert_point, replace_range); + HandleTextInput({}, true); + HandleTextInput([ s UTF8String ], false, std::nullopt, insert_point, replace_range); } /** Insert the given text at the caret. */ @@ -967,17 +968,18 @@ void CocoaDialog(std::string_view title, std::string_view message, std::string_v const char *utf8 = [ s UTF8String ]; if (utf8 != nullptr) { - const char *insert_point = nullptr; - const char *replace_range = nullptr; + std::optional insert_point; + std::optional replace_range; if (replacementRange.location != NSNotFound) { /* Calculate the part to be replaced. */ NSRange marked = [ self markedRange ]; - insert_point = Utf8AdvanceByUtf16Units(_focused_window->GetFocusedTextbuf()->GetText(), replacementRange.location + (marked.location != NSNotFound ? marked.location : 0u)); - replace_range = Utf8AdvanceByUtf16Units(insert_point, replacementRange.length); + std::string_view focused_text{_focused_window->GetFocusedTextbuf()->GetText()}; + insert_point = Utf8AdvanceByUtf16Units(focused_text, replacementRange.location + (marked.location != NSNotFound ? marked.location : 0u)); + replace_range = *insert_point + Utf8AdvanceByUtf16Units(focused_text.substr(*insert_point), replacementRange.length); } /* Convert caret index into a pointer in the UTF-8 string. */ - const char *selection = Utf8AdvanceByUtf16Units(utf8, selRange.location); + size_t selection = Utf8AdvanceByUtf16Units(utf8, selRange.location); HandleTextInput(utf8, true, selection, insert_point, replace_range); } @@ -992,7 +994,7 @@ void CocoaDialog(std::string_view title, std::string_view message, std::string_v /** Unmark the current marked text. */ - (void)unmarkText { - HandleTextInput(nullptr, true); + HandleTextInput({}, true); } /** Get the caret position. */ @@ -1084,8 +1086,8 @@ void CocoaDialog(std::string_view title, std::string_view message, std::string_v std::string_view focused_text = _focused_window->GetFocusedTextbuf()->GetText(); /* Convert range to UTF-8 string pointers. */ - const char *start = Utf8AdvanceByUtf16Units(focused_text, aRange.location); - const char *end = aRange.length != 0 ? Utf8AdvanceByUtf16Units(focused_text, aRange.location + aRange.length) : start; + size_t start = Utf8AdvanceByUtf16Units(focused_text, aRange.location); + size_t end = start + Utf8AdvanceByUtf16Units(focused_text.substr(start), aRange.length); /* Get the bounding rect for the text range.*/ Rect r = _focused_window->GetTextBoundingRect(start, end); diff --git a/src/video/win32_v.cpp b/src/video/win32_v.cpp index c692ff9fc2..b98df2908c 100644 --- a/src/video/win32_v.cpp +++ b/src/video/win32_v.cpp @@ -346,8 +346,8 @@ static LRESULT HandleIMEComposition(HWND hwnd, WPARAM wParam, LPARAM lParam) /* Transmit text to windowing system. */ if (len > 0) { - HandleTextInput(nullptr, true); // Clear marked string. - HandleTextInput(FS2OTTD(str).c_str()); + HandleTextInput({}, true); // Clear marked string. + HandleTextInput(FS2OTTD(str)); } SetCompositionPos(hwnd); @@ -380,9 +380,9 @@ static LRESULT HandleIMEComposition(HWND hwnd, WPARAM wParam, LPARAM lParam) ++caret; } - HandleTextInput(utf8_buf, true, utf8_buf + caret.GetByteOffset()); + HandleTextInput(utf8_buf, true, caret.GetByteOffset()); } else { - HandleTextInput(nullptr, true); + HandleTextInput({}, true); } lParam &= ~(GCS_COMPSTR | GCS_COMPATTR | GCS_COMPCLAUSE | GCS_CURSORPOS | GCS_DELTASTART); @@ -400,7 +400,7 @@ static void CancelIMEComposition(HWND hwnd) if (hIMC != nullptr) ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_CANCEL, 0); ImmReleaseContext(hwnd, hIMC); /* Clear any marked string from the current edit box. */ - HandleTextInput(nullptr, true); + HandleTextInput({}, true); } static bool IsDarkModeEnabled() @@ -597,7 +597,7 @@ LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) case WM_IME_ENDCOMPOSITION: /* Clear any pending composition string. */ - HandleTextInput(nullptr, true); + HandleTextInput({}, true); if (DrawIMECompositionString()) return 0; break; diff --git a/src/window.cpp b/src/window.cpp index 0e4f78348a..6603d310cb 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -390,7 +390,7 @@ void Window::UpdateQueryStringSize() * @param to End of the string range. * @return Rectangle encompassing the string range, relative to the window. */ -/* virtual */ Rect Window::GetTextBoundingRect(const char *from, const char *to) const +/* virtual */ Rect Window::GetTextBoundingRect(size_t from, size_t to) const { if (this->nested_focus != nullptr && this->nested_focus->type == WWT_EDITBOX) { return this->GetQueryString(this->nested_focus->GetIndex())->GetBoundingRect(this, this->nested_focus->GetIndex(), from, to); @@ -2647,7 +2647,7 @@ void HandleCtrlChanged() * @param wid Edit box widget. * @param str Text string to insert. */ -/* virtual */ void Window::InsertTextString(WidgetID wid, const char *str, bool marked, const char *caret, const char *insert_location, const char *replacement_end) +/* virtual */ void Window::InsertTextString(WidgetID wid, std::string_view str, bool marked, std::optional caret, std::optional insert_location, std::optional replacement_end) { QueryString *query = this->GetQueryString(wid); if (query == nullptr) return; @@ -2664,7 +2664,7 @@ void HandleCtrlChanged() * @param marked Is the input a marked composition string from an IME? * @param caret Move the caret to this point in the insertion string. */ -void HandleTextInput(const char *str, bool marked, const char *caret, const char *insert_location, const char *replacement_end) +void HandleTextInput(std::string_view str, bool marked, std::optional caret, std::optional insert_location, std::optional replacement_end) { if (!EditBoxInGlobalFocus()) return; diff --git a/src/window_gui.h b/src/window_gui.h index 4587844380..1de43573d2 100644 --- a/src/window_gui.h +++ b/src/window_gui.h @@ -342,7 +342,7 @@ public: virtual const struct Textbuf *GetFocusedTextbuf() const; virtual Point GetCaretPosition() const; - virtual Rect GetTextBoundingRect(const char *from, const char *to) const; + virtual Rect GetTextBoundingRect(size_t from, size_t to) const; virtual ptrdiff_t GetTextCharacterAtPosition(const Point &pt) const; void InitNested(WindowNumber number = 0); @@ -497,7 +497,7 @@ public: bool SetFocusedWidget(WidgetID widget_index); EventState HandleEditBoxKey(WidgetID wid, char32_t key, uint16_t keycode); - virtual void InsertTextString(WidgetID wid, const char *str, bool marked, const char *caret, const char *insert_location, const char *replacement_end); + virtual void InsertTextString(WidgetID wid, std::string_view str, bool marked, std::optional caret, std::optional insert_location, std::optional replacement_end); void HandleButtonClick(WidgetID widget); int GetRowFromWidget(int clickpos, WidgetID widget, int padding, int line_height = -1) const;