diff options
-rw-r--r-- | src/console_gui.cpp | 8 | ||||
-rw-r--r-- | src/misc_gui.cpp | 28 | ||||
-rw-r--r-- | src/querystring_gui.h | 2 | ||||
-rw-r--r-- | src/video/win32_v.cpp | 32 | ||||
-rw-r--r-- | src/window.cpp | 14 | ||||
-rw-r--r-- | src/window_func.h | 2 | ||||
-rw-r--r-- | src/window_gui.h | 2 |
7 files changed, 88 insertions, 0 deletions
diff --git a/src/console_gui.cpp b/src/console_gui.cpp index 0cc2f670e..772ead610 100644 --- a/src/console_gui.cpp +++ b/src/console_gui.cpp @@ -317,6 +317,14 @@ struct IConsoleWindow : Window } } + virtual Point GetCaretPosition() const + { + int delta = min(this->width - this->line_offset - _iconsole_cmdline.pixels - ICON_RIGHT_BORDERWIDTH, 0); + Point pt = {this->line_offset + delta + _iconsole_cmdline.caretxoffs, this->height - this->line_height}; + + return pt; + } + virtual void OnMouseWheel(int wheel) { this->Scroll(-wheel); diff --git a/src/misc_gui.cpp b/src/misc_gui.cpp index 87847ba70..37a317733 100644 --- a/src/misc_gui.cpp +++ b/src/misc_gui.cpp @@ -785,6 +785,34 @@ void QueryString::DrawEditBox(const Window *w, int wid) const _cur_dpi = old_dpi; } +/** + * Get the current caret position. + * @param w Window the edit box is in. + * @param wid Widget index. + * @return Top-left location of the caret, relative to the window. + */ +Point QueryString::GetCaretPosition(const Window *w, int wid) const +{ + const NWidgetLeaf *wi = w->GetWidget<NWidgetLeaf>(wid); + + assert((wi->type & WWT_MASK) == WWT_EDITBOX); + + bool rtl = _current_text_dir == TD_RTL; + Dimension sprite_size = GetSpriteSize(rtl ? SPR_IMG_DELETE_RIGHT : SPR_IMG_DELETE_LEFT); + int clearbtn_width = sprite_size.width + WD_IMGBTN_LEFT + WD_IMGBTN_RIGHT; + + int left = wi->pos_x + (rtl ? clearbtn_width : 0); + int right = wi->pos_x + (rtl ? wi->current_x : wi->current_x - clearbtn_width) - 1; + + /* Clamp caret position to be inside out current width. */ + const Textbuf *tb = &this->text; + int delta = min(0, (right - left) - tb->pixels - 10); + if (tb->caretxoffs + delta < 0) delta = -tb->caretxoffs; + + Point pt = {left + WD_FRAMERECT_LEFT + tb->caretxoffs + delta, wi->pos_y + WD_FRAMERECT_TOP}; + return pt; +} + void QueryString::ClickEditBox(Window *w, Point pt, int wid, int click_count, bool focus_changed) { const NWidgetLeaf *wi = w->GetWidget<NWidgetLeaf>(wid); diff --git a/src/querystring_gui.h b/src/querystring_gui.h index b2c91f354..a652b382d 100644 --- a/src/querystring_gui.h +++ b/src/querystring_gui.h @@ -53,6 +53,8 @@ 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); + + Point GetCaretPosition(const Window *w, int wid) const; }; void ShowOnScreenKeyboard(Window *parent, int button); diff --git a/src/video/win32_v.cpp b/src/video/win32_v.cpp index a0da4b06f..f7394ba99 100644 --- a/src/video/win32_v.cpp +++ b/src/video/win32_v.cpp @@ -21,6 +21,7 @@ #include "../texteff.hpp" #include "../thread/thread.h" #include "../progress.h" +#include "../window_gui.h" #include "../window_func.h" #include "win32_v.h" #include <windows.h> @@ -500,6 +501,28 @@ static LRESULT HandleCharMsg(uint keycode, WChar charcode) } #if !defined(WINCE) || _WIN32_WCE >= 0x400 +/** Set position of the composition window to the caret position. */ +static void SetCompositionPos(HWND hwnd) +{ + HIMC hIMC = ImmGetContext(hwnd); + if (hIMC != NULL) { + COMPOSITIONFORM cf; + cf.dwStyle = CFS_POINT; + + if (EditBoxInGlobalFocus()) { + /* Get caret position. */ + Point pt = _focused_window->GetCaretPosition(); + cf.ptCurrentPos.x = _focused_window->left + pt.x; + cf.ptCurrentPos.y = _focused_window->top + pt.y; + } else { + cf.ptCurrentPos.x = 0; + cf.ptCurrentPos.y = 0; + } + ImmSetCompositionWindow(hIMC, &cf); + } + ImmReleaseContext(hwnd, hIMC); +} + /** Handle WM_IME_COMPOSITION messages. */ static LRESULT HandleIMEComposition(HWND hwnd, WPARAM wParam, LPARAM lParam) { @@ -515,6 +538,7 @@ static LRESULT HandleIMEComposition(HWND hwnd, WPARAM wParam, LPARAM lParam) /* Transmit text to windowing system. */ if (len > 0) HandleTextInput(FS2OTTD(str)); + SetCompositionPos(hwnd); /* Don't pass the result string on to the default window proc. */ lParam &= ~(GCS_RESULTSTR | GCS_RESULTCLAUSE | GCS_RESULTREADCLAUSE | GCS_RESULTREADSTR); @@ -535,6 +559,7 @@ static void CancelIMEComposition(HWND hwnd) #else +static void SetCompositionPos(HWND hwnd) {} static void CancelIMEComposition(HWND hwnd) {} #endif /* !defined(WINCE) || _WIN32_WCE >= 0x400 */ @@ -548,6 +573,7 @@ static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP switch (msg) { case WM_CREATE: SetTimer(hwnd, TID_POLLMOUSE, MOUSE_POLL_DELAY, (TIMERPROC)TrackMouseTimerProc); + SetCompositionPos(hwnd); break; case WM_ENTERSIZEMOVE: @@ -674,6 +700,10 @@ static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP } #if !defined(WINCE) || _WIN32_WCE >= 0x400 + case WM_IME_STARTCOMPOSITION: + SetCompositionPos(hwnd); + break; + case WM_IME_COMPOSITION: return HandleIMEComposition(hwnd, wParam, lParam); @@ -861,6 +891,7 @@ static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP case WM_SETFOCUS: _wnd.has_focus = true; + SetCompositionPos(hwnd); break; case WM_KILLFOCUS: @@ -1220,4 +1251,5 @@ bool VideoDriver_Win32::AfterBlitterChange() void VideoDriver_Win32::EditBoxLostFocus() { CancelIMEComposition(_wnd.main_wnd); + SetCompositionPos(_wnd.main_wnd); } diff --git a/src/window.cpp b/src/window.cpp index 522a10a6f..2805301f0 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -323,6 +323,20 @@ QueryString *Window::GetQueryString(uint widnum) return query != this->querystrings.End() ? query->second : NULL; } +/** + * Get the current caret position if an edit box has the focus. + * @return Top-left location of the caret, relative to the window. + */ +/* virtual */ Point Window::GetCaretPosition() const +{ + if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) { + return this->GetQueryString(this->nested_focus->index)->GetCaretPosition(this, this->nested_focus->index); + } + + Point pt = {0, 0}; + return pt; +} + /** * Set the window that has the focus diff --git a/src/window_func.h b/src/window_func.h index ee494592b..453b88978 100644 --- a/src/window_func.h +++ b/src/window_func.h @@ -14,6 +14,7 @@ #include "window_type.h" #include "company_type.h" +#include "core/geometry_type.hpp" Window *FindWindowById(WindowClass cls, WindowNumber number); Window *FindWindowByClass(WindowClass cls); @@ -53,5 +54,6 @@ void DeleteWindowById(WindowClass cls, WindowNumber number, bool force = true); void DeleteWindowByClass(WindowClass cls); bool EditBoxInGlobalFocus(); +Point GetCaretPosition(); #endif /* WINDOW_FUNC_H */ diff --git a/src/window_gui.h b/src/window_gui.h index 557fd3145..fe2c8ef62 100644 --- a/src/window_gui.h +++ b/src/window_gui.h @@ -345,6 +345,8 @@ public: const QueryString *GetQueryString(uint widnum) const; QueryString *GetQueryString(uint widnum); + virtual Point GetCaretPosition() const; + void InitNested(WindowNumber number = 0); void CreateNestedTree(bool fill_nested = true); void FinishInitNested(WindowNumber window_number = 0); |