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 "../interface/Theme.h"
11
12 #include <openrct2-ui/interface/Dropdown.h>
13 #include <openrct2-ui/interface/Widget.h>
14 #include <openrct2-ui/windows/Window.h>
15 #include <openrct2/Context.h>
16 #include <openrct2/Game.h>
17 #include <openrct2/Input.h>
18 #include <openrct2/config/Config.h>
19 #include <openrct2/drawing/Drawing.h>
20 #include <openrct2/localisation/Localisation.h>
21 #include <openrct2/sprites.h>
22 #include <openrct2/util/Util.h>
23
24 enum
25 {
26 WINDOW_THEMES_TAB_SETTINGS,
27 WINDOW_THEMES_TAB_MAIN_UI,
28 WINDOW_THEMES_TAB_PARK,
29 WINDOW_THEMES_TAB_TOOLS,
30 WINDOW_THEMES_TAB_RIDES_PEEPS,
31 WINDOW_THEMES_TAB_EDITORS,
32 WINDOW_THEMES_TAB_MISC,
33 WINDOW_THEMES_TAB_PROMPTS,
34 WINDOW_THEMES_TAB_FEATURES,
35 WINDOW_THEMES_TAB_COUNT
36 };
37
38 static void window_themes_mouseup(rct_window* w, rct_widgetindex widgetIndex);
39 static void window_themes_resize(rct_window* w);
40 static void window_themes_mousedown(rct_window* w, rct_widgetindex widgetIndex, rct_widget* widget);
41 static void window_themes_dropdown(rct_window* w, rct_widgetindex widgetIndex, int32_t dropdownIndex);
42 static void window_themes_update(rct_window* w);
43 static void window_themes_scrollgetsize(rct_window* w, int32_t scrollIndex, int32_t* width, int32_t* height);
44 static void window_themes_scrollmousedown(rct_window* w, int32_t scrollIndex, const ScreenCoordsXY& screenCoords);
45 static void window_themes_scrollmouseover(rct_window* w, int32_t scrollIndex, const ScreenCoordsXY& screenCoords);
46 static void window_themes_textinput(rct_window* w, rct_widgetindex widgetIndex, char* text);
47 static void window_themes_invalidate(rct_window* w);
48 static void window_themes_paint(rct_window* w, rct_drawpixelinfo* dpi);
49 static void window_themes_scrollpaint(rct_window* w, rct_drawpixelinfo* dpi, int32_t scrollIndex);
50 static void window_themes_draw_tab_images(rct_drawpixelinfo* dpi, rct_window* w);
51
__anon011d13cd0202(auto& events) 52 static rct_window_event_list window_themes_events([](auto& events) {
53 events.mouse_up = &window_themes_mouseup;
54 events.resize = &window_themes_resize;
55 events.mouse_down = &window_themes_mousedown;
56 events.dropdown = &window_themes_dropdown;
57 events.update = &window_themes_update;
58 events.get_scroll_size = &window_themes_scrollgetsize;
59 events.scroll_mousedown = &window_themes_scrollmousedown;
60 events.scroll_mouseover = &window_themes_scrollmouseover;
61 events.text_input = &window_themes_textinput;
62 events.invalidate = &window_themes_invalidate;
63 events.paint = &window_themes_paint;
64 events.scroll_paint = &window_themes_scrollpaint;
65 });
66
67 enum WINDOW_THEMES_WIDGET_IDX
68 {
69 WIDX_THEMES_BACKGROUND,
70 WIDX_THEMES_TITLE,
71 WIDX_THEMES_CLOSE,
72 WIDX_THEMES_TAB_CONTENT_PANEL,
73 WIDX_THEMES_SETTINGS_TAB,
74 WIDX_THEMES_MAIN_UI_TAB,
75 WIDX_THEMES_PARK_TAB,
76 WIDX_THEMES_TOOLS_TAB,
77 WIDX_THEMES_RIDE_PEEPS_TAB,
78 WIDX_THEMES_EDITORS_TAB,
79 WIDX_THEMES_MISC_TAB,
80 WIDX_THEMES_PROMPTS_TAB,
81 WIDX_THEMES_FEATURES_TAB,
82 WIDX_THEMES_HEADER_WINDOW,
83 WIDX_THEMES_HEADER_PALETTE,
84 WIDX_THEMES_PRESETS,
85 WIDX_THEMES_PRESETS_DROPDOWN,
86 WIDX_THEMES_DUPLICATE_BUTTON,
87 WIDX_THEMES_DELETE_BUTTON,
88 WIDX_THEMES_RENAME_BUTTON,
89 WIDX_THEMES_COLOURBTN_MASK,
90 WIDX_THEMES_LIST,
91 WIDX_THEMES_RCT1_RIDE_LIGHTS,
92 WIDX_THEMES_RCT1_PARK_LIGHTS,
93 WIDX_THEMES_RCT1_SCENARIO_FONT,
94 WIDX_THEMES_RCT1_BOTTOM_TOOLBAR
95 };
96
97 static constexpr const rct_string_id WINDOW_TITLE = STR_THEMES_TITLE;
98 static constexpr const int32_t WW = 320;
99 static constexpr const int32_t WH = 107;
100
101 // clang-format off
102 static rct_widget window_themes_widgets[] = {
103 WINDOW_SHIM(WINDOW_TITLE, WW, WH),
104 MakeWidget({ 0, 43}, {320, 64}, WindowWidgetType::Resize, WindowColour::Secondary ), // tab content panel
105 MakeTab ({ 3, 17}, STR_THEMES_TAB_SETTINGS_TIP ), // settings tab
106 MakeTab ({ 34, 17}, STR_THEMES_TAB_MAIN_TIP ), // main ui tab
107 MakeTab ({ 65, 17}, STR_THEMES_TAB_PARK_TIP ), // park tab
108 MakeTab ({ 96, 17}, STR_THEMES_TAB_TOOLS_TIP ), // tools tab
109 MakeTab ({127, 17}, STR_THEMES_TAB_RIDES_AND_GUESTS_TIP), // rides and peeps tab
110 MakeTab ({158, 17}, STR_THEMES_TAB_EDITORS_TIP ), // editors tab
111 MakeTab ({189, 17}, STR_THEMES_TAB_MISC_TIP ), // misc tab
112 MakeTab ({220, 17}, STR_THEMES_TAB_PROMPTS_TIP ), // prompts tab
113 MakeTab ({251, 17}, STR_THEMES_TAB_FEATURES_TIP ), // features tab
114 MakeWidget({ 5, 46}, {214, 15}, WindowWidgetType::TableHeader, WindowColour::Secondary, STR_THEMES_HEADER_WINDOW ), // Window header
115 MakeWidget({219, 46}, { 97, 15}, WindowWidgetType::TableHeader, WindowColour::Secondary, STR_THEMES_HEADER_PALETTE ), // Palette header
116 MakeWidget({125, 60}, {175, 12}, WindowWidgetType::DropdownMenu, WindowColour::Secondary ), // Preset colour schemes
117 MakeWidget({288, 61}, { 11, 10}, WindowWidgetType::Button, WindowColour::Secondary, STR_DROPDOWN_GLYPH ),
118 MakeWidget({ 10, 82}, { 91, 12}, WindowWidgetType::Button, WindowColour::Secondary, STR_TITLE_EDITOR_ACTION_DUPLICATE, STR_THEMES_ACTION_DUPLICATE_TIP ), // Duplicate button
119 MakeWidget({110, 82}, { 91, 12}, WindowWidgetType::Button, WindowColour::Secondary, STR_TRACK_MANAGE_DELETE, STR_THEMES_ACTION_DELETE_TIP ), // Delete button
120 MakeWidget({210, 82}, { 91, 12}, WindowWidgetType::Button, WindowColour::Secondary, STR_TRACK_MANAGE_RENAME, STR_THEMES_ACTION_RENAME_TIP ), // Rename button
121 MakeWidget({ 0, 0}, { 1, 1}, WindowWidgetType::ColourBtn, WindowColour::Secondary ), // colour button mask
122 MakeWidget({ 3, 60}, {314, 44}, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_VERTICAL ), // staff list
123 MakeWidget({ 10, 54}, {290, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_THEMES_OPTION_RCT1_RIDE_CONTROLS ), // rct1 ride lights
124 MakeWidget({ 10, 69}, {290, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_THEMES_OPTION_RCT1_PARK_CONTROLS ), // rct1 park lights
125 MakeWidget({ 10, 84}, {290, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_THEMES_OPTION_RCT1_SCENARIO_SELECTION_FONT ), // rct1 scenario font
126 MakeWidget({ 10, 99}, {290, 12}, WindowWidgetType::Checkbox, WindowColour::Secondary, STR_THEMES_OPTION_RCT1_BOTTOM_TOOLBAR ), // rct1 bottom toolbar
127 WIDGETS_END,
128 };
129
130 static int32_t window_themes_tab_animation_loops[] = {
131 32,
132 32,
133 1,
134 1,
135 64,
136 32,
137 8,
138 14,
139 38,
140 };
141 static int32_t window_themes_tab_animation_divisor[] = {
142 4,
143 4,
144 1,
145 1,
146 4,
147 2,
148 2,
149 2,
150 2,
151 };
152 static int32_t window_themes_tab_sprites[] = {
153 SPR_TAB_PAINT_0,
154 SPR_TAB_KIOSKS_AND_FACILITIES_0,
155 SPR_TAB_PARK_ENTRANCE,
156 SPR_G2_TAB_LAND,
157 SPR_TAB_RIDE_0,
158 SPR_TAB_WRENCH_0,
159 SPR_TAB_GEARS_0,
160 SPR_TAB_STAFF_OPTIONS_0,
161 SPR_TAB_FINANCES_MARKETING_0,
162 };
163
164 static rct_windowclass window_themes_tab_1_classes[] = {
165 WC_TOP_TOOLBAR,
166 WC_BOTTOM_TOOLBAR,
167 WC_EDITOR_SCENARIO_BOTTOM_TOOLBAR,
168 WC_EDITOR_TRACK_BOTTOM_TOOLBAR,
169 WC_TITLE_MENU,
170 WC_TITLE_EXIT,
171 WC_TITLE_OPTIONS,
172 WC_SCENARIO_SELECT,
173 };
174
175 static rct_windowclass window_themes_tab_2_classes[] = {
176 WC_PARK_INFORMATION,
177 WC_FINANCES,
178 WC_NEW_CAMPAIGN,
179 WC_RESEARCH,
180 WC_MAP,
181 WC_VIEWPORT,
182 WC_RECENT_NEWS,
183 };
184
185 static rct_windowclass window_themes_tab_3_classes[] = {
186 WC_LAND,
187 WC_WATER,
188 WC_CLEAR_SCENERY,
189 WC_LAND_RIGHTS,
190 WC_SCENERY,
191 WC_SCENERY_SCATTER,
192 WC_FOOTPATH,
193 WC_RIDE_CONSTRUCTION,
194 WC_TRACK_DESIGN_PLACE,
195 WC_CONSTRUCT_RIDE,
196 WC_TRACK_DESIGN_LIST,
197 };
198
199 static rct_windowclass window_themes_tab_4_classes[] = {
200 WC_RIDE,
201 WC_RIDE_LIST,
202 WC_PEEP,
203 WC_GUEST_LIST,
204 WC_STAFF,
205 WC_STAFF_LIST,
206 WC_BANNER,
207 };
208
209 static rct_windowclass window_themes_tab_5_classes[] = {
210 WC_EDITOR_OBJECT_SELECTION,
211 WC_EDITOR_INVENTION_LIST,
212 WC_EDITOR_SCENARIO_OPTIONS,
213 WC_EDITOR_OBJECTIVE_OPTIONS,
214 WC_MAPGEN,
215 WC_MANAGE_TRACK_DESIGN,
216 WC_INSTALL_TRACK,
217 };
218
219 static rct_windowclass window_themes_tab_6_classes[] = {
220 WC_CHEATS,
221 WC_TILE_INSPECTOR,
222 WC_VIEW_CLIPPING,
223 WC_THEMES,
224 WC_TITLE_EDITOR,
225 WC_OPTIONS,
226 WC_KEYBOARD_SHORTCUT_LIST,
227 WC_CHANGE_KEYBOARD_SHORTCUT,
228 WC_LOADSAVE,
229 WC_ABOUT,
230 WC_CHANGELOG,
231 WC_SERVER_LIST,
232 WC_MULTIPLAYER,
233 WC_PLAYER,
234 WC_CHAT,
235 WC_CONSOLE,
236 };
237
238 static rct_windowclass window_themes_tab_7_classes[] = {
239 WC_SAVE_PROMPT,
240 WC_DEMOLISH_RIDE_PROMPT,
241 WC_FIRE_PROMPT,
242 WC_TRACK_DELETE_PROMPT,
243 WC_LOADSAVE_OVERWRITE_PROMPT,
244 WC_NETWORK_STATUS,
245 };
246 // clang-format on
247
248 static rct_windowclass* window_themes_tab_classes[] = {
249 nullptr,
250 window_themes_tab_1_classes,
251 window_themes_tab_2_classes,
252 window_themes_tab_3_classes,
253 window_themes_tab_4_classes,
254 window_themes_tab_5_classes,
255 window_themes_tab_6_classes,
256 window_themes_tab_7_classes,
257 };
258
259 static uint8_t _selected_tab = 0;
260 static int16_t _colour_index_1 = -1;
261 static int8_t _colour_index_2 = -1;
262 static constexpr const uint8_t _row_height = 32;
263 static constexpr const uint8_t _button_offset_x = 220;
264 static constexpr const uint8_t _button_offset_y = 3;
265 static constexpr const uint8_t _check_offset_y = 3 + 12 + 2;
266
window_themes_init_vars()267 static void window_themes_init_vars()
268 {
269 _selected_tab = WINDOW_THEMES_TAB_SETTINGS;
270 }
271
get_window_class_tab_index(int32_t index)272 static rct_windowclass get_window_class_tab_index(int32_t index)
273 {
274 rct_windowclass* classes = window_themes_tab_classes[_selected_tab];
275 return classes[index];
276 }
277
get_colour_scheme_tab_count()278 static int32_t get_colour_scheme_tab_count()
279 {
280 switch (_selected_tab)
281 {
282 case 1:
283 return sizeof(window_themes_tab_1_classes);
284 case 2:
285 return sizeof(window_themes_tab_2_classes);
286 case 3:
287 return sizeof(window_themes_tab_3_classes);
288 case 4:
289 return sizeof(window_themes_tab_4_classes);
290 case 5:
291 return sizeof(window_themes_tab_5_classes);
292 case 6:
293 return sizeof(window_themes_tab_6_classes);
294 case 7:
295 return sizeof(window_themes_tab_7_classes);
296 }
297 return 0;
298 }
299
window_themes_draw_tab_images(rct_drawpixelinfo * dpi,rct_window * w)300 static void window_themes_draw_tab_images(rct_drawpixelinfo* dpi, rct_window* w)
301 {
302 for (int32_t i = 0; i < WINDOW_THEMES_TAB_COUNT; i++)
303 {
304 int32_t sprite_idx = window_themes_tab_sprites[i];
305 if (_selected_tab == i)
306 sprite_idx += w->frame_no / window_themes_tab_animation_divisor[_selected_tab];
307 gfx_draw_sprite(
308 dpi, sprite_idx,
309 w->windowPos
310 + ScreenCoordsXY{ w->widgets[WIDX_THEMES_SETTINGS_TAB + i].left, w->widgets[WIDX_THEMES_SETTINGS_TAB + i].top },
311 0);
312 }
313 }
314
window_themes_open()315 rct_window* window_themes_open()
316 {
317 rct_window* window;
318
319 // Check if window is already open
320 window = window_bring_to_front_by_class(WC_THEMES);
321 if (window != nullptr)
322 return window;
323
324 window = WindowCreateAutoPos(320, 107, &window_themes_events, WC_THEMES, WF_10 | WF_RESIZABLE);
325 window->widgets = window_themes_widgets;
326 window->enabled_widgets = (1ULL << WIDX_THEMES_CLOSE) | (1ULL << WIDX_THEMES_SETTINGS_TAB)
327 | (1ULL << WIDX_THEMES_MAIN_UI_TAB) | (1ULL << WIDX_THEMES_PARK_TAB) | (1ULL << WIDX_THEMES_TOOLS_TAB)
328 | (1ULL << WIDX_THEMES_RIDE_PEEPS_TAB) | (1ULL << WIDX_THEMES_EDITORS_TAB) | (1ULL << WIDX_THEMES_MISC_TAB)
329 | (1ULL << WIDX_THEMES_PROMPTS_TAB) | (1ULL << WIDX_THEMES_FEATURES_TAB) | (1ULL << WIDX_THEMES_COLOURBTN_MASK)
330 | (1ULL << WIDX_THEMES_PRESETS) | (1ULL << WIDX_THEMES_PRESETS_DROPDOWN) | (1ULL << WIDX_THEMES_DUPLICATE_BUTTON)
331 | (1ULL << WIDX_THEMES_DELETE_BUTTON) | (1ULL << WIDX_THEMES_RENAME_BUTTON) | (1ULL << WIDX_THEMES_RCT1_RIDE_LIGHTS)
332 | (1ULL << WIDX_THEMES_RCT1_PARK_LIGHTS) | (1ULL << WIDX_THEMES_RCT1_SCENARIO_FONT)
333 | (1ULL << WIDX_THEMES_RCT1_BOTTOM_TOOLBAR);
334
335 window_themes_init_vars();
336
337 WindowInitScrollWidgets(window);
338 window->list_information_type = 0;
339 _colour_index_1 = -1;
340 _colour_index_2 = -1;
341 window->min_width = 320;
342 window->min_height = 107;
343 window->max_width = 320;
344 window->max_height = 107;
345
346 return window;
347 }
348
window_themes_mouseup(rct_window * w,rct_widgetindex widgetIndex)349 static void window_themes_mouseup(rct_window* w, rct_widgetindex widgetIndex)
350 {
351 size_t activeAvailableThemeIndex;
352 const utf8* activeThemeName;
353
354 switch (widgetIndex)
355 {
356 case WIDX_THEMES_CLOSE:
357 window_close(w);
358 break;
359 case WIDX_THEMES_DUPLICATE_BUTTON:;
360 activeAvailableThemeIndex = ThemeManagerGetAvailableThemeIndex();
361 activeThemeName = ThemeManagerGetAvailableThemeName(activeAvailableThemeIndex);
362 window_text_input_open(
363 w, widgetIndex, STR_TITLE_EDITOR_ACTION_DUPLICATE, STR_THEMES_PROMPT_ENTER_THEME_NAME, {}, STR_STRING,
364 reinterpret_cast<uintptr_t>(activeThemeName), 64);
365 break;
366 case WIDX_THEMES_DELETE_BUTTON:
367 if (ThemeGetFlags() & UITHEME_FLAG_PREDEFINED)
368 {
369 context_show_error(STR_THEMES_ERR_CANT_CHANGE_THIS_THEME, STR_NONE, {});
370 }
371 else
372 {
373 ThemeDelete();
374 }
375 break;
376 case WIDX_THEMES_RENAME_BUTTON:
377 if (ThemeGetFlags() & UITHEME_FLAG_PREDEFINED)
378 {
379 context_show_error(STR_THEMES_ERR_CANT_CHANGE_THIS_THEME, STR_NONE, {});
380 }
381 else
382 {
383 activeAvailableThemeIndex = ThemeManagerGetAvailableThemeIndex();
384 activeThemeName = ThemeManagerGetAvailableThemeName(activeAvailableThemeIndex);
385 window_text_input_open(
386 w, widgetIndex, STR_TRACK_MANAGE_RENAME, STR_THEMES_PROMPT_ENTER_THEME_NAME, {}, STR_STRING,
387 reinterpret_cast<uintptr_t>(activeThemeName), 64);
388 }
389 break;
390 }
391 }
392
window_themes_resize(rct_window * w)393 static void window_themes_resize(rct_window* w)
394 {
395 if (_selected_tab == WINDOW_THEMES_TAB_SETTINGS)
396 {
397 w->min_width = 320;
398 w->min_height = 107;
399 w->max_width = 320;
400 w->max_height = 107;
401
402 if (w->width < w->min_width)
403 {
404 w->width = w->min_width;
405 gfx_invalidate_screen();
406 }
407 if (w->height < w->min_height)
408 {
409 w->height = w->min_height;
410 gfx_invalidate_screen();
411 }
412 if (w->width > w->max_width)
413 {
414 w->width = w->max_width;
415 gfx_invalidate_screen();
416 }
417 if (w->height > w->max_height)
418 {
419 w->height = w->max_height;
420 gfx_invalidate_screen();
421 }
422 }
423 else if (_selected_tab == WINDOW_THEMES_TAB_FEATURES)
424 {
425 w->min_width = 320;
426 w->min_height = 122;
427 w->max_width = 320;
428 w->max_height = 122;
429
430 if (w->width < w->min_width)
431 {
432 w->width = w->min_width;
433 gfx_invalidate_screen();
434 }
435 if (w->height < w->min_height)
436 {
437 w->height = w->min_height;
438 gfx_invalidate_screen();
439 }
440 if (w->width > w->max_width)
441 {
442 w->width = w->max_width;
443 gfx_invalidate_screen();
444 }
445 if (w->height > w->max_height)
446 {
447 w->height = w->max_height;
448 gfx_invalidate_screen();
449 }
450 }
451 else
452 {
453 w->min_width = 320;
454 w->min_height = 270;
455 w->max_width = 320;
456 w->max_height = 450;
457
458 if (w->width < w->min_width)
459 {
460 w->width = w->min_width;
461 w->Invalidate();
462 }
463 if (w->height < w->min_height)
464 {
465 w->height = w->min_height;
466 w->Invalidate();
467 }
468 if (w->width > w->max_width)
469 {
470 w->width = w->max_width;
471 w->Invalidate();
472 }
473 if (w->height > w->max_height)
474 {
475 w->height = w->max_height;
476 w->Invalidate();
477 }
478 }
479 }
480
window_themes_mousedown(rct_window * w,rct_widgetindex widgetIndex,rct_widget * widget)481 static void window_themes_mousedown(rct_window* w, rct_widgetindex widgetIndex, rct_widget* widget)
482 {
483 int16_t newSelectedTab;
484 int32_t num_items;
485
486 switch (widgetIndex)
487 {
488 case WIDX_THEMES_SETTINGS_TAB:
489 case WIDX_THEMES_MAIN_UI_TAB:
490 case WIDX_THEMES_PARK_TAB:
491 case WIDX_THEMES_TOOLS_TAB:
492 case WIDX_THEMES_RIDE_PEEPS_TAB:
493 case WIDX_THEMES_EDITORS_TAB:
494 case WIDX_THEMES_MISC_TAB:
495 case WIDX_THEMES_PROMPTS_TAB:
496 case WIDX_THEMES_FEATURES_TAB:
497 newSelectedTab = widgetIndex - WIDX_THEMES_SETTINGS_TAB;
498 if (_selected_tab == newSelectedTab)
499 break;
500 _selected_tab = static_cast<uint8_t>(newSelectedTab);
501 w->scrolls[0].v_top = 0;
502 w->frame_no = 0;
503 window_event_resize_call(w);
504 w->Invalidate();
505 break;
506 case WIDX_THEMES_PRESETS_DROPDOWN:
507 ThemeManagerLoadAvailableThemes();
508 num_items = static_cast<int32_t>(ThemeManagerGetNumAvailableThemes());
509
510 widget--;
511 for (int32_t i = 0; i < num_items; i++)
512 {
513 gDropdownItemsFormat[i] = STR_OPTIONS_DROPDOWN_ITEM;
514 gDropdownItemsArgs[i] = reinterpret_cast<uintptr_t>(ThemeManagerGetAvailableThemeName(i));
515 }
516
517 WindowDropdownShowTextCustomWidth(
518 { w->windowPos.x + widget->left, w->windowPos.y + widget->top }, widget->height() + 1, w->colours[1], 0,
519 Dropdown::Flag::StayOpen, num_items, widget->width() - 3);
520
521 Dropdown::SetChecked(static_cast<int32_t>(ThemeManagerGetAvailableThemeIndex()), true);
522 break;
523 case WIDX_THEMES_RCT1_RIDE_LIGHTS:
524 if (ThemeGetFlags() & UITHEME_FLAG_PREDEFINED)
525 {
526 context_show_error(STR_THEMES_ERR_CANT_CHANGE_THIS_THEME, STR_NONE, {});
527 }
528 else
529 {
530 ThemeSetFlags(ThemeGetFlags() ^ UITHEME_FLAG_USE_LIGHTS_RIDE);
531 ThemeSave();
532 window_invalidate_all();
533 }
534 break;
535 case WIDX_THEMES_RCT1_PARK_LIGHTS:
536 if (ThemeGetFlags() & UITHEME_FLAG_PREDEFINED)
537 {
538 context_show_error(STR_THEMES_ERR_CANT_CHANGE_THIS_THEME, STR_NONE, {});
539 }
540 else
541 {
542 ThemeSetFlags(ThemeGetFlags() ^ UITHEME_FLAG_USE_LIGHTS_PARK);
543 ThemeSave();
544 window_invalidate_all();
545 }
546 break;
547 case WIDX_THEMES_RCT1_SCENARIO_FONT:
548 if (ThemeGetFlags() & UITHEME_FLAG_PREDEFINED)
549 {
550 context_show_error(STR_THEMES_ERR_CANT_CHANGE_THIS_THEME, STR_NONE, {});
551 }
552 else
553 {
554 ThemeSetFlags(ThemeGetFlags() ^ UITHEME_FLAG_USE_ALTERNATIVE_SCENARIO_SELECT_FONT);
555 ThemeSave();
556 window_invalidate_all();
557 }
558 break;
559 case WIDX_THEMES_RCT1_BOTTOM_TOOLBAR:
560 if (ThemeGetFlags() & UITHEME_FLAG_PREDEFINED)
561 {
562 context_show_error(STR_THEMES_ERR_CANT_CHANGE_THIS_THEME, STR_NONE, {});
563 }
564 else
565 {
566 ThemeSetFlags(ThemeGetFlags() ^ UITHEME_FLAG_USE_FULL_BOTTOM_TOOLBAR);
567 ThemeSave();
568 window_invalidate_all();
569 }
570 }
571 }
572
window_themes_dropdown(rct_window * w,rct_widgetindex widgetIndex,int32_t dropdownIndex)573 static void window_themes_dropdown(rct_window* w, rct_widgetindex widgetIndex, int32_t dropdownIndex)
574 {
575 switch (widgetIndex)
576 {
577 case WIDX_THEMES_LIST:
578 if (dropdownIndex != -1)
579 {
580 rct_windowclass wc = get_window_class_tab_index(_colour_index_1);
581 uint8_t colour = ThemeGetColour(wc, _colour_index_2);
582 colour = (colour & COLOUR_FLAG_TRANSLUCENT) | dropdownIndex;
583 ThemeSetColour(wc, _colour_index_2, colour);
584 ColourSchemeUpdateAll();
585 window_invalidate_all();
586 _colour_index_1 = -1;
587 _colour_index_2 = -1;
588 }
589 break;
590 case WIDX_THEMES_PRESETS_DROPDOWN:
591 if (dropdownIndex != -1)
592 {
593 ThemeManagerSetActiveAvailableTheme(dropdownIndex);
594 }
595 break;
596 }
597 }
598
window_themes_update(rct_window * w)599 void window_themes_update(rct_window* w)
600 {
601 w->frame_no++;
602 if (w->frame_no >= window_themes_tab_animation_loops[_selected_tab])
603 w->frame_no = 0;
604
605 widget_invalidate(w, WIDX_THEMES_SETTINGS_TAB + _selected_tab);
606 }
607
window_themes_scrollgetsize(rct_window * w,int32_t scrollIndex,int32_t * width,int32_t * height)608 void window_themes_scrollgetsize(rct_window* w, int32_t scrollIndex, int32_t* width, int32_t* height)
609 {
610 if (_selected_tab == WINDOW_THEMES_TAB_SETTINGS || _selected_tab == WINDOW_THEMES_TAB_FEATURES)
611 return;
612
613 int32_t scrollHeight = get_colour_scheme_tab_count() * _row_height;
614 int32_t i = scrollHeight - window_themes_widgets[WIDX_THEMES_LIST].bottom + window_themes_widgets[WIDX_THEMES_LIST].top
615 + 21;
616 if (i < 0)
617 i = 0;
618 if (i < w->scrolls[0].v_top)
619 {
620 w->scrolls[0].v_top = i;
621 w->Invalidate();
622 }
623
624 *width = 420;
625 *height = scrollHeight;
626 }
627
window_themes_scrollmousedown(rct_window * w,int32_t scrollIndex,const ScreenCoordsXY & screenCoords)628 void window_themes_scrollmousedown(rct_window* w, int32_t scrollIndex, const ScreenCoordsXY& screenCoords)
629 {
630 if (screenCoords.y / _row_height < get_colour_scheme_tab_count())
631 {
632 int32_t y2 = screenCoords.y % _row_height;
633 _colour_index_1 = screenCoords.y / _row_height;
634 _colour_index_2 = ((screenCoords.x - _button_offset_x) / 12);
635
636 rct_windowclass wc = get_window_class_tab_index(_colour_index_1);
637 int32_t numColours = ThemeDescGetNumColours(wc);
638 if (_colour_index_2 < numColours)
639 {
640 if (screenCoords.x >= _button_offset_x && screenCoords.x < _button_offset_x + 12 * 6 && y2 >= _button_offset_y
641 && y2 < _button_offset_y + 11)
642 {
643 if (ThemeGetFlags() & UITHEME_FLAG_PREDEFINED)
644 {
645 context_show_error(STR_THEMES_ERR_CANT_CHANGE_THIS_THEME, STR_THEMES_DESC_CANT_CHANGE_THIS_THEME, {});
646 }
647 else
648 {
649 window_themes_widgets[WIDX_THEMES_COLOURBTN_MASK].type = WindowWidgetType::ColourBtn;
650 window_themes_widgets[WIDX_THEMES_COLOURBTN_MASK].left = _button_offset_x + _colour_index_2 * 12
651 + window_themes_widgets[WIDX_THEMES_LIST].left;
652 window_themes_widgets[WIDX_THEMES_COLOURBTN_MASK].top = _colour_index_1 * _row_height + _button_offset_y
653 - w->scrolls[0].v_top + window_themes_widgets[WIDX_THEMES_LIST].top;
654 window_themes_widgets[WIDX_THEMES_COLOURBTN_MASK].right = window_themes_widgets[WIDX_THEMES_COLOURBTN_MASK]
655 .left
656 + 12;
657 window_themes_widgets[WIDX_THEMES_COLOURBTN_MASK].bottom = window_themes_widgets[WIDX_THEMES_COLOURBTN_MASK]
658 .top
659 + 12;
660
661 uint8_t colour = ThemeGetColour(wc, _colour_index_2);
662 WindowDropdownShowColour(w, &(window_themes_widgets[WIDX_THEMES_COLOURBTN_MASK]), w->colours[1], colour);
663 widget_invalidate(w, WIDX_THEMES_LIST);
664 }
665 }
666 else if (
667 screenCoords.x >= _button_offset_x && screenCoords.x < _button_offset_x + 12 * 6 - 1 && y2 >= _check_offset_y
668 && y2 < _check_offset_y + 11)
669 {
670 if (ThemeGetFlags() & UITHEME_FLAG_PREDEFINED)
671 {
672 context_show_error(STR_THEMES_ERR_CANT_CHANGE_THIS_THEME, STR_THEMES_DESC_CANT_CHANGE_THIS_THEME, {});
673 }
674 else
675 {
676 uint8_t colour = ThemeGetColour(wc, _colour_index_2);
677 if (colour & COLOUR_FLAG_TRANSLUCENT)
678 {
679 colour &= ~COLOUR_FLAG_TRANSLUCENT;
680 }
681 else
682 {
683 colour |= COLOUR_FLAG_TRANSLUCENT;
684 }
685 ThemeSetColour(wc, _colour_index_2, colour);
686 ColourSchemeUpdateAll();
687 window_invalidate_all();
688 }
689 }
690 }
691 }
692 }
693
window_themes_scrollmouseover(rct_window * w,int32_t scrollIndex,const ScreenCoordsXY & screenCoords)694 void window_themes_scrollmouseover(rct_window* w, int32_t scrollIndex, const ScreenCoordsXY& screenCoords)
695 {
696 }
697
window_themes_textinput(rct_window * w,rct_widgetindex widgetIndex,char * text)698 static void window_themes_textinput(rct_window* w, rct_widgetindex widgetIndex, char* text)
699 {
700 if (text == nullptr || text[0] == 0)
701 return;
702
703 switch (widgetIndex)
704 {
705 case WIDX_THEMES_DUPLICATE_BUTTON:
706 case WIDX_THEMES_RENAME_BUTTON:
707 if (filename_valid_characters(text))
708 {
709 if (ThemeGetIndexForName(text) == SIZE_MAX)
710 {
711 if (widgetIndex == WIDX_THEMES_DUPLICATE_BUTTON)
712 {
713 ThemeDuplicate(text);
714 }
715 else
716 {
717 ThemeRename(text);
718 }
719 w->Invalidate();
720 }
721 else
722 {
723 context_show_error(STR_THEMES_ERR_NAME_ALREADY_EXISTS, STR_NONE, {});
724 }
725 }
726 else
727 {
728 context_show_error(STR_ERROR_INVALID_CHARACTERS, STR_NONE, {});
729 }
730 break;
731 }
732 }
733
window_themes_invalidate(rct_window * w)734 void window_themes_invalidate(rct_window* w)
735 {
736 int32_t pressed_widgets = w->pressed_widgets
737 & ~((1LL << WIDX_THEMES_SETTINGS_TAB) | (1LL << WIDX_THEMES_MAIN_UI_TAB) | (1LL << WIDX_THEMES_PARK_TAB)
738 | (1LL << WIDX_THEMES_TOOLS_TAB) | (1LL << WIDX_THEMES_RIDE_PEEPS_TAB) | (1LL << WIDX_THEMES_EDITORS_TAB)
739 | (1LL << WIDX_THEMES_MISC_TAB) | (1LL << WIDX_THEMES_PROMPTS_TAB) | (1LL << WIDX_THEMES_FEATURES_TAB));
740 rct_widgetindex widgetIndex = _selected_tab + WIDX_THEMES_SETTINGS_TAB;
741
742 w->pressed_widgets = pressed_widgets | (1 << widgetIndex);
743
744 if (window_find_by_class(WC_DROPDOWN) == nullptr)
745 {
746 _colour_index_1 = -1;
747 _colour_index_2 = -1;
748 }
749
750 window_themes_widgets[WIDX_THEMES_BACKGROUND].right = w->width - 1;
751 window_themes_widgets[WIDX_THEMES_BACKGROUND].bottom = w->height - 1;
752 window_themes_widgets[WIDX_THEMES_TAB_CONTENT_PANEL].right = w->width - 1;
753 window_themes_widgets[WIDX_THEMES_TAB_CONTENT_PANEL].bottom = w->height - 1;
754 window_themes_widgets[WIDX_THEMES_TITLE].right = w->width - 2;
755 window_themes_widgets[WIDX_THEMES_CLOSE].left = w->width - 2 - 0x0B;
756 window_themes_widgets[WIDX_THEMES_CLOSE].right = w->width - 2 - 0x0B + 0x0A;
757 window_themes_widgets[WIDX_THEMES_LIST].right = w->width - 4;
758 window_themes_widgets[WIDX_THEMES_LIST].bottom = w->height - 0x0F;
759
760 if (_selected_tab == WINDOW_THEMES_TAB_SETTINGS)
761 {
762 window_themes_widgets[WIDX_THEMES_HEADER_WINDOW].type = WindowWidgetType::Empty;
763 window_themes_widgets[WIDX_THEMES_HEADER_PALETTE].type = WindowWidgetType::Empty;
764 window_themes_widgets[WIDX_THEMES_LIST].type = WindowWidgetType::Empty;
765 window_themes_widgets[WIDX_THEMES_RCT1_RIDE_LIGHTS].type = WindowWidgetType::Empty;
766 window_themes_widgets[WIDX_THEMES_RCT1_PARK_LIGHTS].type = WindowWidgetType::Empty;
767 window_themes_widgets[WIDX_THEMES_RCT1_SCENARIO_FONT].type = WindowWidgetType::Empty;
768 window_themes_widgets[WIDX_THEMES_RCT1_BOTTOM_TOOLBAR].type = WindowWidgetType::Empty;
769 window_themes_widgets[WIDX_THEMES_DUPLICATE_BUTTON].type = WindowWidgetType::Button;
770 window_themes_widgets[WIDX_THEMES_DELETE_BUTTON].type = WindowWidgetType::Button;
771 window_themes_widgets[WIDX_THEMES_RENAME_BUTTON].type = WindowWidgetType::Button;
772 window_themes_widgets[WIDX_THEMES_PRESETS].type = WindowWidgetType::DropdownMenu;
773 window_themes_widgets[WIDX_THEMES_PRESETS_DROPDOWN].type = WindowWidgetType::Button;
774 window_themes_widgets[WIDX_THEMES_COLOURBTN_MASK].type = WindowWidgetType::Empty;
775 }
776 else if (_selected_tab == WINDOW_THEMES_TAB_FEATURES)
777 {
778 window_themes_widgets[WIDX_THEMES_HEADER_WINDOW].type = WindowWidgetType::Empty;
779 window_themes_widgets[WIDX_THEMES_HEADER_PALETTE].type = WindowWidgetType::Empty;
780 window_themes_widgets[WIDX_THEMES_LIST].type = WindowWidgetType::Empty;
781 window_themes_widgets[WIDX_THEMES_RCT1_RIDE_LIGHTS].type = WindowWidgetType::Checkbox;
782 window_themes_widgets[WIDX_THEMES_RCT1_PARK_LIGHTS].type = WindowWidgetType::Checkbox;
783 window_themes_widgets[WIDX_THEMES_RCT1_SCENARIO_FONT].type = WindowWidgetType::Checkbox;
784 window_themes_widgets[WIDX_THEMES_RCT1_BOTTOM_TOOLBAR].type = WindowWidgetType::Checkbox;
785 window_themes_widgets[WIDX_THEMES_DUPLICATE_BUTTON].type = WindowWidgetType::Empty;
786 window_themes_widgets[WIDX_THEMES_DELETE_BUTTON].type = WindowWidgetType::Empty;
787 window_themes_widgets[WIDX_THEMES_RENAME_BUTTON].type = WindowWidgetType::Empty;
788 window_themes_widgets[WIDX_THEMES_PRESETS].type = WindowWidgetType::Empty;
789 window_themes_widgets[WIDX_THEMES_PRESETS_DROPDOWN].type = WindowWidgetType::Empty;
790 window_themes_widgets[WIDX_THEMES_COLOURBTN_MASK].type = WindowWidgetType::Empty;
791
792 WidgetSetCheckboxValue(w, WIDX_THEMES_RCT1_RIDE_LIGHTS, ThemeGetFlags() & UITHEME_FLAG_USE_LIGHTS_RIDE);
793 WidgetSetCheckboxValue(w, WIDX_THEMES_RCT1_PARK_LIGHTS, ThemeGetFlags() & UITHEME_FLAG_USE_LIGHTS_PARK);
794 WidgetSetCheckboxValue(
795 w, WIDX_THEMES_RCT1_SCENARIO_FONT, ThemeGetFlags() & UITHEME_FLAG_USE_ALTERNATIVE_SCENARIO_SELECT_FONT);
796 WidgetSetCheckboxValue(w, WIDX_THEMES_RCT1_BOTTOM_TOOLBAR, ThemeGetFlags() & UITHEME_FLAG_USE_FULL_BOTTOM_TOOLBAR);
797 }
798 else
799 {
800 window_themes_widgets[WIDX_THEMES_HEADER_WINDOW].type = WindowWidgetType::TableHeader;
801 window_themes_widgets[WIDX_THEMES_HEADER_PALETTE].type = WindowWidgetType::TableHeader;
802 window_themes_widgets[WIDX_THEMES_LIST].type = WindowWidgetType::Scroll;
803 window_themes_widgets[WIDX_THEMES_RCT1_RIDE_LIGHTS].type = WindowWidgetType::Empty;
804 window_themes_widgets[WIDX_THEMES_RCT1_PARK_LIGHTS].type = WindowWidgetType::Empty;
805 window_themes_widgets[WIDX_THEMES_RCT1_SCENARIO_FONT].type = WindowWidgetType::Empty;
806 window_themes_widgets[WIDX_THEMES_RCT1_BOTTOM_TOOLBAR].type = WindowWidgetType::Empty;
807 window_themes_widgets[WIDX_THEMES_DUPLICATE_BUTTON].type = WindowWidgetType::Empty;
808 window_themes_widgets[WIDX_THEMES_DELETE_BUTTON].type = WindowWidgetType::Empty;
809 window_themes_widgets[WIDX_THEMES_RENAME_BUTTON].type = WindowWidgetType::Empty;
810 window_themes_widgets[WIDX_THEMES_PRESETS].type = WindowWidgetType::Empty;
811 window_themes_widgets[WIDX_THEMES_PRESETS_DROPDOWN].type = WindowWidgetType::Empty;
812 window_themes_widgets[WIDX_THEMES_COLOURBTN_MASK].type = WindowWidgetType::Empty;
813 }
814 }
815
window_themes_paint(rct_window * w,rct_drawpixelinfo * dpi)816 void window_themes_paint(rct_window* w, rct_drawpixelinfo* dpi)
817 {
818 // Widgets
819 WindowDrawWidgets(w, dpi);
820 window_themes_draw_tab_images(dpi, w);
821
822 if (_selected_tab == WINDOW_THEMES_TAB_SETTINGS)
823 {
824 DrawTextBasic(
825 dpi, w->windowPos + ScreenCoordsXY{ 10, window_themes_widgets[WIDX_THEMES_PRESETS].top + 1 },
826 STR_THEMES_LABEL_CURRENT_THEME, {}, { w->colours[1] });
827
828 size_t activeAvailableThemeIndex = ThemeManagerGetAvailableThemeIndex();
829 const utf8* activeThemeName = ThemeManagerGetAvailableThemeName(activeAvailableThemeIndex);
830 auto ft = Formatter();
831 ft.Add<const utf8*>(activeThemeName);
832
833 auto screenPos = w->windowPos
834 + ScreenCoordsXY{ window_themes_widgets[WIDX_THEMES_PRESETS].left + 1,
835 window_themes_widgets[WIDX_THEMES_PRESETS].top };
836 auto width = w->windowPos.x + window_themes_widgets[WIDX_THEMES_PRESETS_DROPDOWN].left
837 - window_themes_widgets[WIDX_THEMES_PRESETS].left - 4;
838
839 DrawTextEllipsised(dpi, screenPos, width, STR_STRING, ft, { w->colours[1] });
840 }
841 }
842
843 /**
844 *
845 * rct2: 0x006BD785
846 */
window_themes_scrollpaint(rct_window * w,rct_drawpixelinfo * dpi,int32_t scrollIndex)847 void window_themes_scrollpaint(rct_window* w, rct_drawpixelinfo* dpi, int32_t scrollIndex)
848 {
849 ScreenCoordsXY screenCoords;
850
851 if (_selected_tab == WINDOW_THEMES_TAB_SETTINGS || _selected_tab == WINDOW_THEMES_TAB_FEATURES)
852 return;
853
854 if ((w->colours[1] & 0x80) == 0)
855 // gfx_fill_rect(dpi, dpi->x, dpi->y, dpi->x + dpi->width - 1, dpi->y + dpi->height - 1,
856 // ColourMapA[w->colours[1]].mid_light);
857 gfx_clear(dpi, ColourMapA[w->colours[1]].mid_light);
858 screenCoords.y = 0;
859 for (int32_t i = 0; i < get_colour_scheme_tab_count(); i++)
860 {
861 if (screenCoords.y > dpi->y + dpi->height)
862 {
863 break;
864 }
865 if (screenCoords.y + _row_height >= dpi->y)
866 {
867 if (i + 1 < get_colour_scheme_tab_count())
868 {
869 int32_t colour = w->colours[1];
870
871 auto leftTop = ScreenCoordsXY{ 0, screenCoords.y + _row_height - 2 };
872 auto rightBottom = ScreenCoordsXY{ window_themes_widgets[WIDX_THEMES_LIST].right,
873 screenCoords.y + _row_height - 2 };
874 auto yPixelOffset = ScreenCoordsXY{ 0, 1 };
875
876 if (colour & COLOUR_FLAG_TRANSLUCENT)
877 {
878 translucent_window_palette windowPalette = TranslucentWindowPalettes[BASE_COLOUR(colour)];
879
880 gfx_filter_rect(dpi, { leftTop, rightBottom }, windowPalette.highlight);
881 gfx_filter_rect(dpi, { leftTop + yPixelOffset, rightBottom + yPixelOffset }, windowPalette.shadow);
882 }
883 else
884 {
885 colour = ColourMapA[w->colours[1]].mid_dark;
886 gfx_fill_rect(dpi, { leftTop, rightBottom }, colour);
887
888 colour = ColourMapA[w->colours[1]].lightest;
889 gfx_fill_rect(dpi, { leftTop + yPixelOffset, rightBottom + yPixelOffset }, colour);
890 }
891 }
892
893 rct_windowclass wc = get_window_class_tab_index(i);
894 int32_t numColours = ThemeDescGetNumColours(wc);
895 for (uint8_t j = 0; j < numColours; j++)
896 {
897 DrawTextBasic(dpi, { 2, screenCoords.y + 4 }, ThemeDescGetName(wc), {}, { w->colours[1] });
898
899 uint8_t colour = ThemeGetColour(wc, j);
900 uint32_t image = SPRITE_ID_PALETTE_COLOUR_1(colour & ~COLOUR_FLAG_TRANSLUCENT) | SPR_PALETTE_BTN;
901 if (i == _colour_index_1 && j == _colour_index_2)
902 {
903 image = SPRITE_ID_PALETTE_COLOUR_1(colour & ~COLOUR_FLAG_TRANSLUCENT) | SPR_PALETTE_BTN_PRESSED;
904 }
905 gfx_draw_sprite(dpi, image, { _button_offset_x + 12 * j, screenCoords.y + _button_offset_y }, 0);
906
907 ScreenCoordsXY topLeft{ _button_offset_x + 12 * j, screenCoords.y + _check_offset_y };
908 ScreenCoordsXY bottomRight{ _button_offset_x + 12 * j + 9, screenCoords.y + _check_offset_y + 10 };
909 gfx_fill_rect_inset(dpi, { topLeft, bottomRight }, w->colours[1], INSET_RECT_F_E0);
910 if (colour & COLOUR_FLAG_TRANSLUCENT)
911 {
912 gfx_draw_string(
913 dpi, topLeft, static_cast<const char*>(CheckBoxMarkString),
914 { static_cast<colour_t>(w->colours[1] & 0x7F), FontSpriteBase::MEDIUM_DARK });
915 }
916 }
917 }
918
919 screenCoords.y += _row_height;
920 }
921 }
922