summaryrefslogtreecommitdiff
path: root/src/window.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/window.cpp')
-rw-r--r--src/window.cpp329
1 files changed, 50 insertions, 279 deletions
diff --git a/src/window.cpp b/src/window.cpp
index 034cff2a0..caf9f2840 100644
--- a/src/window.cpp
+++ b/src/window.cpp
@@ -74,23 +74,10 @@ WindowDesc::WindowDesc(int16 left, int16 top, int16 min_width, int16 min_height,
this->flags = flags;
this->nwid_parts = nwid_parts;
this->nwid_length = nwid_length;
- this->new_widgets = NULL;
-}
-
-/** Get widget array of the window description. */
-const Widget *WindowDesc::GetWidgets() const
-{
- if (this->nwid_parts != NULL) {
- InitializeWidgetArrayFromNestedWidgets(this->nwid_parts, this->nwid_length, &this->new_widgets);
- }
- const Widget *wids = this->new_widgets;
- assert(wids != NULL);
- return wids;
}
WindowDesc::~WindowDesc()
{
- free(this->new_widgets);
}
/**
@@ -103,10 +90,6 @@ void SetFocusedWindow(Window *w)
/* Invalidate focused widget */
if (_focused_window != NULL) {
- if (_focused_window->focused_widget != NULL) {
- uint focused_widget_id = _focused_window->focused_widget - _focused_window->widget;
- _focused_window->SetWidgetDirty(focused_widget_id);
- }
if (_focused_window->nested_focus != NULL) _focused_window->nested_focus->SetDirty(_focused_window);
}
@@ -131,10 +114,7 @@ bool EditBoxInGlobalFocus()
/* The console does not have an edit box so a special case is needed. */
if (_focused_window->window_class == WC_CONSOLE) return true;
- if (_focused_window->nested_array != NULL) {
- return _focused_window->nested_focus != NULL && _focused_window->nested_focus->type == WWT_EDITBOX;
- }
- return _focused_window->focused_widget != NULL && _focused_window->focused_widget->type == WWT_EDITBOX;
+ return _focused_window->nested_focus != NULL && _focused_window->nested_focus->type == WWT_EDITBOX;
}
/**
@@ -144,33 +124,18 @@ bool EditBoxInGlobalFocus()
*/
bool Window::SetFocusedWidget(byte widget_index)
{
- if (this->widget != NULL) {
- /* Do nothing if widget_index is already focused, or if it wasn't a valid widget. */
- if (widget_index >= this->widget_count || this->widget + widget_index == this->focused_widget) return false;
+ /* Do nothing if widget_index is already focused, or if it wasn't a valid widget. */
+ if (widget_index >= this->nested_array_size) return false;
- if (this->focused_widget != NULL) {
- /* Repaint the widget that lost focus. A focused edit box may else leave the caret on the screen. */
- this->SetWidgetDirty(this->focused_widget - this->widget);
- }
- this->focused_widget = &this->widget[widget_index];
- return true;
- }
-
- if (this->nested_array != NULL) {
- /* Do nothing if widget_index is already focused, or if it wasn't a valid widget. */
- if (widget_index >= this->nested_array_size) return false;
+ assert(this->nested_array[widget_index] != NULL); // Setting focus to a non-existing widget is a bad idea.
+ if (this->nested_focus != NULL) {
+ if (this->GetWidget<NWidgetCore>(widget_index) == this->nested_focus) return false;
- assert(this->nested_array[widget_index] != NULL); // Setting focus to a non-existing widget is a bad idea.
- if (this->nested_focus != NULL) {
- if (this->GetWidget<NWidgetCore>(widget_index) == this->nested_focus) return false;
-
- /* Repaint the widget that lost focus. A focused edit box may else leave the caret on the screen. */
- this->nested_focus->SetDirty(this);
- }
- this->nested_focus = this->GetWidget<NWidgetCore>(widget_index);
- return true;
+ /* Repaint the widget that lost focus. A focused edit box may else leave the caret on the screen. */
+ this->nested_focus->SetDirty(this);
}
- NOT_REACHED();
+ this->nested_focus = this->GetWidget<NWidgetCore>(widget_index);
+ return true;
}
/**
@@ -195,27 +160,6 @@ void CDECL Window::SetWidgetsDisabledState(bool disab_stat, int widgets, ...)
}
/**
- * Sets the hidden/shown status of a list of widgets.
- * By default, widgets are visible.
- * On certain conditions, they have to be hidden.
- * @param hidden_stat status to use ie. hidden = true, visible = false
- * @param widgets list of widgets ended by WIDGET_LIST_END
- */
-void CDECL Window::SetWidgetsHiddenState(bool hidden_stat, int widgets, ...)
-{
- va_list wdg_list;
-
- va_start(wdg_list, widgets);
-
- while (widgets != WIDGET_LIST_END) {
- SetWidgetHiddenState(widgets, hidden_stat);
- widgets = va_arg(wdg_list, int);
- }
-
- va_end(wdg_list);
-}
-
-/**
* Sets the lowered/raised status of a list of widgets.
* @param lowered_stat status to use ie: lowered = true, raised = false
* @param widgets list of widgets ended by WIDGET_LIST_END
@@ -240,21 +184,11 @@ void CDECL Window::SetWidgetsLoweredState(bool lowered_stat, int widgets, ...)
*/
void Window::RaiseButtons(bool autoraise)
{
- if (this->widget != NULL) {
- for (uint i = 0; i < this->widget_count; i++) {
- if ((!autoraise || (this->widget[i].type & WWB_PUSHBUTTON)) && this->IsWidgetLowered(i)) {
- this->RaiseWidget(i);
- this->SetWidgetDirty(i);
- }
- }
- }
- if (this->nested_array != NULL) {
- for (uint i = 0; i < this->nested_array_size; i++) {
- if (this->nested_array[i] != NULL && (this->nested_array[i]->type & ~WWB_PUSHBUTTON) < WWT_LAST &&
- (!autoraise || (this->nested_array[i]->type & WWB_PUSHBUTTON)) && this->IsWidgetLowered(i)) {
- this->RaiseWidget(i);
- this->SetWidgetDirty(i);
- }
+ for (uint i = 0; i < this->nested_array_size; i++) {
+ if (this->nested_array[i] != NULL && (this->nested_array[i]->type & ~WWB_PUSHBUTTON) < WWT_LAST &&
+ (!autoraise || (this->nested_array[i]->type & WWB_PUSHBUTTON)) && this->IsWidgetLowered(i)) {
+ this->RaiseWidget(i);
+ this->SetWidgetDirty(i);
}
}
}
@@ -265,15 +199,7 @@ void Window::RaiseButtons(bool autoraise)
*/
void Window::SetWidgetDirty(byte widget_index) const
{
- if (this->widget != NULL) {
- const Widget *wi = &this->widget[widget_index];
-
- /* Don't redraw the window if the widget is invisible or of no-type */
- if (wi->type == WWT_EMPTY || IsWidgetHidden(widget_index)) return;
-
- SetDirtyBlocks(this->left + wi->left, this->top + wi->top, this->left + wi->right + 1, this->top + wi->bottom + 1);
- }
- if (this->nested_array != NULL) this->nested_array[widget_index]->SetDirty(this);
+ this->nested_array[widget_index]->SetDirty(this);
}
/**
@@ -288,18 +214,6 @@ void Window::HandleButtonClick(byte widget)
this->SetWidgetDirty(widget);
}
-/**
- * Return a widget of the requested type from the window.
- * @param widget_type the widget type to look for
- */
-const Widget *Window::GetWidgetOfType(WidgetType widget_type) const
-{
- for (uint i = 0; i < this->widget_count; i++) {
- if (this->widget[i].type == widget_type) return &this->widget[i];
- }
- return NULL;
-}
-
static void StartWindowDrag(Window *w);
static void StartWindowSizing(Window *w, bool to_left);
@@ -314,19 +228,9 @@ static void DispatchLeftClickEvent(Window *w, int x, int y, bool double_click)
{
int widget_index = 0;
if (w->desc_flags & WDF_DEF_WIDGET) {
- const Widget *wi = NULL;
- const NWidgetCore *nw = NULL;
- WidgetType widget_type;
- if (w->widget != NULL) {
- widget_index = GetWidgetFromPos(w, x, y);
- wi = &w->widget[widget_index];
- widget_type = (widget_index >= 0) ? wi->type : WWT_EMPTY;
- } else {
- assert(w->nested_root != NULL);
- nw = w->nested_root->GetWidgetFromPos(x, y);
- widget_index = (nw != NULL) ? nw->index : -1;
- widget_type = (widget_index >= 0) ? nw->type : WWT_EMPTY;
- }
+ const NWidgetCore *nw = w->nested_root->GetWidgetFromPos(x, y);
+ widget_index = (nw != NULL) ? nw->index : -1;
+ WidgetType widget_type = (widget_index >= 0) ? nw->type : WWT_EMPTY;
bool focused_widget_changed = false;
/* If clicked on a window that previously did dot have focus */
@@ -353,9 +257,7 @@ static void DispatchLeftClickEvent(Window *w, int x, int y, bool double_click)
* 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->widget != NULL && w->focused_widget != NULL && w->focused_widget->type == WWT_EDITBOX && // An edit box was previously selected
- w->focused_widget != wi && w->window_class != WC_OSK) || // and focus is going to change and it is not the OSK window
- (w->nested_root != NULL && w->nested_focus != NULL && w->nested_focus->type == WWT_EDITBOX &&
+ if ((w->nested_root != NULL && w->nested_focus != NULL && w->nested_focus->type == WWT_EDITBOX &&
w->nested_focus != nw && w->window_class != WC_OSK)) {
DeleteWindowById(WC_OSK, 0);
}
@@ -383,11 +285,7 @@ static void DispatchLeftClickEvent(Window *w, int x, int y, bool double_click)
break;
}
} else if (widget_type == WWT_SCROLLBAR || widget_type == WWT_SCROLL2BAR || widget_type == WWT_HSCROLLBAR) {
- if (wi != NULL) {
- ScrollbarClickHandler(w, wi, x, y);
- } else {
- ScrollbarClickHandler(w, nw, x, y);
- }
+ ScrollbarClickHandler(w, nw, x, y);
} else if (widget_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);
@@ -415,7 +313,7 @@ static void DispatchLeftClickEvent(Window *w, int x, int y, bool double_click)
if ((w->desc_flags & WDF_RESIZABLE) && widget_type == WWT_RESIZEBOX) {
/* When the resize widget is on the left size of the window
* we assume that that button is used to resize to the left. */
- int left_pos = (wi != NULL) ? wi->left : nw->pos_x;
+ int left_pos = nw->pos_x;
StartWindowSizing(w, left_pos < (w->width / 2));
w->SetWidgetDirty(widget_index);
return;
@@ -446,21 +344,13 @@ static void DispatchLeftClickEvent(Window *w, int x, int y, bool double_click)
static void DispatchRightClickEvent(Window *w, int x, int y)
{
int widget = 0;
- StringID tooltip = 0;
/* default tooltips handler? */
if (w->desc_flags & WDF_STD_TOOLTIPS) {
- if (w->nested_root != NULL) {
- NWidgetCore *wid = w->nested_root->GetWidgetFromPos(x, y);
- if (wid == NULL || wid->index < 0) return;
- widget = wid->index;
- tooltip = wid->tool_tip;
- }
- if (w->widget != NULL) {
- widget = GetWidgetFromPos(w, x, y);
- if (widget < 0) return; // exit if clicked outside of widgets
- tooltip = w->widget[widget].tooltips;
- }
+ NWidgetCore *wid = w->nested_root->GetWidgetFromPos(x, y);
+ if (wid == NULL || wid->index < 0) return;
+ widget = wid->index;
+ StringID tooltip = wid->tool_tip;
if (tooltip != 0) {
GuiShowTooltips(tooltip);
@@ -484,16 +374,6 @@ static void DispatchMouseWheelEvent(Window *w, int widget, int wheel)
if (widget < 0) return;
Scrollbar *sb = NULL;
- if (w->widget != NULL) {
- const Widget *wi1 = &w->widget[widget];
- const Widget *wi2 = &w->widget[widget + 1];
- if (wi1->type == WWT_SCROLLBAR || wi2->type == WWT_SCROLLBAR) {
- sb = &w->vscroll;
- } else if (wi1->type == WWT_SCROLL2BAR || wi2->type == WWT_SCROLL2BAR) {
- sb = &w->vscroll2;
- }
- }
-
if (w->nested_array != NULL && (uint)widget < w->nested_array_size) sb = w->GetWidget<NWidgetCore>(widget)->FindScrollbar(w);
if (sb != NULL && sb->GetCount() > sb->GetCapacity()) {
@@ -698,7 +578,6 @@ Window::~Window()
this->SetDirty();
- free(this->widget);
free(this->nested_array); // Contents is released through deletion of #nested_root.
delete this->nested_root;
@@ -885,76 +764,43 @@ static void BringWindowToFront(Window *w)
}
/**
- * Assign widgets to a new window by initialising its widget pointers, and by
- * copying the widget array \a widget to \c w->widget to allow for resizable
- * windows.
- * @param w Window on which to attach the widget array
- * @param widget pointer of widget array to fill the window with
- *
- * @post \c w->widget points to allocated memory and contains the copied widget array except for the terminating widget,
- * \c w->widget_count contains number of widgets in the allocated memory.
- */
-static void AssignWidgetToWindow(Window *w, const Widget *widget)
-{
- if (widget != NULL) {
- uint index = 1;
-
- for (const Widget *wi = widget; wi->type != WWT_LAST; wi++) index++;
-
- w->widget = MallocT<Widget>(index);
- memcpy(w->widget, widget, sizeof(*w->widget) * index);
- w->widget_count = index - 1;
- } else {
- w->widget = NULL;
- w->widget_count = 0;
- }
-}
-
-/**
* Initializes the data (except the position and initial size) of a new Window.
* @param cls Class of the window, used for identification and grouping. @see WindowClass
- * @param *widget Pointer to the widget array, it is \c NULL when nested widgets are used. @see Widget
* @param window_number Number being assigned to the new window
* @param desc_flags Window flags. @see WindowDefaultFlag
* @return Window pointer of the newly created window
* @pre If nested widgets are used (\a widget is \c NULL), #nested_root and #nested_array_size must be initialized.
* In addition, #nested_array is either \c NULL, or already initialized.
*/
-void Window::InitializeData(WindowClass cls, const Widget *widget, int window_number, uint32 desc_flags)
+void Window::InitializeData(WindowClass cls, int window_number, uint32 desc_flags)
{
/* Set up window properties; some of them are needed to set up smallest size below */
this->window_class = cls;
this->flags4 = WF_WHITE_BORDER_MASK; // just opened windows have a white border
this->owner = INVALID_OWNER;
- this->focused_widget = NULL;
this->nested_focus = NULL;
this->window_number = window_number;
this->desc_flags = desc_flags;
/* If available, initialize nested widget tree. */
- if (widget == NULL) {
- if (this->nested_array == NULL) {
- this->nested_array = CallocT<NWidgetBase *>(this->nested_array_size);
- this->nested_root->SetupSmallestSize(this, true);
- } else {
- this->nested_root->SetupSmallestSize(this, false);
- }
- /* Initialize to smallest size. */
- this->nested_root->AssignSizePosition(ST_SMALLEST, 0, 0, this->nested_root->smallest_x, this->nested_root->smallest_y, false, false, false);
+ if (this->nested_array == NULL) {
+ this->nested_array = CallocT<NWidgetBase *>(this->nested_array_size);
+ this->nested_root->SetupSmallestSize(this, true);
+ } else {
+ this->nested_root->SetupSmallestSize(this, false);
}
- /* Else, all data members of nested widgets have been set to 0 by the #ZeroedMemoryAllocator base class. */
+ /* Initialize to smallest size. */
+ this->nested_root->AssignSizePosition(ST_SMALLEST, 0, 0, this->nested_root->smallest_x, this->nested_root->smallest_y, false, false, false);
/* Further set up window properties,
* this->left, this->top, this->width, this->height, this->resize.width, and this->resize.height are initialized later. */
- AssignWidgetToWindow(this, widget);
this->resize.step_width = (this->nested_root != NULL) ? this->nested_root->resize_x : 1;
this->resize.step_height = (this->nested_root != NULL) ? this->nested_root->resize_y : 1;
/* 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. */
- bool has_editbox = (this->widget != NULL && this->GetWidgetOfType(WWT_EDITBOX) != NULL) ||
- (this->nested_root != NULL && this->nested_root->GetWidgetOfType(WWT_EDITBOX) != NULL);
+ bool has_editbox = this->nested_root != NULL && this->nested_root->GetWidgetOfType(WWT_EDITBOX) != NULL;
if (this->window_class != WC_OSK && (!EditBoxInGlobalFocus() || has_editbox)) SetFocusedWindow(this);
/* Hacky way of specifying always-on-top windows. These windows are
@@ -1075,15 +921,6 @@ void Window::FindWindowPlacementAndResize(int def_width, int def_height)
}
/**
- * Resize window towards the default size given in the window description.
- * @param desc the description to get the default size from.
- */
-void Window::FindWindowPlacementAndResize(const WindowDesc *desc)
-{
- this->FindWindowPlacementAndResize(desc->default_width, desc->default_height);
-}
-
-/**
* Decide whether a given rectangle is a good place to open a completely visible new window.
* The new window should be within screen borders, and not overlap with another already
* existing window (except for the main window in the background).
@@ -1305,21 +1142,6 @@ static Point LocalGetWindowPlacement(const WindowDesc *desc, int16 sm_width, int
}
/**
- * Set the positions of a new window from a WindowDesc and open it.
- *
- * @param *desc The pointer to the WindowDesc to be created
- * @param window_number the window number of the new window
- *
- * @return Window pointer of the newly created window
- */
-Window::Window(const WindowDesc *desc, WindowNumber window_number)
-{
- this->InitializeData(desc->cls, desc->GetWidgets(), window_number, desc->flags);
- Point pt = LocalGetWindowPlacement(desc, desc->minimum_width, desc->minimum_height, window_number);
- this->InitializePositionSize(pt.x, pt.y, desc->minimum_width, desc->minimum_height);
-}
-
-/**
* Perform the first part of the initialization of a nested widget tree.
* Construct a nested widget tree in #nested_root, and optionally fill the #nested_array array to provide quick access to the uninitialized widgets.
* This is mainly useful for setting very basic properties.
@@ -1347,7 +1169,7 @@ void Window::CreateNestedTree(const WindowDesc *desc, bool fill_nested)
*/
void Window::FinishInitNested(const WindowDesc *desc, WindowNumber window_number)
{
- this->InitializeData(desc->cls, NULL, window_number, desc->flags);
+ this->InitializeData(desc->cls, window_number, desc->flags);
Point pt = this->OnInitialPosition(desc, this->nested_root->smallest_x, this->nested_root->smallest_y, window_number);
this->InitializePositionSize(pt.x, pt.y, this->nested_root->smallest_x, this->nested_root->smallest_y);
this->FindWindowPlacementAndResize(desc->default_width, desc->default_height);
@@ -1511,10 +1333,7 @@ static bool HandleMouseOver()
if (w != NULL) {
/* send an event in client coordinates. */
Point pt = { _cursor.pos.x - w->left, _cursor.pos.y - w->top };
- int widget = 0;
- if (w->widget != NULL) {
- widget = GetWidgetFromPos(w, pt.x, pt.y);
- }
+ int widget = w->nested_root->GetWidgetFromPos(pt.x, pt.y)->index;
w->OnMouseOver(pt, widget);
}
@@ -1537,52 +1356,14 @@ void ResizeWindow(Window *w, int delta_x, int delta_y)
w->SetDirty();
- if (w->nested_root != NULL) {
- uint new_xinc = max(0, (w->nested_root->resize_x == 0) ? 0 : (int)(w->nested_root->current_x - w->nested_root->smallest_x) + delta_x);
- uint new_yinc = max(0, (w->nested_root->resize_y == 0) ? 0 : (int)(w->nested_root->current_y - w->nested_root->smallest_y) + delta_y);
- assert(w->nested_root->resize_x == 0 || new_xinc % w->nested_root->resize_x == 0);
- assert(w->nested_root->resize_y == 0 || new_yinc % w->nested_root->resize_y == 0);
-
- w->nested_root->AssignSizePosition(ST_RESIZE, 0, 0, w->nested_root->smallest_x + new_xinc, w->nested_root->smallest_y + new_yinc, false, false, false);
- w->width = w->nested_root->current_x;
- w->height = w->nested_root->current_y;
- } else {
- assert(w->widget != NULL);
-
- bool resize_height = false;
- bool resize_width = false;
- for (Widget *wi = w->widget; wi->type != WWT_LAST; wi++) {
- /* Isolate the resizing flags */
- byte rsizeflag = GB(wi->display_flags, 0, 4);
-
- if (rsizeflag == RESIZE_NONE) continue;
+ uint new_xinc = max(0, (w->nested_root->resize_x == 0) ? 0 : (int)(w->nested_root->current_x - w->nested_root->smallest_x) + delta_x);
+ uint new_yinc = max(0, (w->nested_root->resize_y == 0) ? 0 : (int)(w->nested_root->current_y - w->nested_root->smallest_y) + delta_y);
+ assert(w->nested_root->resize_x == 0 || new_xinc % w->nested_root->resize_x == 0);
+ assert(w->nested_root->resize_y == 0 || new_yinc % w->nested_root->resize_y == 0);
- /* Resize the widget based on its resize-flag */
- if (rsizeflag & RESIZE_LEFT) {
- wi->left += delta_x;
- resize_width = true;
- }
-
- if (rsizeflag & RESIZE_RIGHT) {
- wi->right += delta_x;
- resize_width = true;
- }
-
- if (rsizeflag & RESIZE_TOP) {
- wi->top += delta_y;
- resize_height = true;
- }
-
- if (rsizeflag & RESIZE_BOTTOM) {
- wi->bottom += delta_y;
- resize_height = true;
- }
- }
-
- /* We resized at least 1 widget, so let's resize the window totally */
- if (resize_width) w->width += delta_x;
- if (resize_height) w->height += delta_y;
- }
+ w->nested_root->AssignSizePosition(ST_RESIZE, 0, 0, w->nested_root->smallest_x + new_xinc, w->nested_root->smallest_y + new_yinc, false, false, false);
+ w->width = w->nested_root->current_x;
+ w->height = w->nested_root->current_y;
w->SetDirty();
}
@@ -1758,22 +1539,12 @@ static bool HandleWindowDragging()
/* Search for the title bar rectangle. */
Rect caption_rect;
- if (w->widget != NULL) {
- const Widget *caption = w->GetWidgetOfType(WWT_CAPTION);
- assert(caption != NULL);
- caption_rect.left = caption->left;
- caption_rect.right = caption->right;
- caption_rect.top = caption->top;
- caption_rect.bottom = caption->bottom;
- } else {
- assert(w->nested_root != NULL);
- const NWidgetBase *caption = w->nested_root->GetWidgetOfType(WWT_CAPTION);
- assert(caption != NULL);
- caption_rect.left = caption->pos_x;
- caption_rect.right = caption->pos_x + caption->current_x;
- caption_rect.top = caption->pos_y;
- caption_rect.bottom = caption->pos_y + caption->current_y;
- }
+ const NWidgetBase *caption = w->nested_root->GetWidgetOfType(WWT_CAPTION);
+ assert(caption != NULL);
+ caption_rect.left = caption->pos_x;
+ caption_rect.right = caption->pos_x + caption->current_x;
+ caption_rect.top = caption->pos_y;
+ caption_rect.bottom = caption->pos_y + caption->current_y;
/* Make sure the window doesn't leave the screen */
nx = Clamp(nx, MIN_VISIBLE_TITLE_BAR - caption_rect.right, _screen.width - MIN_VISIBLE_TITLE_BAR - caption_rect.left);