diff -r 22c441f5adf9 -r 33cb70ff2f5d src/window.cpp --- a/src/window.cpp Wed May 07 21:09:51 2008 +0000 +++ b/src/window.cpp Sun May 11 20:09:34 2008 +0000 @@ -44,13 +44,16 @@ bool _scrolling_scrollbar; bool _scrolling_viewport; -bool _popup_menu_active; byte _special_mouse_mode; /** - * Call the window event handler for handling event \a e + * Call the window event handler for handling event \a e. + * This is a temporary helper functions that will be removed + * once all windows that still rely on WindowEvent and + * WindowEventCodes have been rewritten to use the 'OnXXX' + * event handlers. * @param e Window event to handle */ void Window::HandleWindowEvent(WindowEvent *e) @@ -58,6 +61,208 @@ if (wndproc != NULL) wndproc(this, e); } +void Window::OnPaint() +{ + WindowEvent e; + e.event = WE_PAINT; + this->HandleWindowEvent(&e); +} + +bool Window::OnKeyPress(uint16 key, uint16 keycode) +{ + WindowEvent e; + e.event = WE_KEYPRESS; + e.we.keypress.key = key; + e.we.keypress.keycode = keycode; + e.we.keypress.cont = true; + this->HandleWindowEvent(&e); + + return e.we.keypress.cont; +} + +bool Window::OnCTRLStateChange() +{ + WindowEvent e; + e.event = WE_CTRL_CHANGED; + e.we.ctrl.cont = true; + this->HandleWindowEvent(&e); + + return e.we.ctrl.cont; +} + +void Window::OnClick(Point pt, int widget) +{ + WindowEvent e; + e.event = WE_CLICK; + e.we.click.pt = pt; + e.we.click.widget = widget; + this->HandleWindowEvent(&e); +} + +void Window::OnDoubleClick(Point pt, int widget) +{ + WindowEvent e; + e.event = WE_DOUBLE_CLICK; + e.we.click.pt = pt; + e.we.click.widget = widget; + this->HandleWindowEvent(&e); +} + +void Window::OnRightClick(Point pt, int widget) +{ + WindowEvent e; + e.event = WE_RCLICK; + e.we.click.pt = pt; + e.we.click.widget = widget; + this->HandleWindowEvent(&e); +} + +void Window::OnDragDrop(Point pt, int widget) +{ + WindowEvent e; + e.event = WE_DRAGDROP; + e.we.click.pt = pt; + e.we.click.widget = widget; + this->HandleWindowEvent(&e); +} + +void Window::OnScroll(Point delta) +{ + WindowEvent e; + e.event = WE_SCROLL; + e.we.scroll.delta = delta; + this->HandleWindowEvent(&e); +} + +void Window::OnMouseOver(Point pt, int widget) +{ + WindowEvent e; + e.event = WE_MOUSEOVER; + e.we.click.pt = pt; + e.we.click.widget = widget; + this->HandleWindowEvent(&e); +} + +void Window::OnMouseWheel(int wheel) +{ + WindowEvent e; + e.event = WE_MOUSEWHEEL; + e.we.wheel.wheel = wheel; + this->HandleWindowEvent(&e); +} + +void Window::OnMouseLoop() +{ + WindowEvent e; + e.event = WE_MOUSELOOP; + this->HandleWindowEvent(&e); +} + +void Window::OnTick() +{ + WindowEvent e; + e.event = WE_TICK; + this->HandleWindowEvent(&e); +} + +void Window::OnHundredthTick() +{ + WindowEvent e; + e.event = WE_100_TICKS; + this->HandleWindowEvent(&e); +} + +void Window::OnTimeout() +{ + WindowEvent e; + e.event = WE_TIMEOUT; + this->HandleWindowEvent(&e); +} + +void Window::OnResize(Point new_size, Point delta) +{ + WindowEvent e; + e.event = WE_RESIZE; + e.we.sizing.size = new_size; + e.we.sizing.diff = delta; + this->HandleWindowEvent(&e); +} + +void Window::OnDropdownSelect(int widget, int index) +{ + WindowEvent e; + e.event = WE_DROPDOWN_SELECT; + e.we.dropdown.button = widget; + e.we.dropdown.index = index; + this->HandleWindowEvent(&e); +} + +void Window::OnQueryTextFinished(char *str) +{ + WindowEvent e; + e.event = WE_ON_EDIT_TEXT; + e.we.edittext.str = str; + this->HandleWindowEvent(&e); +} + +void Window::OnInvalidateData(int data) +{ + WindowEvent e; + e.event = WE_INVALIDATE_DATA; + e.we.invalidate.data = data; + this->HandleWindowEvent(&e); +} + +void Window::OnPlaceObject(Point pt, TileIndex tile) +{ + WindowEvent e; + e.event = WE_PLACE_OBJ; + e.we.place.pt = pt; + e.we.place.tile = tile; + this->HandleWindowEvent(&e); +} + +void Window::OnPlaceObjectAbort() +{ + WindowEvent e; + e.event = WE_ABORT_PLACE_OBJ; + this->HandleWindowEvent(&e); +} + + +void Window::OnPlaceDrag(ViewportPlaceMethod select_method, byte select_proc, Point pt) +{ + WindowEvent e; + e.event = WE_PLACE_DRAG; + e.we.place.select_method = select_method; + e.we.place.select_proc = select_proc; + e.we.place.pt = pt; + this->HandleWindowEvent(&e); +} + +void Window::OnPlaceMouseUp(ViewportPlaceMethod select_method, byte select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) +{ + WindowEvent e; + e.event = WE_PLACE_MOUSEUP; + e.we.place.select_method = select_method; + e.we.place.select_proc = select_proc; + e.we.place.pt = pt; + e.we.place.tile = end_tile; + e.we.place.starttile = start_tile; + this->HandleWindowEvent(&e); +} + +void Window::OnPlacePresize(Point pt, TileIndex tile) +{ + WindowEvent e; + e.event = WE_PLACE_PRESIZE; + e.we.place.pt = pt; + e.we.place.tile = tile; + this->HandleWindowEvent(&e); +} + + + void CDECL Window::SetWidgetsDisabledState(bool disab_stat, int widgets, ...) { va_list wdg_list; @@ -139,19 +344,15 @@ */ static void DispatchLeftClickEvent(Window *w, int x, int y, bool double_click) { - WindowEvent e; - e.we.click.pt.x = x; - e.we.click.pt.y = y; - e.event = double_click ? WE_DOUBLE_CLICK : WE_CLICK; - + int widget = 0; if (w->desc_flags & WDF_DEF_WIDGET) { - e.we.click.widget = GetWidgetFromPos(w, x, y); - if (e.we.click.widget < 0) return; // exit if clicked outside of widgets + widget = GetWidgetFromPos(w, x, y); + if (widget < 0) return; // exit if clicked outside of widgets /* don't allow any interaction if the button has been disabled */ - if (w->IsWidgetDisabled(e.we.click.widget)) return; + if (w->IsWidgetDisabled(widget)) return; - const Widget *wi = &w->widget[e.we.click.widget]; + const Widget *wi = &w->widget[widget]; if (wi->type & WWB_MASK) { /* special widget handling for buttons*/ @@ -159,20 +360,20 @@ case WWT_PANEL | WWB_PUSHBUTTON: /* WWT_PUSHBTN */ case WWT_IMGBTN | WWB_PUSHBUTTON: /* WWT_PUSHIMGBTN */ case WWT_TEXTBTN | WWB_PUSHBUTTON: /* WWT_PUSHTXTBTN */ - w->HandleButtonClick(e.we.click.widget); + w->HandleButtonClick(widget); break; } } else if (wi->type == WWT_SCROLLBAR || wi->type == WWT_SCROLL2BAR || wi->type == WWT_HSCROLLBAR) { - ScrollbarClickHandler(w, wi, e.we.click.pt.x, e.we.click.pt.y); + ScrollbarClickHandler(w, wi, x, y); } if (w->desc_flags & WDF_STD_BTN) { - if (e.we.click.widget == 0) { /* 'X' */ + if (widget == 0) { /* 'X' */ delete w; return; } - if (e.we.click.widget == 1) { /* 'Title bar' */ + if (widget == 1) { /* 'Title bar' */ StartWindowDrag(w); return; } @@ -180,18 +381,24 @@ if (w->desc_flags & WDF_RESIZABLE && wi->type == WWT_RESIZEBOX) { StartWindowSizing(w); - w->InvalidateWidget(e.we.click.widget); + w->InvalidateWidget(widget); return; } if (w->desc_flags & WDF_STICKY_BUTTON && wi->type == WWT_STICKYBOX) { w->flags4 ^= WF_STICKY; - w->InvalidateWidget(e.we.click.widget); + w->InvalidateWidget(widget); return; } } - w->HandleWindowEvent(&e); + Point pt = { x, y }; + + if (double_click) { + w->OnDoubleClick(pt, widget); + } else { + w->OnClick(pt, widget); + } } /** @@ -202,23 +409,21 @@ */ static void DispatchRightClickEvent(Window *w, int x, int y) { - WindowEvent e; + int widget = 0; /* default tooltips handler? */ if (w->desc_flags & WDF_STD_TOOLTIPS) { - e.we.click.widget = GetWidgetFromPos(w, x, y); - if (e.we.click.widget < 0) return; // exit if clicked outside of widgets + widget = GetWidgetFromPos(w, x, y); + if (widget < 0) return; // exit if clicked outside of widgets - if (w->widget[e.we.click.widget].tooltips != 0) { - GuiShowTooltips(w->widget[e.we.click.widget].tooltips); + if (w->widget[widget].tooltips != 0) { + GuiShowTooltips(w->widget[widget].tooltips); return; } } - e.event = WE_RCLICK; - e.we.click.pt.x = x; - e.we.click.pt.y = y; - w->HandleWindowEvent(&e); + Point pt = { x, y }; + w->OnRightClick(pt, widget); } /** @@ -316,7 +521,7 @@ dp->pitch = _screen.pitch; dp->dst_ptr = BlitterFactoryBase::GetCurrentBlitter()->MoveTo(_screen.dst_ptr, left, top); dp->zoom = ZOOM_LVL_NORMAL; - CallWindowEventNP(*wz, WE_PAINT); + (*wz)->OnPaint(); } /** @@ -346,20 +551,6 @@ } /** - * Dispatch an event to a possibly non-existing window. - * If the window pointer w is \c NULL, the event is not dispatched - * @param w Window to dispatch the event to, may be \c NULL - * @param event Event to dispatch - */ -void CallWindowEventNP(Window *w, int event) -{ - WindowEvent e; - - e.event = event; - w->HandleWindowEvent(&e); -} - -/** * Mark entire window as dirty (in need of re-paint) * @param w Window to redraw * @ingroup dirty @@ -438,7 +629,9 @@ /* Delete any children a window might have in a head-recursive manner */ delete FindChildWindow(this); - CallWindowEventNP(this, WE_DESTROY); + WindowEvent e; + e.event = WE_DESTROY; + this->HandleWindowEvent(&e); if (this->viewport != NULL) DeleteWindowViewport(this); this->SetDirty(); @@ -656,10 +849,18 @@ return (w->original_widget == widget); } -/** Copies 'widget' to 'w->widget' to allow for resizable windows +/** + * 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 */ -void AssignWidgetToWindow(Window *w, const Widget *widget) + * @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->original_widget points to the original widgets, + * \c w->widget_count contains number of widgets in the allocated memory. + */ +static void AssignWidgetToWindow(Window *w, const Widget *widget) { w->original_widget = widget; @@ -668,7 +869,7 @@ for (const Widget *wi = widget; wi->type != WWT_LAST; wi++) index++; - w->widget = ReallocT(w->widget, index); + w->widget = MallocT(index); memcpy(w->widget, widget, sizeof(*w->widget) * index); w->widget_count = index - 1; } else { @@ -677,88 +878,88 @@ } } -/** Open a new window. - * This function is called from AllocateWindow() or AllocateWindowDesc() +/** + * Initializes a new Window. + * This function is called the constructors. * 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 * @param x offset in pixels from the left of the screen * @param y offset in pixels from the top of the screen * @param min_width minimum width in pixels of the window * @param min_height minimum height in pixels of the window - * @param def_width default width in pixels of the window - * @param def_height default 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 * @param window_number number being assigned to the new window * @param data the data to be given during the WE_CREATE message * @return Window pointer of the newly created window */ -static Window *LocalAllocateWindow(int x, int y, int min_width, int min_height, int def_width, int def_height, +void Window::Initialize(int x, int y, int min_width, int min_height, WindowProc *proc, WindowClass cls, const Widget *widget, int window_number, void *data) { - Window *w; - /* We have run out of windows, close one and use that as the place for our new one */ if (_last_z_window == endof(_z_windows)) { - w = FindDeletableWindow(); + Window *w = FindDeletableWindow(); if (w == NULL) w = ForceFindDeletableWindow(); delete w; } - w = new Window(proc); - /* Set up window properties */ - 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 = min_width; - w->height = min_height; - AssignWidgetToWindow(w, widget); - w->resize.width = min_width; - w->resize.height = min_height; - w->resize.step_width = 1; - w->resize.step_height = 1; - w->window_number = window_number; - - { - Window **wz = _last_z_window; + this->window_class = cls; + this->flags4 = WF_WHITE_BORDER_MASK; // just opened windows have a white border + this->caption_color = 0xFF; + this->left = x; + this->top = y; + this->width = min_width; + this->height = min_height; + this->wndproc = proc; + AssignWidgetToWindow(this, widget); + 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; - /* 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 && w->window_class != WC_HIGHSCORE && w->window_class != WC_ENDSCREEN) { - 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--; + /* 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 **wz = _last_z_window; + if (wz != _z_windows && this->window_class != WC_SEND_NETWORK_MSG && this->window_class != WC_HIGHSCORE && this->window_class != WC_ENDSCREEN) { + 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); - } + assert(wz >= _z_windows); + if (wz != _last_z_window) memmove(wz + 1, wz, (byte*)_last_z_window - (byte*)wz); + } - *wz = w; - _last_z_window++; - } + *wz = this; + _last_z_window++; WindowEvent e; e.event = WE_CREATE; e.we.create.data = data; - w->HandleWindowEvent(&e); + this->HandleWindowEvent(&e); +} +/** + * Find a nice spot for this window and resize it towards the default size. + * @param def_width default width in pixels of the window + * @param def_height default height in pixels of the window + */ +void Window::FindWindowPlacementAndResize(int def_width, int def_height) +{ /* Try to make windows smaller when our window is too small. * w->(width|height) is normally the same as min_(width|height), * but this way the GUIs can be made a little more dynamic; * one can use the same spec for multiple windows and those * can then determine the real minimum size of the window. */ - if (w->width != def_width || w->height != def_height) { + if (this->width != def_width || this->height != def_height) { /* Think about the overlapping toolbars when determining the minimum window size */ int free_height = _screen.height; const Window *wt = FindWindowById(WC_STATUS_BAR, 0); @@ -766,45 +967,48 @@ wt = FindWindowById(WC_MAIN_TOOLBAR, 0); if (wt != NULL) free_height -= wt->height; - int enlarge_x = max(min(def_width - w->width, _screen.width - w->width), 0); - int enlarge_y = max(min(def_height - w->height, free_height - w->height), 0); + int enlarge_x = max(min(def_width - this->width, _screen.width - this->width), 0); + int enlarge_y = max(min(def_height - this->height, free_height - this->height), 0); /* 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) enlarge_x -= enlarge_x % (int)w->resize.step_width; - if (w->resize.step_height > 1) enlarge_y -= enlarge_y % (int)w->resize.step_height; - - ResizeWindow(w, enlarge_x, enlarge_y); + if (this->resize.step_width > 1) enlarge_x -= enlarge_x % (int)this->resize.step_width; + if (this->resize.step_height > 1) enlarge_y -= enlarge_y % (int)this->resize.step_height; - WindowEvent e; - e.event = WE_RESIZE; - e.we.sizing.size.x = w->width; - e.we.sizing.size.y = w->height; - e.we.sizing.diff.x = enlarge_x; - e.we.sizing.diff.y = enlarge_y; - w->HandleWindowEvent(&e); + ResizeWindow(this, enlarge_x, enlarge_y); + + Point size; + Point diff; + size.x = this->width; + size.y = this->height; + diff.x = enlarge_x; + diff.y = enlarge_y; + this->OnResize(size, diff); } - int nx = w->left; - int ny = w->top; + int nx = this->left; + int ny = this->top; - if (nx + w->width > _screen.width) nx -= (nx + w->width - _screen.width); + if (nx + this->width > _screen.width) nx -= (nx + this->width - _screen.width); const Window *wt = FindWindowById(WC_MAIN_TOOLBAR, 0); - ny = max(ny, (wt == NULL || w == wt || y == 0) ? 0 : wt->height); + ny = max(ny, (wt == NULL || this == wt || this->top == 0) ? 0 : wt->height); nx = max(nx, 0); - if (w->viewport != NULL) { - w->viewport->left += nx - w->left; - w->viewport->top += ny - w->top; + if (this->viewport != NULL) { + this->viewport->left += nx - this->left; + this->viewport->top += ny - this->top; } - w->left = nx; - w->top = ny; + this->left = nx; + this->top = ny; - w->SetDirty(); + this->SetDirty(); +} - return w; +void Window::FindWindowPlacementAndResize(const WindowDesc *desc) +{ + this->FindWindowPlacementAndResize(desc->default_width, desc->default_height); } /** @@ -821,10 +1025,11 @@ * @param *widget see Widget pointer to the window layout and various elements * @return Window pointer of the newly created window */ -Window *AllocateWindow(int x, int y, int width, int height, - WindowProc *proc, WindowClass cls, const Widget *widget, void *data) +Window::Window(int x, int y, int width, int height, WindowProc *proc, WindowClass cls, const Widget *widget, void *data) { - return LocalAllocateWindow(x, y, width, height, width, height, proc, cls, widget, 0, data); + this->Initialize(x, y, width, height, proc, cls, widget, 0, data); + + if (proc != NULL) this->FindWindowPlacementAndResize(width, height); } @@ -1014,37 +1219,13 @@ * * @return Window pointer of the newly created window */ -static Window *LocalAllocateWindowDesc(const WindowDesc *desc, int window_number, void *data) +Window::Window(const WindowDesc *desc, void *data, WindowNumber window_number) { Point pt = LocalGetWindowPlacement(desc, window_number); - Window *w = LocalAllocateWindow(pt.x, pt.y, desc->minimum_width, desc->minimum_height, desc->default_width, desc->default_height, desc->proc, desc->cls, desc->widgets, window_number, data); - w->desc_flags = desc->flags; - - return w; -} + this->Initialize(pt.x, pt.y, desc->minimum_width, desc->minimum_height, desc->proc, desc->cls, desc->widgets, window_number, data); + this->desc_flags = desc->flags; -/** - * Open a new window. - * @param *desc The pointer to the WindowDesc to be created - * @param data arbitrary data that is send with the WE_CREATE message - * @return Window pointer of the newly created window - */ -Window *AllocateWindowDesc(const WindowDesc *desc, void *data) -{ - return LocalAllocateWindowDesc(desc, 0, data); -} - -/** - * Open a new window. - * @param *desc The pointer to the WindowDesc to be created - * @param window_number the window number of the new window - * @param data arbitrary data that is send with the WE_CREATE message - * @return see Window pointer of the newly created window - */ -Window *AllocateWindowDescFront(const WindowDesc *desc, int window_number, void *data) -{ - if (BringWindowToFrontById(desc->cls, window_number)) return NULL; - return LocalAllocateWindowDesc(desc, window_number, data); + if (desc->proc != NULL) this->FindWindowPlacementAndResize(desc->default_width, desc->default_height); } /** Do a search for a window at specific coordinates. For this we start @@ -1108,14 +1289,14 @@ w->flags4 &= ~(WF_SCROLL_DOWN | WF_SCROLL_UP); w->SetDirty(); } - CallWindowEventNP(w, WE_MOUSELOOP); + w->OnMouseLoop(); } for (wz = _last_z_window; wz != _z_windows;) { Window *w = *--wz; if (w->flags4 & WF_TIMEOUT_MASK && !(--w->flags4 & WF_TIMEOUT_MASK)) { - CallWindowEventNP(w, WE_TIMEOUT); + w->OnTimeout(); if (w->desc_flags & WDF_UNCLICK_BUTTONS) w->RaiseButtons(); } } @@ -1133,15 +1314,13 @@ Window *w = GetCallbackWnd(); if (w == NULL) return; - WindowEvent e; - e.we.place.pt = GetTileBelowCursor(); - if (e.we.place.pt.x == -1) { + Point pt = GetTileBelowCursor(); + if (pt.x == -1) { _thd.selend.x = -1; return; } - e.we.place.tile = TileVirtXY(e.we.place.pt.x, e.we.place.pt.y); - e.event = WE_PLACE_PRESIZE; - w->HandleWindowEvent(&e); + + w->OnPlacePresize(pt, TileVirtXY(pt.x, pt.y)); } static bool HandleDragDrop() @@ -1153,12 +1332,10 @@ if (w != NULL) { /* send an event in client coordinates. */ - WindowEvent e; - e.event = WE_DRAGDROP; - e.we.dragdrop.pt.x = _cursor.pos.x - w->left; - e.we.dragdrop.pt.y = _cursor.pos.y - w->top; - e.we.dragdrop.widget = GetWidgetFromPos(w, e.we.dragdrop.pt.x, e.we.dragdrop.pt.y); - w->HandleWindowEvent(&e); + Point pt; + pt.x = _cursor.pos.x - w->left; + pt.y = _cursor.pos.y - w->top; + w->OnDragDrop(pt, GetWidgetFromPos(w, pt.x, pt.y)); } ResetObjectToPlace(); @@ -1166,31 +1343,6 @@ return false; } -static bool HandlePopupMenu() -{ - if (!_popup_menu_active) return true; - - Window *w = FindWindowById(WC_TOOLBAR_MENU, 0); - if (w == NULL) { - _popup_menu_active = false; - return false; - } - - WindowEvent e; - if (_left_button_down) { - e.event = WE_POPUPMENU_OVER; - e.we.popupmenu.pt = _cursor.pos; - } else { - _popup_menu_active = false; - e.event = WE_POPUPMENU_SELECT; - e.we.popupmenu.pt = _cursor.pos; - } - - w->HandleWindowEvent(&e); - - return false; -} - static bool HandleMouseOver() { Window *w = FindWindowFromPt(_cursor.pos.x, _cursor.pos.y); @@ -1198,11 +1350,8 @@ /* We changed window, put a MOUSEOVER event to the last window */ if (_mouseover_last_w != NULL && _mouseover_last_w != w) { /* Reset mouse-over coordinates of previous window */ - WindowEvent e; - e.event = WE_MOUSEOVER; - e.we.mouseover.pt.x = -1; - e.we.mouseover.pt.y = -1; - _mouseover_last_w->HandleWindowEvent(&e); + Point pt = { -1, -1 }; + _mouseover_last_w->OnMouseOver(pt, 0); } /* _mouseover_last_w will get reset when the window is deleted, see DeleteWindow() */ @@ -1210,14 +1359,12 @@ if (w != NULL) { /* send an event in client coordinates. */ - WindowEvent e; - e.event = WE_MOUSEOVER; - e.we.mouseover.pt.x = _cursor.pos.x - w->left; - e.we.mouseover.pt.y = _cursor.pos.y - w->top; + Point pt = { _cursor.pos.x - w->left, _cursor.pos.y - w->top }; + int widget = 0; if (w->widget != NULL) { - e.we.mouseover.widget = GetWidgetFromPos(w, e.we.mouseover.pt.x, e.we.mouseover.pt.y); + widget = GetWidgetFromPos(w, pt.x, pt.y); } - w->HandleWindowEvent(&e); + w->OnMouseOver(pt, widget); } /* Mouseover never stops execution */ @@ -1421,7 +1568,6 @@ w->SetDirty(); return false; } else if (w->flags4 & WF_SIZING) { - WindowEvent e; int x, y; /* Stop the sizing if the left mouse button was released */ @@ -1458,12 +1604,13 @@ /* 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->HandleWindowEvent(&e); + Point size; + Point diff; + size.x = x + w->width; + size.y = y + w->height; + diff.x = x; + diff.y = y; + w->OnResize(size, diff); return false; } } @@ -1554,8 +1701,6 @@ static bool HandleViewportScroll() { - WindowEvent e; - bool scrollwheel_scrolling = _patches.scrollwheel_scrolling == 1 && (_cursor.v_wheel != 0 || _cursor.h_wheel != 0); if (!_scrolling_viewport) return true; @@ -1568,32 +1713,32 @@ return true; } - if (WP(w, vp_d).follow_vehicle != INVALID_VEHICLE && w == FindWindowById(WC_MAIN_WINDOW, 0)) { + if (w == FindWindowById(WC_MAIN_WINDOW, 0) && w->viewport->follow_vehicle != INVALID_VEHICLE) { /* If the main window is following a vehicle, then first let go of it! */ - const Vehicle *veh = GetVehicle(WP(w, vp_d).follow_vehicle); + const Vehicle *veh = GetVehicle(w->viewport->follow_vehicle); ScrollMainWindowTo(veh->x_pos, veh->y_pos, true); /* This also resets follow_vehicle */ return true; } + Point delta; if (_patches.reverse_scroll) { - e.we.scroll.delta.x = -_cursor.delta.x; - e.we.scroll.delta.y = -_cursor.delta.y; + delta.x = -_cursor.delta.x; + delta.y = -_cursor.delta.y; } else { - e.we.scroll.delta.x = _cursor.delta.x; - e.we.scroll.delta.y = _cursor.delta.y; + delta.x = _cursor.delta.x; + delta.y = _cursor.delta.y; } if (scrollwheel_scrolling) { /* We are using scrollwheels for scrolling */ - e.we.scroll.delta.x = _cursor.h_wheel; - e.we.scroll.delta.y = _cursor.v_wheel; + delta.x = _cursor.h_wheel; + delta.y = _cursor.v_wheel; _cursor.v_wheel = 0; _cursor.h_wheel = 0; } /* Create a scroll-event and send it to the window */ - e.event = WE_SCROLL; - w->HandleWindowEvent(&e); + w->OnScroll(delta); _cursor.delta.x = 0; _cursor.delta.y = 0; @@ -1652,59 +1797,11 @@ return true; } -/** Send a message from one window to another. The receiving window is found by - * @param w Window pointer pointing to the other window - * @param msg Specifies the message to be sent - * @param wparam Specifies additional message-specific information - * @param lparam Specifies additional message-specific information - */ -static void SendWindowMessageW(Window *w, uint msg, uint wparam, uint lparam) -{ - WindowEvent e; - - e.event = WE_MESSAGE; - e.we.message.msg = msg; - e.we.message.wparam = wparam; - e.we.message.lparam = lparam; - - w->HandleWindowEvent(&e); -} - -/** Send a message from one window to another. The receiving window is found by - * @param wnd_class see WindowClass class AND - * @param wnd_num see WindowNumber number, mostly 0 - * @param msg Specifies the message to be sent - * @param wparam Specifies additional message-specific information - * @param lparam Specifies additional message-specific information +/** Handle keyboard input. + * @param raw_key Lower 8 bits contain the ASCII character, the higher 16 bits the keycode */ -void SendWindowMessage(WindowClass wnd_class, WindowNumber wnd_num, int msg, int wparam, int lparam) +void HandleKeypress(uint32 raw_key) { - Window *w = FindWindowById(wnd_class, wnd_num); - if (w != NULL) SendWindowMessageW(w, msg, wparam, lparam); -} - -/** Send a message from one window to another. The message will be sent - * to ALL windows of the windowclass specified in the first parameter - * @param wnd_class see WindowClass class - * @param msg Specifies the message to be sent - * @param wparam Specifies additional message-specific information - * @param lparam Specifies additional message-specific information - */ -void SendWindowMessageClass(WindowClass wnd_class, int msg, int wparam, int lparam) -{ - Window* const *wz; - - FOR_ALL_WINDOWS(wz) { - if ((*wz)->window_class == wnd_class) SendWindowMessageW(*wz, msg, wparam, lparam); - } -} - -/** Handle keyboard input. - * @param key Lower 8 bits contain the ASCII character, the higher 16 bits the keycode - */ -void HandleKeypress(uint32 key) -{ - 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 * to thein this main toolbar. */ @@ -1722,10 +1819,8 @@ if (!IsGeneratingWorld()) _current_player = _local_player; /* Setup event */ - e.event = WE_KEYPRESS; - e.we.keypress.key = GB(key, 0, 16); - e.we.keypress.keycode = GB(key, 16, 16); - e.we.keypress.cont = true; + uint16 key = GB(raw_key, 0, 16); + uint16 keycode = GB(raw_key, 16, 16); /* * The Unicode standard defines an area called the private use area. Code points in this @@ -1734,12 +1829,12 @@ * on a system running OS X. We don't want these keys to show up in text fields and such, * and thus we have to clear the unicode character when we encounter such a key. */ - if (e.we.keypress.key >= 0xE000 && e.we.keypress.key <= 0xF8FF) e.we.keypress.key = 0; + if (key >= 0xE000 && key <= 0xF8FF) key = 0; /* * If both key and keycode is zero, we don't bother to process the event. */ - if (e.we.keypress.key == 0 && e.we.keypress.keycode == 0) return; + 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 || @@ -1765,15 +1860,13 @@ w->window_class != WC_COMPANY_PASSWORD_WINDOW) { continue; } - w->HandleWindowEvent(&e); - if (!e.we.keypress.cont) break; + ; + if (!w->OnKeyPress(key, keycode)) return; } - if (e.we.keypress.cont) { - Window *w = FindWindowById(WC_MAIN_TOOLBAR, 0); - /* When there is no toolbar w is null, check for that */ - if (w != NULL) w->HandleWindowEvent(&e); - } + Window *w = FindWindowById(WC_MAIN_TOOLBAR, 0); + /* When there is no toolbar w is null, check for that */ + if (w != NULL) w->OnKeyPress(key, keycode); } /** @@ -1781,16 +1874,10 @@ */ void HandleCtrlChanged() { - WindowEvent e; - - e.event = WE_CTRL_CHANGED; - e.we.ctrl.cont = true; - /* Call the event, start with the uppermost window. */ for (Window* const *wz = _last_z_window; wz != _z_windows;) { Window *w = *--wz; - w->HandleWindowEvent(&e); - if (!e.we.ctrl.cont) break; + if (!w->OnCTRLStateChange()) break; } } @@ -1828,14 +1915,14 @@ /* here allows scrolling in both x and y axis */ #define scrollspeed 3 if (x - 15 < 0) { - WP(w, vp_d).dest_scrollpos_x += ScaleByZoom((x - 15) * scrollspeed, vp->zoom); + w->viewport->dest_scrollpos_x += ScaleByZoom((x - 15) * scrollspeed, vp->zoom); } else if (15 - (vp->width - x) > 0) { - WP(w, vp_d).dest_scrollpos_x += ScaleByZoom((15 - (vp->width - x)) * scrollspeed, vp->zoom); + w->viewport->dest_scrollpos_x += ScaleByZoom((15 - (vp->width - x)) * scrollspeed, vp->zoom); } if (y - 15 < 0) { - WP(w, vp_d).dest_scrollpos_y += ScaleByZoom((y - 15) * scrollspeed, vp->zoom); + w->viewport->dest_scrollpos_y += ScaleByZoom((y - 15) * scrollspeed, vp->zoom); } else if (15 - (vp->height - y) > 0) { - WP(w, vp_d).dest_scrollpos_y += ScaleByZoom((15 - (vp->height - y)) * scrollspeed, vp->zoom); + w->viewport->dest_scrollpos_y += ScaleByZoom((15 - (vp->height - y)) * scrollspeed, vp->zoom); } #undef scrollspeed } @@ -1862,7 +1949,6 @@ UpdateTileSelection(); if (!VpHandlePlaceSizingDrag()) return; if (!HandleDragDrop()) return; - if (!HandlePopupMenu()) return; if (!HandleWindowDragging()) return; if (!HandleScrollbarScrolling()) return; if (!HandleViewportScroll()) return; @@ -1884,13 +1970,8 @@ if (mousewheel != 0) { if (_patches.scrollwheel_scrolling == 0) { - /* Scrollwheel is in zoom mode. Make the zoom event. */ - WindowEvent e; - /* Send WE_MOUSEWHEEL event to window */ - e.event = WE_MOUSEWHEEL; - e.we.wheel.wheel = mousewheel; - w->HandleWindowEvent(&e); + w->OnMouseWheel(mousewheel); } /* Dispatch a MouseWheelEvent for widgets if it is not a viewport */ @@ -1931,9 +2012,14 @@ } } else { switch (click) { - case MC_DOUBLE_LEFT: DispatchLeftClickEvent(w, x - w->left, y - w->top, true); - /* fallthough, and also give a single-click for backwards compatible */ - case MC_LEFT: DispatchLeftClickEvent(w, x - w->left, y - w->top, false); break; + case MC_DOUBLE_LEFT: + DispatchLeftClickEvent(w, x - w->left, y - w->top, true); + if (_mouseover_last_w == NULL) break; // The window got removed. + /* fallthough, and also give a single-click for backwards compatibility */ + case MC_LEFT: + DispatchLeftClickEvent(w, x - w->left, y - w->top, false); + break; + default: if (!scrollwheel_scrolling || w == NULL || w->window_class != WC_SMALLMAP) break; /* We try to use the scrollwheel to scroll since we didn't touch any of the buttons. @@ -2014,7 +2100,7 @@ if (t >= 100) { for (wz = _last_z_window; wz != _z_windows;) { - CallWindowEventNP(*--wz, WE_4); + (*--wz)->OnHundredthTick(); } t = 0; } @@ -2039,27 +2125,6 @@ DrawMouseCursor(); } - -/** - * In a window with menu_d custom extension, retrieve the menu item number from a position - * @param w Window holding the menu items - * @param x X coordinate of the position - * @param y Y coordinate of the position - * @return Index number of the menu item, or \c -1 if no valid selection under position - */ -int GetMenuItemIndex(const Window *w, int x, int y) -{ - if ((x -= w->left) >= 0 && x < w->width && (y -= w->top + 1) >= 0) { - y /= 10; - - if (y < WP(w, const menu_d).item_count && - !HasBit(WP(w, const menu_d).disabled_items, y)) { - return y; - } - } - return -1; -} - /** * Mark window as dirty (in need of repainting) * @param cls Window class @@ -2110,9 +2175,9 @@ * Mark window data as invalid (in need of re-computing) * @param w Window with invalid data */ -void InvalidateThisWindowData(Window *w) +void InvalidateThisWindowData(Window *w, int data) { - CallWindowEventNP(w, WE_INVALIDATE_DATA); + w->OnInvalidateData(data); w->SetDirty(); } @@ -2121,13 +2186,13 @@ * @param cls Window class * @param number Window number within the class */ -void InvalidateWindowData(WindowClass cls, WindowNumber number) +void InvalidateWindowData(WindowClass cls, WindowNumber number, int data) { Window* const *wz; FOR_ALL_WINDOWS(wz) { Window *w = *wz; - if (w->window_class == cls && w->window_number == number) InvalidateThisWindowData(w); + if (w->window_class == cls && w->window_number == number) InvalidateThisWindowData(w, data); } } @@ -2135,12 +2200,12 @@ * Mark window data of all windows of a given class as invalid (in need of re-computing) * @param cls Window class */ -void InvalidateWindowClassesData(WindowClass cls) +void InvalidateWindowClassesData(WindowClass cls, int data) { Window* const *wz; FOR_ALL_WINDOWS(wz) { - if ((*wz)->window_class == cls) InvalidateThisWindowData(*wz); + if ((*wz)->window_class == cls) InvalidateThisWindowData(*wz, data); } } @@ -2150,7 +2215,7 @@ void CallWindowTickEvent() { for (Window * const *wz = _last_z_window; wz != _z_windows;) { - CallWindowEventNP(*--wz, WE_TICK); + (*--wz)->OnTick(); } } @@ -2267,13 +2332,13 @@ if (neww - w->width != 0) { ResizeWindow(w, min(neww, 640) - w->width, 0); - WindowEvent e; - e.event = WE_RESIZE; - e.we.sizing.size.x = w->width; - e.we.sizing.size.y = w->height; - e.we.sizing.diff.x = neww - w->width; - e.we.sizing.diff.y = 0; - w->HandleWindowEvent(&e); + Point size; + Point delta; + size.x = w->width; + size.y = w->height; + delta.x = neww - w->width; + delta.y = 0; + w->OnResize(size, delta); } top = w->top;