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.
This commit is contained in:
Patric Stout 2023-05-06 19:53:02 +02:00 committed by Patric Stout
parent 61d1b330d1
commit 60399e17bd
10 changed files with 84 additions and 157 deletions

View File

@ -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<int>(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);
}

View File

@ -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<ptrdiff_t>(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);

View File

@ -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<uint32[]> 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);

View File

@ -59,7 +59,7 @@ Font::Font(FontSize size, TextColour colour) :
* @tparam T The type of layouter we want.
*/
template <typename T>
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<const char **>(&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<ICUParagraphLayoutFactory>(line, str, state);
GetLayouter<ICUParagraphLayoutFactory>(line, str_line, state);
if (line.layout == nullptr) {
state = old_state;
str = old_str;
}
}
#endif
#ifdef WITH_UNISCRIBE
if (line.layout == nullptr) {
GetLayouter<UniscribeParagraphLayoutFactory>(line, str, state);
GetLayouter<UniscribeParagraphLayoutFactory>(line, str_line, state);
if (line.layout == nullptr) {
state = old_state;
str = old_str;
}
}
#endif
#ifdef WITH_COCOA
if (line.layout == nullptr) {
GetLayouter<CoreTextParagraphLayoutFactory>(line, str, state);
GetLayouter<CoreTextParagraphLayoutFactory>(line, str_line, state);
if (line.layout == nullptr) {
state = old_state;
str = old_str;
}
}
#endif
if (line.layout == nullptr) {
GetLayouter<FallbackParagraphLayoutFactory>(line, str, state);
GetLayouter<FallbackParagraphLayoutFactory>(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];
}

View File

@ -124,7 +124,7 @@ public:
* It also accounts for the memory allocations and frees.
*/
class Layouter : public std::vector<std::unique_ptr<const ParagraphLayouter::Line>> {
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<LineCacheKey, LineCacheItem, LineCacheCompare> 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<TextColour, Font *> 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();

View File

@ -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<NWidgetLeaf>(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;

View File

@ -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.

View File

@ -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. */

View File

@ -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;
}
/**

View File

@ -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);