(svn r15424) -Codechange: make it possible to have multiple windows with edit box open simultaniously (Zuu).

This commit is contained in:
rubidium 2009-02-09 01:22:29 +00:00
parent 9907742a0f
commit 861e9cefb3
13 changed files with 232 additions and 55 deletions

View File

@ -150,7 +150,6 @@ struct IConsoleWindow : Window
IConsoleWindow(const WindowDesc *desc) : Window(desc)
{
_iconsole_mode = ICONSOLE_OPENED;
_no_scroll++; // override cursor arrows; the gamefield will not scroll
this->height = _screen.height / 3;
this->width = _screen.width;
@ -159,7 +158,6 @@ struct IConsoleWindow : Window
~IConsoleWindow()
{
_iconsole_mode = ICONSOLE_CLOSED;
_no_scroll--;
}
virtual void OnPaint()
@ -180,7 +178,7 @@ struct IConsoleWindow : Window
DoDrawString(_iconsole_cmdline.buf, 10 + delta, this->height - ICON_LINE_HEIGHT, CC_COMMAND);
if (_iconsole_cmdline.caret) {
if (_focused_window == this && _iconsole_cmdline.caret) {
DoDrawString("_", 10 + delta + _iconsole_cmdline.caretxoffs, this->height - ICON_LINE_HEIGHT, TC_WHITE);
}
}
@ -201,6 +199,8 @@ struct IConsoleWindow : Window
virtual EventState OnKeyPress(uint16 key, uint16 keycode)
{
if (_focused_window != this) return ES_NOT_HANDLED;
const int scroll_height = (this->height / ICON_LINE_HEIGHT) - 1;
switch (keycode) {
case WKC_UP:

View File

@ -302,6 +302,7 @@ struct GenerateLandscapeWindow : public QueryStringBaseWindow {
/* snprintf() always outputs trailing '\0', so whole buffer can be used */
snprintf(this->edit_str_buf, this->edit_str_size, "%u", _settings_newgame.game_creation.generation_seed);
InitializeTextBuffer(&this->text, this->edit_str_buf, this->edit_str_size, 120);
this->SetFocusedWidget(GLAND_RANDOM_EDITBOX);
this->caption = STR_NULL;
this->afilter = CS_NUMERAL;

View File

@ -951,8 +951,19 @@ bool HandleCaret(Textbuf *tb)
return false;
}
bool QueryString::HasEditBoxFocus(const Window *w, int wid) const
{
return ((w->window_class == WC_OSK &&
_focused_window == w->parent &&
w->parent->focused_widget &&
w->parent->focused_widget->type == WWT_EDITBOX) ||
w->IsWidgetGloballyFocused(wid));
}
HandleEditBoxResult QueryString::HandleEditBoxKey(Window *w, int wid, uint16 key, uint16 keycode, Window::EventState &state)
{
if (!QueryString::HasEditBoxFocus(w, wid)) return HEBR_NOT_FOCUSED;
state = Window::ES_HANDLED;
switch (keycode) {
@ -990,7 +1001,7 @@ HandleEditBoxResult QueryString::HandleEditBoxKey(Window *w, int wid, uint16 key
void QueryString::HandleEditBox(Window *w, int wid)
{
if (HandleCaret(&this->text)) {
if (HasEditBoxFocus(w, wid) && HandleCaret(&this->text)) {
w->InvalidateWidget(wid);
/* When we're not the OSK, notify 'our' OSK to redraw the widget,
* so the caret changes appropriately. */
@ -1034,7 +1045,7 @@ void QueryString::DrawEditBox(Window *w, int wid)
if (tb->caretxoffs + delta < 0) delta = -tb->caretxoffs;
DoDrawString(tb->buf, delta, 0, TC_YELLOW);
if (tb->caret) DoDrawString("_", tb->caretxoffs + delta, 0, TC_WHITE);
if (HasEditBoxFocus(w, wid) && tb->caret) DoDrawString("_", tb->caretxoffs + delta, 0, TC_WHITE);
_cur_dpi = old_dpi;
}
@ -1072,6 +1083,7 @@ struct QueryStringWindow : public QueryStringBaseWindow
QueryStringWindow(uint16 size, const WindowDesc *desc, Window *parent) : QueryStringBaseWindow(size, desc)
{
this->parent = parent;
this->SetFocusedWidget(QUERY_STR_WIDGET_TEXT);
this->FindWindowPlacementAndResize(desc);
}
@ -1130,6 +1142,7 @@ struct QueryStringWindow : public QueryStringBaseWindow
case HEBR_CONFIRM: this->OnOk();
/* FALL THROUGH */
case HEBR_CANCEL: delete this; break; // close window, abandon changes
case HEBR_NOT_FOCUSED: break;
}
return state;
}
@ -1180,7 +1193,6 @@ static const WindowDesc _query_string_desc = {
void ShowQueryString(StringID str, StringID caption, uint maxsize, uint maxwidth, Window *parent, CharSetFilter afilter, QueryStringFlags flags)
{
DeleteWindowById(WC_QUERY_STRING, 0);
DeleteWindowById(WC_SAVELOAD, 0);
QueryStringWindow *w = new QueryStringWindow(maxsize, &_query_string_desc, parent);
@ -1500,6 +1512,11 @@ public:
strecpy(o_dir.name, _personal_dir, lastof(o_dir.name));
}
/* Focus the edit box by default in the save windows */
if (_saveload_mode == SLD_SAVE_GAME || _saveload_mode == SLD_SAVE_SCENARIO) {
this->SetFocusedWidget(SLWW_SAVE_OSK_TITLE);
}
this->vscroll.cap = 10;
this->resize.step_width = 2;
this->resize.step_height = 10;
@ -1708,7 +1725,6 @@ static const FileType _file_modetotype[] = {
void ShowSaveLoadDialog(SaveLoadDialogMode mode)
{
DeleteWindowById(WC_QUERY_STRING, 0);
DeleteWindowById(WC_SAVELOAD, 0);
const WindowDesc *sld;

View File

@ -278,6 +278,7 @@ public:
this->dest = dest;
this->afilter = CS_ALPHANUMERAL;
InitializeTextBuffer(&this->text, this->edit_str_buf, this->edit_str_size, 0);
this->SetFocusedWidget(NWCW_TEXTBOX);
InvalidateWindowData(WC_NEWS_WINDOW, 0, this->height);
@ -480,6 +481,7 @@ public:
SendChat(this->text.buf, this->dtype, this->dest);
/* FALLTHROUGH */
case HEBR_CANCEL: delete this; break;
case HEBR_NOT_FOCUSED: break;
}
}
return state;

View File

@ -317,6 +317,7 @@ public:
ttd_strlcpy(this->edit_str_buf, "", this->edit_str_size);
this->afilter = CS_ALPHANUMERAL;
InitializeTextBuffer(&this->text, this->edit_str_buf, this->edit_str_size, EDITBOX_MAX_LENGTH);
this->SetFocusedWidget(NCLWW_FILTER);
this->vscroll.cap = 14;
this->resize.step_height = 14;

View File

@ -308,6 +308,7 @@ public:
ttd_strlcpy(this->edit_str_buf, _settings_client.network.client_name, this->edit_str_size);
this->afilter = CS_ALPHANUMERAL;
InitializeTextBuffer(&this->text, this->edit_str_buf, this->edit_str_size, 120);
this->SetFocusedWidget(NGWW_CLIENT);
UpdateNetworkGameWindow(true);
@ -879,6 +880,7 @@ struct NetworkStartServerWindow : public QueryStringBaseWindow {
this->afilter = CS_ALPHANUMERAL;
InitializeTextBuffer(&this->text, this->edit_str_buf, this->edit_str_size, 160);
this->SetFocusedWidget(NSSW_GAMENAME);
this->field = NSSW_GAMENAME;
@ -1882,6 +1884,7 @@ struct NetworkCompanyPasswordWindow : public QueryStringBaseWindow {
this->parent = parent;
this->afilter = CS_ALPHANUMERAL;
InitializeTextBuffer(&this->text, this->edit_str_buf, this->edit_str_size, 0);
this->SetFocusedWidget(NCPWW_PASSWORD);
this->FindWindowPlacementAndResize(desc);
}

View File

@ -131,6 +131,21 @@ struct OskWindow : public Window {
}
switch (widget) {
case OSK_WIDGET_TEXT:
/* Find the edit box of the parent window and give focus to that */
for (uint i = 0; i < this->parent->widget_count; i++) {
Widget &wi = this->parent->widget[i];
if (wi.type == WWT_EDITBOX) {
this->parent->focused_widget = &wi;
break;
}
}
/* Give focus to parent window */
SetFocusedWindow(this->parent);
break;
case OSK_WIDGET_BACKSPACE:
if (DeleteTextBufferChar(&this->qs->text, WKC_BACKSPACE)) this->InvalidateParent();
break;

View File

@ -16,6 +16,7 @@ enum HandleEditBoxResult
HEBR_EDITING = 0, // Other key pressed.
HEBR_CONFIRM, // Return or enter key pressed.
HEBR_CANCEL, // Escape key pressed.
HEBR_NOT_FOCUSED, // Edit box widget not focused.
};
/**
@ -43,6 +44,7 @@ struct QueryString {
free((void*)this->orig);
}
bool HasEditBoxFocus(const Window *w, int wid) const;
void DrawEditBox(Window *w, int wid);
void HandleEditBox(Window *w, int wid);
HandleEditBoxResult HandleEditBoxKey(Window *w, int wid, uint16 key, uint16 keycode, Window::EventState &state);

View File

@ -196,6 +196,7 @@ struct SignWindow : QueryStringBaseWindow, SignList {
this->LowerWidget(QUERY_EDIT_SIGN_WIDGET_TEXT);
UpdateSignEditWindow(si);
this->SetFocusedWidget(QUERY_EDIT_SIGN_WIDGET_TEXT);
this->FindWindowPlacementAndResize(desc);
}
@ -216,6 +217,7 @@ struct SignWindow : QueryStringBaseWindow, SignList {
InitializeTextBuffer(&this->text, this->edit_str_buf, this->edit_str_size, MAX_LENGTH_SIGN_NAME_PIXELS);
this->InvalidateWidget(QUERY_EDIT_SIGN_WIDGET_TEXT);
this->SetFocusedWidget(QUERY_EDIT_SIGN_WIDGET_TEXT);
}
/**
@ -347,9 +349,8 @@ void HandleClickOnSign(const Sign *si)
void ShowRenameSignWindow(const Sign *si)
{
/* Delete all other edit windows and the save window */
/* Delete all other edit windows */
DeleteWindowById(WC_QUERY_STRING, 0);
DeleteWindowById(WC_SAVELOAD, 0);
new SignWindow(&_query_sign_edit_desc, si);
}

View File

@ -185,7 +185,7 @@ static const Widget _main_status_widgets[] = {
static WindowDesc _main_status_desc = {
WDP_CENTER, 0, 320, 12, 640, 12,
WC_STATUS_BAR, WC_NONE,
WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_NO_FOCUS,
_main_status_widgets,
};

View File

@ -1184,7 +1184,7 @@ static const Widget _toolb_normal_widgets[] = {
static const WindowDesc _toolb_normal_desc = {
0, 0, 0, TBP_BUTTONHEIGHT, 640, TBP_BUTTONHEIGHT,
WC_MAIN_TOOLBAR, WC_NONE,
WDF_STD_TOOLTIPS | WDF_DEF_WIDGET,
WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_NO_FOCUS,
_toolb_normal_widgets,
};
@ -1437,7 +1437,7 @@ static const Widget _toolb_scen_widgets[] = {
static const WindowDesc _toolb_scen_desc = {
0, 0, 130, TBP_BUTTONHEIGHT, 640, TBP_BUTTONHEIGHT,
WC_MAIN_TOOLBAR, WC_NONE,
WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_NO_FOCUS,
_toolb_scen_widgets,
};

View File

@ -34,7 +34,13 @@ Window *_z_front_window = NULL;
/** List of windows opened at the screen sorted from the back. */
Window *_z_back_window = NULL;
byte _no_scroll;
/*
* Window that currently have focus. - The main purpose is to generate
* FocusLost events, not to give next window in z-order focus when a
* window is closed.
*/
Window *_focused_window;
Point _cursorpos_drag_start;
int _scrollbar_start_pos;
@ -46,6 +52,51 @@ bool _scrolling_viewport;
byte _special_mouse_mode;
/**
* Set the window that has the focus
* @param w The window to set the focus on
*/
void SetFocusedWindow(Window *w)
{
if (_focused_window == w) return;
/* Invalidate focused widget */
if (_focused_window != NULL && _focused_window->focused_widget != NULL) {
uint focused_widget_id = _focused_window->focused_widget - _focused_window->widget;
_focused_window->InvalidateWidget(focused_widget_id);
}
/* Remember which window was previously focused */
Window *old_focused = _focused_window;
_focused_window = w;
/* So we can inform it that it lost focus */
if (old_focused != NULL) old_focused->OnFocusLost();
if (_focused_window != NULL) _focused_window->OnFocus();
}
/**
* Gets the globally focused widget. Which is the focused widget of the focused window.
* @return A pointer to the globally focused Widget, or NULL if there is no globally focused widget.
*/
const Widget *GetGloballyFocusedWidget()
{
return _focused_window != NULL ? _focused_window->focused_widget : NULL;
}
/**
* Check if an edit box is in global focus. That is if focused window
* has a edit box as focused widget, or if a console is focused.
* @return returns true if an edit box is in global focus or if the focused window is a console, else false
*/
bool EditBoxInGlobalFocus()
{
const Widget *wi = GetGloballyFocusedWidget();
/* The console does not have an edit box so a special case is needed. */
return (wi != NULL && wi->type == WWT_EDITBOX) ||
(_focused_window != NULL && _focused_window->window_class == WC_CONSOLE);
}
/**
* Sets the enabled/disabled status of a list of widgets.
@ -147,6 +198,18 @@ void Window::HandleButtonClick(byte widget)
this->InvalidateWidget(widget);
}
/**
* Checks if the window has at least one widget of given type
* @param widget_type the widget type to look for
*/
bool Window::HasWidgetOfType(WidgetType widget_type) const
{
for (uint i = 0; i < this->widget_count; i++) {
if (this->widget[i].type == widget_type) return true;
}
return false;
}
static void StartWindowDrag(Window *w);
static void StartWindowSizing(Window *w);
@ -159,9 +222,26 @@ static void StartWindowSizing(Window *w);
*/
static void DispatchLeftClickEvent(Window *w, int x, int y, bool double_click)
{
bool focused_widget_changed = false;
int widget = 0;
if (w->desc_flags & WDF_DEF_WIDGET) {
widget = GetWidgetFromPos(w, x, y);
/* If clicked on a window that previously did dot have focus */
if (_focused_window != w &&
(w->desc_flags & WDF_NO_FOCUS) == 0 && // Don't lose focus to toolbars
!(w->desc_flags & WDF_STD_BTN && widget == 0)) { // 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 (widget < 0) return; // exit if clicked outside of widgets
/* don't allow any interaction if the button has been disabled */
@ -169,6 +249,24 @@ static void DispatchLeftClickEvent(Window *w, int x, int y, bool double_click)
const Widget *wi = &w->widget[widget];
/* Clicked on a widget that is not disabled.
* So unless the clicked widget is the caption bar, change focus to this widget */
if (wi->type != WWT_CAPTION) {
/* Close the OSK window if a edit box loses focus */
if (w->focused_widget && w->focused_widget->type == WWT_EDITBOX && // An edit box was previously selected
w->focused_widget != wi && // and focus is going to change
w->window_class != WC_OSK) { // and it is not the OSK window
DeleteWindowById(WC_OSK, 0);
}
if (w->focused_widget != wi) {
/* Repaint the widget that loss focus. A focused edit box may else leave the caret left on the screen */
if (w->focused_widget) w->InvalidateWidget(w->focused_widget - w->widget);
focused_widget_changed = true;
w->focused_widget = wi;
}
}
if (wi->type & WWB_MASK) {
/* special widget handling for buttons*/
switch (wi->type) {
@ -181,7 +279,7 @@ static void DispatchLeftClickEvent(Window *w, int x, int y, bool double_click)
}
} else if (wi->type == WWT_SCROLLBAR || wi->type == WWT_SCROLL2BAR || wi->type == WWT_HSCROLLBAR) {
ScrollbarClickHandler(w, wi, x, y);
} else if (wi->type == WWT_EDITBOX) {
} else if (wi->type == WWT_EDITBOX && !focused_widget_changed) { // Only open the OSK window if clicking on an already focused edit box
/* Open the OSK window if clicked on an edit box */
QueryStringBaseWindow *qs = dynamic_cast<QueryStringBaseWindow*>(w);
if (qs != NULL) {
@ -431,18 +529,16 @@ Window::~Window()
/* Prevent Mouseover() from resetting mouse-over coordinates on a non-existing window */
if (_mouseover_last_w == this) _mouseover_last_w = NULL;
/* Make sure we don't try to access this window as the focused window when it don't exist anymore. */
if (_focused_window == this) _focused_window = NULL;
this->DeleteChildWindows();
if (this->viewport != NULL) DeleteWindowViewport(this);
this->SetDirty();
if (this->widget != NULL) {
for (const Widget *wi = this->widget; wi->type != WWT_LAST; wi++) {
if (wi->type == WWT_EDITBOX) _no_scroll--;
}
free(this->widget);
}
free(this->widget);
this->window_class = WC_INVALID;
}
@ -646,10 +742,6 @@ static void AssignWidgetToWindow(Window *w, const Widget *widget)
w->widget = MallocT<Widget>(index);
memcpy(w->widget, widget, sizeof(*w->widget) * index);
w->widget_count = index - 1;
for (const Widget *wi = w->widget; wi->type != WWT_LAST; wi++) {
if (wi->type == WWT_EDITBOX) _no_scroll++;
}
} else {
w->widget = NULL;
w->widget_count = 0;
@ -682,12 +774,18 @@ void Window::Initialize(int x, int y, int min_width, int min_height,
this->width = min_width;
this->height = min_height;
AssignWidgetToWindow(this, widget);
this->focused_widget = 0;
this->resize.width = min_width;
this->resize.height = min_height;
this->resize.step_width = 1;
this->resize.step_height = 1;
this->window_number = window_number;
/* Give focus to the opened window unless it is the OSK window or 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->HasWidgetOfType(WWT_EDITBOX))) SetFocusedWindow(this);
/* Hacky way of specifying always-on-top windows. These windows are
* always above other windows because they are moved below them.
* status-bar is above news-window because it has been created earlier.
@ -1072,8 +1170,8 @@ void InitWindowSystem()
_z_back_window = NULL;
_z_front_window = NULL;
_focused_window = NULL;
_mouseover_last_w = NULL;
_no_scroll = 0;
_scrolling_viewport = 0;
}
@ -1620,11 +1718,6 @@ static bool MaybeBringWindowToFront(Window *w)
*/
void HandleKeypress(uint32 raw_key)
{
/* Stores if a window with a textfield for typing is open
* If this is the case, keypress events are only passed to windows with text fields and
* to thein this main toolbar. */
bool query_open = false;
/*
* During the generation of the world, there might be
* another thread that is currently building for example
@ -1654,29 +1747,16 @@ void HandleKeypress(uint32 raw_key)
*/
if (key == 0 && keycode == 0) return;
/* check if we have a query string window open before allowing hotkeys */
if (FindWindowById(WC_QUERY_STRING, 0) != NULL ||
FindWindowById(WC_SEND_NETWORK_MSG, 0) != NULL ||
FindWindowById(WC_GENERATE_LANDSCAPE, 0) != NULL ||
FindWindowById(WC_CONSOLE, 0) != NULL ||
FindWindowById(WC_SAVELOAD, 0) != NULL ||
FindWindowById(WC_COMPANY_PASSWORD_WINDOW, 0) != NULL) {
query_open = true;
/* Check if the focused window has a focused editbox */
if (EditBoxInGlobalFocus()) {
/* All input will in this case go to the focused window */
_focused_window->OnKeyPress(key, keycode);
return;
}
/* Call the event, start with the uppermost window. */
Window *w;
FOR_ALL_WINDOWS_FROM_FRONT(w) {
/* if a query window is open, only call the event for certain window types */
if (query_open &&
w->window_class != WC_QUERY_STRING &&
w->window_class != WC_SEND_NETWORK_MSG &&
w->window_class != WC_GENERATE_LANDSCAPE &&
w->window_class != WC_CONSOLE &&
w->window_class != WC_SAVELOAD &&
w->window_class != WC_COMPANY_PASSWORD_WINDOW) {
continue;
}
if (w->OnKeyPress(key, keycode) == Window::ES_HANDLED) return;
}
@ -1791,7 +1871,11 @@ static const int8 scrollamt[16][2] = {
static void HandleKeyScrolling()
{
if (_dirkeys && !_no_scroll) {
/*
* Check that any of the dirkeys is pressed and that the focused window
* dont has an edit-box as focused widget.
*/
if (_dirkeys && !EditBoxInGlobalFocus()) {
int factor = _shift_pressed ? 50 : 10;
ScrollMainViewport(scrollamt[_dirkeys][0] * factor, scrollamt[_dirkeys][1] * factor);
}

View File

@ -59,6 +59,8 @@ enum WindowDefaultFlag {
WDF_STICKY_BUTTON = 1 << 5, ///< Set window to sticky mode; they are not closed unless closed with 'X' (widget 2)
WDF_RESIZABLE = 1 << 6, ///< Window can be resized
WDF_MODAL = 1 << 7, ///< The window is a modal child of some other window, meaning the parent is 'inactive'
WDF_NO_FOCUS = 1 << 8, ///< This window won't get focus/make any other window lose focus when click
};
/**
@ -154,6 +156,7 @@ public:
Widget *widget; ///< Widgets of the window
uint widget_count; ///< Number of widgets of the window
uint32 desc_flags; ///< Window/widgets default flags setting, @see WindowDefaultFlag
const Widget *focused_widget; ///< Currently focused widget or NULL, if no widget has focus
Window *parent; ///< Parent window
Window *z_front; ///< The window in front of us in z-order
@ -169,6 +172,9 @@ public:
void HideWidget(byte widget_index);
void ShowWidget(byte widget_index);
bool IsWidgetHidden(byte widget_index) const;
void SetFocusedWidget(byte widget_index);
bool IsWidgetGloballyFocused(byte widget_index) const;
bool IsWidgetFocused(byte widget_index) const;
void SetWidgetLoweredState(byte widget_index, bool lowered_stat);
void ToggleWidgetLoweredState(byte widget_index);
void LowerWidget(byte widget_index);
@ -176,6 +182,7 @@ public:
bool IsWidgetLowered(byte widget_index) const;
void AlignWidgetRight(byte widget_index_a, byte widget_index_b);
int GetWidgetWidth(byte widget_index) const;
bool HasWidgetOfType(WidgetType widget_type) const;
void RaiseButtons();
void CDECL SetWidgetsDisabledState(bool disab_stat, int widgets, ...);
@ -198,6 +205,15 @@ public:
*/
virtual void OnPaint() {}
/**
* Called when window gains focus
*/
virtual void OnFocus() {}
/**
* Called when window looses focus
*/
virtual void OnFocusLost() {}
/**
* A key has been pressed.
@ -423,6 +439,7 @@ int GetWidgetFromPos(const Window *w, int x, int y);
/* window.cpp */
extern Window *_z_front_window;
extern Window *_z_back_window;
extern Window *_focused_window;
/** Iterate over all windows */
#define FOR_ALL_WINDOWS_FROM_BACK_FROM(w, start) for (w = start; w != NULL; w = w->z_front) if (w->window_class != WC_INVALID)
@ -430,12 +447,6 @@ extern Window *_z_back_window;
#define FOR_ALL_WINDOWS_FROM_BACK(w) FOR_ALL_WINDOWS_FROM_BACK_FROM(w, _z_back_window)
#define FOR_ALL_WINDOWS_FROM_FRONT(w) FOR_ALL_WINDOWS_FROM_FRONT_FROM(w, _z_front_window)
/**
* Disable scrolling of the main viewport when an input-window is active.
* This contains the count of windows with a textbox in them.
*/
extern byte _no_scroll;
extern Point _cursorpos_drag_start;
extern int _scrollbar_start_pos;
@ -455,6 +466,10 @@ enum SpecialMouseMode {
Window *GetCallbackWnd();
void SetFocusedWindow(Window *w);
const Widget *GetGloballyFocusedWidget();
bool EditBoxInGlobalFocus();
void ScrollbarClickHandler(Window *w, const Widget *wi, int x, int y);
void ResizeButtons(Window *w, byte left, byte right);
@ -550,6 +565,43 @@ inline bool Window::IsWidgetHidden(byte widget_index) const
return HasBit(this->widget[widget_index].display_flags, WIDG_HIDDEN);
}
/**
* Set focus within this window to given widget. The function however don't
* change which window that has focus.
* @param widget_index : index of the widget in the window to set focus to
*/
inline void Window::SetFocusedWidget(byte widget_index)
{
if (widget_index < this->widget_count) {
/* Repaint the widget that loss focus. A focused edit box may else leave the caret left on the screen */
if (this->focused_widget && this->focused_widget - this->widget != widget_index) {
this->InvalidateWidget(this->focused_widget - this->widget);
}
this->focused_widget = &this->widget[widget_index];
}
}
/**
* Check if given widget has user input focus. This means that both the window
* has focus and that the given widget has focus within the window.
* @param widget_index : index of the widget in the window to check
* @return true if given widget is the focused window in this window and this window has focus
*/
inline bool Window::IsWidgetGloballyFocused(byte widget_index) const
{
return _focused_window == this && IsWidgetFocused(widget_index);
}
/**
* Check if given widget is focused within this window
* @param widget_index : index of the widget in the window to check
* @return true if given widget is the focused window in this window
*/
inline bool Window::IsWidgetFocused(byte widget_index) const
{
return this->focused_widget == &this->widget[widget_index];
}
/**
* Sets the lowered/raised status of a widget.
* @param widget_index index of this widget in the window