1 /*****************************************************************************
2  * Copyright (c) 2014-2020 OpenRCT2 developers
3  *
4  * For a complete list of all authors, please refer to contributors.md
5  * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
6  *
7  * OpenRCT2 is licensed under the GNU General Public License version 3.
8  *****************************************************************************/
9 
10 #include <openrct2-ui/interface/Dropdown.h>
11 #include <openrct2-ui/interface/Viewport.h>
12 #include <openrct2-ui/interface/Widget.h>
13 #include <openrct2-ui/windows/Window.h>
14 #include <openrct2/Game.h>
15 #include <openrct2/actions/BannerRemoveAction.h>
16 #include <openrct2/actions/BannerSetColourAction.h>
17 #include <openrct2/actions/BannerSetNameAction.h>
18 #include <openrct2/actions/BannerSetStyleAction.h>
19 #include <openrct2/config/Config.h>
20 #include <openrct2/localisation/Localisation.h>
21 #include <openrct2/sprites.h>
22 #include <openrct2/world/Banner.h>
23 #include <openrct2/world/Scenery.h>
24 
25 static constexpr const int32_t WW = 113;
26 static constexpr const int32_t WH = 96;
27 static constexpr const rct_string_id WINDOW_TITLE = STR_BANNER_WINDOW_TITLE;
28 
29 // clang-format off
30 enum WINDOW_BANNER_WIDGET_IDX {
31     WIDX_BACKGROUND,
32     WIDX_TITLE,
33     WIDX_CLOSE,
34     WIDX_VIEWPORT,
35     WIDX_BANNER_TEXT,
36     WIDX_BANNER_NO_ENTRY,
37     WIDX_BANNER_DEMOLISH,
38     WIDX_MAIN_COLOUR,
39     WIDX_TEXT_COLOUR_DROPDOWN,
40     WIDX_TEXT_COLOUR_DROPDOWN_BUTTON
41 };
42 
43 static constexpr const rct_string_id BannerColouredTextFormats[] = {
44     STR_TEXT_COLOR_BLACK,
45     STR_TEXT_COLOR_GREY,
46     STR_TEXT_COLOR_WHITE,
47     STR_TEXT_COLOR_RED,
48     STR_TEXT_COLOR_GREEN,
49     STR_TEXT_COLOR_YELLOW,
50     STR_TEXT_COLOR_TOPAZ,
51     STR_TEXT_COLOR_CELADON,
52     STR_TEXT_COLOR_BABYBLUE,
53     STR_TEXT_COLOR_PALELAVENDER,
54     STR_TEXT_COLOR_PALEGOLD,
55     STR_TEXT_COLOR_LIGHTPINK,
56     STR_TEXT_COLOR_PEARLAQUA,
57     STR_TEXT_COLOR_PALESILVER,
58 };
59 
60 static rct_widget window_banner_widgets[] = {
61     WINDOW_SHIM(WINDOW_TITLE, WW, WH),
62     MakeWidget({      3,      17}, {85, 60}, WindowWidgetType::Viewport,  WindowColour::Secondary, 0x0FFFFFFFE                                        ), // tab content panel
63     MakeWidget({WW - 25,      19}, {24, 24}, WindowWidgetType::FlatBtn,   WindowColour::Secondary, SPR_RENAME,         STR_CHANGE_BANNER_TEXT_TIP     ), // change banner button
64     MakeWidget({WW - 25,      43}, {24, 24}, WindowWidgetType::FlatBtn,   WindowColour::Secondary, SPR_NO_ENTRY,       STR_SET_AS_NO_ENTRY_BANNER_TIP ), // no entry button
65     MakeWidget({WW - 25,      67}, {24, 24}, WindowWidgetType::FlatBtn,   WindowColour::Secondary, SPR_DEMOLISH,       STR_DEMOLISH_BANNER_TIP        ), // demolish button
66     MakeWidget({      5, WH - 16}, {12, 12}, WindowWidgetType::ColourBtn, WindowColour::Secondary, 0xFFFFFFFF,         STR_SELECT_MAIN_SIGN_COLOUR_TIP), // high money
67     MakeWidget({     43, WH - 16}, {39, 12}, WindowWidgetType::DropdownMenu,  WindowColour::Secondary                                                     ), // high money
68     MakeWidget({     70, WH - 15}, {11, 10}, WindowWidgetType::Button,    WindowColour::Secondary, STR_DROPDOWN_GLYPH, STR_SELECT_TEXT_COLOUR_TIP     ), // high money
69     WIDGETS_END,
70 };
71 
72 // clang-format on
73 
74 class BannerWindow final : public Window
75 {
76 private:
77     CoordsXYZ _bannerViewPos;
78 
CreateViewport()79     void CreateViewport()
80     {
81         rct_widget* viewportWidget = &window_banner_widgets[WIDX_VIEWPORT];
82         viewport_create(
83             this, windowPos + ScreenCoordsXY{ viewportWidget->left + 1, viewportWidget->top + 1 },
84             (viewportWidget->width()) - 1, (viewportWidget->height()) - 1, Focus(_bannerViewPos));
85 
86         if (viewport != nullptr)
87             viewport->flags = gConfigGeneral.always_show_gridlines ? VIEWPORT_FLAG_GRIDLINES : 0;
88         Invalidate();
89     }
90 
GetBannerElement()91     BannerElement* GetBannerElement()
92     {
93         auto* banner = GetBanner(number);
94         if (banner == nullptr)
95         {
96             return nullptr;
97         }
98 
99         TileElement* tileElement = map_get_first_element_at(banner->position);
100         if (tileElement == nullptr)
101         {
102             return nullptr;
103         }
104 
105         do
106         {
107             auto* bannerElement = tileElement->AsBanner();
108             if (bannerElement == nullptr)
109             {
110                 continue;
111             }
112             if (bannerElement->GetIndex() == number)
113             {
114                 return bannerElement;
115             }
116         } while (!(tileElement++)->IsLastForTile());
117 
118         return nullptr;
119     }
120 
121 public:
OnOpen()122     void OnOpen() override
123     {
124         widgets = window_banner_widgets;
125         enabled_widgets = (1ULL << WIDX_CLOSE) | (1ULL << WIDX_BANNER_TEXT) | (1ULL << WIDX_BANNER_NO_ENTRY)
126             | (1ULL << WIDX_BANNER_DEMOLISH) | (1ULL << WIDX_MAIN_COLOUR) | (1ULL << WIDX_TEXT_COLOUR_DROPDOWN)
127             | (1ULL << WIDX_TEXT_COLOUR_DROPDOWN_BUTTON);
128         WindowInitScrollWidgets(this);
129     }
130 
Initialise(rct_windownumber _number)131     void Initialise(rct_windownumber _number)
132     {
133         number = _number;
134         auto* banner = GetBanner(number);
135 
136         auto* bannerElement = GetBannerElement();
137         if (bannerElement == nullptr)
138             return;
139 
140         _bannerViewPos = CoordsXYZ{ banner->position.ToCoordsXY().ToTileCentre(), bannerElement->GetBaseZ() };
141         CreateViewport();
142     }
143 
OnMouseDown(rct_widgetindex widgetIndex)144     void OnMouseDown(rct_widgetindex widgetIndex) override
145     {
146         rct_widget* widget = &widgets[widgetIndex];
147         auto* banner = GetBanner(number);
148         if (banner == nullptr)
149         {
150             Close();
151             return;
152         }
153         switch (widgetIndex)
154         {
155             case WIDX_MAIN_COLOUR:
156                 WindowDropdownShowColour(this, widget, TRANSLUCENT(colours[1]), banner->colour);
157                 break;
158             case WIDX_TEXT_COLOUR_DROPDOWN_BUTTON:
159 
160                 for (int32_t i = 0; i < 13; ++i)
161                 {
162                     gDropdownItemsFormat[i] = STR_DROPDOWN_MENU_LABEL;
163                     gDropdownItemsArgs[i] = BannerColouredTextFormats[i + 1];
164                 }
165 
166                 // Switch to the dropdown box widget.
167                 widget--;
168 
169                 WindowDropdownShowTextCustomWidth(
170                     { widget->left + windowPos.x, widget->top + windowPos.y }, widget->height() + 1, colours[1], 0,
171                     Dropdown::Flag::StayOpen, 13, widget->width() - 3);
172 
173                 Dropdown::SetChecked(banner->text_colour - 1, true);
174                 break;
175         }
176     }
177 
OnMouseUp(rct_widgetindex widgetIndex)178     void OnMouseUp(rct_widgetindex widgetIndex) override
179     {
180         auto* banner = GetBanner(number);
181         if (banner == nullptr)
182         {
183             Close();
184             return;
185         }
186         switch (widgetIndex)
187         {
188             case WIDX_CLOSE:
189                 Close();
190                 break;
191             case WIDX_BANNER_DEMOLISH:
192             {
193                 auto* bannerElement = GetBannerElement();
194                 if (bannerElement == nullptr)
195                     break;
196 
197                 auto bannerRemoveAction = BannerRemoveAction(
198                     { banner->position.ToCoordsXY(), bannerElement->GetBaseZ(), bannerElement->GetPosition() });
199                 GameActions::Execute(&bannerRemoveAction);
200                 break;
201             }
202             case WIDX_BANNER_TEXT:
203                 window_text_input_raw_open(
204                     this, WIDX_BANNER_TEXT, STR_BANNER_TEXT, STR_ENTER_BANNER_TEXT, {}, banner->GetText().c_str(), 32);
205                 break;
206             case WIDX_BANNER_NO_ENTRY:
207             {
208                 textinput_cancel();
209                 auto bannerSetStyle = BannerSetStyleAction(
210                     BannerSetStyleType::NoEntry, number, banner->flags ^ BANNER_FLAG_NO_ENTRY);
211                 GameActions::Execute(&bannerSetStyle);
212                 break;
213             }
214         }
215     }
216 
OnDropdown(rct_widgetindex widgetIndex,int32_t dropdownIndex)217     void OnDropdown(rct_widgetindex widgetIndex, int32_t dropdownIndex) override
218     {
219         switch (widgetIndex)
220         {
221             case WIDX_MAIN_COLOUR:
222             {
223                 if (dropdownIndex == -1)
224                     break;
225 
226                 auto bannerSetStyle = BannerSetStyleAction(BannerSetStyleType::PrimaryColour, number, dropdownIndex);
227                 GameActions::Execute(&bannerSetStyle);
228                 break;
229             }
230             case WIDX_TEXT_COLOUR_DROPDOWN_BUTTON:
231             {
232                 if (dropdownIndex == -1)
233                     break;
234                 auto bannerSetStyle = BannerSetStyleAction(BannerSetStyleType::TextColour, number, dropdownIndex + 1);
235                 GameActions::Execute(&bannerSetStyle);
236                 break;
237             }
238         }
239     }
240 
OnTextInput(rct_widgetindex widgetIndex,std::string_view text)241     void OnTextInput(rct_widgetindex widgetIndex, std::string_view text) override
242     {
243         if (widgetIndex == WIDX_BANNER_TEXT)
244         {
245             auto bannerSetNameAction = BannerSetNameAction(number, std::string(text));
246             GameActions::Execute(&bannerSetNameAction);
247         }
248     }
249 
OnViewportRotate()250     void OnViewportRotate() override
251     {
252         RemoveViewport();
253         CreateViewport();
254     }
255 
OnDraw(rct_drawpixelinfo & dpi)256     void OnDraw(rct_drawpixelinfo& dpi) override
257     {
258         DrawWidgets(dpi);
259 
260         if (viewport != nullptr)
261         {
262             window_draw_viewport(&dpi, this);
263         }
264     }
265 
OnPrepareDraw()266     void OnPrepareDraw() override
267     {
268         auto* banner = GetBanner(number);
269         if (banner == nullptr)
270         {
271             return;
272         }
273         rct_widget* colourBtn = &window_banner_widgets[WIDX_MAIN_COLOUR];
274         colourBtn->type = WindowWidgetType::Empty;
275 
276         auto* bannerEntry = get_banner_entry(banner->type);
277         if (bannerEntry != nullptr && (bannerEntry->flags & BANNER_ENTRY_FLAG_HAS_PRIMARY_COLOUR))
278         {
279             colourBtn->type = WindowWidgetType::ColourBtn;
280         }
281         pressed_widgets &= ~(1ULL << WIDX_BANNER_NO_ENTRY);
282         disabled_widgets &= ~(
283             (1ULL << WIDX_BANNER_TEXT) | (1ULL << WIDX_TEXT_COLOUR_DROPDOWN) | (1ULL << WIDX_TEXT_COLOUR_DROPDOWN_BUTTON));
284         if (banner->flags & BANNER_FLAG_NO_ENTRY)
285         {
286             pressed_widgets |= (1ULL << WIDX_BANNER_NO_ENTRY);
287             disabled_widgets |= (1ULL << WIDX_BANNER_TEXT) | (1ULL << WIDX_TEXT_COLOUR_DROPDOWN)
288                 | (1ULL << WIDX_TEXT_COLOUR_DROPDOWN_BUTTON);
289         }
290         colourBtn->image = SPRITE_ID_PALETTE_COLOUR_1(banner->colour) | IMAGE_TYPE_TRANSPARENT | SPR_PALETTE_BTN;
291         rct_widget* dropDownWidget = &window_banner_widgets[WIDX_TEXT_COLOUR_DROPDOWN];
292         dropDownWidget->text = BannerColouredTextFormats[banner->text_colour];
293     }
294 };
295 
296 /**
297  *
298  *  rct2: 0x006BA305
299  */
window_banner_open(rct_windownumber number)300 rct_window* window_banner_open(rct_windownumber number)
301 {
302     auto w = static_cast<BannerWindow*>(window_bring_to_front_by_number(WC_BANNER, number));
303 
304     if (w != nullptr)
305         return w;
306 
307     w = WindowCreate<BannerWindow>(WC_BANNER, WW, WH, 0);
308 
309     if (w != nullptr)
310         w->Initialise(number);
311 
312     return w;
313 }
314