(svn r24774) -Fix: Invert the focus handling of the OSK. Keep the focus at the OSK and close it on losing focus. This makes the editbox in the OSK behave correctly.

This commit is contained in:
frosch 2012-11-28 21:14:28 +00:00
parent bfba90f864
commit 5dfd5e58ee
4 changed files with 41 additions and 63 deletions

View File

@ -706,16 +706,9 @@ void GuiShowTooltips(Window *parent, StringID str, uint paramcount, const uint64
new TooltipsWindow(parent, str, paramcount, params, close_tooltip);
}
bool QueryString::HasEditBoxFocus(const Window *w, int wid) const
{
if (w->IsWidgetGloballyFocused(wid)) return true;
if (w->window_class != WC_OSK || _focused_window != w->parent) return false;
return w->parent->nested_focus != NULL && w->parent->nested_focus->type == WWT_EDITBOX;
}
HandleEditBoxResult QueryString::HandleEditBoxKey(Window *w, int wid, uint16 key, uint16 keycode, EventState &state)
{
if (!QueryString::HasEditBoxFocus(w, wid)) return HEBR_NOT_FOCUSED;
if (!w->IsWidgetGloballyFocused(wid)) return HEBR_NOT_FOCUSED;
state = ES_HANDLED;
@ -757,24 +750,19 @@ HandleEditBoxResult QueryString::HandleEditBoxKey(Window *w, int wid, uint16 key
} else {
state = ES_NOT_HANDLED;
}
break;
}
Window *osk = FindWindowById(WC_OSK, 0);
if (osk != NULL && osk->parent == w) osk->InvalidateData();
return edited ? HEBR_EDITING : HEBR_CURSOR;
}
void QueryString::HandleEditBox(Window *w, int wid)
{
if (HasEditBoxFocus(w, wid) && this->text.HandleCaret()) {
if (w->IsWidgetGloballyFocused(wid) && this->text.HandleCaret()) {
w->SetWidgetDirty(wid);
/* When we're not the OSK, notify 'our' OSK to redraw the widget,
* so the caret changes appropriately. */
if (w->window_class != WC_OSK) {
Window *w_osk = FindWindowById(WC_OSK, 0);
if (w_osk != NULL && w_osk->parent == w) w_osk->InvalidateData();
}
/* For the OSK also invalidate the parent window */
if (w->window_class == WC_OSK) w->InvalidateData();
}
}
@ -818,7 +806,8 @@ void QueryString::DrawEditBox(const Window *w, int wid) const
if (tb->caretxoffs + delta < 0) delta = -tb->caretxoffs;
DrawString(delta, tb->pixels, 0, tb->buf, TC_YELLOW);
if (HasEditBoxFocus(w, wid) && tb->caret) {
bool focussed = w->IsWidgetGloballyFocused(wid) || IsOSKOpenedFor(w, wid);
if (focussed && tb->caret) {
int caret_width = GetStringBoundingBox("_").width;
DrawString(tb->caretxoffs + delta, tb->caretxoffs + delta + caret_width, 0, "_", TC_WHITE);
}

View File

@ -53,11 +53,13 @@ struct OskWindow : public Window {
this->caption = (par_wid->widget_data != STR_NULL) ? par_wid->widget_data : this->qs->caption;
this->text_btn = button;
this->text = &this->qs->text;
this->querystrings[WID_OSK_TEXT] = this->qs;
/* make a copy in case we need to reset later */
this->orig_str_buf = strdup(this->qs->text.buf);
this->InitNested(desc, 0);
this->SetFocusedWidget(WID_OSK_TEXT);
/* Not needed by default. */
this->DisableWidget(WID_OSK_SPECIAL);
@ -105,13 +107,6 @@ struct OskWindow : public Window {
TC_BLACK);
}
virtual void OnPaint()
{
this->DrawWidgets();
this->qs->DrawEditBox(this, WID_OSK_TEXT);
}
virtual void OnClick(Point pt, int widget, int click_count)
{
/* clicked a letter */
@ -127,9 +122,6 @@ struct OskWindow : public Window {
this->UpdateOskState();
this->SetDirty();
}
/* Return focus to the parent widget and window. */
this->parent->SetFocusedWidget(this->text_btn);
SetFocusedWindow(this->parent);
return;
}
@ -195,9 +187,6 @@ struct OskWindow : public Window {
}
break;
}
/* Return focus to the parent widget and window. */
this->parent->SetFocusedWidget(this->text_btn);
SetFocusedWindow(this->parent);
}
virtual void OnEditboxChanged(int widget)
@ -207,24 +196,17 @@ struct OskWindow : public Window {
this->parent->SetWidgetDirty(this->text_btn);
}
virtual void OnMouseLoop()
{
this->qs->HandleEditBox(this, WID_OSK_TEXT);
/* make the caret of the parent window also blink */
this->parent->SetWidgetDirty(this->text_btn);
}
/**
* Some data on this window has become invalid.
* @param data Information about the changed data.
* @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details.
*/
virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
{
if (!gui_scope) return;
this->SetWidgetDirty(WID_OSK_TEXT);
this->parent->SetWidgetDirty(this->text_btn);
}
virtual void OnFocusLost()
{
delete this;
}
};
static const int HALF_KEY_WIDTH = 7; // Width of 1/2 key in pixels.
@ -448,3 +430,15 @@ void UpdateOSKOriginalText(const Window *parent, int button)
osk->SetDirty();
}
/**
* Check whether the OSK is opened for a specific editbox.
* @parent w Window to check for
* @param button Editbox of \a w to check for
* @return true if the OSK is oppened for \a button.
*/
bool IsOSKOpenedFor(const Window *w, int button)
{
OskWindow *osk = dynamic_cast<OskWindow *>(FindWindowById(WC_OSK, 0));
return osk != NULL && osk->parent == w && osk->text_btn == button;
}

View File

@ -62,8 +62,6 @@ struct QueryString {
free(this->orig);
}
private:
bool HasEditBoxFocus(const Window *w, int wid) const;
public:
void DrawEditBox(const Window *w, int wid) const;
void ClickEditBox(Window *w, Point pt, int wid, int click_count, bool focus_changed);
@ -73,5 +71,6 @@ public:
void ShowOnScreenKeyboard(Window *parent, int button);
void UpdateOSKOriginalText(const Window *parent, int button);
bool IsOSKOpenedFor(const Window *w, int button);
#endif /* QUERYSTRING_GUI_H */

View File

@ -422,12 +422,6 @@ static void DispatchLeftClickEvent(Window *w, int x, int y, int click_count)
(w->desc_flags & WDF_NO_FOCUS) == 0 && // Don't lose focus to toolbars
widget_type != WWT_CLOSEBOX) { // Don't change focused window if 'X' (close button) was clicked
focused_widget_changed = true;
if (_focused_window != NULL) {
_focused_window->OnFocusLost();
/* The window that lost focus may have had opened a OSK, window so close it, unless the user has clicked on the OSK window. */
if (w->window_class != WC_OSK) DeleteWindowById(WC_OSK, 0);
}
SetFocusedWindow(w);
w->OnFocus();
}
@ -440,13 +434,9 @@ static void DispatchLeftClickEvent(Window *w, int x, int y, int click_count)
int widget_index = nw->index; ///< Index of the widget
/* Clicked on a widget that is not disabled.
* So unless the clicked widget is the caption bar, change focus to this widget */
if (widget_type != WWT_CAPTION) {
/* Close the OSK window if a edit box loses focus */
if (w->nested_focus != NULL && w->nested_focus->type == WWT_EDITBOX && w->nested_focus != nw && w->window_class != WC_OSK) {
DeleteWindowById(WC_OSK, 0);
}
* So unless the clicked widget is the caption bar, change focus to this widget.
* Exception: In the OSK we always want the editbox to stay focussed. */
if (widget_type != WWT_CAPTION && w->window_class != WC_OSK) {
/* focused_widget_changed is 'now' only true if the window this widget
* is in gained focus. In that case it must remain true, also if the
* local widget focus did not change. As such it's the logical-or of
@ -1199,10 +1189,10 @@ void Window::InitializeData(const WindowDesc *desc, WindowNumber window_number)
this->resize.step_width = this->nested_root->resize_x;
this->resize.step_height = this->nested_root->resize_y;
/* Give focus to the opened window unless it is the OSK window or a text box
/* Give focus to the opened window unless a text box
* of focused window has focus (so we don't interrupt typing). But if the new
* window has a text box, then take focus anyway. */
if (this->window_class != WC_OSK && (!EditBoxInGlobalFocus() || this->nested_root->GetWidgetOfType(WWT_EDITBOX) != NULL)) SetFocusedWindow(this);
if (!EditBoxInGlobalFocus() || this->nested_root->GetWidgetOfType(WWT_EDITBOX) != NULL) SetFocusedWindow(this);
/* Insert the window into the correct location in the z-ordering. */
AddWindowToZOrdering(this);
@ -2275,10 +2265,14 @@ EventState Window::HandleEditBoxKey(int wid, uint16 key, uint16 keycode)
case HEBR_CURSOR:
this->SetWidgetDirty(wid);
/* For the OSK also invalidate the parent window */
if (this->window_class == WC_OSK) this->InvalidateData();
break;
case HEBR_CONFIRM:
if (query->ok_button >= 0) {
if (this->window_class == WC_OSK) {
this->OnClick(Point(), WID_OSK_OK, 1);
} else if (query->ok_button >= 0) {
this->OnClick(Point(), query->ok_button, 1);
} else {
action = query->ok_button;
@ -2286,7 +2280,9 @@ EventState Window::HandleEditBoxKey(int wid, uint16 key, uint16 keycode)
break;
case HEBR_CANCEL:
if (query->cancel_button >= 0) {
if (this->window_class == WC_OSK) {
this->OnClick(Point(), WID_OSK_CANCEL, 1);
} else if (query->cancel_button >= 0) {
this->OnClick(Point(), query->cancel_button, 1);
} else {
action = query->cancel_button;