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