/* $Id$ */ /* * This file is part of OpenTTD. * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . */ /** @file build_confirmation_gui.cpp Transparent confirmation dialog for building anything on the map. */ #include "stdafx.h" #include "string_func.h" #include "strings_func.h" #include "window_func.h" #include "widget_type.h" #include "window_gui.h" #include "gfx_func.h" #include "tilehighlight_func.h" #include "viewport_func.h" #include "zoom_func.h" #include "settings_type.h" #include "station_gui.h" #include "error.h" #include "build_confirmation_func.h" #include "widgets/build_confirmation_widget.h" #include "widgets/misc_widget.h" #include "table/strings.h" #include "safeguards.h" static const NWidgetPart _nested_build_info_widgets[] = { NWidget(WWT_PANEL, COLOUR_GREY, WID_TT_BACKGROUND), SetMinimalSize(200, 32), EndContainer(), }; static WindowDesc _build_info_desc( WDP_MANUAL, NULL, 0, 0, // Coordinates and sizes are not used, WC_TOOLTIPS, WC_NONE, WDF_NO_FOCUS, _nested_build_info_widgets, lengthof(_nested_build_info_widgets) ); /** Window for displaying accepted goods for a station. */ struct BuildInfoWindow : public Window { StationCoverageType sct; bool station; static Money cost; static void show() { bool station = _settings_client.gui.station_show_coverage; // Station info is inaccurate when station coverage area option is disabled StationCoverageType sct = SCT_ALL; if (FindWindowByClass(WC_BUILD_STATION) != NULL) sct = SCT_ALL; else if (FindWindowByClass(WC_BUS_STATION) != NULL) sct = SCT_PASSENGERS_ONLY; else if (FindWindowByClass(WC_TRUCK_STATION) != NULL) sct = SCT_NON_PASSENGERS_ONLY; else station = false; new BuildInfoWindow(station, sct); } BuildInfoWindow(bool station, StationCoverageType sct) : Window(&_build_info_desc) { this->station = station; this->sct = sct; this->InitNested(); CLRBITS(this->flags, WF_WHITE_BORDER); } Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) override { Point pt; pt.y = GetMainViewTop(); pt.x = _screen.width - sm_width - FindWindowById(WC_MAIN_TOOLBAR, 0)->width; return pt; } void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { size->width = GetStringBoundingBox(STR_STATION_BUILD_COVERAGE_AREA_TITLE).width * 2.5; size->height = GetStringHeight(STR_STATION_BUILD_COVERAGE_AREA_TITLE, size->width) * (this->station ? 3 : 1); /* Increase slightly to have some space around the box. */ size->width += 2 + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; size->height += 6 + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; } void DrawWidget(const Rect &r, int widget) const override { /* There is only one widget. */ DrawFrameRect(r.left, r.top, r.right, r.bottom, COLOUR_GREY, FR_NONE); int top = r.top + WD_FRAMERECT_TOP + 4; Money cost = BuildInfoWindow::cost; StringID msg = STR_MESSAGE_ESTIMATED_COST; SetDParam(0, cost); if (cost < 0) { msg = STR_MESSAGE_ESTIMATED_INCOME; SetDParam(0, -cost); } top = DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, top, INT32_MAX, msg); if (!this->station) return; top = DrawStationCoverageAreaText(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, top, sct, _thd.outersize.x / TILE_SIZE / 2, false); if (top - r.top <= GetStringHeight(STR_STATION_BUILD_COVERAGE_AREA_TITLE, r.right - r.left) * 1.5) { DrawStationCoverageAreaText(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, top, sct, _thd.outersize.x / TILE_SIZE / 2, true); } } }; Money BuildInfoWindow::cost = 0; /** GUI for confirming building actions. */ struct BuildConfirmationWindow : Window { // TODO: show estimated price static bool shown; ///< Just to speed up window hiding, HideBuildConfirmationWindow() is called very often. static bool estimating_cost; ///< Calculate action cost instead of executing action. Point selstart; ///< The selection start on the viewport. Point selend; ///< The selection end on the viewport. BuildConfirmationWindow(WindowDesc *desc) : Window(desc) { // Save tile selection points, they will be reset by subsequent code, and we must keep them selstart = _thd.selstart; selend = _thd.selend; this->InitNested(0); Point pt; const Window *w = FindWindowById(WC_MAIN_WINDOW, 0); NWidgetViewport *nvp = this->GetWidget(WID_BC_OK); pt.x = w->viewport->scrollpos_x + ScaleByZoom(_cursor.pos.x - nvp->current_x / 2, w->viewport->zoom); pt.y = w->viewport->scrollpos_y + ScaleByZoom(_cursor.pos.y - nvp->current_y / 4, w->viewport->zoom); nvp->InitializeViewport(this, 0, w->viewport->zoom); nvp->disp_flags |= ND_SHADE_DIMMED; this->viewport->scrollpos_x = pt.x; this->viewport->scrollpos_y = pt.y; this->viewport->dest_scrollpos_x = this->viewport->scrollpos_x; this->viewport->dest_scrollpos_y = this->viewport->scrollpos_y; BuildConfirmationWindow::shown = true; BuildConfirmationWindow::estimating_cost = true; ConfirmationWindowSetEstimatedCost(0); // Clear old value, just in case // This is a hack - we invoke the build command with estimating_cost flag, which is equal to _shift_pressed, // then we select last build tool, restore viewport selection, and hide all windows, which pop up when command is invoked, // and all that just to get cost estimate value. ConfirmPlacingObject(); ToolbarSelectLastTool(); _thd.selstart = selstart; _thd.selend = selend; BuildConfirmationWindow::estimating_cost = false; MoveAllWindowsOffScreen(); } ~BuildConfirmationWindow() { BuildConfirmationWindow::shown = false; } void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_BC_OK: if (pt.y <= (int)GetWidget(WID_BC_OK)->current_y / 2) { _thd.selstart = selstart; _thd.selend = selend; ConfirmPlacingObject(); ToolbarSelectLastTool(); } else { ResetObjectToPlace(); DeleteWindowByClass(WC_BUILD_BRIDGE); //ClearErrorMessages(); Window *w = FindWindowById(WC_ERRMSG, 0); if (w != NULL) delete w; } break; } HideBuildConfirmationWindow(); // this == NULL after this call } void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_BC_OK: size->width = GetMinButtonSize() * 2; size->height = GetMinButtonSize() * 3; break; } } void OnPaint() override { this->DrawWidgets(); DrawButtonFrame(0, 0, this->width - 1, this->height / 2 - 2, STR_BUTTON_OK); DrawButtonFrame(0, this->height / 2, this->width - 1, this->height / 2 - 1, STR_BUTTON_CANCEL); } void DrawButtonFrame(int x, int y, int w, int h, int str) { DrawFrameRect(x, y, x + w, y + h, COLOUR_GREY, FR_BORDERONLY); Dimension d = GetStringBoundingBox(str); DrawFrameRect(x + w / 2 - d.width / 2 - 1, Center(y, h) - 2, x + w / 2 + d.width / 2 + 1, Center(y, h) + d.height, COLOUR_GREY, FR_NONE); DrawString(x, x + w, Center(y, h), str, TC_FROMSTRING, SA_HOR_CENTER); } }; bool BuildConfirmationWindow::shown = false; bool BuildConfirmationWindow::estimating_cost = false; static const NWidgetPart _nested_build_confirmation_widgets[] = { NWidget(WWT_PANEL, COLOUR_GREY, WID_BC_PANEL), NWidget(NWID_VIEWPORT, INVALID_COLOUR, WID_BC_OK), SetSizingType(NWST_VIEWPORT), SetResize(1, 1), SetFill(1, 1), //SetPadding(2, 2, 2, 2), EndContainer(), }; static WindowDesc _build_confirmation_desc( WDP_MANUAL, "build_confirmation", 0, 0, WC_BUILD_CONFIRMATION, WC_NONE, 0, _nested_build_confirmation_widgets, lengthof(_nested_build_confirmation_widgets) ); /** * Show build confirmation window under the mouse cursor */ void ShowBuildConfirmationWindow() { if (ConfirmationWindowEstimatingCost()) return; // Special case, ignore recursive call HideBuildConfirmationWindow(); if (!_settings_client.gui.build_confirmation || _shift_pressed) { ConfirmPlacingObject(); return; } BuildConfirmationWindow *w = new BuildConfirmationWindow(&_build_confirmation_desc); int old_left = w->left; int old_top = w->top; w->left = _cursor.pos.x - w->width / 2; w->top = _cursor.pos.y - w->height / 4; w->viewport->left += w->left - old_left; w->viewport->top += w->top - old_top; w->SetDirty(); MarkWholeScreenDirty(); // I don't know what does this do, but it looks important BuildInfoWindow::show(); } /** * Destroy build confirmation window, this does not cancel current action */ void HideBuildConfirmationWindow() { if (ConfirmationWindowEstimatingCost()) return; // Special case, ignore recursive call if (!BuildConfirmationWindow::shown) return; DeleteWindowById(WC_BUILD_CONFIRMATION, 0); DeleteWindowById(WC_TOOLTIPS, 0); } bool ConfirmationWindowShown() { return BuildConfirmationWindow::shown; } bool BuildConfirmationWindowProcessViewportClick() { if (!BuildConfirmationWindow::shown) return false; Window *w = FindWindowById(WC_BUILD_CONFIRMATION, 0); if (w != NULL && IsInsideBS(_cursor.pos.x, w->left, w->width) && IsInsideBS(_cursor.pos.y, w->top, w->height)) { if (_settings_client.gui.windows_titlebars || !_left_button_down) { Point pt; pt.x = _cursor.pos.x - w->left; pt.y = _cursor.pos.y - w->top; w->OnClick(pt, WID_BC_OK, 1); } return true; } HideBuildConfirmationWindow(); _thd.new_outersize = _thd.outersize; // Revert station catchment area highlight, which is getting set to zero inside drawing funcs return false; } bool ConfirmationWindowEstimatingCost() { return BuildConfirmationWindow::estimating_cost; } void ConfirmationWindowSetEstimatedCost(Money cost) { BuildInfoWindow::cost = cost; }