summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrubidium <rubidium@openttd.org>2011-11-26 16:09:25 +0000
committerrubidium <rubidium@openttd.org>2011-11-26 16:09:25 +0000
commit435b5a08c4f9a3b9a079da6651bac0b287f0218d (patch)
tree693363a9f55374d5f735b5e81ad5d33b76662dab
parent2ba05f1601c0a041ed8f8c6fcc26b4ce2a8dfcf1 (diff)
downloadopenttd-435b5a08c4f9a3b9a079da6651bac0b287f0218d.tar.xz
(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)
-rw-r--r--src/window.cpp208
1 files changed, 129 insertions, 79 deletions
diff --git a/src/window.cpp b/src/window.cpp
index bc61d0c73..b1b37ff65 100644
--- a/src/window.cpp
+++ b/src/window.cpp
@@ -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);
}