1 #include "overlay_menu.h"
2
3 #include "city/view.h"
4 #include "core/time.h"
5 #include "game/state.h"
6 #include "graphics/generic_button.h"
7 #include "graphics/image.h"
8 #include "graphics/lang_text.h"
9 #include "graphics/panel.h"
10 #include "graphics/text.h"
11 #include "graphics/window.h"
12 #include "input/input.h"
13 #include "translation/translation.h"
14 #include "window/city.h"
15
16 #define MENU_X_OFFSET 170
17 #define SUBMENU_X_OFFSET 348
18 #define MENU_Y_OFFSET 72
19 #define MENU_ITEM_HEIGHT 24
20 #define MENU_CLICK_MARGIN 20
21
22 #define MAX_BUTTONS 8
23
24 static void button_menu_item(int index, int param2);
25 static void button_submenu_item(int index, int param2);
26
27 #define OVERLAY_BUTTONS 10
28
29 static generic_button menu_buttons[] = {
30 {0, 0, 160, 24, button_menu_item, button_none, 0, 0},
31 {0, 24, 160, 24, button_menu_item, button_none, 1, 0},
32 {0, 48, 160, 24, button_menu_item, button_none, 2, 0},
33 {0, 72, 160, 24, button_menu_item, button_none, 3, 0},
34 {0, 96, 160, 24, button_menu_item, button_none, 4, 0},
35 {0, 120, 160, 24, button_menu_item, button_none, 5, 0},
36 {0, 144, 160, 24, button_menu_item, button_none, 6, 0},
37 {0, 168, 160, 24, button_menu_item, button_none, 7, 0},
38 {0, 192, 160, 24, button_menu_item, button_none, 8, 0},
39 {0, 216, 160, 24, button_menu_item, button_none, 9, 0},
40 {0, 216, 160, 24, button_menu_item, button_none, 10, 0},
41 };
42 static generic_button submenu_buttons[] = {
43 {0, 0, 160, 24, button_submenu_item, button_none, 0, 0},
44 {0, 24, 160, 24, button_submenu_item, button_none, 1, 0},
45 {0, 48, 160, 24, button_submenu_item, button_none, 2, 0},
46 {0, 72, 160, 24, button_submenu_item, button_none, 3, 0},
47 {0, 96, 160, 24, button_submenu_item, button_none, 4, 0},
48 {0, 120, 160, 24, button_submenu_item, button_none, 5, 0},
49 {0, 144, 160, 24, button_submenu_item, button_none, 6, 0},
50 {0, 168, 160, 24, button_submenu_item, button_none, 7, 0},
51 {0, 192, 160, 24, button_submenu_item, button_none, 8, 0},
52 {0, 216, 160, 24, button_submenu_item, button_none, 9, 0},
53 };
54
55 static const int MENU_ID_TO_OVERLAY[OVERLAY_BUTTONS] = { OVERLAY_NONE, OVERLAY_WATER, 1, 3, 5, 6, 7, OVERLAY_RELIGION, OVERLAY_ROADS, OVERLAY_LEVY };
56 static const int MENU_ID_TO_SUBMENU_ID[OVERLAY_BUTTONS] = { 0, 0, 1, 2, 3, 4, 5, 0, 0 };
57 static const int ADDITIONAL_OVERLAY_TR[] = { TR_OVERLAY_ROADS, TR_OVERLAY_LEVY, TR_OVERLAY_TAVERN, TR_OVERLAY_ARENA_COL, TR_OVERLAY_SENTIMENT, TR_OVERLAY_MOTHBALL, TR_OVERLAY_ENEMY, TR_OVERLAY_WAREHOUSES };
58
59 static const int SUBMENU_ID_TO_OVERLAY[6][OVERLAY_BUTTONS] = {
60 {0},
61 {OVERLAY_FIRE, OVERLAY_DAMAGE, OVERLAY_CRIME, OVERLAY_NATIVE, OVERLAY_PROBLEMS, OVERLAY_ENEMY, 0},
62 {OVERLAY_ENTERTAINMENT, OVERLAY_TAVERN, OVERLAY_THEATER, OVERLAY_AMPHITHEATER, OVERLAY_ARENA, OVERLAY_COLOSSEUM, OVERLAY_HIPPODROME, 0},
63 {OVERLAY_EDUCATION, OVERLAY_SCHOOL, OVERLAY_LIBRARY, OVERLAY_ACADEMY, 0},
64 {OVERLAY_BARBER, OVERLAY_BATHHOUSE, OVERLAY_CLINIC, OVERLAY_HOSPITAL, 0},
65 {OVERLAY_TAX_INCOME, OVERLAY_FOOD_STOCKS, OVERLAY_DESIRABILITY, OVERLAY_SENTIMENT, OVERLAY_MOTHBALL, OVERLAY_WAREHOUSE, 0},
66 };
67
68 static struct {
69 int selected_menu;
70 int selected_submenu;
71 int num_submenu_items;
72 time_millis submenu_focus_time;
73
74 int menu_focus_button_id;
75 int submenu_focus_button_id;
76
77 int keep_submenu_open;
78 } data;
79
init(void)80 static void init(void)
81 {
82 data.selected_submenu = 0;
83 data.num_submenu_items = 0;
84 }
85
draw_background(void)86 static void draw_background(void)
87 {
88 window_city_draw_panels();
89 }
90
get_sidebar_x_offset(void)91 static int get_sidebar_x_offset(void)
92 {
93 int view_x, view_y, view_width, view_height;
94 city_view_get_unscaled_viewport(&view_x, &view_y, &view_width, &view_height);
95 return view_x + view_width;
96 }
97
draw_foreground(void)98 static void draw_foreground(void)
99 {
100 window_city_draw();
101 int x_offset = get_sidebar_x_offset();
102 for (int i = 0; i < OVERLAY_BUTTONS; i++) {
103 label_draw(x_offset - 170, 74 + 24 * i, 10, data.menu_focus_button_id == i + 1 ? 1 : 2);
104 int overlay = MENU_ID_TO_OVERLAY[i];
105 int translation = get_overlay_translation(overlay);
106 if (translation) {
107 text_draw_centered(translation_for(translation), x_offset - 170, 77 + 24 * i, 160, FONT_NORMAL_GREEN, 0);
108 } else {
109 lang_text_draw_centered(14, MENU_ID_TO_OVERLAY[i], x_offset - 170, 77 + 24 * i, 160, FONT_NORMAL_GREEN);
110 }
111 }
112 if (data.selected_submenu > 0) {
113 image_draw(image_group(GROUP_BULLET), x_offset - 185, 80 + 24 * data.selected_menu);
114 for (int i = 0; i < data.num_submenu_items; i++) {
115 int overlay = SUBMENU_ID_TO_OVERLAY[data.selected_submenu][i];
116 int translation = get_overlay_translation(overlay);
117
118 label_draw(x_offset - 348, 74 + 24 * (i + data.selected_menu),
119 10, data.submenu_focus_button_id == i + 1 ? 1 : 2);
120
121 if (translation) {
122 text_draw_centered(translation_for(translation), x_offset - 348, 77 + 24 * (i + data.selected_menu), 160, FONT_NORMAL_GREEN, 0);
123 } else {
124 lang_text_draw_centered(14, overlay, x_offset - 348, 77 + 24 * (i + data.selected_menu), 160, FONT_NORMAL_GREEN);
125 }
126 }
127 }
128 }
129
count_submenu_items(int submenu_id)130 static int count_submenu_items(int submenu_id)
131 {
132 int total = 0;
133 for (int i = 0; i < OVERLAY_BUTTONS && SUBMENU_ID_TO_OVERLAY[submenu_id][i] > 0; i++) {
134 total++;
135 }
136 return total;
137 }
138
open_submenu(int index,int keep_open)139 static void open_submenu(int index, int keep_open)
140 {
141 data.keep_submenu_open = keep_open;
142 data.selected_menu = index;
143 data.selected_submenu = MENU_ID_TO_SUBMENU_ID[index];
144 data.num_submenu_items = count_submenu_items(data.selected_submenu);
145 window_invalidate();
146 }
147
close_submenu(void)148 static void close_submenu(void)
149 {
150 data.keep_submenu_open = 0;
151 data.selected_menu = 0;
152 data.selected_submenu = 0;
153 data.num_submenu_items = 0;
154 window_invalidate();
155 }
156
handle_submenu_focus(void)157 static void handle_submenu_focus(void)
158 {
159 if (data.menu_focus_button_id || data.submenu_focus_button_id) {
160 data.submenu_focus_time = time_get_millis();
161 if (data.menu_focus_button_id) {
162 open_submenu(data.menu_focus_button_id - 1, 0);
163 }
164 } else if (time_get_millis() - data.submenu_focus_time > 500) {
165 close_submenu();
166 }
167 }
168
click_outside_menu(const mouse * m,int x_offset)169 static int click_outside_menu(const mouse *m, int x_offset)
170 {
171 return m->left.went_up &&
172 (m->x < x_offset - MENU_CLICK_MARGIN - (data.selected_submenu ? SUBMENU_X_OFFSET : MENU_X_OFFSET) ||
173 m->x > x_offset + MENU_CLICK_MARGIN ||
174 m->y < MENU_Y_OFFSET - MENU_CLICK_MARGIN ||
175 m->y > MENU_Y_OFFSET + MENU_CLICK_MARGIN + MENU_ITEM_HEIGHT * MAX_BUTTONS);
176 }
177
handle_input(const mouse * m,const hotkeys * h)178 static void handle_input(const mouse *m, const hotkeys *h)
179 {
180 int x_offset = get_sidebar_x_offset();
181 int handled = 0;
182 handled |= generic_buttons_handle_mouse(m, x_offset - MENU_X_OFFSET, MENU_Y_OFFSET,
183 menu_buttons, OVERLAY_BUTTONS, &data.menu_focus_button_id);
184
185 if (!data.keep_submenu_open) {
186 handle_submenu_focus();
187 }
188 if (data.selected_submenu) {
189 handled |= generic_buttons_handle_mouse(
190 m, x_offset - SUBMENU_X_OFFSET, MENU_Y_OFFSET + MENU_ITEM_HEIGHT * data.selected_menu,
191 submenu_buttons, data.num_submenu_items, &data.submenu_focus_button_id);
192 }
193 if (!handled && input_go_back_requested(m, h)) {
194 if (data.keep_submenu_open) {
195 close_submenu();
196 } else {
197 window_city_show();
198 }
199 return;
200 }
201 if (!handled && click_outside_menu(m, x_offset)) {
202 close_submenu();
203 window_city_show();
204 }
205 }
206
button_menu_item(int index,int param2)207 static void button_menu_item(int index, int param2)
208 {
209 if (MENU_ID_TO_SUBMENU_ID[index] == 0) {
210 game_state_set_overlay(MENU_ID_TO_OVERLAY[index]);
211 close_submenu();
212 window_city_show();
213 } else {
214 if (data.keep_submenu_open && data.selected_submenu == MENU_ID_TO_SUBMENU_ID[index]) {
215 close_submenu();
216 } else {
217 open_submenu(index, 1);
218 }
219 }
220 }
221
button_submenu_item(int index,int param2)222 static void button_submenu_item(int index, int param2)
223 {
224 int overlay = SUBMENU_ID_TO_OVERLAY[data.selected_submenu][index];
225 if (overlay) {
226 game_state_set_overlay(overlay);
227 }
228 close_submenu();
229 window_city_show();
230 }
231
window_overlay_menu_show(void)232 void window_overlay_menu_show(void)
233 {
234 window_type window = {
235 WINDOW_OVERLAY_MENU,
236 draw_background,
237 draw_foreground,
238 handle_input
239 };
240 init();
241 window_show(&window);
242 }
243
get_overlay_translation(int overlay)244 int get_overlay_translation(int overlay)
245 {
246 if (overlay >= OVERLAY_ROADS) {
247 return ADDITIONAL_OVERLAY_TR[overlay - OVERLAY_ROADS];
248 } else {
249 return 0;
250 }
251 }
252