Bump version numbers for 3.13
[maemo-rb.git] / apps / plugins / goban / goban.c
blobc20724ed70f6acc18c0aac5dc010d93677f86949
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2007-2009 Joshua Simmons <mud at majidejima dot com>
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include "plugin.h"
23 #include "lib/playback_control.h"
24 #include "lib/configfile.h"
28 #include "goban.h"
29 #include "game.h"
30 #include "board.h"
31 #include "display.h"
32 #include "sgf.h"
33 #include "sgf_storage.h"
34 #include "types.h"
35 #include "util.h"
37 enum play_mode_t play_mode = MODE_PLAY;
39 #if defined(GBN_BUTTON_NAV_MODE)
41 #define NAV_MODE_BOARD 0
42 #define NAV_MODE_TREE 1
44 int nav_mode = NAV_MODE_BOARD;
46 #endif
48 /* the stack that uses this buffer is used for both storing intersections
49 * in board algorithms (could store one short for each board location), and
50 * for parsing (could store an indefinite number of ints, related to how
51 * many levels deep branches go (in other words, how many branches off of
52 * branches there are). 50 should take care of any reasonable file.
54 #define PARSE_STACK_BUFFER_SIZE (max(MAX_BOARD_SIZE * MAX_BOARD_SIZE * sizeof(unsigned short), 50 * sizeof(int)))
56 /* used in SGF file parsing and outputting as well as in liberty counting
57 and capturing/uncapturing */
58 struct stack_t parse_stack;
59 char parse_stack_buffer[PARSE_STACK_BUFFER_SIZE];
61 static void global_setup (void);
62 static void global_cleanup (void);
64 static bool do_main_menu (void);
65 static void do_gameinfo_menu (void);
66 static enum prop_type_t menu_selection_to_prop (int selection);
67 static void do_context_menu (void);
68 static void do_options_menu (void);
70 static bool do_comment_edit (void);
71 static bool do_zoom (void);
72 static void set_defaults (void);
74 bool auto_show_comments = true;
75 bool disable_shutdown = false;
76 unsigned int autosave_time = 0;
77 unsigned int autosave_counter = 0;
79 #define SETTINGS_VERSION 2
80 #define SETTINGS_MIN_VERSION 1
81 #define SETTINGS_FILENAME "goban.cfg"
83 static struct configdata config[] =
84 { /* INT in MAX_INT_SIZE is intersection, not integer */
85 {TYPE_INT, 0, MAX_INT_SIZE,
86 { .int_p = &saved_circle_size },
87 "stone size", NULL},
88 {TYPE_BOOL, 0, 1,
89 { .bool_p = &draw_variations },
90 "draw variations",
91 NULL},
92 {TYPE_BOOL, 0, 1,
93 { .bool_p = &auto_show_comments },
94 "auto show comments",
95 NULL},
96 {TYPE_BOOL, 0, 1,
97 { .bool_p = &disable_shutdown },
98 "disable shutdown",
99 NULL},
100 {TYPE_INT, 0, MAX_AUTOSAVE,
101 { .int_p = &autosave_time },
102 "autosave time",
103 NULL}
106 static void
107 set_defaults (void)
109 saved_circle_size = 0;
110 draw_variations = true;
111 auto_show_comments = true;
113 disable_shutdown = false;
114 autosave_time = 7;
117 static const char*
118 komi_formatter (char *dest, size_t size, int menu_item, const char *unknown)
120 (void) unknown;
121 snprint_fixed (dest, size, menu_item);
122 return dest;
125 static const char*
126 ruleset_formatter (char *dest, size_t size, int menu_item, const char *unknown)
128 (void)dest, (void)size, (void)unknown;
129 return ruleset_names[menu_item];
132 static const char*
133 autosave_formatter (char *dest, size_t size, int menu_item, const char *
134 unknown)
136 (void) unknown;
137 if (menu_item == 0)
139 return "Off";
141 else
143 rb->snprintf (dest, size, "%d minute%s", menu_item,
144 menu_item == 1 ? "" : "s");
145 return dest;
149 static const char*
150 time_formatter (char *dest, size_t size, int menu_item, const char *unknown)
152 int time_values[4]; /* days hours minutes seconds */
153 int min_set, max_set;
154 int temp;
156 (void) unknown;
158 time_values[0] = menu_item / (24 * 60 * 60);
159 menu_item %= (24 * 60 * 60);
160 time_values[1] = menu_item / (60 * 60);
161 menu_item %= (60 * 60);
162 time_values[2] = menu_item / 60;
163 time_values[3] = menu_item % 60;
165 min_set = 500;
166 max_set = -1;
167 int i;
168 for (i = 0;
169 (unsigned int) i < (sizeof (time_values) / sizeof (time_values[0]));
170 ++i)
172 if (time_values[i])
174 if (i < min_set)
176 min_set = i;
179 if (i > max_set)
181 max_set = i;
186 if (max_set == -1)
188 return "0";
191 for (i = min_set; i <= 3; ++i)
193 if (i <= max_set)
195 if (i == 0 || i == 1 || i == min_set)
197 rb->snprintf (dest, size, "%d", time_values[i]);
199 else
201 rb->snprintf (dest, size, "%02d", time_values[i]);
203 temp = rb->strlen (dest);
204 dest += temp;
205 size -= temp;
207 else if (i != 3)
209 continue;
212 if (i == 0) /* days */
214 rb->snprintf (dest, size, " d ");
216 else if (i == 3) /* seconds, print the final units */
218 if (min_set == 0 || min_set == 1)
220 rb->snprintf (dest, size, " h");
222 else if (min_set == 2)
224 rb->snprintf (dest, size, " m");
226 else
228 rb->snprintf (dest, size, " s");
231 else if (i != max_set)
233 rb->snprintf (dest, size, ":");
236 temp = rb->strlen (dest);
237 dest += temp;
238 size -= temp;
240 return dest;
243 enum plugin_status
244 plugin_start (const void *parameter)
246 int btn;
248 rb->mkdir (DEFAULT_SAVE_DIR);
250 global_setup ();
252 #ifdef GBN_TEST
253 run_tests ();
254 return PLUGIN_OK;
255 #endif
257 if (!(parameter && load_game (parameter)))
259 if (parameter)
261 rb->splashf (2 * HZ, "Loading %s failed.", (char *) parameter);
264 if (!load_game (DEFAULT_SAVE))
266 rb->strcpy (save_file, DEFAULT_SAVE);
268 if (!setup_game (MAX_BOARD_SIZE, MAX_BOARD_SIZE, 0, 0))
270 return PLUGIN_ERROR;
274 else
276 /* game loaded */
277 if (rb->strcmp (save_file, DEFAULT_SAVE))
279 /* delete the scratch file if we loaded a game and it wasn't
280 * from the scratch file
282 rb->remove (DEFAULT_SAVE);
286 draw_screen_display ();
288 autosave_counter = 0;
289 for (;;)
291 btn = rb->button_get_w_tmo (HZ * 30);
293 if (disable_shutdown)
295 /* tell rockbox we're not idle */
296 rb->reset_poweroff_timer ();
299 bool is_idle = false;
301 switch (btn)
304 #if defined(GBN_BUTTON_NAV_MODE)
305 case GBN_BUTTON_NAV_MODE:
306 case GBN_BUTTON_NAV_MODE | BUTTON_REPEAT:
307 if (nav_mode == NAV_MODE_TREE)
309 nav_mode = NAV_MODE_BOARD;
310 rb->splash (2 * HZ / 3, "board navigation mode");
311 draw_screen_display ();
313 else
315 nav_mode = NAV_MODE_TREE;
316 rb->splash (2 * HZ / 3, "tree navigation mode");
317 draw_screen_display ();
319 break;
320 #endif
322 #if defined(GBN_BUTTON_ADVANCE)
323 case GBN_BUTTON_ADVANCE:
324 case GBN_BUTTON_ADVANCE | BUTTON_REPEAT:
325 if (has_more_nodes_sgf ())
327 if (!redo_node_sgf ())
329 rb->splash (2 * HZ, "redo failed");
331 draw_screen_display ();
333 break;
334 #endif
336 #if defined(GBN_BUTTON_RETREAT)
337 case GBN_BUTTON_RETREAT:
338 case GBN_BUTTON_RETREAT | BUTTON_REPEAT:
339 if (has_prev_nodes_sgf ())
341 if (!undo_node_sgf ())
343 rb->splash (3 * HZ / 2, "Undo Failed");
345 draw_screen_display ();
347 break;
348 #endif
350 case GBN_BUTTON_PLAY:
351 if (play_mode == MODE_PLAY || play_mode == MODE_FORCE_PLAY)
353 if (!play_move_sgf (cursor_pos, current_player))
355 rb->splash (HZ / 3, "Illegal Move");
358 else if (play_mode == MODE_ADD_BLACK)
360 if (!add_stone_sgf (cursor_pos, BLACK))
362 rb->splash (HZ / 3, "Illegal");
365 else if (play_mode == MODE_ADD_WHITE)
367 if (!add_stone_sgf (cursor_pos, WHITE))
369 rb->splash (HZ / 3, "Illegal");
372 else if (play_mode == MODE_REMOVE)
374 if (!add_stone_sgf (cursor_pos, EMPTY))
376 rb->splash (HZ / 3, "Illegal");
379 else if (play_mode == MODE_MARK)
381 if (!add_mark_sgf (cursor_pos, PROP_MARK))
383 rb->splash (HZ / 3, "Couldn't Mark");
386 else if (play_mode == MODE_CIRCLE)
388 if (!add_mark_sgf (cursor_pos, PROP_CIRCLE))
390 rb->splash (HZ / 3, "Couldn't Mark");
393 else if (play_mode == MODE_SQUARE)
395 if (!add_mark_sgf (cursor_pos, PROP_SQUARE))
397 rb->splash (HZ / 3, "Couldn't Mark");
400 else if (play_mode == MODE_TRIANGLE)
402 if (!add_mark_sgf (cursor_pos, PROP_TRIANGLE))
404 rb->splash (HZ / 3, "Couldn't Mark");
407 else if (play_mode == MODE_LABEL)
409 if (!add_mark_sgf (cursor_pos, PROP_LABEL))
411 rb->splash (HZ / 3, "Couldn't Label");
414 else
416 rb->splash (HZ, "mode not implemented");
419 draw_screen_display ();
420 break;
422 case GBN_BUTTON_RIGHT:
423 case GBN_BUTTON_RIGHT | BUTTON_REPEAT:
424 #if defined(GBN_BUTTON_NAV_MODE)
425 if (nav_mode == NAV_MODE_TREE)
427 if (has_more_nodes_sgf ())
429 if (!redo_node_sgf ())
431 rb->splash (2 * HZ, "Redo Failed");
433 draw_screen_display ();
436 else
438 #endif
439 cursor_pos = WRAP (EAST (cursor_pos));
440 draw_screen_display ();
441 #if defined(GBN_BUTTON_NAV_MODE)
443 #endif
444 break;
446 case GBN_BUTTON_LEFT:
447 case GBN_BUTTON_LEFT | BUTTON_REPEAT:
448 #if defined(GBN_BUTTON_NAV_MODE)
449 if (nav_mode == NAV_MODE_TREE)
451 if (has_prev_nodes_sgf ())
453 if (!undo_node_sgf ())
455 rb->splash (2 * HZ, "Undo Failed");
457 draw_screen_display ();
460 else
462 #endif
463 cursor_pos = WRAP (WEST (cursor_pos));
464 draw_screen_display ();
465 #if defined(GBN_BUTTON_NAV_MODE)
467 #endif
468 break;
470 case GBN_BUTTON_DOWN:
471 case GBN_BUTTON_DOWN | BUTTON_REPEAT:
472 cursor_pos = WRAP (SOUTH (cursor_pos));
473 draw_screen_display ();
474 break;
476 case GBN_BUTTON_UP:
477 case GBN_BUTTON_UP | BUTTON_REPEAT:
478 cursor_pos = WRAP (NORTH (cursor_pos));
479 draw_screen_display ();
480 break;
482 case GBN_BUTTON_MENU:
483 if (do_main_menu ())
485 save_game (DEFAULT_SAVE);
487 global_cleanup ();
488 return PLUGIN_OK;
491 draw_screen_display ();
492 break;
494 #if defined(GBN_BUTTON_CONTEXT)
495 case GBN_BUTTON_CONTEXT:
496 do_context_menu ();
497 draw_screen_display ();
498 break;
499 #endif
501 #if defined(GBN_BUTTON_NEXT_VAR)
502 case GBN_BUTTON_NEXT_VAR:
503 case GBN_BUTTON_NEXT_VAR | BUTTON_REPEAT:
505 int temp;
506 if ((temp = next_variation_sgf ()) >= 0)
508 draw_screen_display ();
509 rb->splashf (2 * HZ / 3, "%d of %d", temp,
510 num_variations_sgf ());
511 draw_screen_display ();
513 else
515 if (num_variations_sgf () > 1)
517 rb->splashf (HZ, "Error %d in next_variation_sgf", temp);
519 draw_screen_display ();
521 break;
523 #endif
525 case BUTTON_NONE:
526 is_idle = true;
527 default:
528 if (rb->default_event_handler (btn) == SYS_USB_CONNECTED)
530 return PLUGIN_USB_CONNECTED;
532 break;
535 if (is_idle && autosave_dirty)
537 ++autosave_counter;
539 if (autosave_time != 0 &&
540 autosave_counter / 2 >= autosave_time)
541 /* counter is in 30 second increments, autosave_time is in
542 * minutes
545 DEBUGF("autosaving\n");
546 rb->splash(HZ / 4, "Autosaving...");
547 save_game(DEFAULT_SAVE);
548 draw_screen_display();
549 autosave_counter = 0;
552 else
554 autosave_counter = 0;
558 return PLUGIN_OK;
561 static void
562 global_cleanup (void)
564 cleanup_sgf ();
565 configfile_save(SETTINGS_FILENAME, config,
566 sizeof(config)/sizeof(*config),
567 SETTINGS_VERSION);
570 static void
571 global_setup (void)
573 setup_stack (&parse_stack, parse_stack_buffer,
574 sizeof (parse_stack_buffer));
575 setup_display ();
576 setup_sgf ();
578 set_defaults();
579 if (configfile_load(SETTINGS_FILENAME, config,
580 sizeof(config)/sizeof(*config),
581 SETTINGS_MIN_VERSION ) < 0)
583 /* If the loading failed, save a new config file (as the disk is
584 already spinning) */
586 /* set defaults again just in case (don't know if they can ever
587 * be messed up by configfile_load, and it's basically free anyway)
589 set_defaults();
591 configfile_save(SETTINGS_FILENAME, config,
592 sizeof(config)/sizeof(*config),
593 SETTINGS_VERSION);
597 enum main_menu_selections
599 MAIN_NEW = 0,
600 MAIN_SAVE,
601 MAIN_SAVE_AS,
602 MAIN_GAME_INFO,
603 MAIN_PLAYBACK,
604 MAIN_ZOOM,
605 MAIN_OPTIONS,
606 MAIN_CONTEXT,
607 MAIN_QUIT
610 static bool
611 do_main_menu (void)
613 int selection = 0;
614 MENUITEM_STRINGLIST (menu, "Rockbox Goban", NULL,
615 "New",
616 "Save",
617 "Save As",
618 "Game Info",
619 "Playback Control",
620 "Zoom Level",
621 "Options",
622 "Context Menu",
623 "Quit");
625 /* for "New" in menu */
626 int new_handi = 0, new_bs = MAX_BOARD_SIZE, new_komi = 15;
628 char new_save_file[SAVE_FILE_LENGTH];
631 bool done = false;
633 while (!done)
635 selection = rb->do_menu (&menu, &selection, NULL, false);
637 switch (selection)
639 case MAIN_NEW:
640 rb->set_int ("board size", "lines", UNIT_INT,
641 &new_bs, NULL, 1, MIN_BOARD_SIZE, MAX_BOARD_SIZE,
642 NULL);
644 rb->set_int ("handicap", "stones", UNIT_INT,
645 &new_handi, NULL, 1, 0, 9, NULL);
647 if (new_handi > 0)
649 new_komi = 1;
651 else
653 new_komi = 13;
656 rb->set_int ("komi", "moku", UNIT_INT, &new_komi, NULL,
657 1, -300, 300, &komi_formatter);
659 setup_game (new_bs, new_bs, new_handi, new_komi);
660 draw_screen_display ();
661 done = true;
662 break;
664 case MAIN_SAVE:
665 if (!save_game (save_file))
667 rb->splash (2 * HZ, "Save Failed!");
669 else
671 rb->splash (2 * HZ / 3, "Saved");
673 done = true;
674 draw_screen_display ();
675 break;
677 case MAIN_SAVE_AS:
678 rb->strcpy (new_save_file, save_file);
680 if (!rb->kbd_input (new_save_file, SAVE_FILE_LENGTH))
682 break;
685 if (!save_game (new_save_file))
687 rb->splash (2 * HZ, "Save Failed!");
689 else
691 rb->strcpy (save_file, new_save_file);
692 rb->splash (2 * HZ / 3, "Saved");
695 done = true;
696 draw_screen_display ();
697 break;
699 case MAIN_GAME_INFO:
700 do_gameinfo_menu ();
701 break;
703 case MAIN_PLAYBACK:
704 if (!audio_stolen_sgf ())
706 playback_control (NULL);
708 else
710 rb->splash (1 * HZ, "Audio has been disabled!");
712 break;
714 case MAIN_ZOOM:
715 if (do_zoom ())
717 return true;
719 done = true;
720 draw_screen_display ();
721 break;
723 case MAIN_OPTIONS:
724 do_options_menu();
725 break;
727 case MAIN_CONTEXT:
728 do_context_menu ();
729 done = true;
730 break;
732 case MAIN_QUIT:
733 case MENU_ATTACHED_USB:
734 return true;
736 case GO_TO_ROOT:
737 case GO_TO_PREVIOUS:
738 default:
740 done = true;
741 break;
745 return false;
748 static void
749 zoom_preview (int current)
751 set_zoom_display (current);
752 draw_screen_display ();
753 rb->splash (0, "Preview");
756 static bool
757 do_zoom (void)
759 unsigned int zoom_level;
760 unsigned int old_val;
761 bool done = false;
763 unsigned int min_val = min_zoom_display ();
764 unsigned int max_val = max_zoom_display ();
766 zoom_level = old_val = current_zoom_display ();
768 int action;
770 zoom_preview (zoom_level);
771 while (!done)
773 switch (action = rb->get_action (CONTEXT_LIST, TIMEOUT_BLOCK))
775 case ACTION_STD_OK:
776 set_zoom_display (zoom_level);
777 done = true;
778 rb->splash (HZ / 2, "Zoom Set");
779 saved_circle_size = intersection_size;
780 break;
782 case ACTION_STD_CANCEL:
783 set_zoom_display (old_val);
784 done = true;
785 rb->splash (HZ / 2, "Cancelled");
786 break;
788 case ACTION_STD_CONTEXT:
789 zoom_level = old_val;
790 zoom_preview (zoom_level);
791 break;
793 case ACTION_STD_NEXT:
794 case ACTION_STD_NEXTREPEAT:
795 zoom_level = zoom_level * 3 / 2;
797 /* 1 * 3 / 2 is 1 again... */
798 if (zoom_level == 1)
800 ++zoom_level;
803 if (zoom_level > max_val)
805 zoom_level = min_val;
808 zoom_preview (zoom_level);
809 break;
811 case ACTION_STD_PREV:
812 case ACTION_STD_PREVREPEAT:
813 zoom_level = zoom_level * 2 / 3;
815 if (zoom_level < min_val)
817 zoom_level = max_val;
819 zoom_preview (zoom_level);
820 break;
822 case ACTION_NONE:
823 break;
825 default:
826 if (rb->default_event_handler (action) == SYS_USB_CONNECTED)
828 return true;
830 break;
834 return false;
837 enum gameinfo_menu_selections
839 GINFO_BASIC_INFO = 0,
840 GINFO_TIME_LIMIT,
841 GINFO_OVERTIME,
842 GINFO_RESULT,
843 GINFO_HANDICAP,
844 GINFO_KOMI,
845 GINFO_RULESET,
846 GINFO_BLACK_PLAYER,
847 GINFO_BLACK_RANK,
848 GINFO_BLACK_TEAM,
849 GINFO_WHITE_PLAYER,
850 GINFO_WHITE_RANK,
851 GINFO_WHITE_TEAM,
852 GINFO_DATE,
853 GINFO_EVENT,
854 GINFO_PLACE,
855 GINFO_ROUND,
856 GINFO_DONE
860 static void
861 do_gameinfo_menu (void)
863 MENUITEM_STRINGLIST (gameinfo_menu, "Game Info", NULL,
864 "Basic Info",
865 "Time Limit",
866 "Overtime",
867 "Result",
868 "Handicap",
869 "Komi",
870 "Ruleset",
871 "Black Player",
872 "Black Rank",
873 "Black Team",
874 "White Player",
875 "White Rank",
876 "White Team",
877 "Date",
878 "Event",
879 "Place",
880 "Round",
881 "Done");
882 /* IMPORTANT:
884 * if you edit this string list, make sure you keep
885 * menu_selection_to_prop function in line with it!! (see the bottom
886 * of this file).
889 int new_ruleset = 0;
891 char *gameinfo_string;
892 int gameinfo_string_size;
894 bool done = false;
895 int selection = 0;
897 while (!done)
899 selection = rb->do_menu (&gameinfo_menu, &selection, NULL, false);
901 switch (selection)
903 case GINFO_OVERTIME:
904 case GINFO_RESULT:
905 case GINFO_BLACK_PLAYER:
906 case GINFO_BLACK_RANK:
907 case GINFO_BLACK_TEAM:
908 case GINFO_WHITE_PLAYER:
909 case GINFO_WHITE_RANK:
910 case GINFO_WHITE_TEAM:
911 case GINFO_DATE:
912 case GINFO_EVENT:
913 case GINFO_PLACE:
914 case GINFO_ROUND:
915 if (!get_header_string_and_size (&header,
916 menu_selection_to_prop
917 (selection), &gameinfo_string,
918 &gameinfo_string_size))
920 rb->splash (3 * HZ, "Couldn't get header string");
921 break;
924 rb->kbd_input (gameinfo_string, gameinfo_string_size);
925 sanitize_string (gameinfo_string);
926 set_game_modified();
927 break;
929 /* these need special handling in some way, so they are
930 separate */
932 case GINFO_BASIC_INFO:
933 metadata_summary();
934 break;
936 case GINFO_TIME_LIMIT:
937 rb->set_int ("Time Limit", "", UNIT_INT, &header.time_limit,
938 NULL, 60, 0, 24 * 60 * 60, &time_formatter);
939 set_game_modified();
940 break;
942 case GINFO_HANDICAP:
943 rb->splashf (0, "%d stones. Start a new game to set handicap",
944 header.handicap);
945 rb->action_userabort(TIMEOUT_BLOCK);
946 break;
948 case GINFO_KOMI:
949 rb->set_int ("Komi", "moku", UNIT_INT, &header.komi, NULL,
950 1, -300, 300, &komi_formatter);
951 set_game_modified();
952 break;
954 case GINFO_RULESET:
955 new_ruleset = 0;
956 rb->set_int ("Ruleset", "", UNIT_INT, &new_ruleset, NULL,
957 1, 0, NUM_RULESETS - 1, &ruleset_formatter);
959 rb->strcpy (header.ruleset, ruleset_names[new_ruleset]);
960 set_game_modified();
961 break;
963 case GINFO_DONE:
964 case GO_TO_ROOT:
965 case GO_TO_PREVIOUS:
966 case MENU_ATTACHED_USB:
967 default:
968 done = true;
969 break;
974 enum context_menu_selections
976 CTX_PLAY = 0,
977 CTX_ADD_BLACK,
978 CTX_ADD_WHITE,
979 CTX_ERASE,
980 CTX_PASS,
981 CTX_NEXT_VAR,
982 CTX_FORCE,
983 CTX_MARK,
984 CTX_CIRCLE,
985 CTX_SQUARE,
986 CTX_TRIANGLE,
987 CTX_LABEL,
988 CTX_COMMENT,
989 CTX_DONE
992 static void
993 do_context_menu (void)
995 int selection;
996 bool done = false;
997 int temp;
999 MENUITEM_STRINGLIST (context_menu, "Context Menu", NULL,
1000 "Play Mode (default)",
1001 "Add Black Mode",
1002 "Add White Mode",
1003 "Erase Stone Mode",
1004 "Pass",
1005 "Next Variation",
1006 "Force Play Mode",
1007 "Mark Mode",
1008 "Circle Mode",
1009 "Square Mode",
1010 "Triangle Mode",
1011 "Label Mode",
1012 "Add/Edit Comment",
1013 "Done");
1015 while (!done)
1017 selection = rb->do_menu (&context_menu, &selection, NULL, false);
1019 switch (selection)
1021 case CTX_PLAY:
1022 play_mode = MODE_PLAY;
1023 done = true;
1024 break;
1026 case CTX_ADD_BLACK:
1027 play_mode = MODE_ADD_BLACK;
1028 done = true;
1029 break;
1031 case CTX_ADD_WHITE:
1032 play_mode = MODE_ADD_WHITE;
1033 done = true;
1034 break;
1036 case CTX_ERASE:
1037 play_mode = MODE_REMOVE;
1038 done = true;
1039 break;
1041 case CTX_PASS:
1042 if (!play_move_sgf (PASS_POS, current_player))
1044 rb->splash (HZ, "Error while passing!");
1046 done = true;
1047 break;
1049 case CTX_NEXT_VAR:
1050 if ((temp = next_variation_sgf ()) >= 0)
1052 draw_screen_display ();
1053 rb->splashf (2 * HZ / 3, "%d of %d", temp,
1054 num_variations_sgf ());
1055 draw_screen_display ();
1057 else
1059 if (num_variations_sgf () > 1)
1061 rb->splashf (HZ, "Error %d in next_variation_sgf", temp);
1063 else
1065 rb->splash (HZ, "No next variation");
1068 break;
1070 case CTX_FORCE:
1071 play_mode = MODE_FORCE_PLAY;
1072 done = true;
1073 break;
1075 case CTX_MARK:
1076 play_mode = MODE_MARK;
1077 done = true;
1078 break;
1080 case CTX_CIRCLE:
1081 play_mode = MODE_CIRCLE;
1082 done = true;
1083 break;
1085 case CTX_SQUARE:
1086 play_mode = MODE_SQUARE;
1087 done = true;
1088 break;
1090 case CTX_TRIANGLE:
1091 play_mode = MODE_TRIANGLE;
1092 done = true;
1093 break;
1095 case CTX_LABEL:
1096 play_mode = MODE_LABEL;
1097 done = true;
1098 break;
1100 case CTX_COMMENT:
1101 if (!do_comment_edit ())
1103 DEBUGF ("Editing comment failed\n");
1104 rb->splash (HZ, "Read or write failed!\n");
1106 done = true;
1107 break;
1109 case CTX_DONE:
1110 case GO_TO_ROOT:
1111 case GO_TO_PREVIOUS:
1112 case MENU_ATTACHED_USB:
1113 default:
1114 done = true;
1115 break;
1120 enum options_menu_selections
1122 OMENU_SHOW_VARIATIONS = 0,
1123 OMENU_DISABLE_POWEROFF,
1124 OMENU_AUTOSAVE_TIME,
1125 OMENU_AUTO_COMMENT
1128 static void
1129 do_options_menu (void)
1131 int selection;
1132 bool done = false;
1134 MENUITEM_STRINGLIST (options_menu, "Options Menu", NULL,
1135 "Show Child Variations?",
1136 "Disable Idle Poweroff?",
1137 "Idle Autosave Time",
1138 "Automatically Show Comments?");
1140 while (!done)
1142 selection = rb->do_menu (&options_menu, &selection, NULL, false);
1144 switch (selection)
1146 case OMENU_SHOW_VARIATIONS:
1147 rb->set_bool("Draw Variations?", &draw_variations);
1148 clear_marks_display ();
1149 set_all_marks_sgf ();
1150 if (draw_variations)
1152 mark_child_variations_sgf ();
1154 break;
1156 case OMENU_DISABLE_POWEROFF:
1157 rb->set_bool("Disable Idle Poweroff?", &disable_shutdown);
1158 break;
1160 case OMENU_AUTOSAVE_TIME:
1161 rb->set_int("Idle Autosave Time", "minutes", UNIT_INT,
1162 &autosave_time, NULL, 1, 0, MAX_AUTOSAVE,
1163 &autosave_formatter);
1164 autosave_counter = 0;
1165 break;
1167 case OMENU_AUTO_COMMENT:
1168 rb->set_bool("Auto Show Comments?", &auto_show_comments);
1169 break;
1171 case GO_TO_ROOT:
1172 case GO_TO_PREVIOUS:
1173 case MENU_ATTACHED_USB:
1174 default:
1175 done = true;
1176 break;
1182 static bool
1183 do_comment_edit (void)
1185 char cbuffer[512];
1187 rb->memset (cbuffer, 0, sizeof (cbuffer));
1189 if (read_comment_sgf (cbuffer, sizeof (cbuffer)) < 0)
1191 return false;
1194 if (!rb->kbd_input (cbuffer, sizeof (cbuffer)))
1196 /* user didn't edit, no reason to write it back */
1197 return true;
1200 if (write_comment_sgf (cbuffer) < 0)
1202 return false;
1205 return true;
1208 static enum prop_type_t
1209 menu_selection_to_prop (int selection)
1211 switch (selection)
1213 case GINFO_OVERTIME:
1214 return PROP_OVERTIME;
1215 case GINFO_RESULT:
1216 return PROP_RESULT;
1217 case GINFO_BLACK_PLAYER:
1218 return PROP_BLACK_NAME;
1219 case GINFO_BLACK_RANK:
1220 return PROP_BLACK_RANK;
1221 case GINFO_BLACK_TEAM:
1222 return PROP_BLACK_TEAM;
1223 case GINFO_WHITE_PLAYER:
1224 return PROP_WHITE_NAME;
1225 case GINFO_WHITE_RANK:
1226 return PROP_WHITE_RANK;
1227 case GINFO_WHITE_TEAM:
1228 return PROP_WHITE_TEAM;
1229 case GINFO_DATE:
1230 return PROP_DATE;
1231 case GINFO_EVENT:
1232 return PROP_EVENT;
1233 case GINFO_PLACE:
1234 return PROP_PLACE;
1235 case GINFO_ROUND:
1236 return PROP_ROUND;
1237 default:
1238 DEBUGF ("Tried to get prop from invalid menu selection!!!\n");
1239 return PROP_PLACE; /* just pick one, there's a major bug if
1240 we got here */