diff --git a/projects/openttd_vs100.vcxproj b/projects/openttd_vs100.vcxproj
index 9f5a991f0c..dcef8274fc 100644
--- a/projects/openttd_vs100.vcxproj
+++ b/projects/openttd_vs100.vcxproj
@@ -573,6 +573,7 @@
+
diff --git a/projects/openttd_vs100.vcxproj.filters b/projects/openttd_vs100.vcxproj.filters
index 0ecfeeb3a3..87463f0af2 100644
--- a/projects/openttd_vs100.vcxproj.filters
+++ b/projects/openttd_vs100.vcxproj.filters
@@ -948,6 +948,9 @@
Header Files
+
+ Header Files
+
Header Files
diff --git a/projects/openttd_vs80.vcproj b/projects/openttd_vs80.vcproj
index 1eec157596..0271ee5e22 100644
--- a/projects/openttd_vs80.vcproj
+++ b/projects/openttd_vs80.vcproj
@@ -1566,6 +1566,10 @@
RelativePath=".\..\src\strgen\strgen.h"
>
+
+
diff --git a/projects/openttd_vs90.vcproj b/projects/openttd_vs90.vcproj
index 22a7302cf2..50f9d26643 100644
--- a/projects/openttd_vs90.vcproj
+++ b/projects/openttd_vs90.vcproj
@@ -1563,6 +1563,10 @@
RelativePath=".\..\src\strgen\strgen.h"
>
+
+
diff --git a/source.list b/source.list
index da9a409f58..d2c9dc8a1f 100644
--- a/source.list
+++ b/source.list
@@ -306,6 +306,7 @@ station_type.h
statusbar_gui.h
stdafx.h
strgen/strgen.h
+string_base.h
string_func.h
string_type.h
stringfilter_type.h
diff --git a/src/console_gui.cpp b/src/console_gui.cpp
index e97e458ff7..ca0a01853d 100644
--- a/src/console_gui.cpp
+++ b/src/console_gui.cpp
@@ -290,46 +290,13 @@ struct IConsoleWindow : Window
MarkWholeScreenDirty();
break;
-#ifdef WITH_COCOA
- case (WKC_META | 'V'):
-#endif
- case (WKC_CTRL | 'V'):
- if (_iconsole_cmdline.InsertClipboard()) {
- IConsoleResetHistoryPos();
- this->SetDirty();
- }
- break;
-
case (WKC_CTRL | 'L'):
IConsoleCmdExec("clear");
break;
-#ifdef WITH_COCOA
- case (WKC_META | 'U'):
-#endif
- case (WKC_CTRL | 'U'):
- _iconsole_cmdline.DeleteAll();
- this->SetDirty();
- break;
-
- case WKC_BACKSPACE: case WKC_DELETE:
- if (_iconsole_cmdline.DeleteChar(keycode)) {
- IConsoleResetHistoryPos();
- this->SetDirty();
- }
- break;
-
- case WKC_LEFT: case WKC_RIGHT: case WKC_END: case WKC_HOME:
- if (_iconsole_cmdline.MovePos(keycode)) {
- IConsoleResetHistoryPos();
- this->SetDirty();
- }
- break;
-
default:
- if (IsValidChar(key, CS_ALPHANUMERAL)) {
+ if (_iconsole_cmdline.HandleKeyPress(key, keycode) != HKPR_NOT_HANDLED) {
IConsoleWindow::scroll = 0;
- _iconsole_cmdline.InsertChar(key);
IConsoleResetHistoryPos();
this->SetDirty();
} else {
diff --git a/src/gfx.cpp b/src/gfx.cpp
index e0a7c060fe..b1851f0ebe 100644
--- a/src/gfx.cpp
+++ b/src/gfx.cpp
@@ -639,6 +639,20 @@ Dimension GetStringBoundingBox(StringID strid)
return GetStringBoundingBox(buffer);
}
+/**
+ * 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 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)
+{
+ Layouter layout(str, INT32_MAX, TC_FROMSTRING, start_fontsize);
+ return layout.GetCharPosition(ch);
+}
+
/**
* Draw single character horizontally centered around (x,y)
* @param c Character (glyph) to draw
diff --git a/src/gfx_func.h b/src/gfx_func.h
index 6ec36ee1b1..1226816b4f 100644
--- a/src/gfx_func.h
+++ b/src/gfx_func.h
@@ -126,6 +126,7 @@ int GetStringLineCount(StringID str, int maxw);
Dimension GetStringMultiLineBoundingBox(StringID str, const Dimension &suggestion);
Dimension GetStringMultiLineBoundingBox(const char *str, const Dimension &suggestion);
void LoadStringWidthTable(bool monospace = false);
+Point GetCharPosInString(const char *str, const char *ch, FontSize start_fontsize = FS_NORMAL);
void DrawDirtyBlocks();
void SetDirtyBlocks(int left, int top, int right, int bottom);
diff --git a/src/gfx_layout.cpp b/src/gfx_layout.cpp
index b477093743..165edee3b6 100644
--- a/src/gfx_layout.cpp
+++ b/src/gfx_layout.cpp
@@ -423,7 +423,7 @@ ParagraphLayout *Layouter::GetParagraphLayout(WChar *buff, WChar *buff_end, Font
* @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)
+Layouter::Layouter(const char *str, int maxw, TextColour colour, FontSize fontsize) : string(str)
{
FontState state(colour, fontsize);
WChar c = 0;
@@ -512,6 +512,59 @@ Dimension Layouter::GetBounds()
return d;
}
+/**
+ * Get the position of a character in the layout.
+ * @param ch Character to get the position of.
+ * @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
+{
+ /* 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;
+#ifdef WITH_ICU
+ /* ICU uses UTF-16 internally which means we need to account for surrogate pairs. */
+ index += len < 4 ? 1 : 2;
+#else
+ index++;
+#endif
+ }
+
+ if (str == ch) {
+ /* Valid character. */
+ const ParagraphLayout::Line *line = *this->Begin();
+
+ /* Pointer to the end-of-string/line marker? Return total line width. */
+ if (*ch == '\0' || *ch == '\n') {
+ Point p = { line->getWidth(), 0 };
+ return p;
+ }
+
+ /* Scan all runs until we've found our code point index. */
+ for (int run_index = 0; run_index < line->countRuns(); run_index++) {
+ const ParagraphLayout::VisualRun *run = line->getVisualRun(run_index);
+
+ for (int i = 0; i < run->getGlyphCount(); i++) {
+ /* Matching glyph? Return position. */
+ if ((size_t)run->getGlyphToCharMap()[i] == index) {
+ Point p = { run->getPositions()[i * 2], run->getPositions()[i * 2 + 1] };
+ return p;
+ }
+ }
+ }
+ }
+
+ Point p = { 0, 0 };
+ return p;
+}
+
/**
* Get a static font instance.
*/
diff --git a/src/gfx_layout.h b/src/gfx_layout.h
index c252d15ebd..27c1e9c082 100644
--- a/src/gfx_layout.h
+++ b/src/gfx_layout.h
@@ -168,6 +168,8 @@ class Layouter : public AutoDeleteSmallVector {
typedef WChar CharType; ///< The type of character used within the layouter.
#endif /* WITH_ICU */
+ const char *string; ///< Pointer to the original string.
+
size_t AppendToBuffer(CharType *buff, const CharType *buffer_last, WChar c);
ParagraphLayout *GetParagraphLayout(CharType *buff, CharType *buff_end, FontMap &fontMapping);
@@ -209,6 +211,7 @@ class Layouter : public AutoDeleteSmallVector {
public:
Layouter(const char *str, int maxw = INT32_MAX, TextColour colour = TC_FROMSTRING, FontSize fontsize = FS_NORMAL);
Dimension GetBounds();
+ Point GetCharPosition(const char *ch) const;
static void ResetFontCache(FontSize size);
static void ResetLineCache();
diff --git a/src/misc_gui.cpp b/src/misc_gui.cpp
index 7b763e7839..9cea9f8762 100644
--- a/src/misc_gui.cpp
+++ b/src/misc_gui.cpp
@@ -715,56 +715,6 @@ void GuiShowTooltips(Window *parent, StringID str, uint paramcount, const uint64
new TooltipsWindow(parent, str, paramcount, params, close_tooltip);
}
-HandleEditBoxResult QueryString::HandleEditBoxKey(Window *w, int wid, uint16 key, uint16 keycode, EventState &state)
-{
- if (!w->IsWidgetGloballyFocused(wid)) return HEBR_NOT_FOCUSED;
-
- state = ES_HANDLED;
-
- bool edited = false;
-
- switch (keycode) {
- case WKC_ESC: return HEBR_CANCEL;
-
- case WKC_RETURN: case WKC_NUM_ENTER: return HEBR_CONFIRM;
-
-#ifdef WITH_COCOA
- case (WKC_META | 'V'):
-#endif
- case (WKC_CTRL | 'V'):
- edited = this->text.InsertClipboard();
- break;
-
-#ifdef WITH_COCOA
- case (WKC_META | 'U'):
-#endif
- case (WKC_CTRL | 'U'):
- this->text.DeleteAll();
- edited = true;
- break;
-
- case WKC_BACKSPACE: case WKC_DELETE:
- case WKC_CTRL | WKC_BACKSPACE: case WKC_CTRL | WKC_DELETE:
- edited = this->text.DeleteChar(keycode);
- break;
-
- case WKC_LEFT: case WKC_RIGHT: case WKC_END: case WKC_HOME:
- case WKC_CTRL | WKC_LEFT: case WKC_CTRL | WKC_RIGHT:
- this->text.MovePos(keycode);
- break;
-
- default:
- if (IsValidChar(key, this->text.afilter)) {
- edited = this->text.InsertChar(key);
- } else {
- state = ES_NOT_HANDLED;
- }
- break;
- }
-
- return edited ? HEBR_EDITING : HEBR_CURSOR;
-}
-
void QueryString::HandleEditBox(Window *w, int wid)
{
if (w->IsWidgetGloballyFocused(wid) && this->text.HandleCaret()) {
diff --git a/src/os/macosx/macos.h b/src/os/macosx/macos.h
index d147dfb0b0..16f34a3dc7 100644
--- a/src/os/macosx/macos.h
+++ b/src/os/macosx/macos.h
@@ -12,32 +12,6 @@
#ifndef MACOS_H
#define MACOS_H
-/* It would seem that to ensure backward compability we have to ensure that we have defined MAC_OS_X_VERSION_10_x everywhere */
-#ifndef MAC_OS_X_VERSION_10_3
-#define MAC_OS_X_VERSION_10_3 1030
-#endif
-
-#ifndef MAC_OS_X_VERSION_10_4
-#define MAC_OS_X_VERSION_10_4 1040
-#endif
-
-#ifndef MAC_OS_X_VERSION_10_5
-#define MAC_OS_X_VERSION_10_5 1050
-#endif
-
-#ifndef MAC_OS_X_VERSION_10_6
-#define MAC_OS_X_VERSION_10_6 1060
-#endif
-
-#ifndef MAC_OS_X_VERSION_10_7
-#define MAC_OS_X_VERSION_10_7 1070
-#endif
-
-#ifndef MAC_OS_X_VERSION_10_8
-#define MAC_OS_X_VERSION_10_8 1080
-#endif
-
-
/** Helper function displaying a message the best possible way. */
void ShowMacDialog(const char *title, const char *message, const char *button_label);
diff --git a/src/os/macosx/osx_stdafx.h b/src/os/macosx/osx_stdafx.h
index ad9c5220c1..5adbde1792 100644
--- a/src/os/macosx/osx_stdafx.h
+++ b/src/os/macosx/osx_stdafx.h
@@ -12,6 +12,37 @@
#ifndef MACOS_STDAFX_H
#define MACOS_STDAFX_H
+
+/* It would seem that to ensure backward compability we have to ensure that we have defined MAC_OS_X_VERSION_10_x everywhere */
+#ifndef MAC_OS_X_VERSION_10_3
+#define MAC_OS_X_VERSION_10_3 1030
+#endif
+
+#ifndef MAC_OS_X_VERSION_10_4
+#define MAC_OS_X_VERSION_10_4 1040
+#endif
+
+#ifndef MAC_OS_X_VERSION_10_5
+#define MAC_OS_X_VERSION_10_5 1050
+#endif
+
+#ifndef MAC_OS_X_VERSION_10_6
+#define MAC_OS_X_VERSION_10_6 1060
+#endif
+
+#ifndef MAC_OS_X_VERSION_10_7
+#define MAC_OS_X_VERSION_10_7 1070
+#endif
+
+#ifndef MAC_OS_X_VERSION_10_8
+#define MAC_OS_X_VERSION_10_8 1080
+#endif
+
+#ifndef MAC_OS_X_VERSION_10_9
+#define MAC_OS_X_VERSION_10_9 1090
+#endif
+
+
#define __STDC_LIMIT_MACROS
#include
diff --git a/src/querystring_gui.h b/src/querystring_gui.h
index 6ec93ffd9a..b2c91f3540 100644
--- a/src/querystring_gui.h
+++ b/src/querystring_gui.h
@@ -16,18 +16,6 @@
#include "textbuf_gui.h"
#include "window_gui.h"
-/**
- * Return values for HandleEditBoxKey
- */
-enum HandleEditBoxResult
-{
- HEBR_EDITING, ///< Editbox content changed.
- HEBR_CURSOR, ///< Non-text change, e.g. cursor position.
- HEBR_CONFIRM, ///< Return or enter key pressed.
- HEBR_CANCEL, ///< Escape key pressed.
- HEBR_NOT_FOCUSED, ///< Edit box widget not focused.
-};
-
/**
* Data stored about a string that can be modified in the GUI
*/
@@ -65,7 +53,6 @@ public:
void DrawEditBox(const Window *w, int wid) const;
void ClickEditBox(Window *w, Point pt, int wid, int click_count, bool focus_changed);
void HandleEditBox(Window *w, int wid);
- HandleEditBoxResult HandleEditBoxKey(Window *w, int wid, uint16 key, uint16 keycode, EventState &state);
};
void ShowOnScreenKeyboard(Window *parent, int button);
diff --git a/src/string.cpp b/src/string.cpp
index 39fc8479c9..ada9f9022a 100644
--- a/src/string.cpp
+++ b/src/string.cpp
@@ -14,6 +14,7 @@
#include "core/alloc_func.hpp"
#include "core/math_func.hpp"
#include "string_func.h"
+#include "string_base.h"
#include "table/control_codes.h"
@@ -650,3 +651,258 @@ int strnatcmp(const char *s1, const char *s2, bool ignore_garbage_at_front)
/* Do a normal comparison if ICU is missing or if we cannot create a collator. */
return strcasecmp(s1, s2);
}
+
+#ifdef WITH_ICU
+
+#include
+#include
+
+/** String iterator using ICU as a backend. */
+class IcuStringIterator : public StringIterator
+{
+ icu::BreakIterator *char_itr; ///< ICU iterator for characters.
+ icu::BreakIterator *word_itr; ///< ICU iterator for words.
+ const char *string; ///< Iteration string in UTF-8.
+
+ SmallVector utf16_str; ///< UTF-16 copy of the string.
+ SmallVector utf16_to_utf8; ///< Mapping from UTF-16 code point position to index in the UTF-8 source string.
+
+public:
+ IcuStringIterator() : char_itr(NULL), word_itr(NULL)
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ this->char_itr = icu::BreakIterator::createCharacterInstance(icu::Locale(_current_language != NULL ? _current_language->isocode : "en"), status);
+ this->word_itr = icu::BreakIterator::createWordInstance(icu::Locale(_current_language != NULL ? _current_language->isocode : "en"), status);
+
+ *this->utf16_str.Append() = '\0';
+ *this->utf16_to_utf8.Append() = 0;
+ }
+
+ virtual ~IcuStringIterator()
+ {
+ delete this->char_itr;
+ delete this->word_itr;
+ }
+
+ virtual void SetString(const char *s)
+ {
+ this->string = s;
+
+ /* Unfortunately current ICU versions only provide rudimentary support
+ * for word break iterators (especially for CJK languages) in combination
+ * with UTF-8 input. As a work around we have to convert the input to
+ * UTF-16 and create a mapping back to UTF-8 character indices. */
+ this->utf16_str.Clear();
+ this->utf16_to_utf8.Clear();
+
+ while (*s != '\0') {
+ size_t idx = s - this->string;
+
+ WChar c = Utf8Consume(&s);
+ if (c < 0x10000) {
+ *this->utf16_str.Append() = (UChar)c;
+ } else {
+ /* Make a surrogate pair. */
+ *this->utf16_str.Append() = (UChar)(0xD800 + ((c - 0x10000) >> 10));
+ *this->utf16_str.Append() = (UChar)(0xDC00 + ((c - 0x10000) & 0x3FF));
+ *this->utf16_to_utf8.Append() = idx;
+ }
+ *this->utf16_to_utf8.Append() = idx;
+ }
+ *this->utf16_str.Append() = '\0';
+ *this->utf16_to_utf8.Append() = s - this->string;
+
+ UText text = UTEXT_INITIALIZER;
+ UErrorCode status = U_ZERO_ERROR;
+ utext_openUChars(&text, this->utf16_str.Begin(), this->utf16_str.Length() - 1, &status);
+ this->char_itr->setText(&text, status);
+ this->word_itr->setText(&text, status);
+ this->char_itr->first();
+ this->word_itr->first();
+ }
+
+ virtual size_t SetCurPosition(size_t pos)
+ {
+ /* Convert incoming position to an UTF-16 string index. */
+ uint utf16_pos = 0;
+ for (uint i = 0; i < this->utf16_to_utf8.Length(); i++) {
+ if (this->utf16_to_utf8[i] == pos) {
+ utf16_pos = i;
+ break;
+ }
+ }
+
+ /* isBoundary has the documented side-effect of setting the current
+ * position to the first valid boundary equal to or greater than
+ * the passed value. */
+ this->char_itr->isBoundary(utf16_pos);
+ return this->utf16_to_utf8[this->char_itr->current()];
+ }
+
+ virtual size_t Next(IterType what)
+ {
+ int32_t pos;
+ switch (what) {
+ case ITER_CHARACTER:
+ pos = this->char_itr->next();
+ break;
+
+ case ITER_WORD:
+ pos = this->word_itr->following(this->char_itr->current());
+ /* The ICU word iterator considers both the start and the end of a word a valid
+ * break point, but we only want word starts. Move to the next location in
+ * case the new position points to whitespace. */
+ while (pos != icu::BreakIterator::DONE && IsWhitespace(Utf16DecodeChar((const uint16 *)&this->utf16_str[pos]))) pos = this->word_itr->next();
+
+ this->char_itr->isBoundary(pos);
+ break;
+
+ default:
+ NOT_REACHED();
+ }
+
+ return pos == icu::BreakIterator::DONE ? END : this->utf16_to_utf8[pos];
+ }
+
+ virtual size_t Prev(IterType what)
+ {
+ int32_t pos;
+ switch (what) {
+ case ITER_CHARACTER:
+ pos = this->char_itr->previous();
+ break;
+
+ case ITER_WORD:
+ pos = this->word_itr->preceding(this->char_itr->current());
+ /* The ICU word iterator considers both the start and the end of a word a valid
+ * break point, but we only want word starts. Move to the previous location in
+ * case the new position points to whitespace. */
+ while (pos != icu::BreakIterator::DONE && IsWhitespace(Utf16DecodeChar((const uint16 *)&this->utf16_str[pos]))) pos = this->word_itr->previous();
+
+ this->char_itr->isBoundary(pos);
+ break;
+
+ default:
+ NOT_REACHED();
+ }
+
+ return pos == icu::BreakIterator::DONE ? END : this->utf16_to_utf8[pos];
+ }
+};
+
+/* static */ StringIterator *StringIterator::Create()
+{
+ return new IcuStringIterator();
+}
+
+#else
+
+/** Fallback simple string iterator. */
+class DefaultStringIterator : public StringIterator
+{
+ const char *string; ///< Current string.
+ size_t len; ///< String length.
+ size_t cur_pos; ///< Current iteration position.
+
+public:
+ DefaultStringIterator() : string(NULL)
+ {
+ }
+
+ virtual void SetString(const char *s)
+ {
+ this->string = s;
+ this->len = strlen(s);
+ this->cur_pos = 0;
+ }
+
+ virtual size_t SetCurPosition(size_t pos)
+ {
+ assert(this->string != NULL && pos <= this->len);
+ /* Sanitize in case we get a position inside an UTF-8 sequence. */
+ while (pos > 0 && IsUtf8Part(this->string[pos])) pos--;
+ return this->cur_pos = pos;
+ }
+
+ virtual size_t Next(IterType what)
+ {
+ assert(this->string != NULL);
+
+ /* Already at the end? */
+ if (this->cur_pos >= this->len) return END;
+
+ switch (what) {
+ case ITER_CHARACTER: {
+ WChar c;
+ this->cur_pos += Utf8Decode(&c, this->string + this->cur_pos);
+ return this->cur_pos;
+ }
+
+ case ITER_WORD: {
+ WChar c;
+ /* Consume current word. */
+ size_t offs = Utf8Decode(&c, this->string + this->cur_pos);
+ while (this->cur_pos < this->len && !IsWhitespace(c)) {
+ this->cur_pos += offs;
+ offs = Utf8Decode(&c, this->string + this->cur_pos);
+ }
+ /* Consume whitespace to the next word. */
+ while (this->cur_pos < this->len && IsWhitespace(c)) {
+ this->cur_pos += offs;
+ offs = Utf8Decode(&c, this->string + this->cur_pos);
+ }
+
+ return this->cur_pos;
+ }
+
+ default:
+ NOT_REACHED();
+ }
+
+ return END;
+ }
+
+ virtual size_t Prev(IterType what)
+ {
+ assert(this->string != NULL);
+
+ /* Already at the beginning? */
+ if (this->cur_pos == 0) return END;
+
+ switch (what) {
+ case ITER_CHARACTER:
+ return this->cur_pos = Utf8PrevChar(this->string + this->cur_pos) - this->string;
+
+ case ITER_WORD: {
+ const char *s = this->string + this->cur_pos;
+ WChar c;
+ /* Consume preceding whitespace. */
+ do {
+ s = Utf8PrevChar(s);
+ Utf8Decode(&c, s);
+ } while (s > this->string && IsWhitespace(c));
+ /* Consume preceding word. */
+ while (s > this->string && !IsWhitespace(c)) {
+ s = Utf8PrevChar(s);
+ Utf8Decode(&c, s);
+ }
+ /* Move caret back to the beginning of the word. */
+ if (IsWhitespace(c)) Utf8Consume(&s);
+
+ return this->cur_pos = s - this->string;
+ }
+
+ default:
+ NOT_REACHED();
+ }
+
+ return END;
+ }
+};
+
+/* static */ StringIterator *StringIterator::Create()
+{
+ return new DefaultStringIterator();
+}
+
+#endif
diff --git a/src/string_base.h b/src/string_base.h
new file mode 100644
index 0000000000..e1eaed3496
--- /dev/null
+++ b/src/string_base.h
@@ -0,0 +1,66 @@
+/* $Id$ */
+
+/*
+ * This file is part of OpenTTD.
+ * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
+ * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see .
+ */
+
+#ifndef STRING_BASE_H
+#define STRING_BASE_H
+
+#include "string_type.h"
+
+/** Class for iterating over different kind of parts of a string. */
+class StringIterator {
+public:
+ /** Type of the iterator. */
+ enum IterType {
+ ITER_CHARACTER, ///< Iterate over characters (or more exactly grapheme clusters).
+ ITER_WORD, ///< Iterate over words.
+ };
+
+ /** Sentinel to indicate end-of-iteration. */
+ static const size_t END = SIZE_MAX;
+
+ /**
+ * Create a new iterator instance.
+ * @return New iterator instance.
+ */
+ static StringIterator *Create();
+
+ virtual ~StringIterator() {}
+
+ /**
+ * Set a new iteration string. Must also be called if the string contents
+ * changed. The cursor is reset to the start of the string.
+ * @param s New string.
+ */
+ virtual void SetString(const char *s) = 0;
+
+ /**
+ * Change the current string cursor.
+ * @param p New cursor position.
+ * @return Actual new cursor position at the next valid character boundary.
+ * @pre p has to be inside the current string.
+ */
+ virtual size_t SetCurPosition(size_t pos) = 0;
+
+ /**
+ * Advance the cursor by one iteration unit.
+ * @return New cursor position (in bytes) or #END if the cursor is already at the end of the string.
+ */
+ virtual size_t Next(IterType what = ITER_CHARACTER) = 0;
+
+ /**
+ * Move the cursor back by one iteration unit.
+ * @return New cursor position (in bytes) or #END if the cursor is already at the start of the string.
+ */
+ virtual size_t Prev(IterType what = ITER_CHARACTER) = 0;
+
+protected:
+ StringIterator() {}
+};
+
+#endif /* STRING_BASE_H */
diff --git a/src/string_func.h b/src/string_func.h
index 25608889dd..d7056f1be1 100644
--- a/src/string_func.h
+++ b/src/string_func.h
@@ -90,7 +90,6 @@ static inline WChar Utf8Consume(const char **s)
return c;
}
-
/**
* Return the length of a UTF-8 encoded character.
* @param c Unicode character.
@@ -147,8 +146,60 @@ static inline char *Utf8PrevChar(char *s)
return ret;
}
+static inline const char *Utf8PrevChar(const char *s)
+{
+ const char *ret = s;
+ while (IsUtf8Part(*--ret)) {}
+ return ret;
+}
+
size_t Utf8StringLength(const char *s);
+/**
+ * Is the given character a lead surrogate code point?
+ * @param c The character to test.
+ * @return True if the character is a lead surrogate code point.
+ */
+static inline bool Utf16IsLeadSurrogate(uint c)
+{
+ return c >= 0xD800 && c <= 0xDBFF;
+}
+
+/**
+ * Is the given character a lead surrogate code point?
+ * @param c The character to test.
+ * @return True if the character is a lead surrogate code point.
+ */
+static inline bool Utf16IsTrailSurrogate(uint c)
+{
+ return c >= 0xDC00 && c <= 0xDFFF;
+}
+
+/**
+ * Convert an UTF-16 surrogate pair to the corresponding Unicode character.
+ * @param lead Lead surrogate code point.
+ * @param trail Trail surrogate code point.
+ * @return Decoded Unicode character.
+ */
+static inline WChar Utf16DecodeSurrogate(uint lead, uint trail)
+{
+ return 0x10000 + (((lead - 0xD800) << 10) | (trail - 0xDC00));
+}
+
+/**
+ * Decode an UTF-16 character.
+ * @param c Pointer to one or two UTF-16 code points.
+ * @return Decoded Unicode character.
+ */
+static inline WChar Utf16DecodeChar(const uint16 *c)
+{
+ if (Utf16IsLeadSurrogate(c[0])) {
+ return Utf16DecodeSurrogate(c[0], c[1]);
+ } else {
+ return *c;
+ }
+}
+
/**
* Is the given character a text direction character.
* @param c The character to test.
diff --git a/src/textbuf.cpp b/src/textbuf.cpp
index f38bfd17b2..c7071565ab 100644
--- a/src/textbuf.cpp
+++ b/src/textbuf.cpp
@@ -43,101 +43,68 @@ bool Textbuf::CanDelChar(bool backspace)
}
/**
- * Get the next character that will be removed by DelChar.
- * @param backspace if set, delete the character before the caret,
- * otherwise, delete the character after it.
- * @return the next character that will be removed by DelChar.
- * @warning You should ensure Textbuf::CanDelChar returns true before calling this function.
+ * Delete a character from a textbuffer, either with 'Delete' or 'Backspace'
+ * The character is delete from the position the caret is at
+ * @param keycode Type of deletion, either WKC_BACKSPACE or WKC_DELETE
+ * @return Return true on successful change of Textbuf, or false otherwise
*/
-WChar Textbuf::GetNextDelChar(bool backspace)
+bool Textbuf::DeleteChar(uint16 keycode)
{
- assert(this->CanDelChar(backspace));
+ bool word = (keycode & WKC_CTRL) != 0;
- const char *s;
- if (backspace) {
- s = Utf8PrevChar(this->buf + this->caretpos);
- } else {
- s = this->buf + this->caretpos;
- }
+ keycode &= ~WKC_SPECIAL_KEYS;
+ if (keycode != WKC_BACKSPACE && keycode != WKC_DELETE) return false;
- WChar c;
- Utf8Decode(&c, s);
- return c;
-}
+ bool backspace = keycode == WKC_BACKSPACE;
-/**
- * Delete a character at the caret position in a text buf.
- * @param backspace if set, delete the character before the caret,
- * else delete the character after it.
- * @warning You should ensure Textbuf::CanDelChar returns true before calling this function.
- */
-void Textbuf::DelChar(bool backspace)
-{
- assert(this->CanDelChar(backspace));
+ if (!CanDelChar(backspace)) return false;
- WChar c;
char *s = this->buf + this->caretpos;
+ uint16 len = 0;
- if (backspace) s = Utf8PrevChar(s);
-
- uint16 len = (uint16)Utf8Decode(&c, s);
- uint width = GetCharacterWidth(FS_NORMAL, c);
-
- this->pixels -= width;
- if (backspace) {
- this->caretpos -= len;
- this->caretxoffs -= width;
+ if (word) {
+ /* Delete a complete word. */
+ if (backspace) {
+ /* Delete whitespace and word in front of the caret. */
+ len = this->caretpos - (uint16)this->char_iter->Prev(StringIterator::ITER_WORD);
+ s -= len;
+ } else {
+ /* Delete word and following whitespace following the caret. */
+ len = (uint16)this->char_iter->Next(StringIterator::ITER_WORD) - this->caretpos;
+ }
+ /* Update character count. */
+ for (const char *ss = s; ss < s + len; Utf8Consume(&ss)) {
+ this->chars--;
+ }
+ } else {
+ /* Delete a single character. */
+ if (backspace) {
+ /* Delete the last code point in front of the caret. */
+ s = Utf8PrevChar(s);
+ WChar c;
+ len = (uint16)Utf8Decode(&c, s);
+ this->chars--;
+ } else {
+ /* Delete the complete character following the caret. */
+ len = (uint16)this->char_iter->Next(StringIterator::ITER_CHARACTER) - this->caretpos;
+ /* Update character count. */
+ for (const char *ss = s; ss < s + len; Utf8Consume(&ss)) {
+ this->chars--;
+ }
+ }
}
/* Move the remaining characters over the marker */
memmove(s, s + len, this->bytes - (s - this->buf) - len);
this->bytes -= len;
- this->chars--;
-}
-/**
- * Delete a character from a textbuffer, either with 'Delete' or 'Backspace'
- * The character is delete from the position the caret is at
- * @param delmode Type of deletion, either WKC_BACKSPACE or WKC_DELETE
- * @return Return true on successful change of Textbuf, or false otherwise
- */
-bool Textbuf::DeleteChar(int delmode)
-{
- if (delmode == WKC_BACKSPACE || delmode == WKC_DELETE) {
- bool backspace = delmode == WKC_BACKSPACE;
- if (CanDelChar(backspace)) {
- this->DelChar(backspace);
- return true;
- }
- return false;
- }
+ if (backspace) this->caretpos -= len;
- if (delmode == (WKC_CTRL | WKC_BACKSPACE) || delmode == (WKC_CTRL | WKC_DELETE)) {
- bool backspace = delmode == (WKC_CTRL | WKC_BACKSPACE);
+ this->UpdateStringIter();
+ this->UpdateWidth();
+ this->UpdateCaretPosition();
- if (!CanDelChar(backspace)) return false;
- WChar c = this->GetNextDelChar(backspace);
-
- /* Backspace: Delete left whitespaces.
- * Delete: Delete right word.
- */
- while (backspace ? IsWhitespace(c) : !IsWhitespace(c)) {
- this->DelChar(backspace);
- if (!this->CanDelChar(backspace)) return true;
- c = this->GetNextDelChar(backspace);
- }
- /* Backspace: Delete left word.
- * Delete: Delete right whitespaces.
- */
- while (backspace ? !IsWhitespace(c) : IsWhitespace(c)) {
- this->DelChar(backspace);
- if (!this->CanDelChar(backspace)) return true;
- c = this->GetNextDelChar(backspace);
- }
- return true;
- }
-
- return false;
+ return true;
}
/**
@@ -148,6 +115,7 @@ void Textbuf::DeleteAll()
memset(this->buf, 0, this->max_bytes);
this->bytes = this->chars = 1;
this->pixels = this->caretpos = this->caretxoffs = 0;
+ this->UpdateStringIter();
}
/**
@@ -159,17 +127,17 @@ void Textbuf::DeleteAll()
*/
bool Textbuf::InsertChar(WChar key)
{
- const byte charwidth = GetCharacterWidth(FS_NORMAL, key);
uint16 len = (uint16)Utf8CharLen(key);
if (this->bytes + len <= this->max_bytes && this->chars + 1 <= this->max_chars) {
memmove(this->buf + this->caretpos + len, this->buf + this->caretpos, this->bytes - this->caretpos);
Utf8Encode(this->buf + this->caretpos, key);
this->chars++;
- this->bytes += len;
- this->pixels += charwidth;
+ this->bytes += len;
+ this->caretpos += len;
- this->caretpos += len;
- this->caretxoffs += charwidth;
+ this->UpdateStringIter();
+ this->UpdateWidth();
+ this->UpdateCaretPosition();
return true;
}
return false;
@@ -187,7 +155,7 @@ bool Textbuf::InsertClipboard()
if (!GetClipboardContents(utf8_buf, lengthof(utf8_buf))) return false;
- uint16 pixels = 0, bytes = 0, chars = 0;
+ uint16 bytes = 0, chars = 0;
WChar c;
for (const char *ptr = utf8_buf; (c = Utf8Consume(&ptr)) != '\0';) {
if (!IsValidChar(c, this->afilter)) break;
@@ -196,9 +164,6 @@ bool Textbuf::InsertClipboard()
if (this->bytes + bytes + len > this->max_bytes) break;
if (this->chars + chars + 1 > this->max_chars) break;
- byte char_pixels = GetCharacterWidth(FS_NORMAL, c);
-
- pixels += char_pixels;
bytes += len;
chars++;
}
@@ -207,8 +172,6 @@ bool Textbuf::InsertClipboard()
memmove(this->buf + this->caretpos + bytes, this->buf + this->caretpos, this->bytes - this->caretpos);
memcpy(this->buf + this->caretpos, utf8_buf, bytes);
- this->pixels += pixels;
- this->caretxoffs += pixels;
this->bytes += bytes;
this->chars += chars;
@@ -217,131 +180,76 @@ bool Textbuf::InsertClipboard()
assert(this->chars <= this->max_chars);
this->buf[this->bytes - 1] = '\0'; // terminating zero
+ this->UpdateStringIter();
+ this->UpdateWidth();
+ this->UpdateCaretPosition();
+
return true;
}
-/**
- * Checks if it is possible to move caret to the left
- * @return true if the caret can be moved to the left, otherwise false.
- */
-bool Textbuf::CanMoveCaretLeft()
+/** Update the character iter after the text has changed. */
+void Textbuf::UpdateStringIter()
{
- return this->caretpos != 0;
+ this->char_iter->SetString(this->buf);
+ size_t pos = this->char_iter->SetCurPosition(this->caretpos);
+ this->caretpos = pos == StringIterator::END ? 0 : (uint16)pos;
}
-/**
- * Moves the caret to the left.
- * @pre Ensure that Textbuf::CanMoveCaretLeft returns true
- * @return The character under the caret.
- */
-WChar Textbuf::MoveCaretLeft()
+/** Update pixel width of the text. */
+void Textbuf::UpdateWidth()
{
- assert(this->CanMoveCaretLeft());
-
- WChar c;
- const char *s = Utf8PrevChar(this->buf + this->caretpos);
- Utf8Decode(&c, s);
- this->caretpos = s - this->buf;
- this->caretxoffs -= GetCharacterWidth(FS_NORMAL, c);
-
- return c;
+ this->pixels = GetStringBoundingBox(this->buf, FS_NORMAL).width;
}
-/**
- * Checks if it is possible to move caret to the right
- * @return true if the caret can be moved to the right, otherwise false.
- */
-bool Textbuf::CanMoveCaretRight()
+/** Update pixel position of the caret. */
+void Textbuf::UpdateCaretPosition()
{
- return this->caretpos < this->bytes - 1;
-}
-
-/**
- * Moves the caret to the right.
- * @pre Ensure that Textbuf::CanMoveCaretRight returns true
- * @return The character under the caret.
- */
-WChar Textbuf::MoveCaretRight()
-{
- assert(this->CanMoveCaretRight());
-
- WChar c;
- this->caretpos += (uint16)Utf8Decode(&c, this->buf + this->caretpos);
- this->caretxoffs += GetCharacterWidth(FS_NORMAL, c);
-
- Utf8Decode(&c, this->buf + this->caretpos);
- return c;
+ this->caretxoffs = this->chars > 1 ? GetCharPosInString(this->buf, this->buf + this->caretpos, FS_NORMAL).x : 0;
}
/**
* Handle text navigation with arrow keys left/right.
* This defines where the caret will blink and the next character interaction will occur
- * @param navmode Direction in which navigation occurs (WKC_CTRL |) WKC_LEFT, (WKC_CTRL |) WKC_RIGHT, WKC_END, WKC_HOME
+ * @param keycode Direction in which navigation occurs (WKC_CTRL |) WKC_LEFT, (WKC_CTRL |) WKC_RIGHT, WKC_END, WKC_HOME
* @return Return true on successful change of Textbuf, or false otherwise
*/
-bool Textbuf::MovePos(int navmode)
+bool Textbuf::MovePos(uint16 keycode)
{
- switch (navmode) {
+ switch (keycode) {
case WKC_LEFT:
- if (this->CanMoveCaretLeft()) {
- this->MoveCaretLeft();
- return true;
- }
- break;
-
case WKC_CTRL | WKC_LEFT: {
- if (!this->CanMoveCaretLeft()) break;
+ if (this->caretpos == 0) break;
- /* Unconditionally move one char to the left. */
- WChar c = this->MoveCaretLeft();
- /* Consume left whitespaces. */
- while (IsWhitespace(c)) {
- if (!this->CanMoveCaretLeft()) return true;
- c = this->MoveCaretLeft();
- }
- /* Consume left word. */
- while (!IsWhitespace(c)) {
- if (!this->CanMoveCaretLeft()) return true;
- c = this->MoveCaretLeft();
- }
- /* Place caret at the beginning of the left word. */
- this->MoveCaretRight();
+ size_t pos = this->char_iter->Prev(keycode & WKC_CTRL ? StringIterator::ITER_WORD : StringIterator::ITER_CHARACTER);
+ if (pos == StringIterator::END) return true;
+
+ this->caretpos = (uint16)pos;
+ this->UpdateCaretPosition();
return true;
}
case WKC_RIGHT:
- if (this->CanMoveCaretRight()) {
- this->MoveCaretRight();
- return true;
- }
- break;
-
case WKC_CTRL | WKC_RIGHT: {
- if (!this->CanMoveCaretRight()) break;
+ if (this->caretpos >= this->bytes - 1) break;
- /* Unconditionally move one char to the right. */
- WChar c = this->MoveCaretRight();
- /* Continue to consume current word. */
- while (!IsWhitespace(c)) {
- if (!this->CanMoveCaretRight()) return true;
- c = this->MoveCaretRight();
- }
- /* Consume right whitespaces. */
- while (IsWhitespace(c)) {
- if (!this->CanMoveCaretRight()) return true;
- c = this->MoveCaretRight();
- }
+ size_t pos = this->char_iter->Next(keycode & WKC_CTRL ? StringIterator::ITER_WORD : StringIterator::ITER_CHARACTER);
+ if (pos == StringIterator::END) return true;
+
+ this->caretpos = (uint16)pos;
+ this->UpdateCaretPosition();
return true;
}
case WKC_HOME:
this->caretpos = 0;
- this->caretxoffs = 0;
+ this->char_iter->SetCurPosition(this->caretpos);
+ this->UpdateCaretPosition();
return true;
case WKC_END:
this->caretpos = this->bytes - 1;
- this->caretxoffs = this->pixels;
+ this->char_iter->SetCurPosition(this->caretpos);
+ this->UpdateCaretPosition();
return true;
default:
@@ -364,6 +272,8 @@ Textbuf::Textbuf(uint16 max_bytes, uint16 max_chars)
assert(max_bytes != 0);
assert(max_chars != 0);
+ this->char_iter = StringIterator::Create();
+
this->afilter = CS_ALPHANUMERAL;
this->max_bytes = max_bytes;
this->max_chars = max_chars == UINT16_MAX ? max_bytes : max_chars;
@@ -373,6 +283,7 @@ Textbuf::Textbuf(uint16 max_bytes, uint16 max_chars)
Textbuf::~Textbuf()
{
+ delete this->char_iter;
free(this->buf);
}
@@ -418,21 +329,21 @@ void Textbuf::UpdateSize()
{
const char *buf = this->buf;
- this->pixels = 0;
this->chars = this->bytes = 1; // terminating zero
WChar c;
while ((c = Utf8Consume(&buf)) != '\0') {
- this->pixels += GetCharacterWidth(FS_NORMAL, c);
this->bytes += Utf8CharLen(c);
this->chars++;
}
-
assert(this->bytes <= this->max_bytes);
assert(this->chars <= this->max_chars);
this->caretpos = this->bytes - 1;
- this->caretxoffs = this->pixels;
+ this->UpdateStringIter();
+ this->UpdateWidth();
+
+ this->UpdateCaretPosition();
}
/**
@@ -450,3 +361,49 @@ bool Textbuf::HandleCaret()
}
return false;
}
+
+HandleKeyPressResult Textbuf::HandleKeyPress(uint16 key, uint16 keycode)
+{
+ bool edited = false;
+
+ switch (keycode) {
+ case WKC_ESC: return HKPR_CANCEL;
+
+ case WKC_RETURN: case WKC_NUM_ENTER: return HKPR_CONFIRM;
+
+#ifdef WITH_COCOA
+ case (WKC_META | 'V'):
+#endif
+ case (WKC_CTRL | 'V'):
+ edited = this->InsertClipboard();
+ break;
+
+#ifdef WITH_COCOA
+ case (WKC_META | 'U'):
+#endif
+ case (WKC_CTRL | 'U'):
+ this->DeleteAll();
+ edited = true;
+ break;
+
+ case WKC_BACKSPACE: case WKC_DELETE:
+ case WKC_CTRL | WKC_BACKSPACE: case WKC_CTRL | WKC_DELETE:
+ edited = this->DeleteChar(keycode);
+ break;
+
+ case WKC_LEFT: case WKC_RIGHT: case WKC_END: case WKC_HOME:
+ case WKC_CTRL | WKC_LEFT: case WKC_CTRL | WKC_RIGHT:
+ this->MovePos(keycode);
+ break;
+
+ default:
+ if (IsValidChar(key, this->afilter)) {
+ edited = this->InsertChar(key);
+ } else {
+ return HKPR_NOT_HANDLED;
+ }
+ break;
+ }
+
+ return edited ? HKPR_EDITING : HKPR_CURSOR;
+}
diff --git a/src/textbuf_type.h b/src/textbuf_type.h
index 2582d1e252..4d1a926fbe 100644
--- a/src/textbuf_type.h
+++ b/src/textbuf_type.h
@@ -14,6 +14,19 @@
#include "string_type.h"
#include "strings_type.h"
+#include "string_base.h"
+
+/**
+ * Return values for Textbuf::HandleKeypress
+ */
+enum HandleKeyPressResult
+{
+ HKPR_EDITING, ///< Textbuf content changed.
+ HKPR_CURSOR, ///< Non-text change, e.g. cursor position.
+ HKPR_CONFIRM, ///< Return or enter key pressed.
+ HKPR_CANCEL, ///< Escape key pressed.
+ HKPR_NOT_HANDLED, ///< Key does not affect editboxes.
+};
/** Helper/buffer for input fields. */
struct Textbuf {
@@ -36,23 +49,26 @@ struct Textbuf {
void CDECL Print(const char *format, ...) WARN_FORMAT(2, 3);
void DeleteAll();
- bool DeleteChar(int delmode);
- bool InsertChar(uint32 key);
bool InsertClipboard();
- bool MovePos(int navmode);
+
+ bool InsertChar(uint32 key);
+
+ bool DeleteChar(uint16 keycode);
+ bool MovePos(uint16 keycode);
+
+ HandleKeyPressResult HandleKeyPress(uint16 key, uint16 keycode);
bool HandleCaret();
void UpdateSize();
private:
- bool CanDelChar(bool backspace);
- WChar GetNextDelChar(bool backspace);
- void DelChar(bool backspace);
- bool CanMoveCaretLeft();
- WChar MoveCaretLeft();
- bool CanMoveCaretRight();
- WChar MoveCaretRight();
+ StringIterator *char_iter;
+ bool CanDelChar(bool backspace);
+
+ void UpdateStringIter();
+ void UpdateWidth();
+ void UpdateCaretPosition();
};
#endif /* TEXTBUF_TYPE_H */
diff --git a/src/video/cocoa/cocoa_v.h b/src/video/cocoa/cocoa_v.h
index 9f7f55c7ce..06bbbfdb2a 100644
--- a/src/video/cocoa/cocoa_v.h
+++ b/src/video/cocoa/cocoa_v.h
@@ -253,6 +253,7 @@ uint QZ_ListModes(OTTD_Point *modes, uint max_modes, CGDirectDisplayID display_i
- (void)setDriver:(CocoaSubdriver*)drv;
- (BOOL)windowShouldClose:(id)sender;
+- (void)windowDidEnterFullScreen:(NSNotification *)aNotification;
@end
diff --git a/src/video/cocoa/cocoa_v.mm b/src/video/cocoa/cocoa_v.mm
index 9e883928bc..ca81715b18 100644
--- a/src/video/cocoa/cocoa_v.mm
+++ b/src/video/cocoa/cocoa_v.mm
@@ -776,6 +776,14 @@ void cocoaReleaseAutoreleasePool()
{
driver->active = false;
}
+/** Window entered fullscreen mode (10.7). */
+- (void)windowDidEnterFullScreen:(NSNotification *)aNotification
+{
+ NSPoint loc = [ driver->cocoaview convertPoint:[ [ aNotification object ] mouseLocationOutsideOfEventStream ] fromView:nil ];
+ BOOL inside = ([ driver->cocoaview hitTest:loc ] == driver->cocoaview);
+
+ if (inside) [ driver->cocoaview mouseEntered:NULL ];
+}
@end
diff --git a/src/video/cocoa/wnd_quartz.mm b/src/video/cocoa/wnd_quartz.mm
index 5d45dcbab3..8033840052 100644
--- a/src/video/cocoa/wnd_quartz.mm
+++ b/src/video/cocoa/wnd_quartz.mm
@@ -290,16 +290,15 @@ bool WindowQuartzSubdriver::SetVideoMode(int width, int height, int bpp)
const int NSWindowCollectionBehaviorFullScreenPrimary = 1 << 7;
const int NSWindowFullScreenButton = 7;
- NSWindowCollectionBehavior behavior = [this->window collectionBehavior];
+ NSWindowCollectionBehavior behavior = [ this->window collectionBehavior ];
behavior |= NSWindowCollectionBehaviorFullScreenPrimary;
- [window setCollectionBehavior:behavior];
+ [ this->window setCollectionBehavior:behavior ];
- NSButton* fullscreenButton =
- [this->window standardWindowButton:NSWindowFullScreenButton];
- [fullscreenButton setAction:@selector(toggleFullScreen:)];
- [fullscreenButton setTarget:this->window];
+ NSButton* fullscreenButton = [ this->window standardWindowButton:NSWindowFullScreenButton ];
+ [ fullscreenButton setAction:@selector(toggleFullScreen:) ];
+ [ fullscreenButton setTarget:this->window ];
- [this->window setCollectionBehavior: NSWindowCollectionBehaviorFullScreenPrimary];
+ [ this->window setCollectionBehavior: NSWindowCollectionBehaviorFullScreenPrimary ];
}
#endif
diff --git a/src/window.cpp b/src/window.cpp
index f818471bd1..d223f5cfd6 100644
--- a/src/window.cpp
+++ b/src/window.cpp
@@ -2250,26 +2250,24 @@ static bool MaybeBringWindowToFront(Window *w)
*/
EventState Window::HandleEditBoxKey(int wid, uint16 key, uint16 keycode)
{
- EventState state = ES_NOT_HANDLED;
-
QueryString *query = this->GetQueryString(wid);
- if (query == NULL) return state;
+ if (query == NULL) return ES_NOT_HANDLED;
int action = QueryString::ACTION_NOTHING;
- switch (query->HandleEditBoxKey(this, wid, key, keycode, state)) {
- case HEBR_EDITING:
+ switch (query->text.HandleKeyPress(key, keycode)) {
+ case HKPR_EDITING:
this->SetWidgetDirty(wid);
this->OnEditboxChanged(wid);
break;
- case HEBR_CURSOR:
+ case HKPR_CURSOR:
this->SetWidgetDirty(wid);
/* For the OSK also invalidate the parent window */
if (this->window_class == WC_OSK) this->InvalidateData();
break;
- case HEBR_CONFIRM:
+ case HKPR_CONFIRM:
if (this->window_class == WC_OSK) {
this->OnClick(Point(), WID_OSK_OK, 1);
} else if (query->ok_button >= 0) {
@@ -2279,7 +2277,7 @@ EventState Window::HandleEditBoxKey(int wid, uint16 key, uint16 keycode)
}
break;
- case HEBR_CANCEL:
+ case HKPR_CANCEL:
if (this->window_class == WC_OSK) {
this->OnClick(Point(), WID_OSK_CANCEL, 1);
} else if (query->cancel_button >= 0) {
@@ -2289,6 +2287,9 @@ EventState Window::HandleEditBoxKey(int wid, uint16 key, uint16 keycode)
}
break;
+ case HKPR_NOT_HANDLED:
+ return ES_NOT_HANDLED;
+
default: break;
}
@@ -2307,7 +2308,7 @@ EventState Window::HandleEditBoxKey(int wid, uint16 key, uint16 keycode)
break;
}
- return state;
+ return ES_HANDLED;
}
/**