1 #include "option_popup.h"
2 
3 #include "assets/assets.h"
4 #include "core/image_group.h"
5 #include "graphics/generic_button.h"
6 #include "graphics/graphics.h"
7 #include "graphics/image.h"
8 #include "graphics/lang_text.h"
9 #include "graphics/panel.h"
10 #include "graphics/screen.h"
11 #include "graphics/scrollbar.h"
12 #include "graphics/text.h"
13 #include "graphics/window.h"
14 #include "input/input.h"
15 #include "translation/translation.h"
16 
17 #define CANCEL_BUTTON 0
18 #define CONFIRM_BUTTON 1
19 #define MAX_OPTIONS 3
20 #define START_Y_OFFSET 88
21 
22 static const int Y_OFFSET_PER_OPTION[2] = { 112, 144 };
23 static int border_image_ids[2];
24 
25 static void on_scroll(void);
26 
27 static void button_select_option(int option, int param2);
28 
29 static generic_button buttons[] = {
30     {40, 0, 180, 20, button_select_option, button_none, CANCEL_BUTTON, 0},
31     {260, 0, 180, 20, button_select_option, button_none, CONFIRM_BUTTON, 0},
32     {20, 0, 0, 0, button_select_option, button_none, 2, 0},
33     {20, 0, 0, 0, button_select_option, button_none, 3, 0},
34     {20, 0, 0, 0, button_select_option, button_none, 4, 0}
35 };
36 
37 static scrollbar_type scrollbar = { 420, START_Y_OFFSET + 40, 0, on_scroll, 4 };
38 
39 static struct {
40     int title;
41     int subtitle;
42     option_menu_item *options;
43     int num_options;
44     int width_blocks;
45     int height_blocks;
46     void (*close_func)(int selection);
47     int focus_button_id;
48     int original_option;
49     int selected_option;
50     int price;
51     int visible_options;
52     int scroll_position;
53     int height;
54     option_menu_row_size row_size;
55 } data;
56 
init(int title,int subtitle,option_menu_item * options,int num_options,void (* close_func)(int selection),int original_option,int price,option_menu_row_size row_size)57 static int init(int title, int subtitle, option_menu_item *options, int num_options,
58     void (*close_func)(int selection), int original_option, int price, option_menu_row_size row_size)
59 {
60     if (window_is(WINDOW_POPUP_DIALOG)) {
61         // don't show popup over popup
62         return 0;
63     }
64     data.num_options = num_options <= MAX_OPTIONS ? num_options : MAX_OPTIONS;
65     data.close_func = close_func;
66     data.title = title;
67     data.subtitle = subtitle;
68     data.width_blocks = 30;
69     data.original_option = original_option;
70     data.selected_option = data.original_option;
71     data.price = price;
72     data.options = options;
73     data.height = 0;
74     data.row_size = row_size;
75 
76     for (int i = 0; i < MAX_OPTIONS; i++) {
77         buttons[i + 2].y = 40 + START_Y_OFFSET + i * Y_OFFSET_PER_OPTION[data.row_size];
78         buttons[i + 2].height = Y_OFFSET_PER_OPTION[data.row_size] - 16;
79     }
80 
81     if (!border_image_ids[0]) {
82         border_image_ids[0] = assets_get_image_id("UI_Elements", "Policy Selection Borders");
83         border_image_ids[1] = assets_get_image_id("UI_Elements", "Monument Mod Selection Borders");
84     }
85     return 1;
86 }
87 
calculate_visible_options(void)88 static void calculate_visible_options(void)
89 {
90     if (data.height == screen_height()) {
91         return;
92     }
93     data.height = screen_height();
94     data.visible_options = (data.height - 160) / Y_OFFSET_PER_OPTION[data.row_size];
95     if (data.visible_options > data.num_options) {
96         data.visible_options = data.num_options;
97     }
98     data.height_blocks = 10 + data.visible_options * (data.row_size == OPTION_MENU_SMALL_ROW ? 7 : 9);
99     buttons[0].y = buttons[1].y = START_Y_OFFSET + 42 + Y_OFFSET_PER_OPTION[data.row_size] * data.visible_options;
100 
101     buttons[2].width = buttons[3].width = buttons[4].width = data.num_options == data.visible_options ? 430 : 400;
102 
103     scrollbar.height = Y_OFFSET_PER_OPTION[data.row_size] * data.visible_options;
104     scrollbar_init(&scrollbar, 0, data.num_options - data.visible_options);
105     if (data.selected_option > data.visible_options) {
106         scrollbar.scroll_position = data.selected_option - data.visible_options;
107     }
108 }
109 
draw_apply_button(int x,int y,int box_width)110 static void draw_apply_button(int x, int y, int box_width)
111 {
112     font_t font = data.selected_option != data.original_option ? FONT_NORMAL_BLACK : FONT_NORMAL_PLAIN;
113     color_t color = data.selected_option != data.original_option ? 0 : COLOR_FONT_LIGHT_GRAY;
114     if (!data.price) {
115         text_draw_centered(translation_for(TR_OPTION_MENU_APPLY), x, y, box_width, font, color);
116     } else {
117         text_draw_with_money(translation_for(TR_OPTION_MENU_APPLY), data.price, " (", ")",
118             x, y, box_width, font, color);
119     }
120 }
121 
draw_background(void)122 static void draw_background(void)
123 {
124     window_draw_underlying_window();
125 
126     calculate_visible_options();
127     graphics_in_dialog_with_size(16 * data.width_blocks, 16 * data.height_blocks);
128     outer_panel_draw(0, 0, data.width_blocks, data.height_blocks);
129 
130     text_draw_centered(translation_for(data.title), 0, 20, 480, FONT_LARGE_BLACK, 0);
131     text_draw_multiline(translation_for(data.subtitle), 20, 60, 440, FONT_NORMAL_BLACK, 0);
132     if (data.price) {
133         text_draw_with_money(translation_for(TR_OPTION_MENU_COST), data.price, " ", ".",
134             20, 110, 0, FONT_NORMAL_BLACK, 0);
135     }
136 
137     int y_offset = START_Y_OFFSET;
138 
139     for (int i = 0; i < data.visible_options; i++) {
140         int text_width = data.num_options == data.visible_options ? 448 : 400;
141         int text_x = 20;
142 
143         if (data.options[i + scrollbar.scroll_position].image_id) {
144             image_draw(data.options[i + scrollbar.scroll_position].image_id, text_x, y_offset + 42);
145             int offset = data.row_size == OPTION_MENU_SMALL_ROW ? 128 : 160;
146             text_x += offset;
147             text_width -= offset;
148         }
149         if (data.selected_option == i + scrollbar.scroll_position + 1) {
150             inner_panel_draw(text_x - 6, y_offset + 44,
151                 text_width / 16,
152                 Y_OFFSET_PER_OPTION[data.row_size] / 16 - 1);
153         }
154         text_draw_multiline(translation_for(data.options[i + scrollbar.scroll_position].header),
155             text_x, y_offset + 49, text_width - 4,
156             data.selected_option == i + scrollbar.scroll_position + 1 ? FONT_NORMAL_WHITE : FONT_NORMAL_BLACK, 0);
157         text_draw_multiline(translation_for(data.options[i + scrollbar.scroll_position].desc),
158             text_x, y_offset + 69, text_width - 4,
159             data.selected_option == i + scrollbar.scroll_position + 1 ? FONT_NORMAL_WHITE : FONT_NORMAL_BLACK, 0);
160 
161 
162         y_offset += Y_OFFSET_PER_OPTION[data.row_size];
163     }
164 
165     lang_text_draw_centered(13, 4, 40, buttons[0].y + 4,
166         180, FONT_NORMAL_BLACK);
167     draw_apply_button(260, buttons[1].y + 4, 180);
168 
169     graphics_reset_dialog();
170 }
171 
draw_option_image_border(int x,int y,int focused)172 static void draw_option_image_border(int x, int y, int focused)
173 {
174     if (data.row_size == OPTION_MENU_SMALL_ROW) {
175         image_draw(border_image_ids[0] + focused, x, y);
176         image_draw(border_image_ids[0] + 2 + focused, x + 105, y + 5);
177         image_draw(border_image_ids[0] + 4 + focused, x, y + 90);
178         image_draw(border_image_ids[0] + 6 + focused, x, y + 5);
179     } else {
180         image_draw(border_image_ids[1] + focused, x, y);
181         image_draw(border_image_ids[1] + 2 + focused, x + 146, y + 5);
182         image_draw(border_image_ids[1] + 4 + focused, x, y + 126);
183         image_draw(border_image_ids[1] + 6 + focused, x, y + 5);
184     }
185 }
186 
draw_foreground(void)187 static void draw_foreground(void)
188 {
189     graphics_in_dialog_with_size(16 * data.width_blocks, 16 * data.height_blocks);
190     for (int i = 0; i < data.visible_options; i++) {
191         if (data.options[i + scrollbar.scroll_position].image_id) {
192             draw_option_image_border(20, buttons[i + 2].y + 2, data.focus_button_id == i + 3);
193         }
194     }
195 
196     button_border_draw(40, buttons[0].y, 180, 20, data.focus_button_id == 1);
197 
198     button_border_draw(260, buttons[1].y, 180, 20,
199         data.focus_button_id == 2 && data.selected_option != data.original_option);
200 
201     if (data.num_options > data.visible_options) {
202         inner_panel_draw(scrollbar.x + 4, scrollbar.y + 32, 2, scrollbar.height / 16 - 4);
203         scrollbar_draw(&scrollbar);
204     }
205 
206     graphics_reset_dialog();
207 }
208 
handle_input(const mouse * m,const hotkeys * h)209 static void handle_input(const mouse *m, const hotkeys *h)
210 {
211     if (input_go_back_requested(m, h)) {
212         data.close_func(0);
213         window_go_back();
214     }
215     const mouse *m_dialog = mouse_in_dialog_with_size(m, data.width_blocks * 16, data.height_blocks * 16);
216     if (scrollbar_handle_mouse(&scrollbar, m_dialog)) {
217         return;
218     }
219     if (generic_buttons_handle_mouse(m_dialog, 0, 0, buttons, data.visible_options + 2, &data.focus_button_id)) {
220         return;
221     }
222 }
223 
on_scroll(void)224 static void on_scroll(void)
225 {
226     window_invalidate();
227 }
228 
button_select_option(int option,int param2)229 static void button_select_option(int option, int param2)
230 {
231     switch (option) {
232         case CANCEL_BUTTON:
233             data.close_func(0);
234             window_go_back();
235             break;
236         case CONFIRM_BUTTON:
237             if (data.selected_option != data.original_option) {
238                 data.close_func(data.selected_option);
239                 window_go_back();
240             }
241             break;
242         default:
243             data.selected_option = option + scrollbar.scroll_position - CONFIRM_BUTTON;
244             window_request_refresh();
245             break;
246     }
247 }
248 
window_option_popup_show(int title,int subtitle,option_menu_item * options,int num_options,void (* close_func)(int selection),int current_option,int price,option_menu_row_size row_size)249 void window_option_popup_show(int title, int subtitle, option_menu_item *options, int num_options,
250     void (*close_func)(int selection), int current_option, int price, option_menu_row_size row_size)
251 {
252     if (init(title, subtitle, options, num_options, close_func, current_option, price, row_size)) {
253         window_type window = {
254             WINDOW_POPUP_DIALOG,
255             draw_background,
256             draw_foreground,
257             handle_input
258         };
259         window_show(&window);
260     }
261 }
262