From e2ec0ddb030afd4e7bdf08d1a8f3cb9361388eae Mon Sep 17 00:00:00 2001 From: michi_cc Date: Mon, 5 Aug 2013 20:37:48 +0000 Subject: (svn r25690) -Change: [OSX] Position the candidate window at the caret position. --- src/console_gui.cpp | 11 +++++++++++ src/misc_gui.cpp | 38 ++++++++++++++++++++++++++++++++++++++ src/querystring_gui.h | 1 + src/video/cocoa/cocoa_v.mm | 29 +++++++++++++++++++++++++++-- src/window.cpp | 16 ++++++++++++++++ src/window_gui.h | 1 + 6 files changed, 94 insertions(+), 2 deletions(-) diff --git a/src/console_gui.cpp b/src/console_gui.cpp index d7ef57a44..530cb8bfd 100644 --- a/src/console_gui.cpp +++ b/src/console_gui.cpp @@ -346,6 +346,17 @@ struct IConsoleWindow : Window return pt; } + virtual Rect GetTextBoundingRect(const char *from, const char *to) const + { + int delta = min(this->width - this->line_offset - _iconsole_cmdline.pixels - ICON_RIGHT_BORDERWIDTH, 0); + + Point p1 = GetCharPosInString(_iconsole_cmdline.buf, from, FS_NORMAL); + Point p2 = from != to ? GetCharPosInString(_iconsole_cmdline.buf, from, FS_NORMAL) : p1; + + Rect r = {this->line_offset + delta + p1.x, this->height - this->line_height, this->line_offset + delta + p2.x, this->height}; + return r; + } + virtual void OnMouseWheel(int wheel) { this->Scroll(-wheel); diff --git a/src/misc_gui.cpp b/src/misc_gui.cpp index cd1f034a8..b309693bf 100644 --- a/src/misc_gui.cpp +++ b/src/misc_gui.cpp @@ -816,6 +816,44 @@ Point QueryString::GetCaretPosition(const Window *w, int wid) const return pt; } +/** + * Get the bounding rectangle for a range of the query string. + * @param w Window the edit box is in. + * @param wid Widget index. + * @param from Start of the string range. + * @param to End of the string range. + * @return Rectangle encompassing the string range, relative to the window. + */ +Rect QueryString::GetBoundingRect(const Window *w, int wid, const char *from, const char *to) const +{ + const NWidgetLeaf *wi = w->GetWidget(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; + + int top = wi->pos_y + WD_FRAMERECT_TOP; + int bottom = wi->pos_y + wi->current_y - 1 - WD_FRAMERECT_BOTTOM; + + /* Clamp caret position to be inside our current width. */ + const Textbuf *tb = &this->text; + int delta = min(0, (right - left) - tb->pixels - 10); + if (tb->caretxoffs + delta < 0) delta = -tb->caretxoffs; + + /* Get location of first and last character. */ + Point p1 = GetCharPosInString(tb->buf, from, FS_NORMAL); + Point p2 = from != to ? GetCharPosInString(tb->buf, to, FS_NORMAL) : p1; + + Rect r = { Clamp(left + p1.x + delta + WD_FRAMERECT_LEFT, left, right), top, Clamp(left + p2.x + delta + WD_FRAMERECT_LEFT, left, right - WD_FRAMERECT_RIGHT), bottom }; + + return r; +} + void QueryString::ClickEditBox(Window *w, Point pt, int wid, int click_count, bool focus_changed) { const NWidgetLeaf *wi = w->GetWidget(wid); diff --git a/src/querystring_gui.h b/src/querystring_gui.h index db6e33076..5c0bdbabe 100644 --- a/src/querystring_gui.h +++ b/src/querystring_gui.h @@ -55,6 +55,7 @@ public: void HandleEditBox(Window *w, int wid); Point GetCaretPosition(const Window *w, int wid) const; + Rect GetBoundingRect(const Window *w, int wid, const char *from, const char *to) const; /** * Get the current text. diff --git a/src/video/cocoa/cocoa_v.mm b/src/video/cocoa/cocoa_v.mm index 16069bb24..e4897ac50 100644 --- a/src/video/cocoa/cocoa_v.mm +++ b/src/video/cocoa/cocoa_v.mm @@ -896,7 +896,14 @@ static const char *Utf8AdvanceByUtf16Units(const char *str, NSUInteger count) /** Get a string corresponding to the given range. */ - (NSAttributedString *)attributedSubstringFromRange:(NSRange)theRange { - return nil; + if (!EditBoxInGlobalFocus()) return nil; + + NSString *s = [ NSString stringWithUTF8String:_focused_window->GetFocusedText() ]; + NSRange valid_range = NSIntersectionRange(NSMakeRange(0, [ s length ]), theRange); + + if (valid_range.length == 0) return nil; + + return [ [ [ NSAttributedString alloc ] initWithString:[ s substringWithRange:valid_range ] ] autorelease ]; } /** Get the character that is rendered at the given point. */ @@ -908,7 +915,25 @@ static const char *Utf8AdvanceByUtf16Units(const char *str, NSUInteger count) /** Get the bounding rect for the given range. */ - (NSRect)firstRectForCharacterRange:(NSRange)aRange { - return NSMakeRect(0, 0, 0, 0); + if (!EditBoxInGlobalFocus()) return NSMakeRect(0, 0, 0, 0); + + /* Convert range to UTF-8 string pointers. */ + const char *start = Utf8AdvanceByUtf16Units(_focused_window->GetFocusedText(), aRange.location); + const char *end = aRange.length != 0 ? Utf8AdvanceByUtf16Units(_focused_window->GetFocusedText(), aRange.location + aRange.length) : start; + + /* Get the bounding rect for the text range.*/ + Rect r = _focused_window->GetTextBoundingRect(start, end); + NSRect view_rect = NSMakeRect(_focused_window->left + r.left, [ self frame ].size.height - _focused_window->top - r.bottom, r.right - r.left, r.bottom - r.top); + +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 + if ([ [ self window ] respondsToSelector:@selector(convertRectToScreen:) ]) { + return [ [ self window ] convertRectToScreen:[ self convertRect:view_rect toView:nil ] ]; + } +#endif + + NSRect window_rect = [ self convertRect:view_rect toView:nil ]; + NSPoint origin = [ [ self window ] convertBaseToScreen:window_rect.origin ]; + return NSMakeRect(origin.x, origin.y, window_rect.size.width, window_rect.size.height); } /** Get all string attributes that we can process for marked text. */ diff --git a/src/window.cpp b/src/window.cpp index 907f575c6..3496c5633 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -377,6 +377,22 @@ QueryString *Window::GetQueryString(uint widnum) return pt; } +/** + * Get the bounding rectangle for a text range if an edit box has the focus. + * @param from Start of the string range. + * @param to End of the string range. + * @return Rectangle encompassing the string range, relative to the window. + */ +/* virtual */ Rect Window::GetTextBoundingRect(const char *from, const char *to) const +{ + if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) { + return this->GetQueryString(this->nested_focus->index)->GetBoundingRect(this, this->nested_focus->index, from, to); + } + + Rect r = {0, 0, 0, 0}; + return r; +} + /** * Set the window that has the focus diff --git a/src/window_gui.h b/src/window_gui.h index 494e5bfcb..da5c992ed 100644 --- a/src/window_gui.h +++ b/src/window_gui.h @@ -349,6 +349,7 @@ public: virtual const char *GetCaret() const; virtual const char *GetMarkedText(size_t *length) const; virtual Point GetCaretPosition() const; + virtual Rect GetTextBoundingRect(const char *from, const char *to) const; void InitNested(WindowNumber number = 0); void CreateNestedTree(bool fill_nested = true); -- cgit v1.2.3-70-g09d2