Index: src/bridge_gui.cpp =================================================================== --- src/bridge_gui.cpp (revision 22637) +++ src/bridge_gui.cpp (working copy) @@ -80,7 +80,7 @@ }; /** Window class for handling the bridge-build GUI. */ -class BuildBridgeWindow : public Window { +class BuildBridgeWindow : public WindowPopup { private: /* Runtime saved values */ static uint16 last_size; ///< Last size of the bridge GUI window. @@ -141,12 +141,13 @@ } public: - BuildBridgeWindow(const WindowDesc *desc, TileIndex start, TileIndex end, uint32 br_type, GUIBridgeList *bl) : Window(), + BuildBridgeWindow(const WindowDesc *desc, TileIndex start, TileIndex end, uint32 br_type, GUIBridgeList *bl) : WindowPopup(WPUT_WIDGET_RELATIVE), start_tile(start), end_tile(end), type(br_type), bridges(bl) { + this->wpu_widget = BBSW_BRIDGE_LIST; this->CreateNestedTree(desc); this->vscroll = this->GetScrollbar(BBSW_SCROLLBAR); /* Change the data, or the caption of the gui. Set it to road or rail, accordingly. */ @@ -220,16 +221,6 @@ } } - virtual Point OnInitialPosition(const WindowDesc *desc, int16 sm_width, int16 sm_height, int window_number) - { - /* Position the window so hopefully the first bridge from the list is under the mouse pointer. */ - NWidgetBase *list = this->GetWidget(BBSW_BRIDGE_LIST); - Point corner; // point of the top left corner of the window. - corner.y = Clamp(_cursor.pos.y - list->pos_y - 5, GetMainViewTop(), GetMainViewBottom() - sm_height); - corner.x = Clamp(_cursor.pos.x - list->pos_x - 5, 0, _screen.width - sm_width); - return corner; - } - virtual void DrawWidget(const Rect &r, int widget) const { switch (widget) { Index: src/window_gui.h =================================================================== --- src/window_gui.h (revision 22637) +++ src/window_gui.h (working copy) @@ -844,4 +844,31 @@ void ScrollbarClickHandler(Window *w, NWidgetCore *nw, int x, int y); + +/** + * #WindowPopup positioning types + */ +enum WindowPopupType { + WPUT_ORIGIN = 1, ///< Align with the top-left corner of the window. + WPUT_WIDGET_RELATIVE, ///< Align from a nested widget. + WPUT_CENTERED, ///< Center the widget under the cursor. Ignore modifiers. +}; + +/** + * Specialized Window bound to open around the cursor's position. + * Its sole purpose is to provide the OnInitialPosition() method + * and an simple interface to control its behaviour. + */ +struct WindowPopup: public Window { +public: + WindowPopup( WindowPopupType t = WPUT_ORIGIN); + virtual Point OnInitialPosition(const WindowDesc *desc, int16 sm_width, int16 sm_height, int window_number); +protected: + uint wpu_widget; ///< The widget to which the computation would be made from when type is #WPUT_WIDGET_RELATIVE. + int wpu_mod_x; ///< The X axis modifier. A negative value would bring the window closer to the left edge of the screen. Default value is -5. + int wpu_mod_y; ///< The Y axis modifier. A negative value would bring the window closer to the top edge of the screen. Default value is -5. +private: + WindowPopupType type; +}; + #endif /* WINDOW_GUI_H */ Index: src/station_gui.cpp =================================================================== --- src/station_gui.cpp (revision 22637) +++ src/station_gui.cpp (working copy) @@ -1360,16 +1360,17 @@ * @tparam T The type of station to join with */ template -struct SelectStationWindow : Window { +struct SelectStationWindow : WindowPopup { CommandContainer select_station_cmd; ///< Command to build new station TileArea area; ///< Location of new station Scrollbar *vscroll; SelectStationWindow(const WindowDesc *desc, CommandContainer cmd, TileArea ta) : - Window(), + WindowPopup(WPUT_WIDGET_RELATIVE), select_station_cmd(cmd), area(ta) { + this->wpu_widget = JSW_PANEL; this->CreateNestedTree(desc); this->vscroll = this->GetScrollbar(JSW_SCROLLBAR); this->GetWidget(JSW_WIDGET_CAPTION)->widget_data = T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_JOIN_WAYPOINT_CAPTION : STR_JOIN_STATION_CAPTION; Index: src/window.cpp =================================================================== --- src/window.cpp (revision 22637) +++ src/window.cpp (working copy) @@ -11,6 +11,7 @@ #include "stdafx.h" #include +#include #include "company_func.h" #include "gfx_func.h" #include "console_func.h" @@ -21,6 +22,7 @@ #include "zoom_func.h" #include "vehicle_base.h" #include "window_func.h" +#include "window_gui.h" #include "tilehighlight_func.h" #include "network/network.h" #include "querystring_gui.h" @@ -2820,3 +2822,52 @@ this->window_class = WC_INVALID; // stop the ancestor from freeing the already (to be) child ResetObjectToPlace(); } + +/** + * Sets safe-initial values. + * @param t The type of positioning desired. + */ +WindowPopup::WindowPopup(WindowPopupType t): Window() +{ + this->type = t; + this->wpu_mod_x = -5; + this->wpu_mod_y = -5; + this->wpu_widget = std::numeric_limits::max(); +} + +/** + * Compute #WindowPopup origin Point. + * + * @param desc The window's #WindowDesc object + * @param sm_width Window's smallest_x. + * @param sm_height Window's smallest_y. Unused. + * @param window_number Unused. + * @return The origin coordinate of the window. + */ +/*virtual*/ Point WindowPopup::OnInitialPosition(const WindowDesc *desc, int16 sm_width, int16 sm_height, int window_number) +{ + int x, y; + + switch (this->type) { + case WPUT_CENTERED: + x = _cursor.pos.x - sm_width / 2; + y = _cursor.pos.y - desc->default_height / 2; + break; + case WPUT_WIDGET_RELATIVE: + if (this->wpu_widget != std::numeric_limits::max()) { + NWidgetBase *wid = this->GetWidget(this->wpu_widget); + x = _cursor.pos.x - wid->pos_x + this->wpu_mod_x; + y = _cursor.pos.y - wid->pos_y + this->wpu_mod_y; + break; + } + case WPUT_ORIGIN: + default: + x = _cursor.pos.x + this->wpu_mod_x; + y = _cursor.pos.y + this->wpu_mod_y; + } + + Point rv; + rv.x = Clamp(x, 0, _screen.width - sm_width); + rv.y = Clamp(y, GetMainViewTop(), GetMainViewBottom() - desc->default_height); + return rv; +}