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