1 #include "help.h"
2
3 #include "gui/msgbox.h"
4 #include "gui/bevel.h"
5 #include "gui/bevdefs.h"
6 #include "gui/dialog.h"
7 #include "gfx/gfx.h"
8 #include "gui/view.h"
9 #include "gui/mouse.h"
10 #include "gui/toolutil.h"
11 #include "gui/slider.h"
12 #include "command.h"
13 #include "shortcutdefs.h"
14 #include <string.h>
15
16 #define SCROLLBAR 10
17 #define TOP_LEFT 0
18 #define TOP_RIGHT 0
19 #define MARGIN 8
20 #define SCREENMARGIN 32
21 #define TITLE 14
22 #define FIELD 14
23 #define CLOSE_BUTTON 12
24 #define ELEMWIDTH data.elemwidth
25 #define LIST_WIDTH data.list_width
26 #define BUTTONS 16
27
28 static struct
29 {
30 int mode;
31 int selected_line;
32 const char *title;
33 SliderParam scrollbar;
34 char **lines;
35 int n_lines;
36 int list_position;
37 int quit;
38 const Font *largefont, *smallfont;
39 GfxSurface *gfx;
40 int elemwidth, list_width;
41 } data;
42
43 extern const KeyShortcut shortcuts[];
44
45 static void help_list_view(GfxDomain *dest_surface, const SDL_Rect *area, const SDL_Event *event, void *param);
46 static void title_view(GfxDomain *dest_surface, const SDL_Rect *area, const SDL_Event *event, void *param);
47 static void window_view(GfxDomain *dest_surface, const SDL_Rect *area, const SDL_Event *event, void *param);
48 static void buttons_view(GfxDomain *dest_surface, const SDL_Rect *area, const SDL_Event *event, void *param);
49
50 static const View filebox_view[] =
51 {
52 {{ SCREENMARGIN, SCREENMARGIN, -SCREENMARGIN, -SCREENMARGIN }, window_view, &data, -1},
53 {{ MARGIN+SCREENMARGIN, SCREENMARGIN+MARGIN, -MARGIN-SCREENMARGIN, TITLE - 2 }, title_view, &data, -1},
54 {{ -SCROLLBAR-MARGIN-SCREENMARGIN, SCREENMARGIN+MARGIN + TITLE, SCROLLBAR, -MARGIN-SCREENMARGIN-BUTTONS }, slider, &data.scrollbar, -1},
55 {{ SCREENMARGIN+MARGIN, SCREENMARGIN+MARGIN + TITLE, -SCROLLBAR-MARGIN-1-SCREENMARGIN, -MARGIN-SCREENMARGIN-BUTTONS }, help_list_view, &data, -1},
56 {{ SCREENMARGIN+MARGIN, -SCREENMARGIN-MARGIN-BUTTONS+2, -MARGIN-SCREENMARGIN, BUTTONS-2 }, buttons_view, &data, -1},
57 {{0, 0, 0, 0}, NULL}
58 };
59
60
deinit_lines()61 static void deinit_lines()
62 {
63 for (int i = 0 ; i < data.n_lines ; ++i)
64 if (data.lines[i]) free(data.lines[i]);
65
66 free(data.lines);
67 data.lines = NULL;
68 data.n_lines = 0;
69 }
70
init_lines(void * section,void * unused1,void * unused2)71 static void init_lines(void * section, void * unused1, void * unused2)
72 {
73 deinit_lines();
74
75 data.mode = CASTPTR(int, section);
76
77 switch (data.mode)
78 {
79 case 0:
80 {
81 data.n_lines = 0;
82
83 const InstructionDesc *commands = list_all_commands();
84
85 for (const InstructionDesc *d = commands ; d->name ; ++d)
86 ++data.n_lines;
87
88 data.lines = realloc(data.lines, sizeof(*data.lines) * data.n_lines);
89
90 for (int i = 0 ; i < data.n_lines ; ++i)
91 {
92 int params = 0;
93 char paramstr[] = "xxxx";
94
95 while ((~0 << (params * 4 + 4) & commands[i].mask) == commands[i].mask)
96 ++params;
97
98 paramstr[params] = '\0';
99
100 char buffer[500];
101
102 snprintf(buffer, sizeof(buffer), "%0*X%s %s", 4-params, commands[i].opcode >> (params * 4), paramstr, commands[i].name);
103
104 if (strlen(buffer) > LIST_WIDTH / data.smallfont->w - 4)
105 {
106 strcpy(&buffer[LIST_WIDTH / data.smallfont->w - 4], "...");
107 }
108
109 data.lines[i] = strdup(buffer);
110 }
111 }
112 break;
113
114 case 1:
115 {
116 data.n_lines = 0;
117
118 for (const KeyShortcut *s = shortcuts ; s->action ; ++s)
119 if (s->description) ++data.n_lines;
120
121 data.lines = realloc(data.lines, sizeof(*data.lines) * data.n_lines);
122
123 for (int i = 0 ; i < data.n_lines ; ++i)
124 {
125 if (shortcuts[i].description)
126 {
127 char buffer[500];
128
129 snprintf(buffer, sizeof(buffer), "%-10s %s", get_shortcut_string(&shortcuts[i]), shortcuts[i].description);
130
131 if (strlen(buffer) > LIST_WIDTH / data.smallfont->w - 4)
132 {
133 strcpy(&buffer[LIST_WIDTH / data.smallfont->w - 4], "...");
134 }
135
136 data.lines[i] = strdup(buffer);
137 }
138 }
139 }
140 break;
141 }
142 }
143
144
buttons_view(GfxDomain * dest_surface,const SDL_Rect * area,const SDL_Event * event,void * param)145 static void buttons_view(GfxDomain *dest_surface, const SDL_Rect *area, const SDL_Event *event, void *param)
146 {
147 SDL_Rect button;
148
149 copy_rect(&button, area);
150
151 button.w = strlen("Commands") * data.smallfont->w + 12;
152
153 button_text_event(dest_surface, event, &button, data.gfx, data.smallfont, data.mode == 0 ? BEV_BUTTON_ACTIVE : BEV_BUTTON, BEV_BUTTON_ACTIVE, "Commands", init_lines, 0, 0, 0);
154 button.x += button.w + 1;
155
156 button.w = strlen("Shortcuts") * data.smallfont->w + 12;
157 button_text_event(dest_surface, event, &button, data.gfx, data.smallfont, data.mode == 1 ? BEV_BUTTON_ACTIVE : BEV_BUTTON, BEV_BUTTON_ACTIVE, "Shortcuts", init_lines, MAKEPTR(1), 0, 0);
158 button.x += button.w + 1;
159 }
160
161
window_view(GfxDomain * dest_surface,const SDL_Rect * area,const SDL_Event * event,void * param)162 void window_view(GfxDomain *dest_surface, const SDL_Rect *area, const SDL_Event *event, void *param)
163 {
164 bevel(dest_surface, area, data.gfx, BEV_MENU);
165 }
166
167
title_view(GfxDomain * dest_surface,const SDL_Rect * area,const SDL_Event * event,void * param)168 void title_view(GfxDomain *dest_surface, const SDL_Rect *area, const SDL_Event *event, void *param)
169 {
170 const char* title = data.title;
171 SDL_Rect titlearea, button;
172 copy_rect(&titlearea, area);
173 titlearea.w -= CLOSE_BUTTON - 4;
174 copy_rect(&button, area);
175 adjust_rect(&button, titlearea.h - CLOSE_BUTTON);
176 button.w = CLOSE_BUTTON;
177 button.x = area->w + area->x - CLOSE_BUTTON;
178 font_write(data.largefont, dest_surface, &titlearea, title);
179 if (button_event(dest_surface, event, &button, data.gfx, BEV_BUTTON, BEV_BUTTON_ACTIVE, DECAL_CLOSE, NULL, MAKEPTR(1), 0, 0) & 1)
180 data.quit = 1;
181 }
182
183
help_list_view(GfxDomain * dest_surface,const SDL_Rect * area,const SDL_Event * event,void * param)184 void help_list_view(GfxDomain *dest_surface, const SDL_Rect *area, const SDL_Event *event, void *param)
185 {
186 SDL_Rect content, pos;
187 copy_rect(&content, area);
188 adjust_rect(&content, 1);
189 copy_rect(&pos, &content);
190 pos.h = data.largefont->h;
191 bevel(dest_surface,area, data.gfx, BEV_FIELD);
192
193 gfx_domain_set_clip(dest_surface, &content);
194
195 for (int i = data.list_position ; i < data.n_lines && pos.y < content.h + content.y ; ++i)
196 {
197 if (data.selected_line == i)
198 {
199 bevel(dest_surface,&pos, data.gfx, BEV_SELECTED_ROW);
200 }
201
202 font_write(data.smallfont, dest_surface, &pos, data.lines[i]);
203
204 if (pos.y + pos.h <= content.h + content.y) slider_set_params(&data.scrollbar, 0, data.n_lines - 1, data.list_position, i, &data.list_position, 1, SLIDER_VERTICAL, data.gfx);
205
206 //check_event(event, &pos, pick_file_action, MAKEPTR(i), 0, 0);
207
208 update_rect(&content, &pos);
209 }
210
211 gfx_domain_set_clip(dest_surface, NULL);
212
213 check_mouse_wheel_event(event, area, &data.scrollbar);
214 }
215
216
helpbox(const char * title,GfxDomain * domain,GfxSurface * gfx,const Font * largefont,const Font * smallfont)217 int helpbox(const char *title, GfxDomain *domain, GfxSurface *gfx, const Font *largefont, const Font *smallfont)
218 {
219 set_repeat_timer(NULL);
220
221 memset(&data, 0, sizeof(data));
222 data.title = title;
223 data.largefont = largefont;
224 data.smallfont = smallfont;
225 data.gfx = gfx;
226 data.elemwidth = domain->screen_w - SCREENMARGIN * 2 - MARGIN * 2 - 16 - 2;
227 data.list_width = domain->screen_w - SCREENMARGIN * 2 - MARGIN * 2 - SCROLLBAR - 2;
228
229 init_lines(0, 0, 0);
230
231 slider_set_params(&data.scrollbar, 0, data.n_lines - 1, data.list_position, 0, &data.list_position, 1, SLIDER_VERTICAL, data.gfx);
232
233 /*for (int i = 0 ; i < data.n_files ; ++i)
234 {
235 if (strcmp(data.files[i].name, last_picked_file) == 0)
236 {
237 data.selected_file = i;
238
239 // We need to draw the view once so the slider gets visibility info
240
241
242 SDL_Event e = {0};
243
244 draw_view(gfx_domain_get_surface(domain), filebox_view, &e);
245 slider_move_position(&data.selected_file, &data.list_position, &data.scrollbar, 0);
246 break;
247 }
248 }*/
249
250 while (!data.quit)
251 {
252 SDL_Event e = { 0 };
253 int got_event = 0;
254 while (SDL_PollEvent(&e))
255 {
256 switch (e.type)
257 {
258 case SDL_QUIT:
259
260 set_repeat_timer(NULL);
261 SDL_PushEvent(&e);
262 deinit_lines();
263 return 0;
264
265 break;
266
267 case SDL_KEYDOWN:
268 {
269 switch (e.key.keysym.sym)
270 {
271 case SDLK_F1:
272 case SDLK_ESCAPE:
273
274 set_repeat_timer(NULL);
275 deinit_lines();
276 return 0;
277
278 break;
279
280 /*case SDLK_KP_ENTER:
281 case SDLK_RETURN:
282 if (data.selected_file != -1) data.picked_file = &data.files[data.selected_file];
283 else goto enter_pressed;
284 break;*/
285
286 case SDLK_DOWN:
287 slider_move_position(&data.selected_line, &data.list_position, &data.scrollbar, 1);
288 break;
289
290 case SDLK_UP:
291 slider_move_position(&data.selected_line, &data.list_position, &data.scrollbar, -1);
292 break;
293
294 case SDLK_PAGEUP:
295 case SDLK_PAGEDOWN:
296 {
297 int items = data.scrollbar.visible_last - data.scrollbar.visible_first;
298
299 if (e.key.keysym.sym == SDLK_PAGEUP)
300 items = -items;
301
302 slider_move_position(&data.selected_line, &data.list_position, &data.scrollbar, items);
303 }
304 break;
305
306 default: break;
307 }
308
309
310 }
311 break;
312
313 case SDL_USEREVENT:
314 e.type = SDL_MOUSEBUTTONDOWN;
315 break;
316
317 case SDL_MOUSEMOTION:
318 if (domain)
319 {
320 e.motion.xrel /= domain->scale;
321 e.motion.yrel /= domain->scale;
322 e.button.x /= domain->scale;
323 e.button.y /= domain->scale;
324 }
325 break;
326
327 case SDL_MOUSEBUTTONDOWN:
328 if (domain)
329 {
330 e.button.x /= domain->scale;
331 e.button.y /= domain->scale;
332 }
333 break;
334
335 case SDL_MOUSEBUTTONUP:
336 {
337 if (e.button.button == SDL_BUTTON_LEFT)
338 mouse_released(&e);
339 }
340 break;
341 }
342
343 if (e.type != SDL_MOUSEMOTION || (e.motion.state)) ++got_event;
344
345 // ensure the last event is a mouse click so it gets passed to the draw/event code
346
347 if (e.type == SDL_MOUSEBUTTONDOWN || (e.type == SDL_MOUSEMOTION && e.motion.state)) break;
348 }
349
350 if (got_event || gfx_domain_is_next_frame(domain))
351 {
352 draw_view(domain, filebox_view, &e);
353 gfx_domain_flip(domain);
354 }
355 else
356 SDL_Delay(5);
357 }
358
359 deinit_lines();
360 return 0;
361 }
362
363