--- a/src/window.cpp Sun Feb 11 21:20:30 2007 +0000
+++ b/src/window.cpp Sun Feb 11 22:57:24 2007 +0000
@@ -19,74 +19,594 @@
// delta between mouse cursor and upper left corner of dragged window
static Point _drag_delta;
-static Window _windows[25];
-Window *_z_windows[lengthof(_windows)];
-Window **_last_z_window; ///< always points to the next free space in the z-array
+/*static*/ WindowList Window::s_list;
-void CDECL SetWindowWidgetsDisabledState(Window *w, bool disab_stat, int widgets, ...)
+//static Window _windows[25];
+//Window *_z_windows[lengthof(_windows)];
+//Window **_last_z_window; ///< always points to the next free space in the z-array
+
+int32 CountedObject::AddRef()
+{
+ return ++m_ref_cnt;
+}
+
+int32 CountedObject::Release()
+{
+ int32 res = --m_ref_cnt;
+ assert(res >= 0);
+ if (res == 0) {
+ FinalRelease();
+ delete this;
+ }
+ return res;
+}
+
+void WindowList::Add(Window *w)
+{
+ /* we will add the new window before first vital window or at the end */
+ Iterator it = w->IsVital() ? m_list.end() : FindFirstVitalWindow();
+ /* it should be now at the proper position where new window should be added */
+ m_list.insert(it, w);
+}
+
+void WindowList::Remove(Window *w)
+{
+ Iterator it = Find(w);
+ if (it != m_list.end()) m_list.erase(it);
+}
+
+WindowList::Iterator WindowList::Find(Window *w)
+{
+ struct Match {
+ Window *m_w;
+ bool EnumProc(Iterator it)
+ {
+ return (*it).w == m_w;
+ }
+ } match = {w};
+
+ Iterator it = EnumT(match);
+ if (it == m_list.end()) {
+ DEBUG(misc, 3, "Window (cls %d, number %d) is not open, probably removed by recursive calls",
+ w->window_class, w->window_number);
+ }
+ return it;
+}
+
+WindowList::Iterator WindowList::FindFirstVitalWindow()
+{
+ struct MatchNonVital {
+ bool EnumProc(Iterator it)
+ {
+ return !(*it).w->IsVital();
+ }
+ } match;
+
+ Iterator it = ReverseEnumT(match);
+ /* we have stopped on last non-vital window. Move one step forward to locate first vital window. */
+ if (it != m_list.end()) ++it;
+ return it;
+}
+
+WindowList::Iterator WindowList::FindByClass(WindowClass cls)
+{
+ struct MatchCls {
+ WindowClass m_cls;
+ bool EnumProc(Iterator it)
+ {
+ Window *w = (*it).w;
+ return w->window_class == m_cls;
+ }
+ } match = {cls};
+
+ Iterator it = EnumT(match);
+ return it;
+}
+
+WindowList::Iterator WindowList::FindById(WindowClass cls, WindowNumber num)
+{
+ struct MatchClsAndId {
+ WindowClass m_cls;
+ WindowNumber m_num;
+ bool EnumProc(Iterator it)
+ {
+ Window *w = (*it).w;
+ return w->window_class == m_cls && w->window_number == m_num;
+ }
+ } match = {cls, num};
+
+ Iterator it = EnumT(match);
+ return it;
+}
+
+/* Open a new window.
+* This function is called from AllocateWindow() or AllocateWindowDesc()
+* See descriptions for those functions for usage
+* See AllocateWindow() for description of arguments.
+* Only addition here is window_number, which is the window_number being assigned to the new window
+*/
+Window::Window(
+ int x, int y, int w, int h,
+ WindowProc *proc, WindowClass cls, const Widget *widget, int wnd_number)
+{
+ //Window *w = FindFreeWindow();
+
+ ///* We have run out of windows, close one and use that as the place for our new one */
+ //if (w == NULL) {
+ // w = FindDeletableWindow();
+ // if (w == NULL) w = ForceFindDeletableWindow();
+ // w->Close();
+ //}
+
+ // Set up window properties
+ //memset(w, 0, sizeof(*w));
+ ZeroInit();
+
+ window_class = cls;
+ flags4 = WF_WHITE_BORDER_MASK; // just opened windows have a white border
+ caption_color = 0xFF;
+ left = x;
+ top = y;
+ width = w;
+ height = h;
+ wndproc = proc;
+ AssignWidgetToWindow(this, widget);
+ resize.width = width;
+ resize.height = height;
+ resize.step_width = 1;
+ resize.step_height = 1;
+ window_number = wnd_number;
+
+ //{
+ // Window **wz = _last_z_window;
+
+ // /* 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 */
+ // if (wz != _z_windows && w->window_class != WC_SEND_NETWORK_MSG) {
+ // if (FindWindowById(WC_MAIN_TOOLBAR, 0) != NULL) wz--;
+ // if (FindWindowById(WC_STATUS_BAR, 0) != NULL) wz--;
+ // if (FindWindowById(WC_NEWS_WINDOW, 0) != NULL) wz--;
+ // if (FindWindowById(WC_SEND_NETWORK_MSG, 0) != NULL) wz--;
+
+ // assert(wz >= _z_windows);
+ // if (wz != _last_z_window) memmove(wz + 1, wz, (byte*)_last_z_window - (byte*)wz);
+ // }
+
+ // *wz = w;
+ // _last_z_window++;
+ //}
+
+ /* add our new window into z-order list */
+ Window::s_list.Add(this);
+
+ SetDirty();
+ CallWindowEventNP(this, WE_CREATE);
+
+ //return w;
+}
+
+/** Find the Window whose parent pointer points to this window
+* @parent w Window to find child of
+* @return return a Window pointer that is the child of w, or NULL otherwise */
+Window* Window::FindChild() const
+{
+ Window *v;
+ FOR_ALL_WINDOWS(v) {
+ if (v->parent == this) return v;
+ }
+
+ return NULL;
+}
+
+void Window::SetDirty() const
+{
+ if (this == NULL) return;
+ SetDirtyBlocks(left, top, left + width, top + height);
+}
+
+/*virtual*/ void Window::FinalRelease()
+{
+ /* Delete any children a window might have in a head-recursive manner */
+ Window *v = FindChild();
+ if (v != NULL) v->Close();
+
+ if (_thd.place_mode != VHM_NONE &&
+ _thd.window_class == window_class &&
+ _thd.window_number == window_number) {
+ ResetObjectToPlace();
+ }
+
+ CallWindowEventNP(this, WE_DESTROY);
+ if (viewport != NULL) DeleteWindowViewport(this);
+
+ SetDirty();
+ free(widget);
+ widget = NULL;
+ widget_count = 0;
+ parent = NULL;
+}
+
+/*virtual*/ void Window::Close()
+{
+ s_list.Remove(this);
+}
+
+/*virtual*/ bool Window::IsVital()
+{
+ WindowClass wc = window_class;
+ return (wc == WC_MAIN_TOOLBAR || wc == WC_STATUS_BAR || wc == WC_NEWS_WINDOW || wc == WC_SEND_NETWORK_MSG);
+}
+
+/**
+* Open a new window. If there is no space for a new window, close an open
+* window. Try to avoid stickied windows, but if there is no else, close one of
+* those as well. Then make sure all created windows are below some always-on-top
+* ones. Finally set all variables and call the WE_CREATE event
+* @param x offset in pixels from the left of the screen
+* @param y offset in pixels from the top of the screen
+* @param width width in pixels of the window
+* @param height height in pixels of the window
+* @param *proc @see WindowProc function to call when any messages/updates happen to the window
+* @param cls @see WindowClass class of the window, used for identification and grouping
+* @param *widget @see Widget pointer to the window layout and various elements
+* @return @see Window pointer of the newly created window
+*/
+/*static*/ Window* Window::Allocate(
+ int x, int y, int width, int height,
+ WindowProc *proc, WindowClass cls, const Widget *widget)
+{
+ return new Window(x, y, width, height, proc, cls, widget, 0);
+}
+
+/*static*/ Window* Window::Get(WindowList::Iterator it)
+{
+ return (it != s_list.m_list.end()) ? (*it).w : NULL;
+}
+
+/*static*/ Window* Window::FindById(WindowClass cls, WindowNumber num)
+{
+ return Get(s_list.FindById(cls, num));
+}
+
+/*static*/ void Window::SetDirtyById(WindowClass cls, WindowNumber num)
+{
+ Window *w = FindById(cls, num);
+ if (w != NULL) w->SetDirty();
+}
+
+void CDECL Window::SetWidgetsDisabledState(bool disab_stat, int widgets, ...)
{
va_list wdg_list;
va_start(wdg_list, widgets);
while (widgets != WIDGET_LIST_END) {
- SetWindowWidgetDisabledState(w, widgets, disab_stat);
- widgets = va_arg(wdg_list, int);
- }
-
- va_end(wdg_list);
-}
-
-void CDECL SetWindowWidgetsHiddenState(Window *w, bool hidden_stat, int widgets, ...)
-{
- va_list wdg_list;
-
- va_start(wdg_list, widgets);
-
- while (widgets != WIDGET_LIST_END) {
- SetWindowWidgetHiddenState(w, widgets, hidden_stat);
+ SetWindowWidgetDisabledState(this, widgets, disab_stat);
widgets = va_arg(wdg_list, int);
}
va_end(wdg_list);
}
-void CDECL SetWindowWidgetsLoweredState(Window *w, bool lowered_stat, int widgets, ...)
+void CDECL Window::SetWidgetsHiddenState(bool hidden_stat, int widgets, ...)
{
va_list wdg_list;
va_start(wdg_list, widgets);
while (widgets != WIDGET_LIST_END) {
- SetWindowWidgetLoweredState(w, widgets, lowered_stat);
+ SetWindowWidgetHiddenState(this, widgets, hidden_stat);
widgets = va_arg(wdg_list, int);
}
va_end(wdg_list);
}
-void RaiseWindowButtons(Window *w)
+void CDECL Window::SetWidgetsLoweredState(bool lowered_stat, int widgets, ...)
+{
+ va_list wdg_list;
+
+ va_start(wdg_list, widgets);
+
+ while (widgets != WIDGET_LIST_END) {
+ SetWindowWidgetLoweredState(this, widgets, lowered_stat);
+ widgets = va_arg(wdg_list, int);
+ }
+
+ va_end(wdg_list);
+}
+
+void Window::RaiseButtons()
{
uint i;
- for (i = 0; i < w->widget_count; i++) {
- if (IsWindowWidgetLowered(w, i)) {
- RaiseWindowWidget(w, i);
- InvalidateWidget(w, i);
+ for (i = 0; i < widget_count; i++) {
+ if (IsWindowWidgetLowered(this, i)) {
+ RaiseWindowWidget(this, i);
+ InvalidateWidget(this, i);
}
}
}
-void HandleButtonClick(Window *w, byte widget)
+void Window::HandleButtonClick(byte widget)
{
- LowerWindowWidget(w, widget);
- w->flags4 |= 5 << WF_TIMEOUT_SHL;
- InvalidateWidget(w, widget);
+ LowerWindowWidget(this, widget);
+ this->flags4 |= 5 << WF_TIMEOUT_SHL;
+ InvalidateWidget(this, widget);
+}
+
+/** 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
+*/
+void Window::BringToFront()
+{
+ WindowPtr wp = this;
+ WindowList::Iterator it = Window::s_list.Find(this);
+ Window::s_list.Remove(this);
+ Window::s_list.Add(this);
+
+ SetDirty();
+}
+
+/** Find a window and make it the top-window on the screen. The window
+* gets a white border for a brief period of time to visualize its
+* "activation"
+* @return a pointer to the window thus activated */
+/*static*/ Window* Window::BringToFrontById(WindowClass cls, WindowNumber num)
+{
+ Window *w = FindById(cls, num);
+ if (w != NULL) {
+ w->flags4 |= WF_WHITE_BORDER_MASK;
+ w->BringToFront();
+ }
+ return w;
+}
+
+static bool _dragging_window;
+
+void Window::StartDrag()
+{
+ flags4 |= WF_DRAGGING;
+ _dragging_window = true;
+
+ _drag_delta.x = left - _cursor.pos.x;
+ _drag_delta.y = top - _cursor.pos.y;
+
+ BringToFront();
+ DeleteWindowById(WC_DROPDOWN_MENU, 0);
+}
+
+bool Window::ContinueDrag()
+{
+ const Widget *t = &widget[1]; // the title bar ... ugh
+ const Window *v;
+ int x;
+ int y;
+ int nx;
+ int ny;
+
+ // Stop the dragging if the left mouse button was released
+ if (!_left_button_down) {
+ flags4 &= ~WF_DRAGGING;
+ _dragging_window = false;
+ return false;
+ }
+
+ SetDirty();
+
+ x = _cursor.pos.x + _drag_delta.x;
+ y = _cursor.pos.y + _drag_delta.y;
+ nx = x;
+ ny = y;
+
+ if (_patches.window_snap_radius != 0) {
+ Window *v;
+
+ int hsnap = _patches.window_snap_radius;
+ int vsnap = _patches.window_snap_radius;
+ int delta;
+
+ FOR_ALL_WINDOWS(v) {
+ if (v == this) continue; // Don't snap at yourself
+
+ if (y + height > v->top && y < v->top + v->height) {
+ // Your left border <-> other right border
+ delta = abs(v->left + v->width - x);
+ if (delta <= hsnap) {
+ nx = v->left + v->width;
+ hsnap = delta;
+ }
+
+ // Your right border <-> other left border
+ delta = abs(v->left - x - width);
+ if (delta <= hsnap) {
+ nx = v->left - width;
+ hsnap = delta;
+ }
+ }
+
+ if (top + height >= v->top && top <= v->top + v->height) {
+ // Your left border <-> other left border
+ delta = abs(v->left - x);
+ if (delta <= hsnap) {
+ nx = v->left;
+ hsnap = delta;
+ }
+
+ // Your right border <-> other right border
+ delta = abs(v->left + v->width - x - width);
+ if (delta <= hsnap) {
+ nx = v->left + v->width - width;
+ hsnap = delta;
+ }
+ }
+
+ if (x + width > v->left && x < v->left + v->width) {
+ // Your top border <-> other bottom border
+ delta = abs(v->top + v->height - y);
+ if (delta <= vsnap) {
+ ny = v->top + v->height;
+ vsnap = delta;
+ }
+
+ // Your bottom border <-> other top border
+ delta = abs(v->top - y - height);
+ if (delta <= vsnap) {
+ ny = v->top - height;
+ vsnap = delta;
+ }
+ }
+
+ if (left + width >= v->left && left <= v->left + v->width) {
+ // Your top border <-> other top border
+ delta = abs(v->top - y);
+ if (delta <= vsnap) {
+ ny = v->top;
+ vsnap = delta;
+ }
+
+ // Your bottom border <-> other bottom border
+ delta = abs(v->top + v->height - y - height);
+ if (delta <= vsnap) {
+ ny = v->top + v->height - height;
+ vsnap = delta;
+ }
+ }
+ }
+ }
+
+ // Make sure the window doesn't leave the screen
+ // 13 is the height of the title bar
+ nx = clamp(nx, 13 - t->right, _screen.width - 13 - t->left);
+ ny = clamp(ny, 0, _screen.height - 13);
+
+ // Make sure the title bar isn't hidden by behind the main tool bar
+ v = Window::FindById(WC_MAIN_TOOLBAR, 0);
+ if (v != NULL) {
+ int v_bottom = v->top + v->height;
+ int v_right = v->left + v->width;
+ if (ny + t->top >= v->top && ny + t->top < v_bottom) {
+ if ((v->left < 13 && nx + t->left < v->left) ||
+ (v_right > _screen.width - 13 && nx + t->right > v_right)) {
+ ny = v_bottom;
+ } else {
+ if (nx + t->left > v->left - 13 &&
+ nx + t->right < v_right + 13) {
+ if (top >= v_bottom) {
+ ny = v_bottom;
+ } else if (left < nx) {
+ nx = v->left - 13 - t->left;
+ } else {
+ nx = v_right + 13 - t->right;
+ }
+ }
+ }
+ }
+ }
+
+ if (viewport != NULL) {
+ viewport->left += nx - left;
+ viewport->top += ny - top;
+ }
+ left = nx;
+ top = ny;
+
+ SetDirty();
+ return false;
+}
+
+void Window::StartSizing()
+{
+ flags4 |= WF_SIZING;
+ _dragging_window = true;
+
+ _drag_delta.x = _cursor.pos.x;
+ _drag_delta.y = _cursor.pos.y;
+
+ BringToFront();
+ DeleteWindowById(WC_DROPDOWN_MENU, 0);
+}
+
+bool Window::ContinueSizing()
+{
+ WindowEvent e;
+ int x, y;
+
+ /* Stop the sizing if the left mouse button was released */
+ if (!_left_button_down) {
+ flags4 &= ~WF_SIZING;
+ SetDirty();
+ _dragging_window = false;
+ return false;
+ }
+
+ x = _cursor.pos.x - _drag_delta.x;
+ y = _cursor.pos.y - _drag_delta.y;
+
+ /* X and Y has to go by step.. calculate it.
+ * The cast to int is necessary else x/y are implicitly casted to
+ * unsigned int, which won't work. */
+ if (resize.step_width > 1) x -= x % (int)resize.step_width;
+
+ if (resize.step_height > 1) y -= y % (int)resize.step_height;
+
+ /* Check if we don't go below the minimum set size */
+ if ((int)width + x < (int)resize.width)
+ x = resize.width - width;
+ if ((int)height + y < (int)resize.height)
+ y = resize.height - height;
+
+ /* Window already on size */
+ if (x == 0 && y == 0) return false;
+
+ /* Now find the new cursor pos.. this is NOT _cursor, because
+ we move in steps. */
+ _drag_delta.x += x;
+ _drag_delta.y += y;
+
+ /* ResizeWindow sets both pre- and after-size to dirty for redrawal */
+ ResizeWindow(this, x, y);
+
+ e.event = WE_RESIZE;
+ e.we.sizing.size.x = x + width;
+ e.we.sizing.size.y = y + height;
+ e.we.sizing.diff.x = x;
+ e.we.sizing.diff.y = y;
+ wndproc(this, &e);
+ return false;
+
+}
+
+/*static*/ bool Window::HandleWindowDragging(void)
+{
+ // Get out immediately if no window is being dragged at all.
+ if (!_dragging_window) return true;
+
+ // Otherwise find the window...
+ Window *w;
+ FOR_ALL_WINDOWS(w) {
+ if (w->flags4 & WF_DRAGGING) {
+ return w->ContinueDrag();
+ } else if (w->flags4 & WF_SIZING) {
+ return w->ContinueSizing();
+ }
+ }
+ _dragging_window = false;
+ return false;
}
-static void StartWindowDrag(Window *w);
-static void StartWindowSizing(Window *w);
static void DispatchLeftClickEvent(Window *w, int x, int y)
{
@@ -112,7 +632,7 @@
case WWT_PANEL | WWB_PUSHBUTTON: /* WWT_PUSHBTN */
case WWT_IMGBTN | WWB_PUSHBUTTON: /* WWT_PUSHIMGBTN */
case WWT_TEXTBTN | WWB_PUSHBUTTON: /* WWT_PUSHTXTBTN */
- HandleButtonClick(w, e.we.click.widget);
+ w->HandleButtonClick(e.we.click.widget);
break;
}
} else if (wi->type == WWT_SCROLLBAR || wi->type == WWT_SCROLL2BAR || wi->type == WWT_HSCROLLBAR) {
@@ -121,18 +641,18 @@
if (w->desc_flags & WDF_STD_BTN) {
if (e.we.click.widget == 0) { /* 'X' */
- DeleteWindow(w);
+ w->Close();
return;
}
if (e.we.click.widget == 1) { /* 'Title bar' */
- StartWindowDrag(w);
+ w->StartDrag();
return;
}
}
if (w->desc_flags & WDF_RESIZABLE && wi->type == WWT_RESIZEBOX) {
- StartWindowSizing(w);
+ w->StartSizing();
InvalidateWidget(w, e.we.click.widget);
return;
}
@@ -196,64 +716,63 @@
int pos = clamp(sb->pos + wheel, 0, sb->count - sb->cap);
if (pos != sb->pos) {
sb->pos = pos;
- SetWindowDirty(w);
+ w->SetDirty();
}
}
}
}
-static void DrawOverlappedWindow(Window* const *wz, int left, int top, int right, int bottom);
+static void DrawOverlappedWindow(WindowList::Iterator it, int left, int top, int right, int bottom);
void DrawOverlappedWindowForAll(int left, int top, int right, int bottom)
{
- Window* const *wz;
DrawPixelInfo bk;
_cur_dpi = &bk;
- FOR_ALL_WINDOWS(wz) {
- const Window *w = *wz;
+ const Window *w;
+ FOR_ALL_WINDOWS(w) {
if (right > w->left &&
bottom > w->top &&
left < w->left + w->width &&
top < w->top + w->height) {
- DrawOverlappedWindow(wz, left, top, right, bottom);
+ DrawOverlappedWindow(it, left, top, right, bottom);
}
}
}
-static void DrawOverlappedWindow(Window* const *wz, int left, int top, int right, int bottom)
+static void DrawOverlappedWindow(WindowList::Iterator wit, int left, int top, int right, int bottom)
{
- Window* const *vz = wz;
- int x;
+ Window *w = (*wit).w;
- while (++vz != _last_z_window) {
- const Window *v = *vz;
+ for (WindowList::Iterator vit = wit; ++vit != Window::s_list.m_list.end(); ) {
+ const Window *v = (*vit).w;
+ int x;
if (right > v->left &&
bottom > v->top &&
left < v->left + v->width &&
top < v->top + v->height) {
if (left < (x=v->left)) {
- DrawOverlappedWindow(wz, left, top, x, bottom);
- DrawOverlappedWindow(wz, x, top, right, bottom);
+ DrawOverlappedWindow(wit, left, top, x, bottom);
+ DrawOverlappedWindow(wit, x, top, right, bottom);
return;
}
if (right > (x=v->left + v->width)) {
- DrawOverlappedWindow(wz, left, top, x, bottom);
- DrawOverlappedWindow(wz, x, top, right, bottom);
+ DrawOverlappedWindow(wit, left, top, x, bottom);
+ DrawOverlappedWindow(wit, x, top, right, bottom);
return;
}
if (top < (x=v->top)) {
- DrawOverlappedWindow(wz, left, top, right, x);
- DrawOverlappedWindow(wz, left, x, right, bottom);
+ DrawOverlappedWindow(wit, left, top, right, x);
+ DrawOverlappedWindow(wit, left, x, right, bottom);
return;
}
if (bottom > (x=v->top + v->height)) {
- DrawOverlappedWindow(wz, left, top, right, x);
- DrawOverlappedWindow(wz, left, x, right, bottom);
+ DrawOverlappedWindow(wit, left, top, right, x);
+ DrawOverlappedWindow(wit, left, x, right, bottom);
return;
}
@@ -265,12 +784,12 @@
DrawPixelInfo *dp = _cur_dpi;
dp->width = right - left;
dp->height = bottom - top;
- dp->left = left - (*wz)->left;
- dp->top = top - (*wz)->top;
+ dp->left = left - w->left;
+ dp->top = top - w->top;
dp->pitch = _screen.pitch;
dp->dst_ptr = _screen.dst_ptr + top * _screen.pitch + left;
dp->zoom = 0;
- CallWindowEventNP(*wz, WE_PAINT);
+ CallWindowEventNP(w, WE_PAINT);
}
}
@@ -282,104 +801,48 @@
w->wndproc(w, &e);
}
-void SetWindowDirty(const Window *w)
-{
- if (w == NULL) return;
- SetDirtyBlocks(w->left, w->top, w->left + w->width, w->top + w->height);
-}
-
-/** Find the Window whose parent pointer points to this window
- * @parent w Window to find child of
- * @return return a Window pointer that is the child of w, or NULL otherwise */
-static Window *FindChildWindow(const Window *w)
-{
- Window* const *wz;
-
- FOR_ALL_WINDOWS(wz) {
- Window *v = *wz;
- if (v->parent == w) return v;
- }
-
- return NULL;
-}
-
/** Find the z-value of a window. A window must already be open
* or the behaviour is undefined but function should never fail */
-Window **FindWindowZPosition(const Window *w)
-{
- Window **wz;
-
- for (wz = _z_windows; wz != _last_z_window; wz++) {
- if (*wz == w) return wz;
- }
-
- DEBUG(misc, 3, "Window (cls %d, number %d) is not open, probably removed by recursive calls",
- w->window_class, w->window_number);
- return NULL;
-}
-
-void DeleteWindow(Window *w)
-{
- Window *v;
- Window **wz;
- if (w == NULL) return;
-
- /* Delete any children a window might have in a head-recursive manner */
- v = FindChildWindow(w);
- if (v != NULL) DeleteWindow(v);
+//WindowList::Iterator FindWindowZPosition(const Window *w)
+//{
+// Window *wz;
+// FOR_ALL_WINDOWS(wz) {
+// if (wz == w) return it;
+// }
+//
+// DEBUG(misc, 3, "Window (cls %d, number %d) is not open, probably removed by recursive calls",
+// w->window_class, w->window_number);
+// return Window::s_list.m_list.end();
+//}
- if (_thd.place_mode != VHM_NONE &&
- _thd.window_class == w->window_class &&
- _thd.window_number == w->window_number) {
- ResetObjectToPlace();
- }
-
- CallWindowEventNP(w, WE_DESTROY);
- if (w->viewport != NULL) DeleteWindowViewport(w);
-
- SetWindowDirty(w);
- free(w->widget);
- w->widget = NULL;
- w->widget_count = 0;
- w->parent = NULL;
-
- /* Find the window in the z-array, and effectively remove it
- * by moving all windows after it one to the left */
- wz = FindWindowZPosition(w);
- if (wz == NULL) return;
- memmove(wz, wz + 1, (byte*)_last_z_window - (byte*)wz);
- _last_z_window--;
-}
-
-Window *FindWindowById(WindowClass cls, WindowNumber number)
-{
- Window* const *wz;
-
- FOR_ALL_WINDOWS(wz) {
- Window *w = *wz;
- if (w->window_class == cls && w->window_number == number) return w;
- }
-
- return NULL;
-}
+//Window *FindWindowById(WindowClass cls, WindowNumber number)
+//{
+// Window *w;
+//
+// FOR_ALL_WINDOWS(w) {
+// if (w->window_class == cls && w->window_number == number) return w;
+// }
+//
+// return NULL;
+//}
void DeleteWindowById(WindowClass cls, WindowNumber number)
{
- DeleteWindow(FindWindowById(cls, number));
+ Window *w = Window::FindById(cls, number);
+ if (w != NULL) w->Close();
}
void DeleteWindowByClass(WindowClass cls)
{
- Window* const *wz;
restart_search:
/* When we find the window to delete, we need to restart the search
* as deleting this window could cascade in deleting (many) others
* anywhere in the z-array */
- FOR_ALL_WINDOWS(wz) {
- Window *w = *wz;
+ Window *w;
+ FOR_ALL_WINDOWS(w) {
if (w->window_class == cls) {
- DeleteWindow(w);
+ w->Close();
goto restart_search;
}
}
@@ -391,16 +854,15 @@
* @param id PlayerID player identifier */
void DeletePlayerWindows(PlayerID id)
{
- Window* const *wz;
restart_search:
/* When we find the window to delete, we need to restart the search
* as deleting this window could cascade in deleting (many) others
* anywhere in the z-array */
- FOR_ALL_WINDOWS(wz) {
- Window *w = *wz;
+ Window *w;
+ FOR_ALL_WINDOWS(w) {
if (w->caption_color == id) {
- DeleteWindow(w);
+ w->Close();
goto restart_search;
}
}
@@ -416,10 +878,9 @@
* @param new_player PlayerID of the new owner of the window */
void ChangeWindowOwner(PlayerID old_player, PlayerID new_player)
{
- Window* const *wz;
+ Window *w;
- FOR_ALL_WINDOWS(wz) {
- Window *w = *wz;
+ FOR_ALL_WINDOWS(w) {
if (w->caption_color != old_player) continue;
if (w->window_class == WC_PLAYER_COLOR) continue;
@@ -436,60 +897,6 @@
}
}
-static void BringWindowToFront(const Window *w);
-
-/** Find a window and make it the top-window on the screen. The window
- * gets a white border for a brief period of time to visualize its
- * "activation"
- * @return a pointer to the window thus activated */
-Window *BringWindowToFrontById(WindowClass cls, WindowNumber number)
-{
- Window *w = FindWindowById(cls, number);
-
- if (w != NULL) {
- w->flags4 |= WF_WHITE_BORDER_MASK;
- BringWindowToFront(w);
- SetWindowDirty(w);
- }
-
- return w;
-}
-
-static inline bool IsVitalWindow(const Window *w)
-{
- WindowClass wc = w->window_class;
- return (wc == WC_MAIN_TOOLBAR || wc == WC_STATUS_BAR || wc == WC_NEWS_WINDOW || wc == WC_SEND_NETWORK_MSG);
-}
-
-/** 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
- */
-static void BringWindowToFront(const Window *w)
-{
- Window *tempz;
- Window **wz = FindWindowZPosition(w);
- Window **vz = _last_z_window;
-
- /* Bring the window just below the vital windows */
- do {
- if (--vz < _z_windows) return;
- } while (IsVitalWindow(*vz));
-
- if (wz == vz) return; // window is already in the right position
- assert(wz < vz);
-
- tempz = *wz;
- memmove(wz, wz + 1, (byte*)vz - (byte*)wz);
- *vz = tempz;
-
- SetWindowDirty(w);
-}
-
/** We have run out of windows, so find a suitable candidate for replacement.
* Keep all important windows intact. These are
* - Main window (gamefield), Toolbar, Statusbar (always on)
@@ -497,18 +904,21 @@
* - Any sticked windows since we wanted to keep these
* @return w pointer to the window that is going to be deleted
*/
-static Window *FindDeletableWindow(void)
-{
- Window* const *wz;
-
- FOR_ALL_WINDOWS(wz) {
- Window *w = *wz;
- if (w->window_class != WC_MAIN_WINDOW && !IsVitalWindow(w) && !(w->flags4 & WF_STICKY)) {
- return w;
- }
- }
- return NULL;
-}
+//static Window *FindDeletableWindow(void)
+//{
+// Window *w;
+// FOR_ALL_WINDOWS(w) {
+// if (w->window_class != WC_MAIN_WINDOW && !IsVitalWindow(w) && !(w->flags4 & WF_STICKY)) {
+// return w;
+// }
+// }
+// FOR_ALL_WINDOWS(w) {
+// if (w->window_class != WC_MAIN_WINDOW && !IsVitalWindow(w)) {
+// return w;
+// }
+// }
+// return NULL;
+//}
/** A window must be freed, and all are marked as important windows. Ease the
* restriction a bit by allowing to delete sticky windows. Keep important/vital
@@ -517,16 +927,16 @@
* @see FindDeletableWindow()
* @return w Pointer to the window that is being deleted
*/
-static Window *ForceFindDeletableWindow(void)
-{
- Window* const *wz;
-
- for (wz = _z_windows;; wz++) {
- Window *w = *wz;
- assert(wz < _last_z_window);
- if (w->window_class != WC_MAIN_WINDOW && !IsVitalWindow(w)) return w;
- }
-}
+//static Window *ForceFindDeletableWindow(void)
+//{
+// Window* const *wz;
+//
+// for (wz = _z_windows;; wz++) {
+// Window *w = *wz;
+// assert(wz < _last_z_window);
+// if (w->window_class != WC_MAIN_WINDOW && !IsVitalWindow(w)) return w;
+// }
+//}
bool IsWindowOfPrototype(const Window *w, const Widget *widget)
{
@@ -553,115 +963,28 @@
}
}
-static Window *FindFreeWindow(void)
-{
- Window *w;
-
- for (w = _windows; w < endof(_windows); w++) {
- Window* const *wz;
- bool window_in_use = false;
-
- FOR_ALL_WINDOWS(wz) {
- if (*wz == w) {
- window_in_use = true;
- break;
- }
- }
-
- if (!window_in_use) return w;
- }
-
- assert(_last_z_window == endof(_z_windows));
- return NULL;
-}
-
-/* Open a new window.
- * This function is called from AllocateWindow() or AllocateWindowDesc()
- * See descriptions for those functions for usage
- * See AllocateWindow() for description of arguments.
- * Only addition here is window_number, which is the window_number being assigned to the new window
- */
-static Window *LocalAllocateWindow(
- int x, int y, int width, int height,
- WindowProc *proc, WindowClass cls, const Widget *widget, int window_number)
-{
- Window *w = FindFreeWindow();
-
- /* We have run out of windows, close one and use that as the place for our new one */
- if (w == NULL) {
- w = FindDeletableWindow();
- if (w == NULL) w = ForceFindDeletableWindow();
- DeleteWindow(w);
- }
+//static Window *FindFreeWindow(void)
+//{
+// Window *w;
+//
+// for (w = _windows; w < endof(_windows); w++) {
+// Window* const *wz;
+// bool window_in_use = false;
+//
+// FOR_ALL_WINDOWS(wz) {
+// if (*wz == w) {
+// window_in_use = true;
+// break;
+// }
+// }
+//
+// if (!window_in_use) return w;
+// }
+//
+// assert(_last_z_window == endof(_z_windows));
+// return NULL;
+//}
- // Set up window properties
- memset(w, 0, sizeof(*w));
- w->window_class = cls;
- w->flags4 = WF_WHITE_BORDER_MASK; // just opened windows have a white border
- w->caption_color = 0xFF;
- w->left = x;
- w->top = y;
- w->width = width;
- w->height = height;
- w->wndproc = proc;
- AssignWidgetToWindow(w, widget);
- w->resize.width = width;
- w->resize.height = height;
- w->resize.step_width = 1;
- w->resize.step_height = 1;
- w->window_number = window_number;
-
- {
- Window **wz = _last_z_window;
-
- /* 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 */
- if (wz != _z_windows && w->window_class != WC_SEND_NETWORK_MSG) {
- if (FindWindowById(WC_MAIN_TOOLBAR, 0) != NULL) wz--;
- if (FindWindowById(WC_STATUS_BAR, 0) != NULL) wz--;
- if (FindWindowById(WC_NEWS_WINDOW, 0) != NULL) wz--;
- if (FindWindowById(WC_SEND_NETWORK_MSG, 0) != NULL) wz--;
-
- assert(wz >= _z_windows);
- if (wz != _last_z_window) memmove(wz + 1, wz, (byte*)_last_z_window - (byte*)wz);
- }
-
- *wz = w;
- _last_z_window++;
- }
-
- SetWindowDirty(w);
- CallWindowEventNP(w, WE_CREATE);
-
- return w;
-}
-
-/**
- * Open a new window. If there is no space for a new window, close an open
- * window. Try to avoid stickied windows, but if there is no else, close one of
- * those as well. Then make sure all created windows are below some always-on-top
- * ones. Finally set all variables and call the WE_CREATE event
- * @param x offset in pixels from the left of the screen
- * @param y offset in pixels from the top of the screen
- * @param width width in pixels of the window
- * @param height height in pixels of the window
- * @param *proc @see WindowProc function to call when any messages/updates happen to the window
- * @param cls @see WindowClass class of the window, used for identification and grouping
- * @param *widget @see Widget pointer to the window layout and various elements
- * @return @see Window pointer of the newly created window
- */
-Window *AllocateWindow(
- int x, int y, int width, int height,
- WindowProc *proc, WindowClass cls, const Widget *widget)
-{
- return LocalAllocateWindow(x, y, width, height, proc, cls, widget, 0);
-}
typedef struct SizeRect {
int left,top,width,height;
@@ -673,7 +996,6 @@
static bool IsGoodAutoPlace1(int left, int top)
{
int right,bottom;
- Window* const *wz;
_awap_r.left= left;
_awap_r.top = top;
@@ -684,8 +1006,8 @@
return false;
// Make sure it is not obscured by any window.
- FOR_ALL_WINDOWS(wz) {
- const Window *w = *wz;
+ Window *w;
+ FOR_ALL_WINDOWS(w) {
if (w->window_class == WC_MAIN_WINDOW) continue;
if (right > w->left &&
@@ -702,7 +1024,6 @@
static bool IsGoodAutoPlace2(int left, int top)
{
int width,height;
- Window* const *wz;
_awap_r.left= left;
_awap_r.top = top;
@@ -713,8 +1034,8 @@
if (top < 22 || top > _screen.height - (height>>2)) return false;
// Make sure it is not obscured by any window.
- FOR_ALL_WINDOWS(wz) {
- const Window *w = *wz;
+ Window *w;
+ FOR_ALL_WINDOWS(w) {
if (w->window_class == WC_MAIN_WINDOW) continue;
if (left + width > w->left &&
@@ -730,7 +1051,6 @@
static Point GetAutoPlacePosition(int width, int height)
{
- Window* const *wz;
Point pt;
_awap_r.width = width;
@@ -738,8 +1058,8 @@
if (IsGoodAutoPlace1(0, 24)) goto ok_pos;
- FOR_ALL_WINDOWS(wz) {
- const Window *w = *wz;
+ Window *w;
+ FOR_ALL_WINDOWS(w) {
if (w->window_class == WC_MAIN_WINDOW) continue;
if (IsGoodAutoPlace1(w->left+w->width+2,w->top)) goto ok_pos;
@@ -752,8 +1072,7 @@
if (IsGoodAutoPlace1(w->left+w->width-width,w->top- height-2)) goto ok_pos;
}
- FOR_ALL_WINDOWS(wz) {
- const Window *w = *wz;
+ FOR_ALL_WINDOWS(w) {
if (w->window_class == WC_MAIN_WINDOW) continue;
if (IsGoodAutoPlace2(w->left+w->width+2,w->top)) goto ok_pos;
@@ -766,9 +1085,7 @@
int left=0,top=24;
restart:;
- FOR_ALL_WINDOWS(wz) {
- const Window *w = *wz;
-
+ FOR_ALL_WINDOWS(w) {
if (w->left == left && w->top == top) {
left += 5;
top += 5;
@@ -796,7 +1113,7 @@
* However if it falls too extremely outside window positions, reposition
* it to an automatic place */
if (desc->parent_cls != 0 /* WC_MAIN_WINDOW */ &&
- (w = FindWindowById(desc->parent_cls, window_number)) != NULL &&
+ (w = Window::FindById(desc->parent_cls, window_number)) != NULL &&
w->left < _screen.width - 20 && w->left > -60 && w->top < _screen.height - 20) {
pt.x = w->left + 10;
@@ -807,11 +1124,11 @@
} else {
switch (desc->left) {
case WDP_ALIGN_TBR: { /* Align the right side with the top toolbar */
- w = FindWindowById(WC_MAIN_TOOLBAR, 0);
+ w = Window::FindById(WC_MAIN_TOOLBAR, 0);
pt.x = (w->left + w->width) - desc->width;
} break;
case WDP_ALIGN_TBL: /* Align the left side with the top toolbar */
- pt.x = FindWindowById(WC_MAIN_TOOLBAR, 0)->left;
+ pt.x = Window::FindById(WC_MAIN_TOOLBAR, 0)->left;
break;
case WDP_AUTO: /* Find a good automatic position for the window */
pt = GetAutoPlacePosition(desc->width, desc->height);
@@ -842,7 +1159,7 @@
}
allocate_window:
- w = LocalAllocateWindow(pt.x, pt.y, desc->width, desc->height, desc->proc, desc->cls, desc->widgets, window_number);
+ w = new Window(pt.x, pt.y, desc->width, desc->height, desc->proc, desc->cls, desc->widgets, window_number);
w->desc_flags = desc->flags;
return w;
}
@@ -867,7 +1184,7 @@
{
Window *w;
- if (BringWindowToFrontById(desc->cls, window_number)) return NULL;
+ if (Window::BringToFrontById(desc->cls, window_number) != NULL) return NULL;
w = LocalAllocateWindowDesc(desc, window_number);
return w;
}
@@ -877,10 +1194,8 @@
* @return a pointer to the found window if any, NULL otherwise */
Window *FindWindowFromPt(int x, int y)
{
- Window* const *wz;
-
- for (wz = _last_z_window; wz != _z_windows;) {
- Window *w = *--wz;
+ Window *w;
+ REVERSED_FOR_ALL_WINDOWS(w) {
if (IS_INSIDE_1D(x, w->left, w->width) && IS_INSIDE_1D(y, w->top, w->height)) {
return w;
}
@@ -893,28 +1208,30 @@
{
IConsoleClose();
- memset(&_windows, 0, sizeof(_windows));
- _last_z_window = _z_windows;
+ //memset(&_windows, 0, sizeof(_windows));
+ //_last_z_window = _z_windows;
InitViewports();
_no_scroll = 0;
}
void UnInitWindowSystem(void)
{
- Window **wz;
+ Window::s_list.m_list.clear();
-restart_search:
- /* Delete all windows, reset z-array.
- *When we find the window to delete, we need to restart the search
- * as deleting this window could cascade in deleting (many) others
- * anywhere in the z-array. We call DeleteWindow() so that it can properly
- * release own alloc'd memory, which otherwise could result in memleaks */
- FOR_ALL_WINDOWS(wz) {
- DeleteWindow(*wz);
- goto restart_search;
- }
-
- assert(_last_z_window == _z_windows);
+// Window **wz;
+//
+//restart_search:
+// /* Delete all windows, reset z-array.
+// *When we find the window to delete, we need to restart the search
+// * as deleting this window could cascade in deleting (many) others
+// * anywhere in the z-array. We call DeleteWindow() so that it can properly
+// * release own alloc'd memory, which otherwise could result in memleaks */
+// FOR_ALL_WINDOWS(wz) {
+// DeleteWindow(*wz);
+// goto restart_search;
+// }
+//
+// assert(_last_z_window == _z_windows);
}
void ResetWindowSystem(void)
@@ -930,31 +1247,26 @@
static void DecreaseWindowCounters(void)
{
Window *w;
- Window* const *wz;
-
- for (wz = _last_z_window; wz != _z_windows;) {
- w = *--wz;
+ REVERSED_FOR_ALL_WINDOWS(w) {
// Unclick scrollbar buttons if they are pressed.
if (w->flags4 & (WF_SCROLL_DOWN | WF_SCROLL_UP)) {
w->flags4 &= ~(WF_SCROLL_DOWN | WF_SCROLL_UP);
- SetWindowDirty(w);
+ w->SetDirty();
}
CallWindowEventNP(w, WE_MOUSELOOP);
}
- for (wz = _last_z_window; wz != _z_windows;) {
- w = *--wz;
-
+ REVERSED_FOR_ALL_WINDOWS(w) {
if (w->flags4&WF_TIMEOUT_MASK && !(--w->flags4&WF_TIMEOUT_MASK)) {
CallWindowEventNP(w, WE_TIMEOUT);
- if (w->desc_flags & WDF_UNCLICK_BUTTONS) RaiseWindowButtons(w);
+ if (w->desc_flags & WDF_UNCLICK_BUTTONS) w->RaiseButtons();
}
}
}
Window *GetCallbackWnd(void)
{
- return FindWindowById(_thd.window_class, _thd.window_number);
+ return Window::FindById(_thd.window_class, _thd.window_number);
}
static void HandlePlacePresize(void)
@@ -1008,7 +1320,7 @@
if (!_popup_menu_active) return true;
- w = FindWindowById(WC_TOOLBAR_MENU, 0);
+ w = Window::FindById(WC_TOOLBAR_MENU, 0);
if (w == NULL) {
_popup_menu_active = false;
return false;
@@ -1030,9 +1342,13 @@
static bool HandleMouseOver(void)
{
+ static WindowClass last_cls;
+ static WindowNumber last_num;
+
Window *w;
WindowEvent e;
- static Window *last_w = NULL;
+
+ Window *last_w = Window::FindById(last_cls, last_num);
w = FindWindowFromPt(_cursor.pos.x, _cursor.pos.y);
@@ -1043,7 +1359,9 @@
e.we.mouseover.pt.y = -1;
if (last_w->wndproc) last_w->wndproc(last_w, &e);
}
- last_w = w;
+
+ last_cls = w->window_class;
+ last_num = w->window_number;
if (w != NULL) {
// send an event in client coordinates.
@@ -1074,7 +1392,7 @@
if (x == 0 && y == 0) return;
- SetWindowDirty(w);
+ w->SetDirty();
for (wi = w->widget; wi->type != WWT_LAST; wi++) {
/* Isolate the resizing flags */
byte rsizeflag = GB(wi->display_flags, 0, 4);
@@ -1107,238 +1425,11 @@
if (resize_width) w->width += x;
if (resize_height) w->height += y;
- SetWindowDirty(w);
+ w->SetDirty();
}
-static bool _dragging_window;
-
-static bool HandleWindowDragging(void)
-{
- Window* const *wz;
- // Get out immediately if no window is being dragged at all.
- if (!_dragging_window) return true;
-
- // Otherwise find the window...
- FOR_ALL_WINDOWS(wz) {
- Window *w = *wz;
-
- if (w->flags4 & WF_DRAGGING) {
- const Widget *t = &w->widget[1]; // the title bar ... ugh
- const Window *v;
- int x;
- int y;
- int nx;
- int ny;
-
- // Stop the dragging if the left mouse button was released
- if (!_left_button_down) {
- w->flags4 &= ~WF_DRAGGING;
- break;
- }
-
- SetWindowDirty(w);
-
- x = _cursor.pos.x + _drag_delta.x;
- y = _cursor.pos.y + _drag_delta.y;
- nx = x;
- ny = y;
-
- if (_patches.window_snap_radius != 0) {
- Window* const *vz;
-
- int hsnap = _patches.window_snap_radius;
- int vsnap = _patches.window_snap_radius;
- int delta;
-
- FOR_ALL_WINDOWS(vz) {
- const Window *v = *vz;
-
- if (v == w) continue; // Don't snap at yourself
-
- if (y + w->height > v->top && y < v->top + v->height) {
- // Your left border <-> other right border
- delta = abs(v->left + v->width - x);
- if (delta <= hsnap) {
- nx = v->left + v->width;
- hsnap = delta;
- }
-
- // Your right border <-> other left border
- delta = abs(v->left - x - w->width);
- if (delta <= hsnap) {
- nx = v->left - w->width;
- hsnap = delta;
- }
- }
-
- if (w->top + w->height >= v->top && w->top <= v->top + v->height) {
- // Your left border <-> other left border
- delta = abs(v->left - x);
- if (delta <= hsnap) {
- nx = v->left;
- hsnap = delta;
- }
-
- // Your right border <-> other right border
- delta = abs(v->left + v->width - x - w->width);
- if (delta <= hsnap) {
- nx = v->left + v->width - w->width;
- hsnap = delta;
- }
- }
-
- if (x + w->width > v->left && x < v->left + v->width) {
- // Your top border <-> other bottom border
- delta = abs(v->top + v->height - y);
- if (delta <= vsnap) {
- ny = v->top + v->height;
- vsnap = delta;
- }
-
- // Your bottom border <-> other top border
- delta = abs(v->top - y - w->height);
- if (delta <= vsnap) {
- ny = v->top - w->height;
- vsnap = delta;
- }
- }
-
- if (w->left + w->width >= v->left && w->left <= v->left + v->width) {
- // Your top border <-> other top border
- delta = abs(v->top - y);
- if (delta <= vsnap) {
- ny = v->top;
- vsnap = delta;
- }
-
- // Your bottom border <-> other bottom border
- delta = abs(v->top + v->height - y - w->height);
- if (delta <= vsnap) {
- ny = v->top + v->height - w->height;
- vsnap = delta;
- }
- }
- }
- }
-
- // Make sure the window doesn't leave the screen
- // 13 is the height of the title bar
- nx = clamp(nx, 13 - t->right, _screen.width - 13 - t->left);
- ny = clamp(ny, 0, _screen.height - 13);
-
- // Make sure the title bar isn't hidden by behind the main tool bar
- v = FindWindowById(WC_MAIN_TOOLBAR, 0);
- if (v != NULL) {
- int v_bottom = v->top + v->height;
- int v_right = v->left + v->width;
- if (ny + t->top >= v->top && ny + t->top < v_bottom) {
- if ((v->left < 13 && nx + t->left < v->left) ||
- (v_right > _screen.width - 13 && nx + t->right > v_right)) {
- ny = v_bottom;
- } else {
- if (nx + t->left > v->left - 13 &&
- nx + t->right < v_right + 13) {
- if (w->top >= v_bottom) {
- ny = v_bottom;
- } else if (w->left < nx) {
- nx = v->left - 13 - t->left;
- } else {
- nx = v_right + 13 - t->right;
- }
- }
- }
- }
- }
-
- if (w->viewport != NULL) {
- w->viewport->left += nx - w->left;
- w->viewport->top += ny - w->top;
- }
- w->left = nx;
- w->top = ny;
-
- SetWindowDirty(w);
- return false;
- } else if (w->flags4 & WF_SIZING) {
- WindowEvent e;
- int x, y;
-
- /* Stop the sizing if the left mouse button was released */
- if (!_left_button_down) {
- w->flags4 &= ~WF_SIZING;
- SetWindowDirty(w);
- break;
- }
-
- x = _cursor.pos.x - _drag_delta.x;
- y = _cursor.pos.y - _drag_delta.y;
-
- /* X and Y has to go by step.. calculate it.
- * The cast to int is necessary else x/y are implicitly casted to
- * unsigned int, which won't work. */
- if (w->resize.step_width > 1) x -= x % (int)w->resize.step_width;
-
- if (w->resize.step_height > 1) y -= y % (int)w->resize.step_height;
-
- /* Check if we don't go below the minimum set size */
- if ((int)w->width + x < (int)w->resize.width)
- x = w->resize.width - w->width;
- if ((int)w->height + y < (int)w->resize.height)
- y = w->resize.height - w->height;
-
- /* Window already on size */
- if (x == 0 && y == 0) return false;
-
- /* Now find the new cursor pos.. this is NOT _cursor, because
- we move in steps. */
- _drag_delta.x += x;
- _drag_delta.y += y;
-
- /* ResizeWindow sets both pre- and after-size to dirty for redrawal */
- ResizeWindow(w, x, y);
-
- e.event = WE_RESIZE;
- e.we.sizing.size.x = x + w->width;
- e.we.sizing.size.y = y + w->height;
- e.we.sizing.diff.x = x;
- e.we.sizing.diff.y = y;
- w->wndproc(w, &e);
- return false;
- }
- }
-
- _dragging_window = false;
- return false;
-}
-
-static void StartWindowDrag(Window *w)
-{
- w->flags4 |= WF_DRAGGING;
- _dragging_window = true;
-
- _drag_delta.x = w->left - _cursor.pos.x;
- _drag_delta.y = w->top - _cursor.pos.y;
-
- BringWindowToFront(w);
- DeleteWindowById(WC_DROPDOWN_MENU, 0);
-}
-
-static void StartWindowSizing(Window *w)
-{
- w->flags4 |= WF_SIZING;
- _dragging_window = true;
-
- _drag_delta.x = _cursor.pos.x;
- _drag_delta.y = _cursor.pos.y;
-
- BringWindowToFront(w);
- DeleteWindowById(WC_DROPDOWN_MENU, 0);
-}
-
-
static bool HandleScrollbarScrolling(void)
{
- Window* const *wz;
int i;
int pos;
Scrollbar *sb;
@@ -1347,14 +1438,13 @@
if (!_scrolling_scrollbar) return true;
// Find the scrolling window
- FOR_ALL_WINDOWS(wz) {
- Window *w = *wz;
-
+ Window *w;
+ FOR_ALL_WINDOWS(w) {
if (w->flags4 & WF_SCROLL_MIDDLE) {
// Abort if no button is clicked any more.
if (!_left_button_down) {
w->flags4 &= ~WF_SCROLL_MIDDLE;
- SetWindowDirty(w);
+ w->SetDirty();
break;
}
@@ -1373,7 +1463,7 @@
pos = min(max(0, i + _scrollbar_start_pos) * sb->count / _scrollbar_size, max(0, sb->count - sb->cap));
if (pos != sb->pos) {
sb->pos = pos;
- SetWindowDirty(w);
+ w->SetDirty();
}
return false;
}
@@ -1423,32 +1513,30 @@
* modal-popup; function returns a false and child window gets a white border
* @param w Window to bring on-top
* @return false if the window has an active modal child, true otherwise */
-static bool MaybeBringWindowToFront(const Window *w)
+static bool MaybeBringWindowToFront(Window *w)
{
bool bring_to_front = false;
- Window* const *wz;
- Window* const *uz;
if (w->window_class == WC_MAIN_WINDOW ||
- IsVitalWindow(w) ||
+ w->IsVital() ||
w->window_class == WC_TOOLTIPS ||
w->window_class == WC_DROPDOWN_MENU) {
return true;
}
- wz = FindWindowZPosition(w);
- for (uz = wz; ++uz != _last_z_window;) {
- Window *u = *uz;
+ WindowList::Iterator wit = Window::s_list.Find(w);
+ for (WindowList::Iterator it = wit; it != Window::s_list.m_list.end(); it++) {
+ Window *u = (*it).w;
/* A modal child will prevent the activation of the parent window */
if (u->parent == w && (u->desc_flags & WDF_MODAL)) {
u->flags4 |= WF_WHITE_BORDER_MASK;
- SetWindowDirty(u);
+ u->SetDirty();
return false;
}
if (u->window_class == WC_MAIN_WINDOW ||
- IsVitalWindow(u) ||
+ u->IsVital() ||
u->window_class == WC_TOOLTIPS ||
u->window_class == WC_DROPDOWN_MENU) {
continue;
@@ -1465,7 +1553,7 @@
bring_to_front = true;
}
- if (bring_to_front) BringWindowToFront(w);
+ if (bring_to_front) w->BringToFront();
return true;
}
@@ -1496,7 +1584,7 @@
*/
void SendWindowMessage(WindowClass wnd_class, WindowNumber wnd_num, int msg, int wparam, int lparam)
{
- Window *w = FindWindowById(wnd_class, wnd_num);
+ Window *w = Window::FindById(wnd_class, wnd_num);
if (w != NULL) SendWindowMessageW(w, msg, wparam, lparam);
}
@@ -1509,10 +1597,10 @@
*/
void SendWindowMessageClass(WindowClass wnd_class, int msg, int wparam, int lparam)
{
- Window* const *wz;
+ Window *w;
- FOR_ALL_WINDOWS(wz) {
- if ((*wz)->window_class == wnd_class) SendWindowMessageW(*wz, msg, wparam, lparam);
+ FOR_ALL_WINDOWS(w) {
+ if (w->window_class == wnd_class) SendWindowMessageW(w, msg, wparam, lparam);
}
}
@@ -1521,7 +1609,6 @@
* 16 bits the keycode */
void HandleKeypress(uint32 key)
{
- Window* const *wz;
WindowEvent e;
/* 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
@@ -1546,18 +1633,17 @@
e.we.keypress.cont = true;
// 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) {
+ if (Window::FindById(WC_QUERY_STRING, 0) != NULL ||
+ Window::FindById(WC_SEND_NETWORK_MSG, 0) != NULL ||
+ Window::FindById(WC_GENERATE_LANDSCAPE, 0) != NULL ||
+ Window::FindById(WC_CONSOLE, 0) != NULL ||
+ Window::FindById(WC_SAVELOAD, 0) != NULL) {
query_open = true;
}
// Call the event, start with the uppermost window.
- for (wz = _last_z_window; wz != _z_windows;) {
- Window *w = *--wz;
-
+ Window *w;
+ REVERSED_FOR_ALL_WINDOWS(w) {
// if a query window is open, only call the event for certain window types
if (query_open &&
w->window_class != WC_QUERY_STRING &&
@@ -1572,7 +1658,7 @@
}
if (e.we.keypress.cont) {
- Window *w = FindWindowById(WC_MAIN_TOOLBAR, 0);
+ Window *w = Window::FindById(WC_MAIN_TOOLBAR, 0);
// When there is no toolbar w is null, check for that
if (w != NULL) w->wndproc(w, &e);
}
@@ -1630,13 +1716,13 @@
DecreaseWindowCounters();
HandlePlacePresize();
UpdateTileSelection();
- if (!VpHandlePlaceSizingDrag()) return;
- if (!HandleDragDrop()) return;
- if (!HandlePopupMenu()) return;
- if (!HandleWindowDragging()) return;
- if (!HandleScrollbarScrolling()) return;
- if (!HandleViewportScroll()) return;
- if (!HandleMouseOver()) return;
+ if (!VpHandlePlaceSizingDrag()) return;
+ if (!HandleDragDrop()) return;
+ if (!HandlePopupMenu()) return;
+ if (!Window::HandleWindowDragging()) return;
+ if (!HandleScrollbarScrolling()) return;
+ if (!HandleViewportScroll()) return;
+ if (!HandleMouseOver()) return;
x = _cursor.pos.x;
y = _cursor.pos.y;
@@ -1744,31 +1830,30 @@
void UpdateWindows(void)
{
- Window* const *wz;
static int we4_timer = 0;
int t = we4_timer + 1;
+ Window *w;
if (t >= 100) {
- for (wz = _last_z_window; wz != _z_windows;) {
- CallWindowEventNP(*--wz, WE_4);
+ REVERSED_FOR_ALL_WINDOWS(w) {
+ CallWindowEventNP(w, WE_4);
}
t = 0;
}
we4_timer = t;
- for (wz = _last_z_window; wz != _z_windows;) {
- Window *w = *--wz;
+ REVERSED_FOR_ALL_WINDOWS(w) {
if (w->flags4 & WF_WHITE_BORDER_MASK) {
w->flags4 -= WF_WHITE_BORDER_ONE;
- if (!(w->flags4 & WF_WHITE_BORDER_MASK)) SetWindowDirty(w);
+ if (!(w->flags4 & WF_WHITE_BORDER_MASK)) w->SetDirty();
}
}
DrawDirtyBlocks();
- FOR_ALL_WINDOWS(wz) {
- if ((*wz)->viewport != NULL) UpdateViewportPosition(*wz);
+ FOR_ALL_WINDOWS(w) {
+ if (w->viewport != NULL) UpdateViewportPosition(w);
}
DrawTextMessage();
// Redraw mouse cursor in case it was hidden
@@ -1791,11 +1876,10 @@
void InvalidateWindow(WindowClass cls, WindowNumber number)
{
- Window* const *wz;
+ Window *w;
- FOR_ALL_WINDOWS(wz) {
- const Window *w = *wz;
- if (w->window_class == cls && w->window_number == number) SetWindowDirty(w);
+ FOR_ALL_WINDOWS(w) {
+ if (w->window_class == cls && w->window_number == number) w->SetDirty();
}
}
@@ -1811,10 +1895,8 @@
void InvalidateWindowWidget(WindowClass cls, WindowNumber number, byte widget_index)
{
- Window* const *wz;
-
- FOR_ALL_WINDOWS(wz) {
- const Window *w = *wz;
+ Window *w;
+ FOR_ALL_WINDOWS(w) {
if (w->window_class == cls && w->window_number == number) {
InvalidateWidget(w, widget_index);
}
@@ -1823,57 +1905,51 @@
void InvalidateWindowClasses(WindowClass cls)
{
- Window* const *wz;
-
- FOR_ALL_WINDOWS(wz) {
- if ((*wz)->window_class == cls) SetWindowDirty(*wz);
+ Window *w;
+ FOR_ALL_WINDOWS(w) {
+ if (w->window_class == cls) w->SetDirty();
}
}
void InvalidateThisWindowData(Window *w)
{
CallWindowEventNP(w, WE_INVALIDATE_DATA);
- SetWindowDirty(w);
+ w->SetDirty();
}
void InvalidateWindowData(WindowClass cls, WindowNumber number)
{
- Window* const *wz;
-
- FOR_ALL_WINDOWS(wz) {
- Window *w = *wz;
+ Window *w;
+ FOR_ALL_WINDOWS(w) {
if (w->window_class == cls && w->window_number == number) InvalidateThisWindowData(w);
}
}
void InvalidateWindowClassesData(WindowClass cls)
{
- Window* const *wz;
-
- FOR_ALL_WINDOWS(wz) {
- if ((*wz)->window_class == cls) InvalidateThisWindowData(*wz);
+ Window *w;
+ FOR_ALL_WINDOWS(w) {
+ if (w->window_class == cls) InvalidateThisWindowData(w);
}
}
void CallWindowTickEvent(void)
{
- Window* const *wz;
-
- for (wz = _last_z_window; wz != _z_windows;) {
- CallWindowEventNP(*--wz, WE_TICK);
+ Window *w;
+ REVERSED_FOR_ALL_WINDOWS(w) {
+ CallWindowEventNP(w, WE_TICK);
}
}
void DeleteNonVitalWindows(void)
{
- Window* const *wz;
restart_search:
/* When we find the window to delete, we need to restart the search
* as deleting this window could cascade in deleting (many) others
* anywhere in the z-array */
- FOR_ALL_WINDOWS(wz) {
- Window *w = *wz;
+ Window *w;
+ FOR_ALL_WINDOWS(w) {
if (w->window_class != WC_MAIN_WINDOW &&
w->window_class != WC_SELECT_GAME &&
w->window_class != WC_MAIN_TOOLBAR &&
@@ -1882,7 +1958,7 @@
w->window_class != WC_TOOLTIPS &&
(w->flags4 & WF_STICKY) == 0) { // do not delete windows which are 'pinned'
- DeleteWindow(w);
+ w->Close();
goto restart_search;
}
}
@@ -1895,8 +1971,6 @@
* that standard windows (status bar, etc.) are not stickied, so these aren't affected */
void DeleteAllNonVitalWindows(void)
{
- Window* const *wz;
-
/* Delete every window except for stickied ones, then sticky ones as well */
DeleteNonVitalWindows();
@@ -1904,9 +1978,10 @@
/* When we find the window to delete, we need to restart the search
* as deleting this window could cascade in deleting (many) others
* anywhere in the z-array */
- FOR_ALL_WINDOWS(wz) {
- if ((*wz)->flags4 & WF_STICKY) {
- DeleteWindow(*wz);
+ Window *w;
+ FOR_ALL_WINDOWS(w) {
+ if (w->flags4 & WF_STICKY) {
+ w->Close();
goto restart_search;
}
}
@@ -1925,7 +2000,7 @@
DEBUG(misc, 5, "Repositioning Main Toolbar...");
if (w == NULL || w->window_class != WC_MAIN_TOOLBAR) {
- w = FindWindowById(WC_MAIN_TOOLBAR, 0);
+ w = Window::FindById(WC_MAIN_TOOLBAR, 0);
}
switch (_patches.toolbar_pos) {
@@ -1939,10 +2014,8 @@
void RelocateAllWindows(int neww, int newh)
{
- Window* const *wz;
-
- FOR_ALL_WINDOWS(wz) {
- Window *w = *wz;
+ Window *w;
+ FOR_ALL_WINDOWS(w) {
int left, top;
if (w->window_class == WC_MAIN_WINDOW) {