+static void execSetupGraphics_setScalingTypes()
+{
+ if (scaling_types == NULL)
+ {
+ int i;
+
+ for (i = 0; scaling_types_list[i].value != NULL; i++)
+ {
+ TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
+ char identifier[32], name[32];
+ char *value = scaling_types_list[i].value;
+ char *text = scaling_types_list[i].text;
+
+ ti->node_top = &scaling_types;
+ ti->sort_priority = i;
+
+ sprintf(identifier, "%s", value);
+ sprintf(name, "%s", text);
+
+ setString(&ti->identifier, identifier);
+ setString(&ti->name, name);
+ setString(&ti->name_sorting, name);
+ setString(&ti->infotext, "Anti-Aliasing");
+
+ pushTreeInfo(&scaling_types, ti);
+ }
+
+ /* sort scaling type values to start with lowest scaling type value */
+ sortTreeInfo(&scaling_types);
+
+ /* set current scaling type value to configured scaling type value */
+ scaling_type_current =
+ getTreeInfoFromIdentifier(scaling_types, setup.window_scaling_quality);
+
+ /* if that fails, set current scaling type to reliable default value */
+ if (scaling_type_current == NULL)
+ scaling_type_current =
+ getTreeInfoFromIdentifier(scaling_types, SCALING_QUALITY_DEFAULT);
+
+ /* if that also fails, set current scaling type to first available value */
+ if (scaling_type_current == NULL)
+ scaling_type_current = scaling_types;
+ }
+
+ setup.window_scaling_quality = scaling_type_current->identifier;
+
+ /* needed for displaying scaling type text instead of identifier */
+ scaling_type_text = scaling_type_current->name;
+}
+
+static void execSetupGraphics_setScreenModes()
+{
+ // if (screen_modes == NULL && video.fullscreen_available)
+ if (screen_modes == NULL && video.fullscreen_modes != NULL)
+ {
+ int i;
+
+ for (i = 0; video.fullscreen_modes[i].width != -1; i++)
+ {
+ TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
+ char identifier[32], name[32];
+ int x = video.fullscreen_modes[i].width;
+ int y = video.fullscreen_modes[i].height;
+ int xx, yy;
+
+ get_aspect_ratio_from_screen_mode(&video.fullscreen_modes[i], &xx, &yy);
+
+ ti->node_top = &screen_modes;
+ ti->sort_priority = x * 10000 + y;
+
+ sprintf(identifier, "%dx%d", x, y);
+ sprintf(name, "%d x %d [%d:%d]", x, y, xx, yy);
+
+ setString(&ti->identifier, identifier);
+ setString(&ti->name, name);
+ setString(&ti->name_sorting, name);
+ setString(&ti->infotext, "Fullscreen Mode");
+
+ pushTreeInfo(&screen_modes, ti);
+ }
+
+ /* sort fullscreen modes to start with lowest available screen resolution */
+ sortTreeInfo(&screen_modes);
+
+ /* set current screen mode for fullscreen mode to configured setup value */
+ screen_mode_current = getTreeInfoFromIdentifier(screen_modes,
+ setup.fullscreen_mode);
+
+ /* if that fails, set current screen mode to reliable default value */
+ if (screen_mode_current == NULL)
+ screen_mode_current = getTreeInfoFromIdentifier(screen_modes,
+ DEFAULT_FULLSCREEN_MODE);
+
+ /* if that also fails, set current screen mode to first available mode */
+ if (screen_mode_current == NULL)
+ screen_mode_current = screen_modes;
+
+ if (screen_mode_current == NULL)
+ video.fullscreen_available = FALSE;
+ }
+
+ // if (video.fullscreen_available)
+ if (screen_mode_current != NULL)
+ {
+ setup.fullscreen_mode = screen_mode_current->identifier;
+
+ /* needed for displaying screen mode name instead of identifier */
+ screen_mode_text = screen_mode_current->name;
+ }
+}
+
+static void execSetupGraphics()
+{
+ if (setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE)
+ {
+ // update "setup.window_scaling_percent" from list selection
+ execSetupGraphics_setWindowSizes(FALSE);
+ }
+ else
+ {
+ // update list selection from "setup.window_scaling_percent"
+ execSetupGraphics_setWindowSizes(TRUE);
+ }
+
+ execSetupGraphics_setScalingTypes();
+ execSetupGraphics_setScreenModes();
+
+ setup_mode = SETUP_MODE_GRAPHICS;
+
+ DrawSetupScreen();
+
+#if defined(TARGET_SDL2)
+ // window scaling may have changed at this point
+ ToggleFullscreenOrChangeWindowScalingIfNeeded();
+
+ // window scaling quality may have changed at this point
+ if (!strEqual(setup.window_scaling_quality, video.window_scaling_quality))
+ SDLSetWindowScalingQuality(setup.window_scaling_quality);
+#endif
+}
+
+#if !defined(PLATFORM_ANDROID)
+#if defined(TARGET_SDL2)
+static void execSetupChooseWindowSize()
+{
+ setup_mode = SETUP_MODE_CHOOSE_WINDOW_SIZE;
+
+ DrawSetupScreen();
+}
+
+static void execSetupChooseScalingType()
+{
+ setup_mode = SETUP_MODE_CHOOSE_SCALING_TYPE;
+
+ DrawSetupScreen();
+}
+#else
+static void execSetupChooseScreenMode()
+{
+ if (!video.fullscreen_available)
+ return;
+
+ setup_mode = SETUP_MODE_CHOOSE_SCREEN_MODE;
+
+ DrawSetupScreen();
+}
+#endif
+#endif
+
+static void execSetupChooseVolumeSimple()
+{
+ setup_mode = SETUP_MODE_CHOOSE_VOLUME_SIMPLE;
+
+ DrawSetupScreen();
+}
+
+static void execSetupChooseVolumeLoops()
+{
+ setup_mode = SETUP_MODE_CHOOSE_VOLUME_LOOPS;
+
+ DrawSetupScreen();
+}
+
+static void execSetupChooseVolumeMusic()
+{
+ setup_mode = SETUP_MODE_CHOOSE_VOLUME_MUSIC;
+
+ DrawSetupScreen();
+}
+
+static void execSetupSound()
+{
+ if (volumes_simple == NULL)
+ {
+ int i;
+
+ for (i = 0; volumes_list[i].value != -1; i++)
+ {
+ TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
+ char identifier[32], name[32];
+ int value = volumes_list[i].value;
+ char *text = volumes_list[i].text;
+
+ ti->node_top = &volumes_simple;
+ ti->sort_priority = value;
+
+ sprintf(identifier, "%d", value);
+ sprintf(name, "%s", text);
+
+ setString(&ti->identifier, identifier);
+ setString(&ti->name, name);
+ setString(&ti->name_sorting, name);
+ setString(&ti->infotext, "Sound Volume");
+
+ pushTreeInfo(&volumes_simple, ti);
+ }
+
+ /* sort volume values to start with lowest volume value */
+ sortTreeInfo(&volumes_simple);
+
+ /* set current volume value to configured volume value */
+ volume_simple_current =
+ getTreeInfoFromIdentifier(volumes_simple,i_to_a(setup.volume_simple));
+
+ /* if that fails, set current volume to reliable default value */
+ if (volume_simple_current == NULL)
+ volume_simple_current =
+ getTreeInfoFromIdentifier(volumes_simple, i_to_a(100));
+
+ /* if that also fails, set current volume to first available value */
+ if (volume_simple_current == NULL)
+ volume_simple_current = volumes_simple;
+ }
+
+ if (volumes_loops == NULL)
+ {
+ int i;
+
+ for (i = 0; volumes_list[i].value != -1; i++)
+ {
+ TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
+ char identifier[32], name[32];
+ int value = volumes_list[i].value;
+ char *text = volumes_list[i].text;
+
+ ti->node_top = &volumes_loops;
+ ti->sort_priority = value;
+
+ sprintf(identifier, "%d", value);
+ sprintf(name, "%s", text);
+
+ setString(&ti->identifier, identifier);
+ setString(&ti->name, name);
+ setString(&ti->name_sorting, name);
+ setString(&ti->infotext, "Loops Volume");
+
+ pushTreeInfo(&volumes_loops, ti);
+ }
+
+ /* sort volume values to start with lowest volume value */
+ sortTreeInfo(&volumes_loops);
+
+ /* set current volume value to configured volume value */
+ volume_loops_current =
+ getTreeInfoFromIdentifier(volumes_loops,i_to_a(setup.volume_loops));
+
+ /* if that fails, set current volume to reliable default value */
+ if (volume_loops_current == NULL)
+ volume_loops_current =
+ getTreeInfoFromIdentifier(volumes_loops, i_to_a(100));
+
+ /* if that also fails, set current volume to first available value */
+ if (volume_loops_current == NULL)
+ volume_loops_current = volumes_loops;
+ }
+
+ if (volumes_music == NULL)
+ {
+ int i;
+
+ for (i = 0; volumes_list[i].value != -1; i++)
+ {
+ TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
+ char identifier[32], name[32];
+ int value = volumes_list[i].value;
+ char *text = volumes_list[i].text;
+
+ ti->node_top = &volumes_music;
+ ti->sort_priority = value;
+
+ sprintf(identifier, "%d", value);
+ sprintf(name, "%s", text);
+
+ setString(&ti->identifier, identifier);
+ setString(&ti->name, name);
+ setString(&ti->name_sorting, name);
+ setString(&ti->infotext, "Music Volume");
+
+ pushTreeInfo(&volumes_music, ti);
+ }
+
+ /* sort volume values to start with lowest volume value */
+ sortTreeInfo(&volumes_music);
+
+ /* set current volume value to configured volume value */
+ volume_music_current =
+ getTreeInfoFromIdentifier(volumes_music,i_to_a(setup.volume_music));
+
+ /* if that fails, set current volume to reliable default value */
+ if (volume_music_current == NULL)
+ volume_music_current =
+ getTreeInfoFromIdentifier(volumes_music, i_to_a(100));
+
+ /* if that also fails, set current volume to first available value */
+ if (volume_music_current == NULL)
+ volume_music_current = volumes_music;
+ }
+
+ setup.volume_simple = atoi(volume_simple_current->identifier);
+ setup.volume_loops = atoi(volume_loops_current->identifier);
+ setup.volume_music = atoi(volume_music_current->identifier);
+
+ /* needed for displaying volume text instead of identifier */
+ volume_simple_text = volume_simple_current->name;
+ volume_loops_text = volume_loops_current->name;
+ volume_music_text = volume_music_current->name;
+
+ setup_mode = SETUP_MODE_SOUND;
+
+ DrawSetupScreen();
+}
+
+static void execSetupChooseTouchControls()
+{
+ setup_mode = SETUP_MODE_CHOOSE_TOUCH_CONTROL;
+
+ DrawSetupScreen();
+}
+
+static void execSetupChooseMoveDistance()
+{
+ setup_mode = SETUP_MODE_CHOOSE_MOVE_DISTANCE;
+
+ DrawSetupScreen();
+}
+
+static void execSetupChooseDropDistance()
+{
+ setup_mode = SETUP_MODE_CHOOSE_DROP_DISTANCE;
+
+ DrawSetupScreen();
+}
+
+static void execSetupTouch()
+{
+ if (touch_controls == NULL)
+ {
+ int i;
+
+ for (i = 0; touch_controls_list[i].value != NULL; i++)
+ {
+ TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
+ char identifier[32], name[32];
+ char *value = touch_controls_list[i].value;
+ char *text = touch_controls_list[i].text;
+
+ ti->node_top = &touch_controls;
+ ti->sort_priority = i;
+
+ sprintf(identifier, "%s", value);
+ sprintf(name, "%s", text);
+
+ setString(&ti->identifier, identifier);
+ setString(&ti->name, name);
+ setString(&ti->name_sorting, name);
+ setString(&ti->infotext, "Control Type");
+
+ pushTreeInfo(&touch_controls, ti);
+ }
+
+ /* sort touch control values to start with lowest touch control value */
+ sortTreeInfo(&touch_controls);
+
+ /* set current touch control value to configured touch control value */
+ touch_control_current =
+ getTreeInfoFromIdentifier(touch_controls, setup.touch.control_type);
+
+ /* if that fails, set current touch control to reliable default value */
+ if (touch_control_current == NULL)
+ touch_control_current =
+ getTreeInfoFromIdentifier(touch_controls, TOUCH_CONTROL_DEFAULT);
+
+ /* if that also fails, set current touch control to first available value */
+ if (touch_control_current == NULL)
+ touch_control_current = touch_controls;
+ }
+
+ if (move_distances == NULL)
+ {
+ int i;
+
+ for (i = 0; distances_list[i].value != -1; i++)
+ {
+ TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
+ char identifier[32], name[32];
+ int value = distances_list[i].value;
+ char *text = distances_list[i].text;
+
+ ti->node_top = &move_distances;
+ ti->sort_priority = value;
+
+ sprintf(identifier, "%d", value);
+ sprintf(name, "%s", text);
+
+ setString(&ti->identifier, identifier);
+ setString(&ti->name, name);
+ setString(&ti->name_sorting, name);
+ setString(&ti->infotext, "Move Distance");
+
+ pushTreeInfo(&move_distances, ti);
+ }
+
+ /* sort distance values to start with lowest distance value */
+ sortTreeInfo(&move_distances);
+
+ /* set current distance value to configured distance value */
+ move_distance_current =
+ getTreeInfoFromIdentifier(move_distances,
+ i_to_a(setup.touch.move_distance));
+
+ /* if that fails, set current distance to reliable default value */
+ if (move_distance_current == NULL)
+ move_distance_current =
+ getTreeInfoFromIdentifier(move_distances, i_to_a(1));
+
+ /* if that also fails, set current distance to first available value */
+ if (move_distance_current == NULL)
+ move_distance_current = move_distances;
+ }
+
+ if (drop_distances == NULL)
+ {
+ int i;
+
+ for (i = 0; distances_list[i].value != -1; i++)
+ {
+ TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
+ char identifier[32], name[32];
+ int value = distances_list[i].value;
+ char *text = distances_list[i].text;
+
+ ti->node_top = &drop_distances;
+ ti->sort_priority = value;
+
+ sprintf(identifier, "%d", value);
+ sprintf(name, "%s", text);
+
+ setString(&ti->identifier, identifier);
+ setString(&ti->name, name);
+ setString(&ti->name_sorting, name);
+ setString(&ti->infotext, "Drop Distance");
+
+ pushTreeInfo(&drop_distances, ti);
+ }
+
+ /* sort distance values to start with lowest distance value */
+ sortTreeInfo(&drop_distances);
+
+ /* set current distance value to configured distance value */
+ drop_distance_current =
+ getTreeInfoFromIdentifier(drop_distances,
+ i_to_a(setup.touch.drop_distance));
+
+ /* if that fails, set current distance to reliable default value */
+ if (drop_distance_current == NULL)
+ drop_distance_current =
+ getTreeInfoFromIdentifier(drop_distances, i_to_a(1));
+
+ /* if that also fails, set current distance to first available value */
+ if (drop_distance_current == NULL)
+ drop_distance_current = drop_distances;
+ }
+
+ setup.touch.control_type = touch_control_current->identifier;
+ setup.touch.move_distance = atoi(move_distance_current->identifier);
+ setup.touch.drop_distance = atoi(drop_distance_current->identifier);
+
+ /* needed for displaying volume text instead of identifier */
+ touch_controls_text = touch_control_current->name;
+ move_distance_text = move_distance_current->name;
+ drop_distance_text = drop_distance_current->name;
+
+ setup_mode = SETUP_MODE_TOUCH;
+
+ DrawSetupScreen();
+}
+
+static void execSetupArtwork()
+{
+#if 0
+ printf("::: '%s', '%s', '%s'\n",
+ artwork.gfx_current->subdir,
+ artwork.gfx_current->fullpath,
+ artwork.gfx_current->basepath);
+#endif
+
+ setup.graphics_set = artwork.gfx_current->identifier;
+ setup.sounds_set = artwork.snd_current->identifier;
+ setup.music_set = artwork.mus_current->identifier;
+
+ /* needed if last screen (setup choice) changed graphics, sounds or music */
+ ReloadCustomArtwork(0);
+
+ /* needed for displaying artwork name instead of artwork identifier */
+ graphics_set_name = artwork.gfx_current->name;
+ sounds_set_name = artwork.snd_current->name;
+ music_set_name = artwork.mus_current->name;
+
+ setup_mode = SETUP_MODE_ARTWORK;
+
+ DrawSetupScreen();
+}
+
+static void execSetupChooseGraphics()
+{
+ setup_mode = SETUP_MODE_CHOOSE_GRAPHICS;
+
+ DrawSetupScreen();
+}
+
+static void execSetupChooseSounds()
+{
+ setup_mode = SETUP_MODE_CHOOSE_SOUNDS;
+
+ DrawSetupScreen();
+}
+
+static void execSetupChooseMusic()
+{
+ setup_mode = SETUP_MODE_CHOOSE_MUSIC;
+
+ DrawSetupScreen();
+}
+
+#if !defined(PLATFORM_ANDROID)
+static void execSetupInput()
+{
+ setup_mode = SETUP_MODE_INPUT;
+
+ DrawSetupScreen();
+}
+#endif
+
+static void execSetupShortcuts()
+{
+ setup_mode = SETUP_MODE_SHORTCUTS;
+
+ DrawSetupScreen();
+}
+
+static void execSetupShortcuts1()
+{
+ setup_mode = SETUP_MODE_SHORTCUTS_1;
+
+ DrawSetupScreen();
+}
+
+static void execSetupShortcuts2()
+{
+ setup_mode = SETUP_MODE_SHORTCUTS_2;
+
+ DrawSetupScreen();
+}
+
+static void execSetupShortcuts3()
+{
+ setup_mode = SETUP_MODE_SHORTCUTS_3;
+
+ DrawSetupScreen();
+}
+
+static void execSetupShortcuts4()
+{
+ setup_mode = SETUP_MODE_SHORTCUTS_4;
+
+ DrawSetupScreen();
+}
+
+static void execSetupShortcuts5()
+{
+ setup_mode = SETUP_MODE_SHORTCUTS_5;
+
+ DrawSetupScreen();
+}
+
+static void execExitSetup()