(svn r23336) -Fix [FS#4709]: bring some more order in the ordering of the windows, e.g. don't let a save or load dialog get hidden by a new message (monoid)

pull/155/head
rubidium 13 years ago
parent 9a533fb58b
commit 4cbd3f4c5d

@ -837,7 +837,7 @@ void ChangeWindowOwner(Owner old_owner, Owner new_owner)
static void BringWindowToFront(Window *w);
/**
* Find a window and make it the top-window on the screen.
* Find a window and make it the relative top-window on the screen.
* The window gets unshaded if it was shaded, and a white border is drawn at its edges for a brief period of time to visualize its "activation".
* @param cls WindowClass of the window to activate
* @param number WindowNumber of the window to activate
@ -873,42 +873,142 @@ static inline bool IsVitalWindow(const Window *w)
}
/**
* On clicking on a window, make it the frontmost window of all. However
* there are certain windows that always need to be on-top; these include
* - Toolbar, Statusbar (always on)
* - New window, Chatbar (only if open)
* The window is marked dirty for a repaint if the window is actually moved
* @param w window that is put into the foreground
* @return pointer to the window, the same as the input pointer
* Get the z-priority for a given window. This is used in comparison with other z-priority values;
* a window with a given z-priority will appear above other windows with a lower value, and below
* those with a higher one (the ordering within z-priorities is arbitrary).
* @param w The window to get the z-priority for
* @pre w->window_class != WC_INVALID
* @return The window's z-priority
*/
static void BringWindowToFront(Window *w)
static uint GetWindowZPriority(const Window *w)
{
assert(w->window_class != WC_INVALID);
uint z_priority = 0;
switch (w->window_class) {
case WC_ENDSCREEN:
++z_priority;
case WC_HIGHSCORE:
++z_priority;
case WC_TOOLTIPS:
++z_priority;
case WC_DROPDOWN_MENU:
++z_priority;
case WC_MAIN_TOOLBAR:
case WC_STATUS_BAR:
++z_priority;
case WC_ERRMSG:
case WC_CONFIRM_POPUP_QUERY:
++z_priority;
case WC_SAVELOAD:
++z_priority;
case WC_MODAL_PROGRESS:
++z_priority;
case WC_CONSOLE:
++z_priority;
case WC_SEND_NETWORK_MSG:
case WC_NEWS_WINDOW:
++z_priority;
default:
++z_priority;
case WC_MAIN_WINDOW:
return z_priority;
}
}
/**
* Adds a window to the z-ordering, according to its z-priority.
* @param w Window to add
*/
static void AddWindowToZOrdering(Window *w)
{
Window *v = _z_front_window;
assert(w->z_front == NULL && w->z_back == NULL);
if (_z_front_window == NULL) {
/* It's the only window. */
_z_front_window = _z_back_window = w;
w->z_front = w->z_back = NULL;
} else {
/* Search down the z-ordering for its location. */
Window *v = _z_front_window;
uint last_z_priority = UINT_MAX;
while (v != NULL && (v->window_class == WC_INVALID || GetWindowZPriority(v) > GetWindowZPriority(w))) {
if (v->window_class != WC_INVALID) {
/* Sanity check z-ordering, while we're at it. */
assert(last_z_priority >= GetWindowZPriority(v));
last_z_priority = GetWindowZPriority(v);
}
v = v->z_back;
}
/* Bring the window just below the vital windows */
for (; v != NULL && v != w && IsVitalWindow(v); v = v->z_back) { }
if (v == NULL) {
/* It's the new back window. */
w->z_front = _z_back_window;
w->z_back = NULL;
_z_back_window->z_back = w;
_z_back_window = w;
} else if (v == _z_front_window) {
/* It's the new front window. */
w->z_front = NULL;
w->z_back = _z_front_window;
_z_front_window->z_front = w;
_z_front_window = w;
} else {
/* It's somewhere else in the z-ordering. */
w->z_front = v->z_front;
w->z_back = v;
v->z_front->z_back = w;
v->z_front = w;
}
}
}
if (v == NULL || w == v) return; // window is already in the right position
/* w cannot be at the top already! */
assert(w != _z_front_window);
/**
* Removes a window from the z-ordering.
* @param w Window to remove
*/
static void RemoveWindowFromZOrdering(Window *w)
{
if (w->z_front == NULL) {
assert(_z_front_window == w);
_z_front_window = w->z_back;
} else {
w->z_front->z_back = w->z_back;
}
if (w->z_back == NULL) {
assert(_z_back_window == w);
_z_back_window = w->z_front;
} else {
w->z_back->z_front = w->z_front;
}
w->z_front->z_back = w->z_back;
w->z_front = v->z_front;
w->z_back = v;
w->z_front = w->z_back = NULL;
}
if (v->z_front == NULL) {
_z_front_window = w;
} else {
v->z_front->z_back = w;
}
v->z_front = w;
/**
* On clicking on a window, make it the frontmost window of all windows with an equal
* or lower z-priority. The window is marked dirty for a repaint
* @param w window that is put into the relative foreground
*/
static void BringWindowToFront(Window *w)
{
RemoveWindowFromZOrdering(w);
AddWindowToZOrdering(w);
w->SetDirty();
}
@ -953,45 +1053,8 @@ void Window::InitializeData(const WindowDesc *desc, WindowNumber window_number)
* 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);
/* 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.
* Also, as the chat-window is excluded from this, it will always be
* the last window, thus always on top.
* XXX - Yes, ugly, probably needs something like w->always_on_top flag
* to implement correctly, but even then you need some kind of distinction
* between on-top of chat/news and status windows, because these conflict */
Window *w = _z_front_window;
if (w != NULL && this->window_class != WC_SEND_NETWORK_MSG && this->window_class != WC_HIGHSCORE && this->window_class != WC_ENDSCREEN) {
if (FindWindowById(WC_MAIN_TOOLBAR, 0) != NULL) w = w->z_back;
if (FindWindowById(WC_STATUS_BAR, 0) != NULL) w = w->z_back;
if (FindWindowById(WC_NEWS_WINDOW, 0) != NULL) w = w->z_back;
if (FindWindowByClass(WC_SEND_NETWORK_MSG) != NULL) w = w->z_back;
if (w == NULL) {
_z_back_window->z_front = this;
this->z_back = _z_back_window;
_z_back_window = this;
} else {
if (w->z_front == NULL) {
_z_front_window = this;
} else {
this->z_front = w->z_front;
w->z_front->z_back = this;
}
this->z_back = w;
w->z_front = this;
}
} else {
this->z_back = _z_front_window;
if (_z_front_window != NULL) {
_z_front_window->z_front = this;
} else {
_z_back_window = this;
}
_z_front_window = this;
}
/* Insert the window into the correct location in the z-ordering. */
AddWindowToZOrdering(this);
}
/**
@ -1955,13 +2018,13 @@ static EventState HandleViewportScroll()
}
/**
* Check if a window can be made top-most window, and if so do
* Check if a window can be made relative top-most window, and if so do
* it. If a window does not obscure any other windows, it will not
* be brought to the foreground. Also if the only obscuring windows
* are so-called system-windows, the window will not be moved.
* The function will return false when a child window of this window is a
* modal-popup; function returns a false and child window gets a white border
* @param w Window to bring on-top
* @param w Window to bring relatively on-top
* @return false if the window has an active modal child, true otherwise
*/
static bool MaybeBringWindowToFront(Window *w)
@ -2392,20 +2455,7 @@ void InputLoop()
if (w->window_class != WC_INVALID) continue;
/* Find the window in the z-array, and effectively remove it
* by moving all windows after it one to the left. This must be
* done before removing the child so we cannot cause recursion
* between the deletion of the parent and the child. */
if (w->z_front == NULL) {
_z_front_window = w->z_back;
} else {
w->z_front->z_back = w->z_back;
}
if (w->z_back == NULL) {
_z_back_window = w->z_front;
} else {
w->z_back->z_front = w->z_front;
}
RemoveWindowFromZOrdering(w);
free(w);
}

Loading…
Cancel
Save