diff options
Diffstat (limited to 'apps/plugins/puzzles/rockbox.c')
-rw-r--r-- | apps/plugins/puzzles/rockbox.c | 535 |
1 files changed, 131 insertions, 404 deletions
diff --git a/apps/plugins/puzzles/rockbox.c b/apps/plugins/puzzles/rockbox.c index 263a19f421..27060208fc 100644 --- a/apps/plugins/puzzles/rockbox.c +++ b/apps/plugins/puzzles/rockbox.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * \/ \/ \/ \/ \/ | 7 | * \/ \/ \/ \/ \/ |
8 | * $Id$ | 8 | * $Id$ |
9 | * | 9 | * |
10 | * Copyright (C) 2016-2020 Franklin Wei | 10 | * Copyright (C) 2016-2024 Franklin Wei |
11 | * | 11 | * |
12 | * This program is free software; you can redistribute it and/or | 12 | * This program is free software; you can redistribute it and/or |
13 | * modify it under the terms of the GNU General Public License | 13 | * modify it under the terms of the GNU General Public License |
@@ -24,10 +24,9 @@ | |||
24 | * ================================ | 24 | * ================================ |
25 | * | 25 | * |
26 | * This file contains the majority of the rockbox-specific code for | 26 | * This file contains the majority of the rockbox-specific code for |
27 | * the sgt-puzzles port. It implements a set of functions for the | 27 | * the sgt-puzzles port. It implements an API for the backend to call |
28 | * backend to call to actually run the games, as well as rockbox UI | 28 | * to run the games, as well as the rockbox UI code (menus, input, |
29 | * code (menus, input, etc). For a good overview of the rest of the | 29 | * etc). For a good overview of the rest of the puzzles code, see: |
30 | * puzzles code, see: | ||
31 | * | 30 | * |
32 | * <https://www.chiark.greenend.org.uk/~sgtatham/puzzles/devel/>. | 31 | * <https://www.chiark.greenend.org.uk/~sgtatham/puzzles/devel/>. |
33 | * | 32 | * |
@@ -37,7 +36,7 @@ | |||
37 | * Contents of this file | 36 | * Contents of this file |
38 | * --------------------- | 37 | * --------------------- |
39 | * | 38 | * |
40 | * By rough order of appearnce in this file: | 39 | * By rough order of appearance in this file: |
41 | * | 40 | * |
42 | * 1) "Zoom" feature | 41 | * 1) "Zoom" feature |
43 | * | 42 | * |
@@ -62,8 +61,7 @@ | |||
62 | * mode switching. In commit 5094aaa, this behavior was changed so | 61 | * mode switching. In commit 5094aaa, this behavior was changed so |
63 | * that the frontend can now query the backend for the on-screen | 62 | * that the frontend can now query the backend for the on-screen |
64 | * cursor location and move the viewport accordingly through the | 63 | * cursor location and move the viewport accordingly through the |
65 | * new midend_get_cursor_location() API (which is not yet merged | 64 | * new midend_get_cursor_location() API. |
66 | * into Simon's tree as of October 2020). | ||
67 | * | 65 | * |
68 | * 2) Font management | 66 | * 2) Font management |
69 | * | 67 | * |
@@ -82,8 +80,8 @@ | |||
82 | * | 80 | * |
83 | * 3) Drawing API | 81 | * 3) Drawing API |
84 | * | 82 | * |
85 | * The sgt-puzzles backend wants a set of function pointers to the | 83 | * The sgt-puzzles backend wants a set of function pointers to |
86 | * usual drawing primitives. [1] If the `zoom_enabled' switch is | 84 | * typical drawing primitives. [1] If the `zoom_enabled' switch is |
87 | * on, these call upon the "zoomed" drawing routines in (1). | 85 | * on, these call upon the "zoomed" drawing routines in (1). |
88 | * | 86 | * |
89 | * In the normal un-zoomed case, these functions generally rely on | 87 | * In the normal un-zoomed case, these functions generally rely on |
@@ -108,7 +106,7 @@ | |||
108 | * a) Mouse mode | 106 | * a) Mouse mode |
109 | * | 107 | * |
110 | * This mode is designed to accommodate puzzles without a | 108 | * This mode is designed to accommodate puzzles without a |
111 | * keyboard or cursor interface (currently only "Loopy"). We | 109 | * keyboard or cursor interface (currently only Loopyx). We |
112 | * remap the cursor keys to move an on-screen cursor rather | 110 | * remap the cursor keys to move an on-screen cursor rather |
113 | * than sending arrow keys to the game. | 111 | * than sending arrow keys to the game. |
114 | * | 112 | * |
@@ -163,6 +161,11 @@ | |||
163 | * cases by waiting until a key has been released before we | 161 | * cases by waiting until a key has been released before we |
164 | * send the input keystroke(s) to the game. | 162 | * send the input keystroke(s) to the game. |
165 | * | 163 | * |
164 | * e) Key repeat | ||
165 | * | ||
166 | * In some games, we would like to send repeated key events to | ||
167 | * allow long drags. Currently, this is only used in Untangle. | ||
168 | * | ||
166 | * 5) Game configuration and preset management | 169 | * 5) Game configuration and preset management |
167 | * | 170 | * |
168 | * The backend games specify a hierarchy of user-adjustable game | 171 | * The backend games specify a hierarchy of user-adjustable game |
@@ -170,6 +173,10 @@ | |||
170 | * generation, etc. Also supplied are a set of "presets" that | 173 | * generation, etc. Also supplied are a set of "presets" that |
171 | * specify a predetermined set of configuration parameters. | 174 | * specify a predetermined set of configuration parameters. |
172 | * | 175 | * |
176 | * In 2023, Simon introduced a User Preferences system that allows | ||
177 | * further customization of the game UI (e.g., "snap to grid" in | ||
178 | * Untangle). Rockbox support for this was added in July 2024. | ||
179 | * | ||
173 | * 6) In-game help | 180 | * 6) In-game help |
174 | * | 181 | * |
175 | * The sgt-puzzles manual (src/puzzles.but) contains a chapter | 182 | * The sgt-puzzles manual (src/puzzles.but) contains a chapter |
@@ -315,6 +322,7 @@ static struct viewport clip_rect; | |||
315 | static bool clipped = false, zoom_enabled = false, view_mode = true, mouse_mode = false; | 322 | static bool clipped = false, zoom_enabled = false, view_mode = true, mouse_mode = false; |
316 | 323 | ||
317 | static int mouse_x, mouse_y; | 324 | static int mouse_x, mouse_y; |
325 | static bool mouse_dragging = false; /* for sticky mode only */ | ||
318 | 326 | ||
319 | extern bool audiobuf_available; /* defined in rbmalloc.c */ | 327 | extern bool audiobuf_available; /* defined in rbmalloc.c */ |
320 | 328 | ||
@@ -339,6 +347,7 @@ static struct { | |||
339 | bool ignore_repeats; /* ignore repeated button events (currently in all games but Untangle) */ | 347 | bool ignore_repeats; /* ignore repeated button events (currently in all games but Untangle) */ |
340 | bool rclick_on_hold; /* if in mouse mode, send right-click on long-press of select */ | 348 | bool rclick_on_hold; /* if in mouse mode, send right-click on long-press of select */ |
341 | bool numerical_chooser; /* repurpose select to activate a numerical chooser */ | 349 | bool numerical_chooser; /* repurpose select to activate a numerical chooser */ |
350 | bool sticky_mouse; /* if mouse left button should be persistent and toggled on/off */ | ||
342 | } input_settings; | 351 | } input_settings; |
343 | 352 | ||
344 | static bool accept_input = true; | 353 | static bool accept_input = true; |
@@ -741,12 +750,13 @@ static void rb_color(int n) | |||
741 | fatal("bad color %d", n); | 750 | fatal("bad color %d", n); |
742 | return; | 751 | return; |
743 | } | 752 | } |
744 | rb->lcd_set_foreground(colors[n]); | 753 | if(colors) |
754 | rb->lcd_set_foreground(colors[n]); | ||
745 | } | 755 | } |
746 | 756 | ||
747 | /* clipping is implemented through viewports and offsetting | 757 | /* clipping is implemented through viewports and offsetting |
748 | * coordinates */ | 758 | * coordinates */ |
749 | static void rb_clip(void *handle, int x, int y, int w, int h) | 759 | static void rb_clip(drawing *dr, int x, int y, int w, int h) |
750 | { | 760 | { |
751 | if(!zoom_enabled) | 761 | if(!zoom_enabled) |
752 | { | 762 | { |
@@ -776,7 +786,7 @@ static void rb_clip(void *handle, int x, int y, int w, int h) | |||
776 | } | 786 | } |
777 | } | 787 | } |
778 | 788 | ||
779 | static void rb_unclip(void *handle) | 789 | static void rb_unclip(drawing *dr) |
780 | { | 790 | { |
781 | if(!zoom_enabled) | 791 | if(!zoom_enabled) |
782 | { | 792 | { |
@@ -793,7 +803,7 @@ static void rb_unclip(void *handle) | |||
793 | } | 803 | } |
794 | } | 804 | } |
795 | 805 | ||
796 | static void rb_draw_text(void *handle, int x, int y, int fonttype, | 806 | static void rb_draw_text(drawing *dr, int x, int y, int fonttype, |
797 | int fontsize, int align, int color, const char *text) | 807 | int fontsize, int align, int color, const char *text) |
798 | { | 808 | { |
799 | (void) fontsize; | 809 | (void) fontsize; |
@@ -858,7 +868,7 @@ static void rb_draw_text(void *handle, int x, int y, int fonttype, | |||
858 | } | 868 | } |
859 | } | 869 | } |
860 | 870 | ||
861 | static void rb_draw_rect(void *handle, int x, int y, int w, int h, int color) | 871 | static void rb_draw_rect(drawing *dr, int x, int y, int w, int h, int color) |
862 | { | 872 | { |
863 | rb_color(color); | 873 | rb_color(color); |
864 | if(!zoom_enabled) | 874 | if(!zoom_enabled) |
@@ -1000,7 +1010,7 @@ static void draw_antialiased_line(fb_data *fb, int w, int h, int x0, int y0, int | |||
1000 | } | 1010 | } |
1001 | } | 1011 | } |
1002 | 1012 | ||
1003 | static void rb_draw_line(void *handle, int x1, int y1, int x2, int y2, | 1013 | static void rb_draw_line(drawing *dr, int x1, int y1, int x2, int y2, |
1004 | int color) | 1014 | int color) |
1005 | { | 1015 | { |
1006 | rb_color(color); | 1016 | rb_color(color); |
@@ -1028,349 +1038,7 @@ static void rb_draw_line(void *handle, int x1, int y1, int x2, int y2, | |||
1028 | } | 1038 | } |
1029 | } | 1039 | } |
1030 | 1040 | ||
1031 | #if 0 | 1041 | static void rb_draw_circle(drawing *dr, int cx, int cy, int radius, |
1032 | /* | ||
1033 | * draw filled polygon | ||
1034 | * originally by Sebastian Leonhardt (ulmutul) | ||
1035 | * 'count' : number of coordinate pairs | ||
1036 | * 'pxy': array of coordinates. pxy[0]=x0,pxy[1]=y0,... | ||
1037 | * note: provide space for one extra coordinate, because the starting point | ||
1038 | * will automatically be inserted as end point. | ||
1039 | */ | ||
1040 | |||
1041 | /* | ||
1042 | * helper function: | ||
1043 | * find points of intersection between polygon and scanline | ||
1044 | */ | ||
1045 | |||
1046 | #define MAX_INTERSECTION 32 | ||
1047 | |||
1048 | static void fill_poly_line(int scanline, int count, int *pxy) | ||
1049 | { | ||
1050 | int i; | ||
1051 | int j; | ||
1052 | int num_of_intersects; | ||
1053 | int direct, old_direct; | ||
1054 | //intersections of every line with scanline (y-coord) | ||
1055 | int intersection[MAX_INTERSECTION]; | ||
1056 | /* add starting point as ending point */ | ||
1057 | pxy[count*2] = pxy[0]; | ||
1058 | pxy[count*2+1] = pxy[1]; | ||
1059 | |||
1060 | old_direct=0; | ||
1061 | num_of_intersects=0; | ||
1062 | for (i=0; i<count*2; i+=2) { | ||
1063 | int x1=pxy[i]; | ||
1064 | int y1=pxy[i+1]; | ||
1065 | int x2=pxy[i+2]; | ||
1066 | int y2=pxy[i+3]; | ||
1067 | // skip if line is outside of scanline | ||
1068 | if (y1 < y2) { | ||
1069 | if (scanline < y1 || scanline > y2) | ||
1070 | continue; | ||
1071 | } | ||
1072 | else { | ||
1073 | if (scanline < y2 || scanline > y1) | ||
1074 | continue; | ||
1075 | } | ||
1076 | // calculate x-coord of intersection | ||
1077 | if (y1==y2) { | ||
1078 | direct=0; | ||
1079 | } | ||
1080 | else { | ||
1081 | direct = y1>y2 ? 1 : -1; | ||
1082 | // omit double intersections, if both lines lead in the same direction | ||
1083 | intersection[num_of_intersects] = | ||
1084 | x1+((scanline-y1)*(x2-x1))/(y2-y1); | ||
1085 | if ( (direct!=old_direct) | ||
1086 | || (intersection[num_of_intersects] != intersection[num_of_intersects-1]) | ||
1087 | ) | ||
1088 | ++num_of_intersects; | ||
1089 | } | ||
1090 | old_direct = direct; | ||
1091 | } | ||
1092 | |||
1093 | // sort points of intersection | ||
1094 | for (i=0; i<num_of_intersects-1; ++i) { | ||
1095 | for (j=i+1; j<num_of_intersects; ++j) { | ||
1096 | if (intersection[j]<intersection[i]) { | ||
1097 | int temp=intersection[i]; | ||
1098 | intersection[i]=intersection[j]; | ||
1099 | intersection[j]=temp; | ||
1100 | } | ||
1101 | } | ||
1102 | } | ||
1103 | // draw | ||
1104 | for (i=0; i<num_of_intersects; i+=2) { | ||
1105 | rb->lcd_hline(intersection[i], intersection[i+1], scanline); | ||
1106 | } | ||
1107 | } | ||
1108 | |||
1109 | /* two extra elements at end of pxy needed */ | ||
1110 | static void v_fillarea(int count, int *pxy) | ||
1111 | { | ||
1112 | int i; | ||
1113 | int y1, y2; | ||
1114 | |||
1115 | // find min and max y coords | ||
1116 | y1=y2=pxy[1]; | ||
1117 | for (i=3; i<count*2; i+=2) { | ||
1118 | if (pxy[i] < y1) y1 = pxy[i]; | ||
1119 | else if (pxy[i] > y2) y2 = pxy[i]; | ||
1120 | } | ||
1121 | |||
1122 | for (i=y1; i<=y2; ++i) { | ||
1123 | fill_poly_line(i, count, pxy); | ||
1124 | } | ||
1125 | } | ||
1126 | #endif | ||
1127 | |||
1128 | /* I'm a horrible person: this was copy-pasta'd straight from | ||
1129 | * xlcd_draw.c */ | ||
1130 | |||
1131 | /* sort the given coordinates by increasing x value */ | ||
1132 | static void sort_points_by_increasing_x(int* x1, int* y1, | ||
1133 | int* x2, int* y2, | ||
1134 | int* x3, int* y3) | ||
1135 | { | ||
1136 | int x, y; | ||
1137 | if (*x1 > *x3) | ||
1138 | { | ||
1139 | if (*x2 < *x3) /* x2 < x3 < x1 */ | ||
1140 | { | ||
1141 | x = *x1; *x1 = *x2; *x2 = *x3; *x3 = x; | ||
1142 | y = *y1; *y1 = *y2; *y2 = *y3; *y3 = y; | ||
1143 | } | ||
1144 | else if (*x2 > *x1) /* x3 < x1 < x2 */ | ||
1145 | { | ||
1146 | x = *x1; *x1 = *x3; *x3 = *x2; *x2 = x; | ||
1147 | y = *y1; *y1 = *y3; *y3 = *y2; *y2 = y; | ||
1148 | } | ||
1149 | else /* x3 <= x2 <= x1 */ | ||
1150 | { | ||
1151 | x = *x1; *x1 = *x3; *x3 = x; | ||
1152 | y = *y1; *y1 = *y3; *y3 = y; | ||
1153 | } | ||
1154 | } | ||
1155 | else | ||
1156 | { | ||
1157 | if (*x2 < *x1) /* x2 < x1 <= x3 */ | ||
1158 | { | ||
1159 | x = *x1; *x1 = *x2; *x2 = x; | ||
1160 | y = *y1; *y1 = *y2; *y2 = y; | ||
1161 | } | ||
1162 | else if (*x2 > *x3) /* x1 <= x3 < x2 */ | ||
1163 | { | ||
1164 | x = *x2; *x2 = *x3; *x3 = x; | ||
1165 | y = *y2; *y2 = *y3; *y3 = y; | ||
1166 | } | ||
1167 | /* else already sorted */ | ||
1168 | } | ||
1169 | } | ||
1170 | |||
1171 | #define sort_points_by_increasing_y(x1, y1, x2, y2, x3, y3) \ | ||
1172 | sort_points_by_increasing_x(y1, x1, y2, x2, y3, x3) | ||
1173 | |||
1174 | /* draw a filled triangle, using horizontal lines for speed */ | ||
1175 | static void zoom_filltriangle(int x1, int y1, | ||
1176 | int x2, int y2, | ||
1177 | int x3, int y3) | ||
1178 | { | ||
1179 | long fp_x1, fp_x2, fp_dx1, fp_dx2; | ||
1180 | int y; | ||
1181 | sort_points_by_increasing_y(&x1, &y1, &x2, &y2, &x3, &y3); | ||
1182 | |||
1183 | if (y1 < y3) /* draw */ | ||
1184 | { | ||
1185 | fp_dx1 = ((x3 - x1) << 16) / (y3 - y1); | ||
1186 | fp_x1 = (x1 << 16) + (1<<15) + (fp_dx1 >> 1); | ||
1187 | |||
1188 | if (y1 < y2) /* first part */ | ||
1189 | { | ||
1190 | fp_dx2 = ((x2 - x1) << 16) / (y2 - y1); | ||
1191 | fp_x2 = (x1 << 16) + (1<<15) + (fp_dx2 >> 1); | ||
1192 | for (y = y1; y < y2; y++) | ||
1193 | { | ||
1194 | zoom_hline(fp_x1 >> 16, fp_x2 >> 16, y); | ||
1195 | fp_x1 += fp_dx1; | ||
1196 | fp_x2 += fp_dx2; | ||
1197 | } | ||
1198 | } | ||
1199 | if (y2 < y3) /* second part */ | ||
1200 | { | ||
1201 | fp_dx2 = ((x3 - x2) << 16) / (y3 - y2); | ||
1202 | fp_x2 = (x2 << 16) + (1<<15) + (fp_dx2 >> 1); | ||
1203 | for (y = y2; y < y3; y++) | ||
1204 | { | ||
1205 | zoom_hline(fp_x1 >> 16, fp_x2 >> 16, y); | ||
1206 | fp_x1 += fp_dx1; | ||
1207 | fp_x2 += fp_dx2; | ||
1208 | } | ||
1209 | } | ||
1210 | } | ||
1211 | } | ||
1212 | |||
1213 | /* Should probably refactor this */ | ||
1214 | static void rb_draw_poly(void *handle, int *coords, int npoints, | ||
1215 | int fillcolor, int outlinecolor) | ||
1216 | { | ||
1217 | if(!zoom_enabled) | ||
1218 | { | ||
1219 | LOGF("rb_draw_poly"); | ||
1220 | |||
1221 | if(fillcolor >= 0) | ||
1222 | { | ||
1223 | rb_color(fillcolor); | ||
1224 | #if 1 | ||
1225 | /* serious hack: draw a bunch of triangles between adjacent points */ | ||
1226 | /* this generally works, even with some concave polygons */ | ||
1227 | for(int i = 2; i < npoints; ++i) | ||
1228 | { | ||
1229 | int x1, y1, x2, y2, x3, y3; | ||
1230 | x1 = coords[0]; | ||
1231 | y1 = coords[1]; | ||
1232 | x2 = coords[(i - 1) * 2]; | ||
1233 | y2 = coords[(i - 1) * 2 + 1]; | ||
1234 | x3 = coords[i * 2]; | ||
1235 | y3 = coords[i * 2 + 1]; | ||
1236 | offset_coords(&x1, &y1); | ||
1237 | offset_coords(&x2, &y2); | ||
1238 | offset_coords(&x3, &y3); | ||
1239 | xlcd_filltriangle(x1, y1, | ||
1240 | x2, y2, | ||
1241 | x3, y3); | ||
1242 | |||
1243 | #ifdef DEBUG_MENU | ||
1244 | if(debug_settings.polyanim) | ||
1245 | { | ||
1246 | rb->lcd_update(); | ||
1247 | rb->sleep(HZ/4); | ||
1248 | } | ||
1249 | #endif | ||
1250 | #if 0 | ||
1251 | /* debug code */ | ||
1252 | rb->lcd_set_foreground(LCD_RGBPACK(255,0,0)); | ||
1253 | rb->lcd_drawpixel(x1, y1); | ||
1254 | rb->lcd_drawpixel(x2, y2); | ||
1255 | rb->lcd_drawpixel(x3, y3); | ||
1256 | rb->lcd_update(); | ||
1257 | rb->sleep(HZ); | ||
1258 | rb_color(fillcolor); | ||
1259 | rb->lcd_drawpixel(x1, y1); | ||
1260 | rb->lcd_drawpixel(x2, y2); | ||
1261 | rb->lcd_drawpixel(x3, y3); | ||
1262 | rb->lcd_update(); | ||
1263 | #endif | ||
1264 | } | ||
1265 | #else | ||
1266 | int *pxy = smalloc(sizeof(int) * 2 * npoints + 2); | ||
1267 | /* copy points, offsetted */ | ||
1268 | for(int i = 0; i < npoints; ++i) | ||
1269 | { | ||
1270 | pxy[2 * i + 0] = coords[2 * i + 0]; | ||
1271 | pxy[2 * i + 1] = coords[2 * i + 1]; | ||
1272 | offset_coords(&pxy[2*i+0], &pxy[2*i+1]); | ||
1273 | } | ||
1274 | v_fillarea(npoints, pxy); | ||
1275 | sfree(pxy); | ||
1276 | #endif | ||
1277 | } | ||
1278 | |||
1279 | /* draw outlines last so they're not covered by the fill */ | ||
1280 | assert(outlinecolor >= 0); | ||
1281 | rb_color(outlinecolor); | ||
1282 | |||
1283 | for(int i = 1; i < npoints; ++i) | ||
1284 | { | ||
1285 | int x1, y1, x2, y2; | ||
1286 | x1 = coords[2 * (i - 1)]; | ||
1287 | y1 = coords[2 * (i - 1) + 1]; | ||
1288 | x2 = coords[2 * i]; | ||
1289 | y2 = coords[2 * i + 1]; | ||
1290 | if(debug_settings.no_aa) | ||
1291 | { | ||
1292 | offset_coords(&x1, &y1); | ||
1293 | offset_coords(&x2, &y2); | ||
1294 | rb->lcd_drawline(x1, y1, | ||
1295 | x2, y2); | ||
1296 | } | ||
1297 | else | ||
1298 | draw_antialiased_line(lcd_fb, LCD_WIDTH, LCD_HEIGHT, x1, y1, x2, y2); | ||
1299 | |||
1300 | #ifdef DEBUG_MENU | ||
1301 | if(debug_settings.polyanim) | ||
1302 | { | ||
1303 | rb->lcd_update(); | ||
1304 | rb->sleep(HZ/4); | ||
1305 | } | ||
1306 | #endif | ||
1307 | } | ||
1308 | |||
1309 | int x1, y1, x2, y2; | ||
1310 | x1 = coords[0]; | ||
1311 | y1 = coords[1]; | ||
1312 | x2 = coords[2 * (npoints - 1)]; | ||
1313 | y2 = coords[2 * (npoints - 1) + 1]; | ||
1314 | if(debug_settings.no_aa) | ||
1315 | { | ||
1316 | offset_coords(&x1, &y1); | ||
1317 | offset_coords(&x2, &y2); | ||
1318 | |||
1319 | rb->lcd_drawline(x1, y1, | ||
1320 | x2, y2); | ||
1321 | } | ||
1322 | else | ||
1323 | draw_antialiased_line(lcd_fb, LCD_WIDTH, LCD_HEIGHT, x1, y1, x2, y2); | ||
1324 | } | ||
1325 | else | ||
1326 | { | ||
1327 | LOGF("rb_draw_poly"); | ||
1328 | |||
1329 | if(fillcolor >= 0) | ||
1330 | { | ||
1331 | rb_color(fillcolor); | ||
1332 | |||
1333 | /* serious hack: draw a bunch of triangles between adjacent points */ | ||
1334 | /* this generally works, even with some concave polygons */ | ||
1335 | for(int i = 2; i < npoints; ++i) | ||
1336 | { | ||
1337 | int x1, y1, x2, y2, x3, y3; | ||
1338 | x1 = coords[0]; | ||
1339 | y1 = coords[1]; | ||
1340 | x2 = coords[(i - 1) * 2]; | ||
1341 | y2 = coords[(i - 1) * 2 + 1]; | ||
1342 | x3 = coords[i * 2]; | ||
1343 | y3 = coords[i * 2 + 1]; | ||
1344 | zoom_filltriangle(x1, y1, | ||
1345 | x2, y2, | ||
1346 | x3, y3); | ||
1347 | } | ||
1348 | } | ||
1349 | |||
1350 | /* draw outlines last so they're not covered by the fill */ | ||
1351 | assert(outlinecolor >= 0); | ||
1352 | rb_color(outlinecolor); | ||
1353 | |||
1354 | for(int i = 1; i < npoints; ++i) | ||
1355 | { | ||
1356 | int x1, y1, x2, y2; | ||
1357 | x1 = coords[2 * (i - 1)]; | ||
1358 | y1 = coords[2 * (i - 1) + 1]; | ||
1359 | x2 = coords[2 * i]; | ||
1360 | y2 = coords[2 * i + 1]; | ||
1361 | draw_antialiased_line(zoom_fb, zoom_w, zoom_h, x1, y1, x2, y2); | ||
1362 | } | ||
1363 | |||
1364 | int x1, y1, x2, y2; | ||
1365 | x1 = coords[0]; | ||
1366 | y1 = coords[1]; | ||
1367 | x2 = coords[2 * (npoints - 1)]; | ||
1368 | y2 = coords[2 * (npoints - 1) + 1]; | ||
1369 | draw_antialiased_line(zoom_fb, zoom_w, zoom_h, x1, y1, x2, y2); | ||
1370 | } | ||
1371 | } | ||
1372 | |||
1373 | static void rb_draw_circle(void *handle, int cx, int cy, int radius, | ||
1374 | int fillcolor, int outlinecolor) | 1042 | int fillcolor, int outlinecolor) |
1375 | { | 1043 | { |
1376 | if(!zoom_enabled) | 1044 | if(!zoom_enabled) |
@@ -1442,7 +1110,7 @@ static void trim_rect(int *x, int *y, int *w, int *h) | |||
1442 | *h = y1 - y0; | 1110 | *h = y1 - y0; |
1443 | } | 1111 | } |
1444 | 1112 | ||
1445 | static blitter *rb_blitter_new(void *handle, int w, int h) | 1113 | static blitter *rb_blitter_new(drawing *dr, int w, int h) |
1446 | { | 1114 | { |
1447 | LOGF("rb_blitter_new"); | 1115 | LOGF("rb_blitter_new"); |
1448 | blitter *b = snew(blitter); | 1116 | blitter *b = snew(blitter); |
@@ -1453,7 +1121,7 @@ static blitter *rb_blitter_new(void *handle, int w, int h) | |||
1453 | return b; | 1121 | return b; |
1454 | } | 1122 | } |
1455 | 1123 | ||
1456 | static void rb_blitter_free(void *handle, blitter *bl) | 1124 | static void rb_blitter_free(drawing *dr, blitter *bl) |
1457 | { | 1125 | { |
1458 | LOGF("rb_blitter_free"); | 1126 | LOGF("rb_blitter_free"); |
1459 | sfree(bl->bmp.data); | 1127 | sfree(bl->bmp.data); |
@@ -1462,7 +1130,7 @@ static void rb_blitter_free(void *handle, blitter *bl) | |||
1462 | } | 1130 | } |
1463 | 1131 | ||
1464 | /* copy a section of the framebuffer */ | 1132 | /* copy a section of the framebuffer */ |
1465 | static void rb_blitter_save(void *handle, blitter *bl, int x, int y) | 1133 | static void rb_blitter_save(drawing *dr, blitter *bl, int x, int y) |
1466 | { | 1134 | { |
1467 | /* no viewport offset */ | 1135 | /* no viewport offset */ |
1468 | #if LCD_STRIDEFORMAT == VERTICAL_STRIDE | 1136 | #if LCD_STRIDEFORMAT == VERTICAL_STRIDE |
@@ -1491,7 +1159,7 @@ static void rb_blitter_save(void *handle, blitter *bl, int x, int y) | |||
1491 | #endif | 1159 | #endif |
1492 | } | 1160 | } |
1493 | 1161 | ||
1494 | static void rb_blitter_load(void *handle, blitter *bl, int x, int y) | 1162 | static void rb_blitter_load(drawing *dr, blitter *bl, int x, int y) |
1495 | { | 1163 | { |
1496 | LOGF("rb_blitter_load"); | 1164 | LOGF("rb_blitter_load"); |
1497 | if(!bl->have_data) | 1165 | if(!bl->have_data) |
@@ -1521,7 +1189,7 @@ static void rb_blitter_load(void *handle, blitter *bl, int x, int y) | |||
1521 | } | 1189 | } |
1522 | } | 1190 | } |
1523 | 1191 | ||
1524 | static void rb_draw_update(void *handle, int x, int y, int w, int h) | 1192 | static void rb_draw_update(drawing *dr, int x, int y, int w, int h) |
1525 | { | 1193 | { |
1526 | LOGF("rb_draw_update(%d, %d, %d, %d)", x, y, w, h); | 1194 | LOGF("rb_draw_update(%d, %d, %d, %d)", x, y, w, h); |
1527 | 1195 | ||
@@ -1545,9 +1213,9 @@ static void rb_draw_update(void *handle, int x, int y, int w, int h) | |||
1545 | need_draw_update = true; | 1213 | need_draw_update = true; |
1546 | } | 1214 | } |
1547 | 1215 | ||
1548 | static void rb_start_draw(void *handle) | 1216 | static void rb_start_draw(drawing *dr) |
1549 | { | 1217 | { |
1550 | (void) handle; | 1218 | (void) dr; |
1551 | 1219 | ||
1552 | /* ... mumble mumble ... not ... reentrant ... mumble mumble ... */ | 1220 | /* ... mumble mumble ... not ... reentrant ... mumble mumble ... */ |
1553 | 1221 | ||
@@ -1558,9 +1226,9 @@ static void rb_start_draw(void *handle) | |||
1558 | ud_d = LCD_HEIGHT; | 1226 | ud_d = LCD_HEIGHT; |
1559 | } | 1227 | } |
1560 | 1228 | ||
1561 | static void rb_end_draw(void *handle) | 1229 | static void rb_end_draw(drawing *dr) |
1562 | { | 1230 | { |
1563 | (void) handle; | 1231 | (void) dr; |
1564 | 1232 | ||
1565 | if(debug_settings.highlight_cursor) | 1233 | if(debug_settings.highlight_cursor) |
1566 | { | 1234 | { |
@@ -1587,7 +1255,7 @@ static void rb_end_draw(void *handle) | |||
1587 | #endif | 1255 | #endif |
1588 | } | 1256 | } |
1589 | 1257 | ||
1590 | static void rb_status_bar(void *handle, const char *text) | 1258 | static void rb_status_bar(drawing *dr, const char *text) |
1591 | { | 1259 | { |
1592 | if(titlebar) | 1260 | if(titlebar) |
1593 | sfree(titlebar); | 1261 | sfree(titlebar); |
@@ -1619,7 +1287,8 @@ static void draw_title(bool clear_first) | |||
1619 | rb->lcd_setfont(cur_font = FONT_UI); | 1287 | rb->lcd_setfont(cur_font = FONT_UI); |
1620 | rb->lcd_getstringsize(str, &w, &h); | 1288 | rb->lcd_getstringsize(str, &w, &h); |
1621 | 1289 | ||
1622 | rb->lcd_set_foreground(BG_COLOR); | 1290 | |
1291 | rb->lcd_set_foreground(colors ? colors[0] : BG_COLOR); | ||
1623 | rb->lcd_fillrect(0, LCD_HEIGHT - h, clear_first ? LCD_WIDTH : w, h); | 1292 | rb->lcd_fillrect(0, LCD_HEIGHT - h, clear_first ? LCD_WIDTH : w, h); |
1624 | 1293 | ||
1625 | rb->lcd_set_drawmode(DRMODE_FG); | 1294 | rb->lcd_set_drawmode(DRMODE_FG); |
@@ -1685,7 +1354,7 @@ static void draw_mouse(void) | |||
1685 | * glyph exists in a font) */ | 1354 | * glyph exists in a font) */ |
1686 | #if 0 | 1355 | #if 0 |
1687 | /* See: https://www.chiark.greenend.org.uk/~sgtatham/puzzles/devel/drawing.html#drawing-text-fallback */ | 1356 | /* See: https://www.chiark.greenend.org.uk/~sgtatham/puzzles/devel/drawing.html#drawing-text-fallback */ |
1688 | static char *rb_text_fallback(void *handle, const char *const *strings, | 1357 | static char *rb_text_fallback(drawing *dr, const char *const *strings, |
1689 | int nstrings) | 1358 | int nstrings) |
1690 | { | 1359 | { |
1691 | struct font *pf = rb->font_get(cur_font); | 1360 | struct font *pf = rb->font_get(cur_font); |
@@ -1718,10 +1387,11 @@ static char *rb_text_fallback(void *handle, const char *const *strings, | |||
1718 | #endif | 1387 | #endif |
1719 | 1388 | ||
1720 | const drawing_api rb_drawing = { | 1389 | const drawing_api rb_drawing = { |
1390 | 1, | ||
1721 | rb_draw_text, | 1391 | rb_draw_text, |
1722 | rb_draw_rect, | 1392 | rb_draw_rect, |
1723 | rb_draw_line, | 1393 | rb_draw_line, |
1724 | rb_draw_poly, | 1394 | draw_polygon_fallback, |
1725 | rb_draw_circle, | 1395 | rb_draw_circle, |
1726 | rb_draw_update, | 1396 | rb_draw_update, |
1727 | rb_clip, | 1397 | rb_clip, |
@@ -2016,9 +1686,17 @@ static int process_input(int tmo, bool do_pausemenu) | |||
2016 | LOGF("sending left click"); | 1686 | LOGF("sending left click"); |
2017 | send_click(LEFT_BUTTON, true); /* right-click is handled earlier */ | 1687 | send_click(LEFT_BUTTON, true); /* right-click is handled earlier */ |
2018 | } | 1688 | } |
2019 | } | 1689 | } else if(input_settings.sticky_mouse) { |
2020 | else | 1690 | if(pressed & BTN_FIRE) { |
2021 | { | 1691 | send_click(LEFT_BUTTON, false); |
1692 | accept_input = false; | ||
1693 | mouse_dragging = !mouse_dragging; | ||
1694 | } else if(mouse_dragging) { | ||
1695 | send_click(LEFT_DRAG, false); | ||
1696 | } else { | ||
1697 | send_click(LEFT_RELEASE, false); | ||
1698 | } | ||
1699 | } else { | ||
2022 | if(pressed & BTN_FIRE) { | 1700 | if(pressed & BTN_FIRE) { |
2023 | send_click(LEFT_BUTTON, false); | 1701 | send_click(LEFT_BUTTON, false); |
2024 | accept_input = false; | 1702 | accept_input = false; |
@@ -2268,7 +1946,7 @@ static void zoom(void) | |||
2268 | zoom_clipl = 0; | 1946 | zoom_clipl = 0; |
2269 | zoom_clipr = zoom_w; | 1947 | zoom_clipr = zoom_w; |
2270 | 1948 | ||
2271 | midend_size(me, &zoom_w, &zoom_h, true); | 1949 | midend_size(me, &zoom_w, &zoom_h, true, 1.0); |
2272 | 1950 | ||
2273 | /* Allocating the framebuffer will mostly likely grab the | 1951 | /* Allocating the framebuffer will mostly likely grab the |
2274 | * audiobuffer, which will make impossible to load new fonts, and | 1952 | * audiobuffer, which will make impossible to load new fonts, and |
@@ -2448,7 +2126,6 @@ static int list_choose(const char *list_str, const char *title, int sel) | |||
2448 | struct gui_synclist list; | 2126 | struct gui_synclist list; |
2449 | 2127 | ||
2450 | rb->gui_synclist_init(&list, &config_choices_formatter, (void*)list_str, false, 1, NULL); | 2128 | rb->gui_synclist_init(&list, &config_choices_formatter, (void*)list_str, false, 1, NULL); |
2451 | rb->gui_synclist_set_icon_callback(&list, NULL); | ||
2452 | rb->gui_synclist_set_nb_items(&list, n); | 2129 | rb->gui_synclist_set_nb_items(&list, n); |
2453 | 2130 | ||
2454 | rb->gui_synclist_select_item(&list, sel); | 2131 | rb->gui_synclist_select_item(&list, sel); |
@@ -2634,10 +2311,10 @@ const char *config_formatter(int sel, void *data, char *buf, size_t len) | |||
2634 | return buf; | 2311 | return buf; |
2635 | } | 2312 | } |
2636 | 2313 | ||
2637 | static bool config_menu(void) | 2314 | static bool config_menu_core(int which) |
2638 | { | 2315 | { |
2639 | char *title; | 2316 | char *title; |
2640 | config_item *config = midend_get_config(me, CFG_SETTINGS, &title); | 2317 | config_item *config = midend_get_config(me, which, &title); |
2641 | 2318 | ||
2642 | rb->lcd_setfont(cur_font = FONT_UI); | 2319 | rb->lcd_setfont(cur_font = FONT_UI); |
2643 | 2320 | ||
@@ -2661,7 +2338,6 @@ static bool config_menu(void) | |||
2661 | struct gui_synclist list; | 2338 | struct gui_synclist list; |
2662 | 2339 | ||
2663 | rb->gui_synclist_init(&list, &config_formatter, config, false, 1, NULL); | 2340 | rb->gui_synclist_init(&list, &config_formatter, config, false, 1, NULL); |
2664 | rb->gui_synclist_set_icon_callback(&list, NULL); | ||
2665 | rb->gui_synclist_set_nb_items(&list, n); | 2341 | rb->gui_synclist_set_nb_items(&list, n); |
2666 | 2342 | ||
2667 | rb->gui_synclist_select_item(&list, 0); | 2343 | rb->gui_synclist_select_item(&list, 0); |
@@ -2689,7 +2365,7 @@ static bool config_menu(void) | |||
2689 | old_str = dupstr(old.u.string.sval); | 2365 | old_str = dupstr(old.u.string.sval); |
2690 | 2366 | ||
2691 | bool freed_str = do_configure_item(config, pos); | 2367 | bool freed_str = do_configure_item(config, pos); |
2692 | const char *err = midend_set_config(me, CFG_SETTINGS, config); | 2368 | const char *err = midend_set_config(me, which, config); |
2693 | 2369 | ||
2694 | if(err) | 2370 | if(err) |
2695 | { | 2371 | { |
@@ -2728,6 +2404,16 @@ done: | |||
2728 | return success; | 2404 | return success; |
2729 | } | 2405 | } |
2730 | 2406 | ||
2407 | static bool config_menu(void) | ||
2408 | { | ||
2409 | return config_menu_core(CFG_SETTINGS); | ||
2410 | } | ||
2411 | |||
2412 | static bool preferences_menu(void) | ||
2413 | { | ||
2414 | return config_menu_core(CFG_PREFS); | ||
2415 | } | ||
2416 | |||
2731 | static const char *preset_formatter(int sel, void *data, char *buf, size_t len) | 2417 | static const char *preset_formatter(int sel, void *data, char *buf, size_t len) |
2732 | { | 2418 | { |
2733 | struct preset_menu *menu = data; | 2419 | struct preset_menu *menu = data; |
@@ -2746,7 +2432,6 @@ static int do_preset_menu(struct preset_menu *menu, char *title, int selected) | |||
2746 | struct gui_synclist list; | 2432 | struct gui_synclist list; |
2747 | 2433 | ||
2748 | rb->gui_synclist_init(&list, &preset_formatter, menu, false, 1, NULL); | 2434 | rb->gui_synclist_init(&list, &preset_formatter, menu, false, 1, NULL); |
2749 | rb->gui_synclist_set_icon_callback(&list, NULL); | ||
2750 | rb->gui_synclist_set_nb_items(&list, menu->n_entries); | 2435 | rb->gui_synclist_set_nb_items(&list, menu->n_entries); |
2751 | 2436 | ||
2752 | rb->gui_synclist_select_item(&list, selected); | 2437 | rb->gui_synclist_select_item(&list, selected); |
@@ -2809,6 +2494,7 @@ static bool presets_menu(void) | |||
2809 | 2494 | ||
2810 | static void quick_help(void) | 2495 | static void quick_help(void) |
2811 | { | 2496 | { |
2497 | #ifndef NO_HELP_TEXT | ||
2812 | #if defined(FOR_REAL) && defined(DEBUG_MENU) | 2498 | #if defined(FOR_REAL) && defined(DEBUG_MENU) |
2813 | if(++help_times >= 5) | 2499 | if(++help_times >= 5) |
2814 | { | 2500 | { |
@@ -2819,11 +2505,12 @@ static void quick_help(void) | |||
2819 | 2505 | ||
2820 | rb->splash(0, quick_help_text); | 2506 | rb->splash(0, quick_help_text); |
2821 | rb->button_get(true); | 2507 | rb->button_get(true); |
2822 | return; | 2508 | #endif |
2823 | } | 2509 | } |
2824 | 2510 | ||
2825 | static void full_help(const char *name) | 2511 | static void full_help(const char *name) |
2826 | { | 2512 | { |
2513 | #ifndef NO_HELP_TEXT | ||
2827 | unsigned old_bg = rb->lcd_get_background(); | 2514 | unsigned old_bg = rb->lcd_get_background(); |
2828 | 2515 | ||
2829 | bool orig_clipped = clipped; | 2516 | bool orig_clipped = clipped; |
@@ -2878,6 +2565,7 @@ static void full_help(const char *name) | |||
2878 | 2565 | ||
2879 | if(orig_clipped) | 2566 | if(orig_clipped) |
2880 | rb_clip(NULL, clip_rect.x, clip_rect.y, clip_rect.width, clip_rect.height); | 2567 | rb_clip(NULL, clip_rect.x, clip_rect.y, clip_rect.width, clip_rect.height); |
2568 | #endif | ||
2881 | } | 2569 | } |
2882 | 2570 | ||
2883 | static void init_default_settings(void) | 2571 | static void init_default_settings(void) |
@@ -3028,6 +2716,11 @@ static int pausemenu_cb(int action, | |||
3028 | if(!midend_which_game(me)->can_solve) | 2716 | if(!midend_which_game(me)->can_solve) |
3029 | return ACTION_EXIT_MENUITEM; | 2717 | return ACTION_EXIT_MENUITEM; |
3030 | break; | 2718 | break; |
2719 | case 7: | ||
2720 | case 8: | ||
2721 | if(!help_valid) | ||
2722 | return ACTION_EXIT_MENUITEM; | ||
2723 | break; | ||
3031 | case 9: | 2724 | case 9: |
3032 | if(audiobuf_available) | 2725 | if(audiobuf_available) |
3033 | break; | 2726 | break; |
@@ -3078,7 +2771,7 @@ static void reset_drawing(void) | |||
3078 | rb->lcd_set_viewport(NULL); | 2771 | rb->lcd_set_viewport(NULL); |
3079 | rb->lcd_set_backdrop(NULL); | 2772 | rb->lcd_set_backdrop(NULL); |
3080 | rb->lcd_set_foreground(LCD_BLACK); | 2773 | rb->lcd_set_foreground(LCD_BLACK); |
3081 | rb->lcd_set_background(BG_COLOR); | 2774 | rb->lcd_set_background(colors ? colors[0] : BG_COLOR); |
3082 | } | 2775 | } |
3083 | 2776 | ||
3084 | /* Make a new game, but tell the user through a splash so they don't | 2777 | /* Make a new game, but tell the user through a splash so they don't |
@@ -3108,8 +2801,9 @@ static int pause_menu(void) | |||
3108 | "Game Type", // 10 | 2801 | "Game Type", // 10 |
3109 | "Debug Menu", // 11 | 2802 | "Debug Menu", // 11 |
3110 | "Configure Game", // 12 | 2803 | "Configure Game", // 12 |
3111 | "Quit without Saving", // 13 | 2804 | "Preferences", // 13 |
3112 | "Quit"); // 14 | 2805 | "Quit without Saving", // 14 |
2806 | "Quit"); // 15 | ||
3113 | 2807 | ||
3114 | #if defined(FOR_REAL) && defined(DEBUG_MENU) | 2808 | #if defined(FOR_REAL) && defined(DEBUG_MENU) |
3115 | help_times = 0; | 2809 | help_times = 0; |
@@ -3190,15 +2884,19 @@ static int pause_menu(void) | |||
3190 | quit = true; | 2884 | quit = true; |
3191 | } | 2885 | } |
3192 | break; | 2886 | break; |
3193 | case 13: | 2887 | case 13: |
3194 | return -2; | 2888 | preferences_menu(); |
2889 | // do not go straight into game. | ||
2890 | break; | ||
3195 | case 14: | 2891 | case 14: |
2892 | return -2; | ||
2893 | case 15: | ||
3196 | return -3; | 2894 | return -3; |
3197 | default: | 2895 | default: |
3198 | break; | 2896 | break; |
3199 | } | 2897 | } |
3200 | } | 2898 | } |
3201 | rb->lcd_set_background(BG_COLOR); | 2899 | rb->lcd_set_background(colors ? colors[0] : BG_COLOR); |
3202 | rb->lcd_clear_display(); | 2900 | rb->lcd_clear_display(); |
3203 | midend_force_redraw(me); | 2901 | midend_force_redraw(me); |
3204 | rb->lcd_update(); | 2902 | rb->lcd_update(); |
@@ -3217,7 +2915,7 @@ static void fix_size(void) | |||
3217 | rb->lcd_setfont(cur_font = FONT_UI); | 2915 | rb->lcd_setfont(cur_font = FONT_UI); |
3218 | rb->lcd_getstringsize("X", NULL, &h_x); | 2916 | rb->lcd_getstringsize("X", NULL, &h_x); |
3219 | h -= h_x; | 2917 | h -= h_x; |
3220 | midend_size(me, &w, &h, true); | 2918 | midend_size(me, &w, &h, true, 1.0); |
3221 | } | 2919 | } |
3222 | 2920 | ||
3223 | static void init_tlsf(void) | 2921 | static void init_tlsf(void) |
@@ -3245,6 +2943,7 @@ static void init_colors(void) | |||
3245 | float *floatcolors = midend_colors(me, &ncolors); | 2943 | float *floatcolors = midend_colors(me, &ncolors); |
3246 | 2944 | ||
3247 | /* convert them to packed RGB */ | 2945 | /* convert them to packed RGB */ |
2946 | sfree(colors); | ||
3248 | colors = smalloc(ncolors * sizeof(unsigned)); | 2947 | colors = smalloc(ncolors * sizeof(unsigned)); |
3249 | unsigned *ptr = colors; | 2948 | unsigned *ptr = colors; |
3250 | float *floatptr = floatcolors; | 2949 | float *floatptr = floatcolors; |
@@ -3277,32 +2976,39 @@ static bool string_in_list(const char *target, const char **list) | |||
3277 | static void tune_input(const char *name) | 2976 | static void tune_input(const char *name) |
3278 | { | 2977 | { |
3279 | static const char *want_spacebar[] = { | 2978 | static const char *want_spacebar[] = { |
2979 | "Black Box", | ||
2980 | "Bridges", | ||
2981 | "Galaxies", | ||
2982 | "Keen", | ||
3280 | "Magnets", | 2983 | "Magnets", |
3281 | "Map", | 2984 | "Map", |
3282 | "Mines", | 2985 | "Mines", |
3283 | "Palisade", | 2986 | "Palisade", |
2987 | "Pattern", | ||
3284 | "Rectangles", | 2988 | "Rectangles", |
2989 | "Signpost", | ||
2990 | "Singles", | ||
2991 | "Solo", | ||
2992 | "Tents", | ||
2993 | "Towers", | ||
2994 | "Unequal", | ||
2995 | "Group", | ||
3285 | NULL | 2996 | NULL |
3286 | }; | 2997 | }; |
3287 | 2998 | ||
3288 | /* these get a spacebar on long click - you must also add to the | 2999 | /* these get a spacebar on long click - this implicitly enables |
3289 | * falling_edge list below! */ | 3000 | * falling-edge button events (see below)! */ |
3290 | input_settings.want_spacebar = string_in_list(name, want_spacebar); | 3001 | input_settings.want_spacebar = string_in_list(name, want_spacebar); |
3291 | 3002 | ||
3292 | static const char *falling_edge[] = { | 3003 | static const char *falling_edge[] = { |
3293 | "Inertia", | 3004 | "Inertia", |
3294 | "Magnets", | ||
3295 | "Map", | ||
3296 | "Mines", | ||
3297 | "Palisade", | ||
3298 | "Rectangles", | ||
3299 | NULL | 3005 | NULL |
3300 | }; | 3006 | }; |
3301 | 3007 | ||
3302 | /* wait until a key is released to send an action (useful for | 3008 | /* wait until a key is released to send an action (useful for |
3303 | * chording in Inertia; must be enabled if the game needs a | 3009 | * chording in Inertia; must be enabled if the game needs a |
3304 | * spacebar) */ | 3010 | * spacebar) */ |
3305 | input_settings.falling_edge = string_in_list(name, falling_edge); | 3011 | input_settings.falling_edge = string_in_list(name, falling_edge) || input_settings.want_spacebar; |
3306 | 3012 | ||
3307 | /* For want_spacebar to work, events must be sent on the falling | 3013 | /* For want_spacebar to work, events must be sent on the falling |
3308 | * edge */ | 3014 | * edge */ |
@@ -3322,6 +3028,7 @@ static void tune_input(const char *name) | |||
3322 | static const char *no_rclick_on_hold[] = { | 3028 | static const char *no_rclick_on_hold[] = { |
3323 | "Map", | 3029 | "Map", |
3324 | "Signpost", | 3030 | "Signpost", |
3031 | "Slide", | ||
3325 | "Untangle", | 3032 | "Untangle", |
3326 | NULL | 3033 | NULL |
3327 | }; | 3034 | }; |
@@ -3330,11 +3037,21 @@ static void tune_input(const char *name) | |||
3330 | 3037 | ||
3331 | static const char *mouse_games[] = { | 3038 | static const char *mouse_games[] = { |
3332 | "Loopy", | 3039 | "Loopy", |
3040 | "Slide", | ||
3333 | NULL | 3041 | NULL |
3334 | }; | 3042 | }; |
3335 | 3043 | ||
3336 | mouse_mode = string_in_list(name, mouse_games); | 3044 | mouse_mode = string_in_list(name, mouse_games); |
3337 | 3045 | ||
3046 | static const char *sticky_mouse_games[] = { | ||
3047 | "Map", | ||
3048 | "Signpost", | ||
3049 | "Slide", | ||
3050 | "Untangle", | ||
3051 | }; | ||
3052 | |||
3053 | input_settings.sticky_mouse = string_in_list(name, sticky_mouse_games); | ||
3054 | |||
3338 | static const char *number_chooser_games[] = { | 3055 | static const char *number_chooser_games[] = { |
3339 | "Filling", | 3056 | "Filling", |
3340 | "Keen", | 3057 | "Keen", |
@@ -3627,8 +3344,11 @@ static int mainmenu_cb(int action, | |||
3627 | if(!load_success) | 3344 | if(!load_success) |
3628 | return ACTION_EXIT_MENUITEM; | 3345 | return ACTION_EXIT_MENUITEM; |
3629 | break; | 3346 | break; |
3347 | case 2: | ||
3630 | case 3: | 3348 | case 3: |
3631 | break; | 3349 | if(!help_valid) |
3350 | return ACTION_EXIT_MENUITEM; | ||
3351 | break; | ||
3632 | case 4: | 3352 | case 4: |
3633 | if(audiobuf_available) | 3353 | if(audiobuf_available) |
3634 | break; | 3354 | break; |
@@ -3691,8 +3411,9 @@ static void puzzles_main(void) | |||
3691 | "Playback Control", // 4 | 3411 | "Playback Control", // 4 |
3692 | "Game Type", // 5 | 3412 | "Game Type", // 5 |
3693 | "Configure Game", // 6 | 3413 | "Configure Game", // 6 |
3694 | "Quit without Saving", // 7 | 3414 | "Preferences", // 7 |
3695 | "Quit"); // 8 | 3415 | "Quit without Saving", // 8 |
3416 | "Quit"); // 9 | ||
3696 | 3417 | ||
3697 | bool quit = false; | 3418 | bool quit = false; |
3698 | int sel = 0; | 3419 | int sel = 0; |
@@ -3738,11 +3459,14 @@ static void puzzles_main(void) | |||
3738 | goto game_loop; | 3459 | goto game_loop; |
3739 | } | 3460 | } |
3740 | break; | 3461 | break; |
3741 | case 8: | 3462 | case 7: |
3463 | preferences_menu(); | ||
3464 | break; | ||
3465 | case 9: | ||
3742 | if(load_success) | 3466 | if(load_success) |
3743 | save_game(); | 3467 | save_game(); |
3744 | /* fall through */ | 3468 | /* fall through */ |
3745 | case 7: | 3469 | case 8: |
3746 | /* we don't care about freeing anything because tlsf will | 3470 | /* we don't care about freeing anything because tlsf will |
3747 | * be wiped out the next time around */ | 3471 | * be wiped out the next time around */ |
3748 | return; | 3472 | return; |
@@ -3787,12 +3511,14 @@ static void puzzles_main(void) | |||
3787 | /* quit without saving */ | 3511 | /* quit without saving */ |
3788 | midend_free(me); | 3512 | midend_free(me); |
3789 | sfree(colors); | 3513 | sfree(colors); |
3514 | colors = NULL; | ||
3790 | return; | 3515 | return; |
3791 | case -3: | 3516 | case -3: |
3792 | /* save and quit */ | 3517 | /* save and quit */ |
3793 | save_game(); | 3518 | save_game(); |
3794 | midend_free(me); | 3519 | midend_free(me); |
3795 | sfree(colors); | 3520 | sfree(colors); |
3521 | colors = NULL; | ||
3796 | return; | 3522 | return; |
3797 | default: | 3523 | default: |
3798 | break; | 3524 | break; |
@@ -3822,6 +3548,7 @@ static void puzzles_main(void) | |||
3822 | rb->yield(); | 3548 | rb->yield(); |
3823 | } | 3549 | } |
3824 | sfree(colors); | 3550 | sfree(colors); |
3551 | colors = NULL; | ||
3825 | } | 3552 | } |
3826 | } | 3553 | } |
3827 | 3554 | ||