From 60399e17bd1571943f67e52ff694021cf1270c8e Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Sat, 6 May 2023 19:53:02 +0200 Subject: [PATCH] Codechange: C++-ify the Layouter and related functions They all now access a std::string_view, instead of a "const char *" or std::string (in some cases). Additionally, GetCharAtPosition and friends now return an index instead of a "const char *", as it makes for a more clear interface. --- src/console_gui.cpp | 4 +- src/gfx.cpp | 85 ++++++---------------------------- src/gfx_func.h | 31 ++++--------- src/gfx_layout.cpp | 88 +++++++++++++++++------------------- src/gfx_layout.h | 10 ++-- src/misc_gui.cpp | 6 +-- src/querystring_gui.h | 2 +- src/video/cocoa/cocoa_wnd.mm | 7 +-- src/window.cpp | 6 +-- src/window_gui.h | 2 +- 10 files changed, 84 insertions(+), 157 deletions(-) diff --git a/src/console_gui.cpp b/src/console_gui.cpp index b5f5fa5d02..c9d91b8fe4 100644 --- a/src/console_gui.cpp +++ b/src/console_gui.cpp @@ -318,11 +318,11 @@ struct IConsoleWindow : Window return r; } - const char *GetTextCharacterAtPosition(const Point &pt) const override + ptrdiff_t GetTextCharacterAtPosition(const Point &pt) const override { int delta = std::min(this->width - this->line_offset - _iconsole_cmdline.pixels - ICON_RIGHT_BORDERWIDTH, 0); - if (!IsInsideMM(pt.y, this->height - this->line_height, this->height)) return nullptr; + if (!IsInsideMM(pt.y, this->height - this->line_height, this->height)) return -1; return GetCharAtPosition(_iconsole_cmdline.buf, pt.x - delta); } diff --git a/src/gfx.cpp b/src/gfx.cpp index 8799bdbc95..53ca6ab349 100644 --- a/src/gfx.cpp +++ b/src/gfx.cpp @@ -642,7 +642,7 @@ static int DrawLayoutLine(const ParagraphLayouter::Line &line, int y, int left, * @return In case of left or center alignment the right most pixel we have drawn to. * In case of right alignment the left most pixel we have drawn to. */ -int DrawString(int left, int right, int top, const char *str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize) +int DrawString(int left, int right, int top, std::string_view str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize) { /* The string may contain control chars to change the font, just use the biggest font for clipping. */ int max_height = std::max({FONT_HEIGHT_SMALL, FONT_HEIGHT_NORMAL, FONT_HEIGHT_LARGE, FONT_HEIGHT_MONO}); @@ -661,28 +661,6 @@ int DrawString(int left, int right, int top, const char *str, TextColour colour, return DrawLayoutLine(*layout.front(), top, left, right, align, underline, true); } -/** - * Draw string, possibly truncated to make it fit in its allocated space - * - * @param left The left most position to draw on. - * @param right The right most position to draw on. - * @param top The top most position to draw on. - * @param str String to draw. - * @param colour Colour used for drawing the string, for details see _string_colourmap in - * table/palettes.h or docs/ottd-colourtext-palette.png or the enum TextColour in gfx_type.h - * @param align The alignment of the string when drawing left-to-right. In the - * case a right-to-left language is chosen this is inverted so it - * will be drawn in the right direction. - * @param underline Whether to underline what has been drawn or not. - * @param fontsize The size of the initial characters. - * @return In case of left or center alignment the right most pixel we have drawn to. - * In case of right alignment the left most pixel we have drawn to. - */ -int DrawString(int left, int right, int top, const std::string &str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize) -{ - return DrawString(left, right, top, str.c_str(), colour, align, underline, fontsize); -} - /** * Draw string, possibly truncated to make it fit in its allocated space * @@ -713,7 +691,7 @@ int DrawString(int left, int right, int top, StringID str, TextColour colour, St * @param maxw maximum string width * @return height of pixels of string when it is drawn */ -int GetStringHeight(const char *str, int maxw, FontSize fontsize) +int GetStringHeight(std::string_view str, int maxw, FontSize fontsize) { Layouter layout(str, maxw, TC_FROMSTRING, fontsize); return layout.GetBounds().height; @@ -765,7 +743,7 @@ Dimension GetStringMultiLineBoundingBox(StringID str, const Dimension &suggestio * @param suggestion Suggested bounding box. * @return Bounding box for the multi-line string, may be bigger than \a suggestion. */ -Dimension GetStringMultiLineBoundingBox(const char *str, const Dimension &suggestion) +Dimension GetStringMultiLineBoundingBox(std::string_view str, const Dimension &suggestion) { Dimension box = {suggestion.width, (uint)GetStringHeight(str, suggestion.width)}; return box; @@ -787,7 +765,7 @@ Dimension GetStringMultiLineBoundingBox(const char *str, const Dimension &sugges * * @return If \a align is #SA_BOTTOM, the top to where we have written, else the bottom to where we have written. */ -int DrawStringMultiLine(int left, int right, int top, int bottom, const char *str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize) +int DrawStringMultiLine(int left, int right, int top, int bottom, std::string_view str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize) { int maxw = right - left + 1; int maxh = bottom - top + 1; @@ -833,28 +811,6 @@ int DrawStringMultiLine(int left, int right, int top, int bottom, const char *st return ((align & SA_VERT_MASK) == SA_BOTTOM) ? first_line : last_line; } - -/** - * Draw string, possibly over multiple lines. - * - * @param left The left most position to draw on. - * @param right The right most position to draw on. - * @param top The top most position to draw on. - * @param bottom The bottom most position to draw on. - * @param str String to draw. - * @param colour Colour used for drawing the string, for details see _string_colourmap in - * table/palettes.h or docs/ottd-colourtext-palette.png or the enum TextColour in gfx_type.h - * @param align The horizontal and vertical alignment of the string. - * @param underline Whether to underline all strings - * @param fontsize The size of the initial characters. - * - * @return If \a align is #SA_BOTTOM, the top to where we have written, else the bottom to where we have written. - */ -int DrawStringMultiLine(int left, int right, int top, int bottom, const std::string &str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize) -{ - return DrawStringMultiLine(left, right, top, bottom, str.c_str(), colour, align, underline, fontsize); -} - /** * Draw string, possibly over multiple lines. * @@ -888,30 +844,15 @@ int DrawStringMultiLine(int left, int right, int top, int bottom, StringID str, * @param start_fontsize Fontsize to start the text with * @return string width and height in pixels */ -Dimension GetStringBoundingBox(const char *str, FontSize start_fontsize) +Dimension GetStringBoundingBox(std::string_view str, FontSize start_fontsize) { Layouter layout(str, INT32_MAX, TC_FROMSTRING, start_fontsize); return layout.GetBounds(); } -/** - * Return the string dimension in pixels. The height and width are returned - * in a single Dimension value. TINYFONT, BIGFONT modifiers are only - * supported as the first character of the string. The returned dimensions - * are therefore a rough estimation correct for all the current strings - * but not every possible combination - * @param str string to calculate pixel-width - * @param start_fontsize Fontsize to start the text with - * @return string width and height in pixels - */ -Dimension GetStringBoundingBox(const std::string &str, FontSize start_fontsize) -{ - return GetStringBoundingBox(str.c_str(), start_fontsize); -} - /** * Get bounding box of a string. Uses parameters set by #SetDParam if needed. - * Has the same restrictions as #GetStringBoundingBox(const char *str, FontSize start_fontsize). + * Has the same restrictions as #GetStringBoundingBox(std::string_view str, FontSize start_fontsize). * @param strid String to examine. * @return Width and height of the bounding box for the string in pixels. */ @@ -946,10 +887,14 @@ uint GetStringListWidth(const StringID *list, FontSize fontsize) * @param start_fontsize Font size to start the text with. * @return Upper left corner of the glyph associated with the character. */ -Point GetCharPosInString(const char *str, const char *ch, FontSize start_fontsize) +Point GetCharPosInString(std::string_view str, const char *ch, 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()); + Layouter layout(str, INT32_MAX, TC_FROMSTRING, start_fontsize); - return layout.GetCharPosition(ch); + return layout.GetCharPosition(it_ch); } /** @@ -957,11 +902,11 @@ Point GetCharPosInString(const char *str, const char *ch, FontSize start_fontsiz * @param str String to test. * @param x Position relative to the start of the string. * @param start_fontsize Font size to start the text with. - * @return Pointer to the character at the position or nullptr if there is no character at the position. + * @return Index of the character position or -1 if there is no character at the position. */ -const char *GetCharAtPosition(const char *str, int x, FontSize start_fontsize) +ptrdiff_t GetCharAtPosition(std::string_view str, int x, FontSize start_fontsize) { - if (x < 0) return nullptr; + if (x < 0) return -1; Layouter layout(str, INT32_MAX, TC_FROMSTRING, start_fontsize); return layout.GetCharAtPosition(x); diff --git a/src/gfx_func.h b/src/gfx_func.h index 78891e1dc7..2d212c066c 100644 --- a/src/gfx_func.h +++ b/src/gfx_func.h @@ -95,11 +95,9 @@ void DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub void DrawSpriteIgnorePadding(SpriteID img, PaletteID pal, const Rect &r, bool clicked, StringAlignment align); /* widget.cpp */ std::unique_ptr DrawSpriteToRgbaBuffer(SpriteID spriteId, ZoomLevel zoom = ZOOM_LVL_GUI); -int DrawString(int left, int right, int top, const char *str, TextColour colour = TC_FROMSTRING, StringAlignment align = SA_LEFT, bool underline = false, FontSize fontsize = FS_NORMAL); -int DrawString(int left, int right, int top, const std::string &str, TextColour colour = TC_FROMSTRING, StringAlignment align = SA_LEFT, bool underline = false, FontSize fontsize = FS_NORMAL); +int DrawString(int left, int right, int top, std::string_view str, TextColour colour = TC_FROMSTRING, StringAlignment align = SA_LEFT, bool underline = false, FontSize fontsize = FS_NORMAL); int DrawString(int left, int right, int top, StringID str, TextColour colour = TC_FROMSTRING, StringAlignment align = SA_LEFT, bool underline = false, FontSize fontsize = FS_NORMAL); -int DrawStringMultiLine(int left, int right, int top, int bottom, const char *str, TextColour colour = TC_FROMSTRING, StringAlignment align = (SA_TOP | SA_LEFT), bool underline = false, FontSize fontsize = FS_NORMAL); -int DrawStringMultiLine(int left, int right, int top, int bottom, const std::string &str, TextColour colour = TC_FROMSTRING, StringAlignment align = (SA_TOP | SA_LEFT), bool underline = false, FontSize fontsize = FS_NORMAL); +int DrawStringMultiLine(int left, int right, int top, int bottom, std::string_view str, TextColour colour = TC_FROMSTRING, StringAlignment align = (SA_TOP | SA_LEFT), bool underline = false, FontSize fontsize = FS_NORMAL); int DrawStringMultiLine(int left, int right, int top, int bottom, StringID str, TextColour colour = TC_FROMSTRING, StringAlignment align = (SA_TOP | SA_LEFT), bool underline = false, FontSize fontsize = FS_NORMAL); void DrawCharCentered(WChar c, const Rect &r, TextColour colour); @@ -110,12 +108,7 @@ void GfxDrawLine(int left, int top, int right, int bottom, int colour, int width void DrawBox(int x, int y, int dx1, int dy1, int dx2, int dy2, int dx3, int dy3); /* Versions of DrawString/DrawStringMultiLine that accept a Rect instead of separate left, right, top and bottom parameters. */ -static inline int DrawString(const Rect &r, const char *str, TextColour colour = TC_FROMSTRING, StringAlignment align = SA_LEFT, bool underline = false, FontSize fontsize = FS_NORMAL) -{ - return DrawString(r.left, r.right, r.top, str, colour, align, underline, fontsize); -} - -static inline int DrawString(const Rect &r, const std::string &str, TextColour colour = TC_FROMSTRING, StringAlignment align = SA_LEFT, bool underline = false, FontSize fontsize = FS_NORMAL) +static inline int DrawString(const Rect &r, std::string_view str, TextColour colour = TC_FROMSTRING, StringAlignment align = SA_LEFT, bool underline = false, FontSize fontsize = FS_NORMAL) { return DrawString(r.left, r.right, r.top, str, colour, align, underline, fontsize); } @@ -125,12 +118,7 @@ static inline int DrawString(const Rect &r, StringID str, TextColour colour = TC return DrawString(r.left, r.right, r.top, str, colour, align, underline, fontsize); } -static inline int DrawStringMultiLine(const Rect &r, const char *str, TextColour colour = TC_FROMSTRING, StringAlignment align = (SA_TOP | SA_LEFT), bool underline = false, FontSize fontsize = FS_NORMAL) -{ - return DrawStringMultiLine(r.left, r.right, r.top, r.bottom, str, colour, align, underline, fontsize); -} - -static inline int DrawStringMultiLine(const Rect &r, const std::string &str, TextColour colour = TC_FROMSTRING, StringAlignment align = (SA_TOP | SA_LEFT), bool underline = false, FontSize fontsize = FS_NORMAL) +static inline int DrawStringMultiLine(const Rect &r, std::string_view str, TextColour colour = TC_FROMSTRING, StringAlignment align = (SA_TOP | SA_LEFT), bool underline = false, FontSize fontsize = FS_NORMAL) { return DrawStringMultiLine(r.left, r.right, r.top, r.bottom, str, colour, align, underline, fontsize); } @@ -145,18 +133,17 @@ static inline void GfxFillRect(const Rect &r, int colour, FillRectMode mode = FI GfxFillRect(r.left, r.top, r.right, r.bottom, colour, mode); } -Dimension GetStringBoundingBox(const char *str, FontSize start_fontsize = FS_NORMAL); -Dimension GetStringBoundingBox(const std::string &str, FontSize start_fontsize = FS_NORMAL); +Dimension GetStringBoundingBox(std::string_view str, FontSize start_fontsize = FS_NORMAL); Dimension GetStringBoundingBox(StringID strid, FontSize start_fontsize = FS_NORMAL); uint GetStringListWidth(const StringID *list, FontSize fontsize = FS_NORMAL); -int GetStringHeight(const char *str, int maxw, FontSize fontsize = FS_NORMAL); +int GetStringHeight(std::string_view str, int maxw, FontSize fontsize = FS_NORMAL); int GetStringHeight(StringID str, int maxw); int GetStringLineCount(StringID str, int maxw); Dimension GetStringMultiLineBoundingBox(StringID str, const Dimension &suggestion); -Dimension GetStringMultiLineBoundingBox(const char *str, const Dimension &suggestion); +Dimension GetStringMultiLineBoundingBox(std::string_view str, const Dimension &suggestion); void LoadStringWidthTable(bool monospace = false); -Point GetCharPosInString(const char *str, const char *ch, FontSize start_fontsize = FS_NORMAL); -const char *GetCharAtPosition(const char *str, int x, FontSize start_fontsize = FS_NORMAL); +Point GetCharPosInString(std::string_view str, const char *ch, FontSize start_fontsize = FS_NORMAL); +ptrdiff_t GetCharAtPosition(std::string_view str, int x, FontSize start_fontsize = FS_NORMAL); void DrawDirtyBlocks(); void AddDirtyBlock(int left, int top, int right, int bottom); diff --git a/src/gfx_layout.cpp b/src/gfx_layout.cpp index 6ddb0c4b85..5e149dc38f 100644 --- a/src/gfx_layout.cpp +++ b/src/gfx_layout.cpp @@ -59,7 +59,7 @@ Font::Font(FontSize size, TextColour colour) : * @tparam T The type of layouter we want. */ template -static inline void GetLayouter(Layouter::LineCacheItem &line, const char *&str, FontState &state) +static inline void GetLayouter(Layouter::LineCacheItem &line, std::string_view str, FontState &state) { if (line.buffer != nullptr) free(line.buffer); @@ -72,15 +72,18 @@ static inline void GetLayouter(Layouter::LineCacheItem &line, const char *&str, line.buffer = buff_begin; fontMapping.clear(); + auto cur = str.begin(); + /* * Go through the whole string while adding Font instances to the font map * whenever the font changes, and convert the wide characters into a format * usable by ParagraphLayout. */ - for (; buff < buffer_last;) { - WChar c = Utf8Consume(const_cast(&str)); + for (; buff < buffer_last && cur != str.end();) { + WChar c = Utf8Consume(cur); if (c == '\0' || c == '\n') { - break; + /* Caller should already have filtered out these characters. */ + NOT_REACHED(); } else if (c >= SCC_BLUE && c <= SCC_BLACK) { state.SetColour((TextColour)(c - SCC_BLUE)); } else if (c == SCC_PUSH_COLOUR) { @@ -123,65 +126,51 @@ static inline void GetLayouter(Layouter::LineCacheItem &line, const char *&str, * @param colour The colour of the font. * @param fontsize The size of font to use. */ -Layouter::Layouter(const char *str, int maxw, TextColour colour, FontSize fontsize) : string(str) +Layouter::Layouter(std::string_view str, int maxw, TextColour colour, FontSize fontsize) : string(str) { FontState state(colour, fontsize); - WChar c = 0; - do { - /* Scan string for end of line */ - const char *lineend = str; - for (;;) { - size_t len = Utf8Decode(&c, lineend); - if (c == '\0' || c == '\n') break; - lineend += len; - } + while (true) { + auto line_length = str.find_first_of('\n'); + auto str_line = str.substr(0, line_length); - LineCacheItem& line = GetCachedParagraphLayout(str, lineend - str, state); + LineCacheItem &line = GetCachedParagraphLayout(str_line, state); if (line.layout != nullptr) { - /* Line is in cache */ - str = lineend + 1; state = line.state_after; line.layout->Reflow(); } else { /* Line is new, layout it */ FontState old_state = state; -#if (defined(WITH_ICU_I18N) && defined(WITH_HARFBUZZ)) || defined(WITH_UNISCRIBE) || defined(WITH_COCOA) - const char *old_str = str; -#endif #if defined(WITH_ICU_I18N) && defined(WITH_HARFBUZZ) if (line.layout == nullptr) { - GetLayouter(line, str, state); + GetLayouter(line, str_line, state); if (line.layout == nullptr) { state = old_state; - str = old_str; } } #endif #ifdef WITH_UNISCRIBE if (line.layout == nullptr) { - GetLayouter(line, str, state); + GetLayouter(line, str_line, state); if (line.layout == nullptr) { state = old_state; - str = old_str; } } #endif #ifdef WITH_COCOA if (line.layout == nullptr) { - GetLayouter(line, str, state); + GetLayouter(line, str_line, state); if (line.layout == nullptr) { state = old_state; - str = old_str; } } #endif if (line.layout == nullptr) { - GetLayouter(line, str, state); + GetLayouter(line, str_line, state); } } @@ -191,7 +180,15 @@ Layouter::Layouter(const char *str, int maxw, TextColour colour, FontSize fontsi if (l == nullptr) break; this->push_back(std::move(l)); } - } while (c != '\0'); + + /* Break out if this was the last line. */ + if (line_length == std::string_view::npos) { + break; + } + + /* Go to the next line. */ + str.remove_prefix(line_length + 1); + } } /** @@ -210,21 +207,18 @@ Dimension Layouter::GetBounds() /** * Get the position of a character in the layout. - * @param ch Character to get the position of. + * @param ch Character to get the position of. Must be an iterator of the string passed to the constructor. * @return Upper left corner of the character relative to the start of the string. * @note Will only work right for single-line strings. */ -Point Layouter::GetCharPosition(const char *ch) const +Point Layouter::GetCharPosition(std::string_view::const_iterator ch) const { /* Find the code point index which corresponds to the char * pointer into our UTF-8 source string. */ size_t index = 0; - const char *str = this->string; - while (str < ch) { - WChar c; - size_t len = Utf8Decode(&c, str); - if (c == '\0' || c == '\n') break; - str += len; + auto str = this->string.begin(); + while (str < ch && str != this->string.end()) { + WChar c = Utf8Consume(str); index += this->front()->GetInternalCharLength(c); } @@ -233,7 +227,7 @@ Point Layouter::GetCharPosition(const char *ch) const const auto &line = this->front(); /* Pointer to the end-of-string/line marker? Return total line width. */ - if (*ch == '\0' || *ch == '\n') { + if (ch == this->string.end() || *ch == '\0' || *ch == '\n') { Point p = { line->GetWidth(), 0 }; return p; } @@ -259,9 +253,9 @@ Point Layouter::GetCharPosition(const char *ch) const /** * Get the character that is at a position. * @param x Position in the string. - * @return Pointer to the character at the position or nullptr if no character is at the position. + * @return Index of the position or -1 if no character is at the position. */ -const char *Layouter::GetCharAtPosition(int x) const +ptrdiff_t Layouter::GetCharAtPosition(int x) const { const auto &line = this->front(); @@ -280,17 +274,18 @@ const char *Layouter::GetCharAtPosition(int x) const size_t index = run.GetGlyphToCharMap()[i]; size_t cur_idx = 0; - for (const char *str = this->string; *str != '\0'; ) { - if (cur_idx == index) return str; + int char_index = 0; + for (auto str = this->string.begin(); str != this->string.end(); char_index++) { + if (cur_idx == index) return char_index; - WChar c = Utf8Consume(&str); + WChar c = Utf8Consume(str); cur_idx += line->GetInternalCharLength(c); } } } } - return nullptr; + return -1; } /** @@ -332,18 +327,17 @@ void Layouter::ResetFontCache(FontSize size) * Get reference to cache item. * If the item does not exist yet, it is default constructed. * @param str Source string of the line (including colour and font size codes). - * @param len Length of \a str in bytes (no termination). * @param state State of the font at the beginning of the line. * @return Reference to cache item. */ -Layouter::LineCacheItem &Layouter::GetCachedParagraphLayout(const char *str, size_t len, const FontState &state) +Layouter::LineCacheItem &Layouter::GetCachedParagraphLayout(std::string_view str, const FontState &state) { if (linecache == nullptr) { /* Create linecache on first access to avoid trouble with initialisation order of static variables. */ linecache = new LineCache(); } - if (auto match = linecache->find(LineCacheQuery{state, std::string_view{str, len}}); + if (auto match = linecache->find(LineCacheQuery{state, str}); match != linecache->end()) { return match->second; } @@ -351,7 +345,7 @@ Layouter::LineCacheItem &Layouter::GetCachedParagraphLayout(const char *str, siz /* Create missing entry */ LineCacheKey key; key.state_before = state; - key.str.assign(str, len); + key.str.assign(str); return (*linecache)[key]; } diff --git a/src/gfx_layout.h b/src/gfx_layout.h index 504bd51a9b..ec983ee89e 100644 --- a/src/gfx_layout.h +++ b/src/gfx_layout.h @@ -124,7 +124,7 @@ public: * It also accounts for the memory allocations and frees. */ class Layouter : public std::vector> { - const char *string; ///< Pointer to the original string. + std::string_view string; ///< Pointer to the original string. /** Key into the linecache */ struct LineCacheKey { @@ -168,17 +168,17 @@ private: typedef std::map LineCache; static LineCache *linecache; - static LineCacheItem &GetCachedParagraphLayout(const char *str, size_t len, const FontState &state); + static LineCacheItem &GetCachedParagraphLayout(std::string_view str, const FontState &state); typedef SmallMap FontColourMap; static FontColourMap fonts[FS_END]; public: static Font *GetFont(FontSize size, TextColour colour); - Layouter(const char *str, int maxw = INT32_MAX, TextColour colour = TC_FROMSTRING, FontSize fontsize = FS_NORMAL); + Layouter(std::string_view str, int maxw = INT32_MAX, TextColour colour = TC_FROMSTRING, FontSize fontsize = FS_NORMAL); Dimension GetBounds(); - Point GetCharPosition(const char *ch) const; - const char *GetCharAtPosition(int x) const; + Point GetCharPosition(std::string_view::const_iterator ch) const; + ptrdiff_t GetCharAtPosition(int x) const; static void ResetFontCache(FontSize size); static void ResetLineCache(); diff --git a/src/misc_gui.cpp b/src/misc_gui.cpp index 351fd087e4..c25cea77a4 100644 --- a/src/misc_gui.cpp +++ b/src/misc_gui.cpp @@ -896,9 +896,9 @@ Rect QueryString::GetBoundingRect(const Window *w, int wid, const char *from, co * @param w Window the edit box is in. * @param wid Widget index. * @param pt Position to test. - * @return Pointer to the character at the position or nullptr if no character is at the position. + * @return Index of the character position or -1 if no character is at the position. */ -const char *QueryString::GetCharAtPosition(const Window *w, int wid, const Point &pt) const +ptrdiff_t QueryString::GetCharAtPosition(const Window *w, int wid, const Point &pt) const { const NWidgetLeaf *wi = w->GetWidget(wid); @@ -910,7 +910,7 @@ const char *QueryString::GetCharAtPosition(const Window *w, int wid, const Point Rect r = wi->GetCurrentRect().Indent(clearbtn_width, !rtl).Shrink(WidgetDimensions::scaled.framerect); - if (!IsInsideMM(pt.y, r.top, r.bottom)) return nullptr; + if (!IsInsideMM(pt.y, r.top, r.bottom)) return -1; /* Clamp caret position to be inside our current width. */ const Textbuf *tb = &this->text; diff --git a/src/querystring_gui.h b/src/querystring_gui.h index 1556334c3d..79eadc7993 100644 --- a/src/querystring_gui.h +++ b/src/querystring_gui.h @@ -54,7 +54,7 @@ public: Point GetCaretPosition(const Window *w, int wid) const; Rect GetBoundingRect(const Window *w, int wid, const char *from, const char *to) const; - const char *GetCharAtPosition(const Window *w, int wid, const Point &pt) const; + ptrdiff_t GetCharAtPosition(const Window *w, int wid, const Point &pt) const; /** * Get the current text. diff --git a/src/video/cocoa/cocoa_wnd.mm b/src/video/cocoa/cocoa_wnd.mm index d4fc5b292e..445d412303 100644 --- a/src/video/cocoa/cocoa_wnd.mm +++ b/src/video/cocoa/cocoa_wnd.mm @@ -1057,10 +1057,11 @@ void CocoaDialog(const char *title, const char *message, const char *buttonLabel Point pt = { (int)view_pt.x, (int)[ self frame ].size.height - (int)view_pt.y }; - const char *ch = _focused_window->GetTextCharacterAtPosition(pt); - if (ch == nullptr) return NSNotFound; + auto index = _focused_window->GetTextCharacterAtPosition(pt); + if (index == -1) return NSNotFound; - return CountUtf16Units(_focused_window->GetFocusedText(), ch); + auto text = _focused_window->GetFocusedText(); + return CountUtf16Units(text, text + index); } /** Get the bounding rect for the given range. */ diff --git a/src/window.cpp b/src/window.cpp index c12aab6e37..ae4d35ef4f 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -440,15 +440,15 @@ void Window::UpdateQueryStringSize() /** * Get the character that is rendered at a position by the focused edit box. * @param pt The position to test. - * @return Pointer to the character at the position or nullptr if no character is at the position. + * @return Index of the character position or -1 if no character is at the position. */ -/* virtual */ const char *Window::GetTextCharacterAtPosition(const Point &pt) const +/* virtual */ ptrdiff_t Window::GetTextCharacterAtPosition(const Point &pt) const { if (this->nested_focus != nullptr && this->nested_focus->type == WWT_EDITBOX) { return this->GetQueryString(this->nested_focus->index)->GetCharAtPosition(this, this->nested_focus->index, pt); } - return nullptr; + return -1; } /** diff --git a/src/window_gui.h b/src/window_gui.h index 253292455d..7784c2dc8a 100644 --- a/src/window_gui.h +++ b/src/window_gui.h @@ -281,7 +281,7 @@ public: virtual const char *GetMarkedText(size_t *length) const; virtual Point GetCaretPosition() const; virtual Rect GetTextBoundingRect(const char *from, const char *to) const; - virtual const char *GetTextCharacterAtPosition(const Point &pt) const; + virtual ptrdiff_t GetTextCharacterAtPosition(const Point &pt) const; void InitNested(WindowNumber number = 0); void CreateNestedTree(bool fill_nested = true);