Changeset - r19819:048b8ca075ad
[Not reviewed]
master
0 4 0
frosch - 12 years ago 2012-11-28 21:14:28
frosch@openttd.org
(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.
4 files changed with 41 insertions and 63 deletions:
0 comments (0 inline, 0 general)
src/misc_gui.cpp
Show inline comments
 
@@ -703,22 +703,15 @@ void GuiShowTooltips(Window *parent, Str
 

	
 
	if (str == STR_NULL) return;
 

	
 
	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;
 

	
 
	bool edited = false;
 

	
 
	switch (keycode) {
 
@@ -754,30 +747,25 @@ HandleEditBoxResult QueryString::HandleE
 
		default:
 
			if (IsValidChar(key, this->afilter)) {
 
				edited = this->text.InsertChar(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();
 
	}
 
}
 

	
 
void QueryString::DrawEditBox(const Window *w, int wid) const
 
{
 
	const NWidgetLeaf *wi = w->GetWidget<NWidgetLeaf>(wid);
 
@@ -815,13 +803,14 @@ void QueryString::DrawEditBox(const Wind
 
	const Textbuf *tb = &this->text;
 
	int delta = min(0, (right - left) - tb->pixels - 10);
 

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

	
 
	_cur_dpi = old_dpi;
 
}
src/osk_gui.cpp
Show inline comments
 
@@ -50,17 +50,19 @@ struct OskWindow : public Window {
 

	
 
		assert(parent->querystrings.Contains(button));
 
		this->qs         = parent->querystrings.Find(button)->second;
 
		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);
 

	
 
		this->UpdateOskState();
 
	}
 
@@ -102,19 +104,12 @@ struct OskWindow : public Window {
 
		DrawCharCentered(_keyboard[this->shift][widget],
 
			r.left + 8,
 
			r.top + 3,
 
			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 */
 
		if (widget >= WID_OSK_LETTERS) {
 
			WChar c = _keyboard[this->shift][widget - WID_OSK_LETTERS];
 

	
 
@@ -124,15 +119,12 @@ struct OskWindow : public Window {
 

	
 
			if (HasBit(_keystate, KEYS_SHIFT)) {
 
				ToggleBit(_keystate, KEYS_SHIFT);
 
				this->UpdateOskState();
 
				this->SetDirty();
 
			}
 
			/* Return focus to the parent widget and window. */
 
			this->parent->SetFocusedWidget(this->text_btn);
 
			SetFocusedWindow(this->parent);
 
			return;
 
		}
 

	
 
		switch (widget) {
 
			case WID_OSK_BACKSPACE:
 
				if (this->qs->text.DeleteChar(WKC_BACKSPACE)) this->OnEditboxChanged(WID_OSK_TEXT);
 
@@ -192,42 +184,32 @@ struct OskWindow : public Window {
 
					qs->text.MovePos(WKC_END);
 
					this->OnEditboxChanged(WID_OSK_TEXT);
 
					delete this;
 
				}
 
				break;
 
		}
 
		/* Return focus to the parent widget and window. */
 
		this->parent->SetFocusedWidget(this->text_btn);
 
		SetFocusedWindow(this->parent);
 
	}
 

	
 
	virtual void OnEditboxChanged(int widget)
 
	{
 
		this->SetWidgetDirty(WID_OSK_TEXT);
 
		this->parent->OnEditboxChanged(this->text_btn);
 
		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.
 
static const int INTER_KEY_SPACE = 2; // Number of pixels between two keys.
 

	
 
/**
 
@@ -445,6 +427,18 @@ void UpdateOSKOriginalText(const Window 
 

	
 
	free(osk->orig_str_buf);
 
	osk->orig_str_buf = strdup(osk->qs->text.buf);
 

	
 
	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;
 
}
src/querystring_gui.h
Show inline comments
 
@@ -59,19 +59,18 @@ struct QueryString {
 
	 */
 
	~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);
 
	void HandleEditBox(Window *w, int wid);
 
	HandleEditBoxResult HandleEditBoxKey(Window *w, int wid, uint16 key, uint16 keycode, EventState &state);
 
};
 

	
 
void ShowOnScreenKeyboard(Window *parent, int button);
 
void UpdateOSKOriginalText(const Window *parent, int button);
 
bool IsOSKOpenedFor(const Window *w, int button);
 

	
 
#endif /* QUERYSTRING_GUI_H */
src/window.cpp
Show inline comments
 
@@ -419,37 +419,27 @@ static void DispatchLeftClickEvent(Windo
 
	bool focused_widget_changed = false;
 
	/* If clicked on a window that previously did dot have focus */
 
	if (_focused_window != w &&                 // We already have focus, right?
 
			(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();
 
	}
 

	
 
	if (nw == NULL) return; // exit if clicked outside of widgets
 

	
 
	/* don't allow any interaction if the button has been disabled */
 
	if (nw->IsDisabled()) return;
 

	
 
	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
 
		 * both changed states.
 
		 *
 
		 * If this is not preserved, then the OSK window would be opened when
 
@@ -1196,16 +1186,16 @@ void Window::InitializeData(const Window
 

	
 
	/* Further set up window properties,
 
	 * this->left, this->top, this->width, this->height, this->resize.width, and this->resize.height are initialized later. */
 
	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);
 
}
 

	
 
/**
 
@@ -2272,24 +2262,30 @@ EventState Window::HandleEditBoxKey(int 
 
			this->SetWidgetDirty(wid);
 
			this->OnEditboxChanged(wid);
 
			break;
 

	
 
		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;
 
			}
 
			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;
 
			}
 
			break;
 

	
0 comments (0 inline, 0 general)