1 /*
2 * Schism Tracker - a cross-platform Impulse Tracker clone
3 * copyright (c) 2003-2005 Storlek <storlek@rigelseven.com>
4 * copyright (c) 2005-2008 Mrs. Brisby <mrs.brisby@nimh.org>
5 * copyright (c) 2009 Storlek & Mrs. Brisby
6 * copyright (c) 2010-2012 Storlek
7 * URL: http://schismtracker.org/
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 /* this is a little ad-hoc; i did some work trying to bring it back into CVS
25 LARGELY because I can't remember all the font characters. :)
26 */
27 #include "headers.h"
28 #include "it.h"
29 #include "dmoz.h"
30 #include "page.h"
31 #include "version.h"
32 #include "log.h"
33
34 #include "sdlmain.h"
35 #include <string.h>
36
37 static const uint8_t itfmap_chars[] = {
38 128, 129, 130, ' ', 128, 129, 141, ' ', 142, 143, 144, ' ', 168, 'C', '-', '0',
39 131, ' ', 132, ' ', 131, ' ', 132, ' ', 145, ' ', 146, ' ', 168, 'D', '-', '1',
40 133, 134, 135, ' ', 140, 134, 135, ' ', 147, 148, 149, ' ', 168, 'E', '-', '2',
41 ' ', ' ', ' ', ' ', ' ', 139, 134, 138, 153, 148, 152, ' ', 168, 'F', '-', '3',
42 174, ' ', ' ', ' ', 155, 132, ' ', 131, 146, ' ', 145, ' ', 168, 'G', '-', '4',
43 175, ' ', ' ', ' ', 156, 137, 129, 136, 151, 143, 150, ' ', 168, 'A', '-', '5',
44 176, ' ', ' ', ' ', 157, ' ', 184, 184, 191, '6', '4', 192, 168, 'B', '-', '6',
45 176, 177, ' ', ' ', 158, 163, 250, 250, 250, 250, 250, ' ', 168, 'C', '#', '7',
46 176, 178, ' ', ' ', 159, 164, ' ', ' ', ' ', 185, 186, ' ', 168, 'D', '#', '8',
47 176, 179, 180, ' ', 160, 165, ' ', ' ', ' ', 189, 190, ' ', 168, 'E', '#', '9',
48 176, 179, 181, ' ', 161, 166, ' ', ' ', ' ', 187, 188, ' ', 168, 'F', '#', '1',
49 176, 179, 182, ' ', 162, 167, 126, 126, 126, ' ', ' ', ' ', 168, 'G', '#', '2',
50 154, 154, 154, 154, ' ', ' ', 205, 205, 205, ' ', 183, ' ', 168, 'A', '#', '3',
51 169, 170, 171, 172, ' ', ' ', '^', '^', '^', ' ', 173, ' ', 168, 'B', '#', '4',
52 193, 194, 195, 196, 197, 198, 199, 200, 201, ' ', ' ', ' ', ' ', ' ', ' ', ' ',
53 };
54 static const uint8_t helptext_gen[] =
55 "Tab Next box \xa8 Alt-C Copy\n"
56 "Shift-Tab Prev. box \xa8 Alt-P Paste\n"
57 "F2-F4 Switch box \xa8 Alt-M Mix paste\n"
58 "\x18\x19\x1a\x1b Dump core \xa8 Alt-Z Clear\n"
59 "Ctrl-S/F10 Save font \xa8 Alt-H Flip horiz\n"
60 "Ctrl-R/F9 Load font \xa8 Alt-V Flip vert\n"
61 "Backspace Reset font \xa8 Alt-I Invert\n"
62 "Ctrl-Bksp BIOS font \xa8 Alt-Bk Reset text\n"
63 " \xa8 0-9 Palette\n"
64 "Ctrl-Q Exit \xa8 (+10 with shift)\n";
65
66 static const uint8_t helptext_editbox[] =
67 "Space Plot/clear point\n"
68 "Ins/Del Fill/clear horiz.\n"
69 "...w/Shift Fill/clear vert.\n"
70 "\n"
71 "+/- Next/prev. char.\n"
72 "PgUp/PgDn Next/previous row\n"
73 "Home/End Top/bottom corner\n"
74 "\n" "Shift-\x18\x19\x1a\x1b Shift character\n"
75 "[/] Rotate 90\xf8\n";
76
77 static const uint8_t helptext_charmap[] =
78 "Home/End First/last char.\n";
79
80 static const uint8_t helptext_fontlist[] =
81 "Home/End First/last font\n"
82 "Enter Load/save file\n"
83 "Escape Hide font list\n"
84 "\n\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a"
85 "\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\x9a\n\n"
86 "Remember to save as font.cfg\n"
87 "to change the default font!\n";
88
89 /* --------------------------------------------------------------------- */
90 /* statics & local constants
91 note: x/y are for the top left corner of the frame, but w/h define the size of its *contents* */
92
93 #define EDITBOX_X 0
94 #define EDITBOX_Y 0
95 #define EDITBOX_W 9
96 #define EDITBOX_H 11
97
98 #define CHARMAP_X 17
99 #define CHARMAP_Y 0
100 #define CHARMAP_W 16
101 #define CHARMAP_H 16
102
103 #define ITFMAP_X 41
104 #define ITFMAP_Y 0
105 #define ITFMAP_W 16
106 #define ITFMAP_H 15
107
108 #define FONTLIST_X 65
109 #define FONTLIST_Y 0
110 #define VISIBLE_FONTS 22 /* this should be called FONTLIST_H... */
111
112 #define HELPTEXT_X 0
113 #define HELPTEXT_Y 31
114
115 /* don't randomly mess with these for obvious reasons */
116 #define INNER_X(x) ((x) + 3)
117 #define INNER_Y(y) ((y) + 4)
118
119 #define FRAME_RIGHT 3
120 #define FRAME_BOTTOM 3
121
122 #define WITHIN(n,l,u) ((n) >= (l) && (n) < (u))
123 #define POINT_IN(x,y,item) \
124 (WITHIN((x), INNER_X(item##_X), INNER_X(item##_X) + item##_W) \
125 && WITHIN((y), INNER_Y(item##_Y), INNER_Y(item##_Y) + item##_H))
126 #define POINT_IN_FRAME(x,y,item) \
127 (WITHIN((x), item##_X, INNER_X(item##_X) + item##_W + FRAME_RIGHT) \
128 && WITHIN((y), item##_Y, INNER_Y(item##_Y) + item##_H + FRAME_BOTTOM))
129
130 static int edit_x = 3, edit_y = 3;
131 static uint8_t current_char = 'A';
132 static int itfmap_pos = -1;
133
134 static enum {
135 EDITBOX, CHARMAP, ITFMAP, FONTLIST
136 } selected_item = EDITBOX;
137
138 static enum {
139 MODE_OFF, MODE_LOAD, MODE_SAVE
140 } fontlist_mode = MODE_OFF;
141
142 static dmoz_filelist_t flist;
143 static int top_font = 0, cur_font = 0;
144
145
fontlist_reposition(void)146 static void fontlist_reposition(void)
147 {
148 if (cur_font < 0)
149 cur_font = 0; /* weird! */
150 if (cur_font < top_font)
151 top_font = cur_font;
152 else if (cur_font > top_font + (VISIBLE_FONTS - 1))
153 top_font = cur_font - (VISIBLE_FONTS - 1);
154 }
155
fontgrep(dmoz_file_t * f)156 static int fontgrep(dmoz_file_t *f)
157 {
158 const char *ext;
159
160 if (f->sort_order == -100)
161 return 1; /* this is our font.cfg, at the top of the list */
162 if (f->type & TYPE_BROWSABLE_MASK)
163 return 0; /* we don't care about directories and stuff */
164 ext = get_extension(f->base);
165 return (strcasecmp(ext, ".itf") == 0 || strcasecmp(ext, ".fnt") == 0);
166 }
167
load_fontlist(void)168 static void load_fontlist(void)
169 {
170 char *font_dir, *p;
171 struct stat st = {};
172
173 dmoz_free(&flist, NULL);
174
175 top_font = cur_font = 0;
176
177 font_dir = dmoz_path_concat_len(cfg_dir_dotschism, "fonts", strlen(cfg_dir_dotschism), 5);
178 mkdir(font_dir, 0755);
179 p = dmoz_path_concat_len(font_dir, "font.cfg", strlen(font_dir), 8);
180 dmoz_add_file(&flist, p, str_dup("font.cfg"), &st, -100); /* put it on top */
181 if (dmoz_read(font_dir, &flist, NULL, NULL) < 0)
182 log_perror(font_dir);
183 free(font_dir);
184 dmoz_filter_filelist(&flist, fontgrep, &cur_font, NULL);
185 while (dmoz_worker());
186 fontlist_reposition();
187
188 /* p is freed by dmoz_free */
189 }
190
191
192
193 static uint8_t clipboard[8] = { 0 };
194
195 #define INCR_WRAPPED(n) (((n) & 0xf0) | (((n) + 1) & 0xf))
196 #define DECR_WRAPPED(n) (((n) & 0xf0) | (((n) - 1) & 0xf))
197
198 /* if this is nonzero, the screen will be redrawn. none of the functions
199 * except main should call draw_anything -- set this instead. */
draw_frame(const char * name,int x,int y,int inner_width,int inner_height,int active)200 static void draw_frame(const char* name, int x, int y, int inner_width, int inner_height, int active)
201 {
202 int n, c;
203 int len = strlen(name);
204
205 if (len > inner_width + 2)
206 len = inner_width + 2;
207 c = (status.flags & INVERTED_PALETTE) ? 1 : 3;
208
209 draw_box(x, y + 1, x + inner_width + 5,
210 y + inner_height + 6, BOX_THIN | BOX_CORNER | BOX_OUTSET);
211 draw_box(x + 1, y + 2, x + inner_width + 4,
212 y + inner_height + 5, BOX_THIN | BOX_INNER | BOX_INSET);
213
214 draw_char(128, x, y, c, 2);
215 for (n = 0; n < len + 1; n++)
216 draw_char(129, x + n + 1, y, c, 2);
217 draw_char(130, x + n, y, c, 2);
218 draw_char(131, x, y + 1, c, 2);
219 draw_char(137, x + len + 1, y + 1, c, 2);
220
221 switch (active) {
222 case 0: /* inactive */
223 n = 0;
224 break;
225 case -1: /* disabled */
226 n = 1;
227 break;
228 default: /* active */
229 n = 3;
230 break;
231 }
232 draw_text_len(name, len, x + 1, y + 1, n, 2);
233 }
234
235 /* --------------------------------------------------------------------- */
236
draw_editbox(void)237 static inline void draw_editbox(void)
238 {
239 int c;
240 char buf[12];
241 int ci = current_char << 3, i, j, fg;
242
243 for (i = 0; i < 8; i++) {
244 draw_char('1' + i, INNER_X(EDITBOX_X) + i + 1,
245 INNER_Y(EDITBOX_Y) + 2, (i == edit_x ? 3 : 1), 0);
246 draw_char('1' + i, INNER_X(EDITBOX_X),
247 INNER_Y(EDITBOX_Y) + i + 3, (i == edit_y ? 3 : 1), 0);
248
249 for (j = 0; j < 8; j++) {
250 if (font_data[ci + j] & (128 >> i)) {
251 c = 15;
252 fg = 6;
253 } else {
254 c = 173;
255 fg = 1;
256 }
257 if (selected_item == EDITBOX && i == edit_x && j == edit_y)
258 draw_char(c, INNER_X(EDITBOX_X) + 1 + i,
259 INNER_Y(EDITBOX_Y) + 3 + j, 0, 3);
260 else
261 draw_char(c, INNER_X(EDITBOX_X) + 1 + i,
262 INNER_Y(EDITBOX_Y) + 3 + j, fg, 0);
263 }
264 }
265 draw_char(current_char, INNER_X(EDITBOX_X), INNER_Y(EDITBOX_Y), 5, 0);
266
267 sprintf(buf, "%3d $%02X", current_char, current_char);
268 draw_text(buf, INNER_X(EDITBOX_X) + 2, INNER_Y(EDITBOX_Y), 5, 0);
269 }
270
draw_charmap(void)271 static inline void draw_charmap(void)
272 {
273 int n = 256;
274
275 if (selected_item == CHARMAP) {
276 while (n) {
277 n--;
278 draw_char(n, INNER_X(CHARMAP_X) + n % 16, INNER_Y(CHARMAP_Y) + n / 16,
279 (n == current_char ? 0 : 1), (n == current_char ? 3 : 0));
280 }
281 } else {
282 while (n) {
283 n--;
284 draw_char(n, INNER_X(CHARMAP_X) + n % 16, INNER_Y(CHARMAP_Y) + n / 16,
285 (n == current_char ? 3 : 1), 0);
286 }
287 }
288 }
289
draw_itfmap(void)290 static inline void draw_itfmap(void)
291 {
292 int n, fg, bg;
293 uint8_t *ptr;
294
295 if (itfmap_pos < 0 || itfmap_chars[itfmap_pos] != current_char) {
296 ptr = (unsigned char *) strchr((char *) itfmap_chars, current_char);
297 if (ptr == NULL)
298 itfmap_pos = -1;
299 else
300 itfmap_pos = ptr - itfmap_chars;
301 }
302
303 for (n = 0; n < 240; n++) {
304 fg = 1;
305 bg = 0;
306 if (n == itfmap_pos) {
307 if (selected_item == ITFMAP) {
308 fg = 0;
309 bg = 3;
310 } else {
311 fg = 3;
312 }
313 }
314 draw_char(itfmap_chars[n],
315 INNER_X(ITFMAP_X) + n % 16, INNER_Y(ITFMAP_Y) + n / 16, fg, bg);
316 }
317 }
318
draw_fontlist(void)319 static inline void draw_fontlist(void)
320 {
321 int x, pos = 0, n = top_font, cfg, cbg;
322 dmoz_file_t *f;
323 char *ptr;
324
325 if (selected_item == FONTLIST) {
326 cfg = 0;
327 cbg = 3;
328 } else {
329 cfg = 3;
330 cbg = 0;
331 }
332
333 if (top_font < 0) top_font = 0;
334 if (n < 0) n = 0;
335
336 while (n < flist.num_files && pos < VISIBLE_FONTS) {
337 x = 1;
338 f = flist.files[n];
339 if (!f) break;
340 ptr = f->base;
341 if (n == cur_font) {
342 draw_char(183, INNER_X(FONTLIST_X), INNER_Y(FONTLIST_Y) + pos, cfg, cbg);
343 while (x < 9 && *ptr && (n == 0 || *ptr != '.')) {
344 draw_char(*ptr,
345 INNER_X(FONTLIST_X) + x,
346 INNER_Y(FONTLIST_Y) + pos, cfg, cbg);
347 x++;
348 ptr++;
349 }
350 while (x < 9) {
351 draw_char(0,
352 INNER_X(FONTLIST_X) + x,
353 INNER_Y(FONTLIST_Y) + pos, cfg, cbg);
354 x++;
355 }
356 } else {
357 draw_char(173, INNER_X(FONTLIST_X), INNER_Y(FONTLIST_Y) + pos, 2, 0);
358 while (x < 9 && *ptr && (n == 0 || *ptr != '.')) {
359 draw_char(*ptr,
360 INNER_X(FONTLIST_X) + x, INNER_Y(FONTLIST_Y) + pos, 5, 0);
361 x++;
362 ptr++;
363 }
364 while (x < 9) {
365 draw_char(0, INNER_X(FONTLIST_X) + x, INNER_Y(FONTLIST_Y) + pos, 5, 0);
366 x++;
367 }
368 }
369 n++;
370 pos++;
371 }
372 }
373
draw_helptext(void)374 static inline void draw_helptext(void)
375 {
376 const uint8_t *ptr = helptext_gen;
377 const uint8_t *eol;
378 int line;
379 int column;
380
381 for (line = INNER_Y(HELPTEXT_Y); *ptr; line++) {
382 eol = (unsigned char *) strchr((char *) ptr, '\n');
383 if (!eol)
384 eol = (unsigned char *) strchr((char *) ptr, '\0');
385 for (column = INNER_X(HELPTEXT_X); ptr < eol; ptr++, column++)
386 draw_char(*ptr, column, line, 12, 0);
387 ptr++;
388 }
389 for (line = 0; line < 10; line++)
390 draw_char(168, INNER_X(HELPTEXT_X) + 43, INNER_Y(HELPTEXT_Y) + line, 12, 0);
391
392 /* context sensitive stuff... oooh :) */
393 switch (selected_item) {
394 case EDITBOX:
395 ptr = helptext_editbox;
396 break;
397 case CHARMAP:
398 case ITFMAP:
399 ptr = helptext_charmap;
400 break;
401 case FONTLIST:
402 ptr = helptext_fontlist;
403 break;
404 }
405 for (line = INNER_Y(HELPTEXT_Y); *ptr; line++) {
406 eol = (unsigned char *) strchr((char *) ptr, '\n');
407 if (!eol)
408 eol = (unsigned char *) strchr((char *) ptr, '\0');
409 draw_char(168, INNER_X(HELPTEXT_X) + 43, line, 12, 0);
410 for (column = INNER_X(HELPTEXT_X) + 45; ptr < eol; ptr++, column++)
411 draw_char(*ptr, column, line, 12, 0);
412 ptr++;
413 }
414 draw_text(ver_short_copyright, 77 - strlen(ver_short_copyright), 46, 1, 0);
415 }
416
draw_time(void)417 static inline void draw_time(void)
418 {
419 char buf[16];
420 sprintf(buf, "%.2d:%.2d:%.2d", status.tmnow.tm_hour, status.tmnow.tm_min, status.tmnow.tm_sec);
421 draw_text(buf, 3, 46, 1, 0);
422 }
423
424 extern unsigned int color_set[16];
425
draw_screen(void)426 static void draw_screen(void)
427 {
428 draw_frame("Edit Box", EDITBOX_X, EDITBOX_Y, 9, 11, !!(selected_item == EDITBOX));
429 draw_editbox();
430
431 draw_frame("Current Font", CHARMAP_X, CHARMAP_Y, 16, 16, !!(selected_item == CHARMAP));
432 draw_charmap();
433
434 draw_frame("Preview", ITFMAP_X, ITFMAP_Y, 16, 15, !!(selected_item == ITFMAP));
435 draw_itfmap();
436
437 switch (fontlist_mode) {
438 case MODE_LOAD:
439 draw_frame("Load/Browse", FONTLIST_X, FONTLIST_Y, 9,
440 VISIBLE_FONTS, !!(selected_item == FONTLIST));
441 draw_fontlist();
442 break;
443 case MODE_SAVE:
444 draw_frame("Save As...", FONTLIST_X, FONTLIST_Y, 9,
445 VISIBLE_FONTS, !!(selected_item == FONTLIST));
446 draw_fontlist();
447 break;
448 default: /* Off? (I sure hope so!) */
449 break;
450 }
451
452 draw_frame("Quick Help", HELPTEXT_X, HELPTEXT_Y, 74, 12, -1);
453 draw_helptext();
454
455 draw_time();
456 }
handle_key_editbox(struct key_event * k)457 static void handle_key_editbox(struct key_event * k)
458 {
459 uint8_t tmp[8] = { 0 };
460 int ci = current_char << 3;
461 int n, bit;
462 uint8_t *ptr = font_data + ci;
463
464 switch (k->sym) {
465 case SDLK_UP:
466 if (k->mod & KMOD_SHIFT) {
467 int s = ptr[0];
468 for (n = 0; n < 7; n++)
469 ptr[n] = ptr[n + 1];
470 ptr[7] = s;
471 } else {
472 if (--edit_y < 0)
473 edit_y = 7;
474 }
475 break;
476 case SDLK_DOWN:
477 if (k->mod & KMOD_SHIFT) {
478 int s = ptr[7];
479 for (n = 7; n; n--)
480 ptr[n] = ptr[n - 1];
481 ptr[0] = s;
482 } else {
483 edit_y = (edit_y + 1) % 8;
484 }
485 break;
486 case SDLK_LEFT:
487 if (k->mod & KMOD_SHIFT) {
488 for (n = 0; n < 8; n++, ptr++)
489 *ptr = (*ptr >> 7) | (*ptr << 1);
490 } else {
491 if (--edit_x < 0)
492 edit_x = 7;
493 }
494 break;
495 case SDLK_RIGHT:
496 if (k->mod & KMOD_SHIFT) {
497 for (n = 0; n < 8; n++, ptr++)
498 *ptr = (*ptr << 7) | (*ptr >> 1);
499 } else {
500 edit_x = (edit_x + 1) % 8;
501 }
502 break;
503 case SDLK_HOME:
504 edit_x = edit_y = 0;
505 break;
506 case SDLK_END:
507 edit_x = edit_y = 7;
508 break;
509 case SDLK_SPACE:
510 ptr[edit_y] ^= (128 >> edit_x);
511 break;
512 case SDLK_INSERT:
513 if (k->mod & KMOD_SHIFT) {
514 for (n = 0; n < 8; n++)
515 ptr[n] |= (128 >> edit_x);
516 } else {
517 ptr[edit_y] = 255;
518 }
519 break;
520 case SDLK_DELETE:
521 if (k->mod & KMOD_SHIFT) {
522 for (n = 0; n < 8; n++)
523 ptr[n] &= ~(128 >> edit_x);
524 } else {
525 ptr[edit_y] = 0;
526 }
527 break;
528 case SDLK_LEFTBRACKET:
529 for (n = 0; n < 8; n++)
530 for (bit = 0; bit < 8; bit++)
531 if (ptr[n] & (1 << bit))
532 tmp[bit] |= 1 << (7 - n);
533 memcpy(ptr, tmp, 8);
534 break;
535 case SDLK_RIGHTBRACKET:
536 for (n = 0; n < 8; n++)
537 for (bit = 0; bit < 8; bit++)
538 if (ptr[n] & (1 << bit))
539 tmp[7 - bit] |= 1 << n;
540 memcpy(ptr, tmp, 8);
541 break;
542 case SDLK_PLUS:
543 case SDLK_EQUALS:
544 current_char++;
545 break;
546 case SDLK_MINUS:
547 case SDLK_UNDERSCORE:
548 current_char--;
549 break;
550 case SDLK_PAGEUP:
551 current_char -= 16;
552 break;
553 case SDLK_PAGEDOWN:
554 current_char += 16;
555 break;
556 default:
557 return;
558 }
559
560 status.flags |= NEED_UPDATE;
561 }
562
handle_key_charmap(struct key_event * k)563 static void handle_key_charmap(struct key_event * k)
564 {
565 switch (k->sym) {
566 case SDLK_UP:
567 current_char -= 16;
568 break;
569 case SDLK_DOWN:
570 current_char += 16;
571 break;
572 case SDLK_LEFT:
573 current_char = DECR_WRAPPED(current_char);
574 break;
575 case SDLK_RIGHT:
576 current_char = INCR_WRAPPED(current_char);
577 break;
578 case SDLK_HOME:
579 current_char = 0;
580 break;
581 case SDLK_END:
582 current_char = 255;
583 break;
584 default:
585 return;
586 }
587 status.flags |= NEED_UPDATE;
588 }
589
handle_key_itfmap(struct key_event * k)590 static void handle_key_itfmap(struct key_event * k)
591 {
592 switch (k->sym) {
593 case SDLK_UP:
594 if (itfmap_pos < 0) {
595 itfmap_pos = 224;
596 } else {
597 itfmap_pos -= 16;
598 if (itfmap_pos < 0)
599 itfmap_pos += 240;
600 }
601 current_char = itfmap_chars[itfmap_pos];
602 break;
603 case SDLK_DOWN:
604 if (itfmap_pos < 0)
605 itfmap_pos = 16;
606 else
607 itfmap_pos = (itfmap_pos + 16) % 240;
608 current_char = itfmap_chars[itfmap_pos];
609 break;
610 case SDLK_LEFT:
611 if (itfmap_pos < 0)
612 itfmap_pos = 15;
613 else
614 itfmap_pos = DECR_WRAPPED(itfmap_pos);
615 current_char = itfmap_chars[itfmap_pos];
616 break;
617 case SDLK_RIGHT:
618 if (itfmap_pos < 0)
619 itfmap_pos = 0;
620 else
621 itfmap_pos = INCR_WRAPPED(itfmap_pos);
622 current_char = itfmap_chars[itfmap_pos];
623 break;
624 case SDLK_HOME:
625 current_char = itfmap_chars[0];
626 itfmap_pos = 0;
627 break;
628 case SDLK_END:
629 current_char = itfmap_chars[239];
630 itfmap_pos = 239;
631 break;
632 default:
633 return;
634 }
635 status.flags |= NEED_UPDATE;
636 }
637
confirm_font_save_ok(void * vf)638 static void confirm_font_save_ok(void *vf)
639 {
640 char *f = vf;
641 if (font_save(f) != 0) {
642 fprintf(stderr, "%s\n", SDL_GetError());
643 return;
644 }
645 selected_item = EDITBOX;
646 }
647
handle_key_fontlist(struct key_event * k)648 static void handle_key_fontlist(struct key_event * k)
649 {
650 int new_font = cur_font;
651
652 switch (k->sym) {
653 case SDLK_HOME:
654 new_font = 0;
655 break;
656 case SDLK_END:
657 new_font = flist.num_files - 1;
658 break;
659 case SDLK_UP:
660 new_font--;
661 break;
662 case SDLK_DOWN:
663 new_font++;
664 break;
665 case SDLK_PAGEUP:
666 new_font -= VISIBLE_FONTS;
667 break;
668 case SDLK_PAGEDOWN:
669 new_font += VISIBLE_FONTS;
670 break;
671 case SDLK_ESCAPE:
672 selected_item = EDITBOX;
673 fontlist_mode = MODE_OFF;
674 break;
675 case SDLK_RETURN:
676 if (k->state == KEY_PRESS)
677 return;
678 switch (fontlist_mode) {
679 case MODE_LOAD:
680 if (cur_font < flist.num_files
681 && flist.files[cur_font]
682 && font_load(flist.files[cur_font]->base) != 0) {
683 fprintf(stderr, "%s\n", SDL_GetError());
684 font_reset();
685 }
686 break;
687 case MODE_SAVE:
688 if (cur_font < flist.num_files && flist.files[cur_font]) {
689 if (strcasecmp(flist.files[cur_font]->base,"font.cfg") != 0) {
690 dialog_create(DIALOG_OK_CANCEL, "Overwrite font file?",
691 confirm_font_save_ok, NULL, 1, flist.files[cur_font]->base);
692 return;
693 }
694 confirm_font_save_ok(flist.files[cur_font]->base);
695 }
696 selected_item = EDITBOX;
697 /* fontlist_mode = MODE_OFF; */
698 break;
699 default:
700 /* should never happen */
701 return;
702 }
703 break;
704 default:
705 return;
706 }
707
708 if (new_font != cur_font) {
709 new_font = CLAMP(new_font, 0, flist.num_files - 1);
710 if (new_font == cur_font)
711 return;
712 cur_font = new_font;
713 fontlist_reposition();
714 }
715 status.flags |= NEED_UPDATE;
716 }
717
718 /* --------------------------------------------------------------------- */
719
handle_mouse_editbox(struct key_event * k)720 static void handle_mouse_editbox(struct key_event *k)
721 {
722 int n, ci = current_char << 3, xrel, yrel;
723 uint8_t *ptr = font_data + ci;
724
725 xrel = k->x - INNER_X(EDITBOX_X);
726 yrel = k->y - INNER_Y(EDITBOX_Y);
727
728 if (xrel > 0 && yrel > 2) {
729 edit_x = xrel - 1;
730 edit_y = yrel - 3;
731 switch (k->mouse_button) {
732 case MOUSE_BUTTON_LEFT: /* set */
733 ptr[edit_y] |= (128 >> edit_x);
734 break;
735 case MOUSE_BUTTON_MIDDLE: /* invert */
736 if (k->state == KEY_RELEASE)
737 return;
738 ptr[edit_y] ^= (128 >> edit_x);
739 break;
740 case MOUSE_BUTTON_RIGHT: /* clear */
741 ptr[edit_y] &= ~(128 >> edit_x);
742 break;
743 }
744 } else if (xrel == 0 && yrel == 2) {
745 /* clicking at the origin modifies the entire character */
746 switch (k->mouse_button) {
747 case MOUSE_BUTTON_LEFT: /* set */
748 for (n = 0; n < 8; n++)
749 ptr[n] = 255;
750 break;
751 case MOUSE_BUTTON_MIDDLE: /* invert */
752 if (k->state == KEY_RELEASE)
753 return;
754 for (n = 0; n < 8; n++)
755 ptr[n] ^= 255;
756 break;
757 case MOUSE_BUTTON_RIGHT: /* clear */
758 for (n = 0; n < 8; n++)
759 ptr[n] = 0;
760 break;
761 }
762 } else if (xrel == 0 && yrel > 2) {
763 edit_y = yrel - 3;
764 switch (k->mouse_button) {
765 case MOUSE_BUTTON_LEFT: /* set */
766 ptr[edit_y] = 255;
767 break;
768 case MOUSE_BUTTON_MIDDLE: /* invert */
769 if (k->state == KEY_RELEASE)
770 return;
771 ptr[edit_y] ^= 255;
772 break;
773 case MOUSE_BUTTON_RIGHT: /* clear */
774 ptr[edit_y] = 0;
775 break;
776 }
777 } else if (yrel == 2 && xrel > 0) {
778 edit_x = xrel - 1;
779 switch (k->mouse_button) {
780 case MOUSE_BUTTON_LEFT: /* set */
781 for (n = 0; n < 8; n++)
782 ptr[n] |= (128 >> edit_x);
783 break;
784 case MOUSE_BUTTON_MIDDLE: /* invert */
785 if (k->state == KEY_RELEASE)
786 return;
787 for (n = 0; n < 8; n++)
788 ptr[n] ^= (128 >> edit_x);
789 break;
790 case MOUSE_BUTTON_RIGHT: /* clear */
791 for (n = 0; n < 8; n++)
792 ptr[n] &= ~(128 >> edit_x);
793 break;
794 }
795 }
796 }
797
handle_mouse_charmap(struct key_event * k)798 static void handle_mouse_charmap(struct key_event *k)
799 {
800 int xrel = k->x - INNER_X(CHARMAP_X), yrel = k->y - INNER_Y(CHARMAP_Y);
801 if (!k->mouse) return;
802 current_char = 16 * yrel + xrel;
803 }
804
handle_mouse_itfmap(struct key_event * k)805 static void handle_mouse_itfmap(struct key_event *k)
806 {
807 int xrel = k->x - INNER_X(ITFMAP_X), yrel = k->y - INNER_Y(ITFMAP_Y);
808 if (!k->mouse) return;
809 itfmap_pos = 16 * yrel + xrel;
810 current_char = itfmap_chars[itfmap_pos];
811 }
812
handle_mouse(struct key_event * k)813 static void handle_mouse(struct key_event * k)
814 {
815 int x = k->x, y = k->y;
816 if (POINT_IN_FRAME(x, y, EDITBOX)) {
817 selected_item = EDITBOX;
818 if (POINT_IN(x, y, EDITBOX))
819 handle_mouse_editbox(k);
820 } else if (POINT_IN_FRAME(x, y, CHARMAP)) {
821 selected_item = CHARMAP;
822 if (POINT_IN(x, y, CHARMAP))
823 handle_mouse_charmap(k);
824 } else if (POINT_IN_FRAME(x, y, ITFMAP)) {
825 selected_item = ITFMAP;
826 if (POINT_IN(x, y, ITFMAP))
827 handle_mouse_itfmap(k);
828 } else {
829 //printf("stray click\n");
830 return;
831 }
832 status.flags |= NEED_UPDATE;
833 }
834
835
fontedit_handle_key(struct key_event * k)836 static int fontedit_handle_key(struct key_event * k)
837 {
838 int n, ci = current_char << 3;
839 uint8_t *ptr = font_data + ci;
840
841 if (k->mouse == MOUSE_SCROLL_UP || k->mouse == MOUSE_SCROLL_DOWN) {
842 /* err... */
843 return 0;
844 }
845
846 if (k->mouse == MOUSE_CLICK) {
847 handle_mouse(k);
848 return 1;
849 }
850
851 /* kp is special */
852 switch (k->orig_sym) {
853 case SDLK_KP0:
854 if (k->state == KEY_RELEASE)
855 return 1;
856 k->sym += 10;
857 /* fall through */
858 case SDLK_KP1...SDLK_KP9:
859 if (k->state == KEY_RELEASE)
860 return 1;
861 n = k->sym - SDLK_KP1;
862 if (k->mod & KMOD_SHIFT)
863 n += 10;
864 palette_load_preset(n);
865 palette_apply();
866 status.flags |= NEED_UPDATE;
867 return 1;
868 default:
869 break;
870 };
871
872 switch (k->sym) {
873 case '0':
874 if (k->state == KEY_RELEASE)
875 return 1;
876 k->sym += 10;
877 /* fall through */
878 case '1'...'9':
879 if (k->state == KEY_RELEASE)
880 return 1;
881 n = k->sym - '1';
882 if (k->mod & KMOD_SHIFT)
883 n += 10;
884 palette_load_preset(n);
885 palette_apply();
886 status.flags |= NEED_UPDATE;
887 return 1;
888 case SDLK_F2:
889 if (k->state == KEY_RELEASE)
890 return 1;
891 selected_item = EDITBOX;
892 status.flags |= NEED_UPDATE;
893 return 1;
894 case SDLK_F3:
895 if (k->state == KEY_RELEASE)
896 return 1;
897 selected_item = CHARMAP;
898 status.flags |= NEED_UPDATE;
899 return 1;
900 case SDLK_F4:
901 if (k->state == KEY_RELEASE)
902 return 1;
903 selected_item = ITFMAP;
904 status.flags |= NEED_UPDATE;
905 return 1;
906 case SDLK_TAB:
907 if (k->state == KEY_RELEASE)
908 return 1;
909 if (k->mod & KMOD_SHIFT) {
910 if (selected_item == 0)
911 selected_item = (fontlist_mode == MODE_OFF ? 2 : 3);
912 else
913 selected_item--;
914 } else {
915 selected_item = (selected_item + 1) % (fontlist_mode == MODE_OFF ? 3 : 4);
916 }
917 status.flags |= NEED_UPDATE;
918 return 1;
919 case SDLK_c:
920 if (k->state == KEY_RELEASE)
921 return 1;
922 if (k->mod & KMOD_ALT) {
923 memcpy(clipboard, ptr, 8);
924 return 1;
925 }
926 break;
927 case SDLK_p:
928 if (k->state == KEY_RELEASE)
929 return 1;
930 if (k->mod & KMOD_ALT) {
931 memcpy(ptr, clipboard, 8);
932 status.flags |= NEED_UPDATE;
933 return 1;
934 }
935 break;
936 case SDLK_m:
937 if (k->state == KEY_RELEASE)
938 return 1;
939 if (k->mod & KMOD_CTRL) {
940 SDL_ToggleCursor();
941 return 1;
942 } else if (k->mod & KMOD_ALT) {
943 for (n = 0; n < 8; n++)
944 ptr[n] |= clipboard[n];
945 status.flags |= NEED_UPDATE;
946 return 1;
947 }
948 break;
949 case SDLK_z:
950 if (k->state == KEY_RELEASE)
951 return 1;
952 if (k->mod & KMOD_ALT) {
953 memset(ptr, 0, 8);
954 status.flags |= NEED_UPDATE;
955 return 1;
956 }
957 break;
958 case SDLK_h:
959 if (k->state == KEY_RELEASE)
960 return 1;
961 if (k->mod & KMOD_ALT) {
962 for (n = 0; n < 8; n++) {
963 int r = ptr[n];
964 r = ((r >> 1) & 0x55) | ((r << 1) & 0xaa);
965 r = ((r >> 2) & 0x33) | ((r << 2) & 0xcc);
966 r = ((r >> 4) & 0x0f) | ((r << 4) & 0xf0);
967 ptr[n] = r;
968 }
969 status.flags |= NEED_UPDATE;
970 return 1;
971 }
972 break;
973 case SDLK_v:
974 if (k->state == KEY_RELEASE)
975 return 1;
976 if (k->mod & KMOD_ALT) {
977 for (n = 0; n < 4; n++) {
978 uint8_t r = ptr[n];
979 ptr[n] = ptr[7 - n];
980 ptr[7 - n] = r;
981 }
982 status.flags |= NEED_UPDATE;
983 return 1;
984 }
985 break;
986 case SDLK_i:
987 if (k->state == KEY_RELEASE)
988 return 1;
989 if (k->mod & KMOD_ALT) {
990 for (n = 0; n < 8; n++)
991 font_data[ci + n] ^= 255;
992 status.flags |= NEED_UPDATE;
993 return 1;
994 }
995 break;
996
997 /* ----------------------------------------------------- */
998
999 case SDLK_l:
1000 case SDLK_r:
1001 if (k->state == KEY_RELEASE)
1002 return 1;
1003 if (!(k->mod & KMOD_CTRL)) break;
1004 /* fall through */
1005 case SDLK_F9:
1006 if (k->state == KEY_RELEASE)
1007 return 1;
1008 load_fontlist();
1009 fontlist_mode = MODE_LOAD;
1010 selected_item = FONTLIST;
1011 status.flags |= NEED_UPDATE;
1012 return 1;
1013 case SDLK_s:
1014 if (k->state == KEY_RELEASE)
1015 return 1;
1016 if (!(k->mod & KMOD_CTRL)) break;
1017 /* fall through */
1018 case SDLK_F10:
1019 /* a bit weird, but this ensures that font.cfg
1020 * is always the default font to save to, but
1021 * without the annoyance of moving the cursor
1022 * back to it every time f10 is pressed. */
1023 if (fontlist_mode != MODE_SAVE) {
1024 cur_font = top_font = 0;
1025 load_fontlist();
1026 fontlist_mode = MODE_SAVE;
1027 }
1028 selected_item = FONTLIST;
1029 status.flags |= NEED_UPDATE;
1030 return 1;
1031 case SDLK_BACKSPACE:
1032 if (k->state == KEY_RELEASE)
1033 return 1;
1034 if (k->mod & KMOD_CTRL) {
1035 font_reset_bios();
1036 } else if (k->mod & KMOD_ALT) {
1037 font_reset_char(current_char);
1038 } else {
1039 font_reset_upper();
1040 }
1041 status.flags |= NEED_UPDATE;
1042 return 1;
1043 case SDLK_RETURN:
1044 return 0;
1045 case SDLK_q:
1046 if (k->mod & KMOD_CTRL)
1047 return 0;
1048 if (k->state == KEY_RELEASE)
1049 return 1;
1050 break;
1051 default:
1052 if (k->state == KEY_RELEASE)
1053 return 1;
1054 break;
1055 }
1056
1057 switch (selected_item) {
1058 case EDITBOX:
1059 handle_key_editbox(k);
1060 break;
1061 case CHARMAP:
1062 handle_key_charmap(k);
1063 break;
1064 case ITFMAP:
1065 handle_key_itfmap(k);
1066 break;
1067 case FONTLIST:
1068 handle_key_fontlist(k);
1069 break;
1070 default:
1071 break;
1072 }
1073 return 1;
1074 }
1075
1076
1077 static struct widget fontedit_widget_hack[1];
1078
fontedit_key_hack(struct key_event * k)1079 static int fontedit_key_hack(struct key_event *k)
1080 {
1081 switch (k->sym) {
1082 case SDLK_r: case SDLK_l: case SDLK_s:
1083 case SDLK_c: case SDLK_p: case SDLK_m:
1084 case SDLK_z: case SDLK_v: case SDLK_h:
1085 case SDLK_i: case SDLK_q: case SDLK_w:
1086 case SDLK_F1...SDLK_F12:
1087 return fontedit_handle_key(k);
1088 case SDLK_RETURN:
1089 if (status.dialog_type & (DIALOG_MENU|DIALOG_BOX)) return 0;
1090 if (selected_item == FONTLIST) {
1091 handle_key_fontlist(k);
1092 return 1;
1093 }
1094 default:
1095 break;
1096 };
1097 return 0;
1098 }
1099
do_nil(void)1100 static void do_nil(void) {}
fontedit_load_page(struct page * page)1101 void fontedit_load_page(struct page *page)
1102 {
1103 page->title = "";
1104 page->draw_full = draw_screen;
1105 page->total_widgets = 1;
1106 page->pre_handle_key = fontedit_key_hack;
1107 page->widgets = fontedit_widget_hack;
1108 create_other(fontedit_widget_hack, 0, fontedit_handle_key, do_nil);
1109 }
1110