rnd-20140331-1-src
[rocksndiamonds.git] / src / screens.c
index 6543e1688174a3926e792a91652c81cd859c9d52..47c66fb3ffed37b5c66506196117519bb54d7799 100644 (file)
 
 /* sub-screens on the setup screen (specific) */
 #define SETUP_MODE_CHOOSE_GAME_SPEED   15
-#define SETUP_MODE_CHOOSE_SCREEN_MODE  16
-#define SETUP_MODE_CHOOSE_WINDOW_SIZE  17
-#define SETUP_MODE_CHOOSE_SCROLL_DELAY 18
-#define SETUP_MODE_CHOOSE_GRAPHICS     19
-#define SETUP_MODE_CHOOSE_SOUNDS       20
-#define SETUP_MODE_CHOOSE_MUSIC                21
-#define SETUP_MODE_CHOOSE_VOLUME_SIMPLE        22
-#define SETUP_MODE_CHOOSE_VOLUME_LOOPS 23
-#define SETUP_MODE_CHOOSE_VOLUME_MUSIC 24
-
-#define MAX_SETUP_MODES                        25
+#define SETUP_MODE_CHOOSE_SCROLL_DELAY 16
+#define SETUP_MODE_CHOOSE_SCREEN_MODE  17
+#define SETUP_MODE_CHOOSE_WINDOW_SIZE  18
+#define SETUP_MODE_CHOOSE_SCALING_TYPE 19
+#define SETUP_MODE_CHOOSE_GRAPHICS     20
+#define SETUP_MODE_CHOOSE_SOUNDS       21
+#define SETUP_MODE_CHOOSE_MUSIC                22
+#define SETUP_MODE_CHOOSE_VOLUME_SIMPLE        23
+#define SETUP_MODE_CHOOSE_VOLUME_LOOPS 24
+#define SETUP_MODE_CHOOSE_VOLUME_MUSIC 25
+
+#define MAX_SETUP_MODES                        26
 
 /* for input setup functions */
 #define SETUPINPUT_SCREEN_POS_START    0
 /* for various menu stuff  */
 #define MENU_SCREEN_START_XPOS         1
 #define MENU_SCREEN_START_YPOS         2
+#if 1
+#define MENU_SCREEN_VALUE_XPOS         (SCR_FIELDX - 3)
+#define MENU_SCREEN_MAX_XPOS           (SCR_FIELDX - 1)
+#else
 #define MENU_SCREEN_VALUE_XPOS         14
 #define MENU_SCREEN_MAX_XPOS           (SCR_FIELDX - 1)
+#endif
 #define MENU_TITLE1_YPOS               8
 #define MENU_TITLE2_YPOS               46
-#define MAX_INFO_ELEMENTS_ON_SCREEN    10
+#define MENU_SCREEN_INFO_XSTART                16
+#define MENU_SCREEN_INFO_YSTART1       100
+#define MENU_SCREEN_INFO_YSTART2       128
+#define MENU_SCREEN_INFO_YSTEP         (TILEY + 4)
+#define MENU_SCREEN_INFO_YBOTTOM       (SYSIZE - 20)
+#define MENU_SCREEN_INFO_YSIZE         (MENU_SCREEN_INFO_YBOTTOM -     \
+                                        MENU_SCREEN_INFO_YSTART2 -     \
+                                        TILEY / 2)
+#define MAX_INFO_ELEMENTS_ON_SCREEN    128
+#if 1
+#define NUM_INFO_ELEMENTS_ON_SCREEN    MIN(MENU_SCREEN_INFO_YSIZE /    \
+                                            MENU_SCREEN_INFO_YSTEP,    \
+                                            MAX_INFO_ELEMENTS_ON_SCREEN)
+#else
+#define NUM_INFO_ELEMENTS_ON_SCREEN    10
+#endif
 #define MAX_MENU_ENTRIES_ON_SCREEN     (SCR_FIELDY - MENU_SCREEN_START_YPOS)
+#if 1
+#define MAX_MENU_TEXT_LENGTH_BIG       13
+#define MAX_MENU_TEXT_LENGTH_MEDIUM    (MAX_MENU_TEXT_LENGTH_BIG * 2)
+#else
 #define MAX_MENU_TEXT_LENGTH_BIG       (MENU_SCREEN_VALUE_XPOS -       \
                                         MENU_SCREEN_START_XPOS)
 #define MAX_MENU_TEXT_LENGTH_MEDIUM    (MAX_MENU_TEXT_LENGTH_BIG * 2)
+#endif
 
 /* buttons and scrollbars identifiers */
 #define SCREEN_CTRL_ID_PREV_LEVEL      0
@@ -167,6 +193,7 @@ static void HandleInfoScreen_Program(int);
 static void HandleInfoScreen_Version(int);
 
 static void MapScreenMenuGadgets(int);
+static void MapScreenGadgets(int);
 static void MapScreenTreeGadgets(TreeInfo *);
 
 static struct GadgetInfo *screen_gadget[NUM_SCREEN_GADGETS];
@@ -180,6 +207,9 @@ static TreeInfo *screen_mode_current = NULL;
 static TreeInfo *window_sizes = NULL;
 static TreeInfo *window_size_current = NULL;
 
+static TreeInfo *scaling_types = NULL;
+static TreeInfo *scaling_type_current = NULL;
+
 static TreeInfo *scroll_delays = NULL;
 static TreeInfo *scroll_delay_current = NULL;
 
@@ -220,6 +250,19 @@ static struct
   {    -1,     NULL                            },
 };
 
+static struct
+{
+  char *value;
+  char *text;
+} scaling_types_list[] =
+{
+  {    SCALING_QUALITY_NEAREST, "None"         },
+  {    SCALING_QUALITY_LINEAR,  "Linear"       },
+  {    SCALING_QUALITY_BEST,    "Anisotropic"  },
+
+  {    NULL,                    NULL           },
+};
+
 static struct
 {
   int value;
@@ -1317,6 +1360,8 @@ void DrawMainMenuExt(int fade_mask, boolean do_fading)
   static LevelDirTree *leveldir_last_valid = NULL;
   boolean levelset_has_changed = FALSE;
 
+  LimitScreenUpdates(FALSE);
+
   FadeSetLeaveScreen();
 
   /* do not fade out here -- function may continue and fade on editor screen */
@@ -1344,7 +1389,8 @@ void DrawMainMenuExt(int fade_mask, boolean do_fading)
   }
 
   /* needed if last screen was the setup screen and fullscreen state changed */
-  ToggleFullscreenIfNeeded();
+  // (moved to "execSetupGraphics()" to change fullscreen state directly)
+  // ToggleFullscreenOrChangeWindowScalingIfNeeded();
 
   /* leveldir_current may be invalid (level group, parent link) */
   if (!validLevelSeries(leveldir_current))
@@ -1367,8 +1413,11 @@ void DrawMainMenuExt(int fade_mask, boolean do_fading)
 #if 1
   FadeOut(fade_mask);
 
+#if 0
   /* needed if last screen was the editor screen */
   UndrawSpecialEditorDoor();
+#endif
+
 #if 0
   if (fade_mask == REDRAW_FIELD)
     BackToFront();
@@ -1380,6 +1429,11 @@ void DrawMainMenuExt(int fade_mask, boolean do_fading)
   ChangeViewportPropertiesIfNeeded();
 #endif
 
+#if 1
+  /* needed if last screen was the editor screen */
+  UndrawSpecialEditorDoor();
+#endif
+
 #if defined(TARGET_SDL)
   SetDrawtoField(DRAW_BACKBUFFER);
 #endif
@@ -1418,7 +1472,7 @@ void DrawMainMenuExt(int fade_mask, boolean do_fading)
   InitializeMainControls();
 
   DrawCursorAndText_Main(-1, FALSE);
-  DrawPreviewLevel(TRUE);
+  DrawPreviewLevelInitial();
 
   HandleMainMenu(0, 0, 0, 0, MB_MENU_INITIALIZE);
 
@@ -1439,7 +1493,13 @@ void DrawMainMenuExt(int fade_mask, boolean do_fading)
   MapScreenMenuGadgets(SCREEN_MASK_MAIN);
 
 #if 1
-  if (fade_mask == REDRAW_ALL)
+  /* copy actual game door content to door double buffer for OpenDoor() */
+  BlitBitmap(drawto, bitmap_db_door_2, VX, VY, VXSIZE, VYSIZE, 0, 0);
+#endif
+
+#if 1
+  // if (fade_mask == REDRAW_ALL)
+  // (always redraw current door state)
   {
     int door_state = GetDoorState();
 
@@ -1449,6 +1509,12 @@ void DrawMainMenuExt(int fade_mask, boolean do_fading)
   }
 #endif
 
+#if 0
+  redraw_mask |= REDRAW_ALL;
+  BackToFront();
+  Delay(3000);
+#endif
+
   DrawMaskedBorder(REDRAW_ALL);
 
   FadeIn(fade_mask);
@@ -1735,7 +1801,7 @@ void HandleMainMenu_SelectLevel(int step, int direction)
   {
     /* skipping levels is only allowed when trying to skip single level */
     if (setup.skip_levels && step == 1 &&
-       Request("Level still unsolved ! Skip despite handicap ?", REQ_ASK))
+       Request("Level still unsolved! Skip despite handicap?", REQ_ASK))
     {
       leveldir_current->handicap_level++;
       SaveLevelSetup_SeriesInfo();
@@ -1757,13 +1823,13 @@ void HandleMainMenu_SelectLevel(int step, int direction)
             mci->pos_text->font);
 
     LoadLevel(level_nr);
-    DrawPreviewLevel(TRUE);
+    DrawPreviewLevelInitial();
 
     TapeErase();
     LoadTape(level_nr);
     DrawCompleteVideoDisplay();
 
-    /* needed because DrawPreviewLevel() takes some time */
+    /* needed because DrawPreviewLevelInitial() takes some time */
     BackToFront();
     SyncDisplay();
   }
@@ -1832,6 +1898,10 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
   {
     game_status = GAME_MODE_LEVELNR;
 
+#if 1
+    ChangeViewportPropertiesIfNeeded();
+#endif
+
     DrawChooseLevelNr();
   }
   else if (pos >= MAIN_CONTROL_NAME && pos <= MAIN_CONTROL_QUIT)
@@ -1871,6 +1941,10 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
          gotoTopLevelDir();
 #endif
 
+#if 1
+         ChangeViewportPropertiesIfNeeded();
+#endif
+
          DrawChooseLevelSet();
        }
       }
@@ -1878,13 +1952,19 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
       {
        game_status = GAME_MODE_SCORES;
 
+#if 1
+       ChangeViewportPropertiesIfNeeded();
+#endif
+
        DrawHallOfFame(-1);
       }
       else if (pos == MAIN_CONTROL_EDITOR)
       {
        if (leveldir_current->readonly &&
            !strEqual(setup.player_name, "Artsoft"))
-         Request("This level is read only !", REQ_CONFIRM);
+         Request("This level is read only!", REQ_CONFIRM);
+
+       CloseDoor(DOOR_CLOSE_2);
 
        game_status = GAME_MODE_EDITOR;
 
@@ -1902,6 +1982,10 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
        game_status = GAME_MODE_INFO;
        info_mode = INFO_MODE_MAIN;
 
+#if 1
+       ChangeViewportPropertiesIfNeeded();
+#endif
+
        DrawInfoScreen();
       }
       else if (pos == MAIN_CONTROL_GAME)
@@ -1913,6 +1997,10 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
        game_status = GAME_MODE_SETUP;
        setup_mode = SETUP_MODE_MAIN;
 
+#if 1
+       ChangeViewportPropertiesIfNeeded();
+#endif
+
        DrawSetupScreen();
       }
       else if (pos == MAIN_CONTROL_QUIT)
@@ -1920,17 +2008,19 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
        SaveLevelSetup_LastSeries();
        SaveLevelSetup_SeriesInfo();
 
-        if (Request("Do you really want to quit ?", REQ_ASK | REQ_STAY_CLOSED))
+        if (Request("Do you really want to quit?", REQ_ASK | REQ_STAY_CLOSED))
          game_status = GAME_MODE_QUIT;
       }
     }
   }
 
+#if 0
   if (game_status == GAME_MODE_MAIN)
   {
-    DrawPreviewLevel(FALSE);
+    DrawPreviewLevelAnimation();
     DoAnimation();
   }
+#endif
 }
 
 
@@ -2210,11 +2300,11 @@ void DrawInfoScreen_HelpAnim(int start, int max_anims, boolean init)
 {
   static int infoscreen_step[MAX_INFO_ELEMENTS_ON_SCREEN];
   static int infoscreen_frame[MAX_INFO_ELEMENTS_ON_SCREEN];
-  int xstart = mSX + 16;
-  int ystart1 = mSY - SY + 100;
-  int ystart2 = mSY + 64 + 2 * 32;
-  int ybottom = mSY - SY + SYSIZE - 20;
-  int ystep = TILEY + 4;
+  int xstart = mSX + MENU_SCREEN_INFO_XSTART;
+  int ystart1 = mSY - SY + MENU_SCREEN_INFO_YSTART1;
+  int ystart2 = mSY + MENU_SCREEN_INFO_YSTART2;
+  int ybottom = mSY - SY + MENU_SCREEN_INFO_YBOTTOM;
+  int ystep = MENU_SCREEN_INFO_YSTEP;
   int element, action, direction;
   int graphic;
   int delay;
@@ -2223,7 +2313,7 @@ void DrawInfoScreen_HelpAnim(int start, int max_anims, boolean init)
 
   if (init)
   {
-    for (i = 0; i < MAX_INFO_ELEMENTS_ON_SCREEN; i++)
+    for (i = 0; i < NUM_INFO_ELEMENTS_ON_SCREEN; i++)
       infoscreen_step[i] = infoscreen_frame[i] = 0;
 
     ClearField();
@@ -2240,7 +2330,7 @@ void DrawInfoScreen_HelpAnim(int start, int max_anims, boolean init)
   i = j = 0;
   while (helpanim_info[j].element != HELPANIM_LIST_END)
   {
-    if (i >= start + MAX_INFO_ELEMENTS_ON_SCREEN ||
+    if (i >= start + NUM_INFO_ELEMENTS_ON_SCREEN ||
        i >= max_anims)
       break;
     else if (i < start)
@@ -2401,7 +2491,7 @@ void HandleInfoScreen_Elements(int button)
   static int num_anims;
   static int num_pages;
   static int page;
-  int anims_per_page = MAX_INFO_ELEMENTS_ON_SCREEN;
+  int anims_per_page = NUM_INFO_ELEMENTS_ON_SCREEN;
   int i;
 
   if (button == MB_MENU_INITIALIZE)
@@ -3303,7 +3393,9 @@ void HandleInfoScreen(int mx, int my, int dx, int dy, int button)
   else
     HandleInfoScreen_Main(mx, my, dx, dy, button);
 
+#if 0
   DoAnimation();
+#endif
 }
 
 
@@ -3411,8 +3503,25 @@ static void DrawChooseTree(TreeInfo **ti_ptr)
   InitAnimation();
 }
 
+static void AdjustScrollbar(int id, int items_max, int items_visible,
+                           int item_position)
+{
+  struct GadgetInfo *gi = screen_gadget[id];
+
+  if (item_position > items_max - items_visible)
+    item_position = items_max - items_visible;
+
+  ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max,
+              GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
+              GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END);
+}
+
 static void AdjustChooseTreeScrollbar(int id, int first_entry, TreeInfo *ti)
 {
+#if 1
+  AdjustScrollbar(id, numTreeInfoInGroup(ti), NUM_MENU_ENTRIES_ON_SCREEN,
+                 first_entry);
+#else
   struct GadgetInfo *gi = screen_gadget[id];
   int items_max, items_visible, item_position;
 
@@ -3426,6 +3535,7 @@ static void AdjustChooseTreeScrollbar(int id, int first_entry, TreeInfo *ti)
   ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max,
               GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
               GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END);
+#endif
 }
 
 static void drawChooseTreeList(int first_entry, int num_page_entries,
@@ -3613,11 +3723,12 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
     }
     else if (game_status == GAME_MODE_SETUP)
     {
-      if (setup_mode == SETUP_MODE_CHOOSE_GAME_SPEED)
+      if (setup_mode == SETUP_MODE_CHOOSE_GAME_SPEED ||
+         setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY)
        execSetupGame();
       else if (setup_mode == SETUP_MODE_CHOOSE_SCREEN_MODE ||
               setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE ||
-              setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY)
+              setup_mode == SETUP_MODE_CHOOSE_SCALING_TYPE)
        execSetupGraphics();
       else if (setup_mode == SETUP_MODE_CHOOSE_VOLUME_SIMPLE ||
               setup_mode == SETUP_MODE_CHOOSE_VOLUME_LOOPS ||
@@ -3666,6 +3777,45 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
     if (ti->cl_cursor + dy < 0 ||
        ti->cl_cursor + dy > num_page_entries - 1)
     {
+#if 1
+      boolean redraw = FALSE;
+
+      if (ABS(dy) == SCROLL_PAGE)
+       step = num_page_entries - 1;
+
+      if (dy < 0 && ti->cl_first > 0)
+      {
+       /* scroll page/line up */
+
+       ti->cl_first -= step;
+       if (ti->cl_first < 0)
+         ti->cl_first = 0;
+
+       redraw = TRUE;
+      }
+      else if (dy > 0 && ti->cl_first + num_page_entries < num_entries)
+      {
+       /* scroll page/line down */
+
+       ti->cl_first += step;
+       if (ti->cl_first + num_page_entries > num_entries)
+         ti->cl_first = MAX(0, num_entries - num_page_entries);
+
+       redraw = TRUE;
+      }
+
+      if (redraw)
+      {
+       drawChooseTreeList(ti->cl_first, num_page_entries, ti);
+       drawChooseTreeInfo(ti->cl_first + ti->cl_cursor, ti);
+       drawChooseTreeCursor(ti->cl_cursor, TRUE);
+
+       AdjustChooseTreeScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL,
+                                 ti->cl_first, ti);
+      }
+
+#else
+
       if (ABS(dy) == SCROLL_PAGE)
        step = num_page_entries - 1;
 
@@ -3699,6 +3849,7 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
        AdjustChooseTreeScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL,
                                  ti->cl_first, ti);
       }
+#endif
 
       return;
     }
@@ -3746,6 +3897,11 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
       mx < screen_gadget[SCREEN_CTRL_ID_SCROLL_VERTICAL]->x &&
       y >= 0 && y < num_page_entries)
   {
+#if 0
+    printf("::: TEST/HandleChooseTree [%d, %d, %d, %d]\n", Counter(),
+          button, mx, screen_gadget[SCREEN_CTRL_ID_SCROLL_VERTICAL]->x);
+#endif
+
     if (button)
     {
       if (y != ti->cl_cursor)
@@ -3808,11 +3964,12 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
 
        if (game_status == GAME_MODE_SETUP)
        {
-         if (setup_mode == SETUP_MODE_CHOOSE_GAME_SPEED)
+         if (setup_mode == SETUP_MODE_CHOOSE_GAME_SPEED ||
+             setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY)
            execSetupGame();
          else if (setup_mode == SETUP_MODE_CHOOSE_SCREEN_MODE ||
                   setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE ||
-                  setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY)
+                  setup_mode == SETUP_MODE_CHOOSE_SCALING_TYPE)
            execSetupGraphics();
          else if (setup_mode == SETUP_MODE_CHOOSE_VOLUME_SIMPLE ||
                   setup_mode == SETUP_MODE_CHOOSE_VOLUME_LOOPS ||
@@ -3849,7 +4006,9 @@ void HandleChooseLevelSet(int mx, int my, int dx, int dy, int button)
 {
   HandleChooseTree(mx, my, dx, dy, button, &leveldir_current);
 
+#if 0
   DoAnimation();
+#endif
 }
 
 void DrawChooseLevelNr()
@@ -3920,7 +4079,9 @@ void HandleChooseLevelNr(int mx, int my, int dx, int dy, int button)
   HandleChooseTree(mx, my, dx, dy, button, &leveldir_current);
 #endif
 
+#if 0
   DoAnimation();
+#endif
 }
 
 void DrawHallOfFame(int highlight_position)
@@ -3963,7 +4124,7 @@ void DrawHallOfFame(int highlight_position)
 
 static void drawHallOfFameList(int first_entry, int highlight_position)
 {
-  int i;
+  int i, j;
 
   SetMainBackgroundImage(IMG_BACKGROUND_SCORES);
   ClearField();
@@ -3982,12 +4143,22 @@ static void drawHallOfFameList(int first_entry, int highlight_position)
     int font_nr4 = (active ? FONT_TEXT_4_ACTIVE : FONT_TEXT_4);
     int dx1 = 3 * getFontWidth(font_nr1);
     int dx2 = dx1 + getFontWidth(font_nr1);
+#if 1
+    int dx3 = SXSIZE - 5 * getFontWidth(font_nr4);
+    int num_dots = (dx3 - dx2) / getFontWidth(font_nr3);
+#else
     int dx3 = dx2 + 25 * getFontWidth(font_nr3);
+#endif
     int sy = mSY + 64 + i * 32;
 
     DrawText(mSX, sy, int2str(entry + 1, 3), font_nr1);
     DrawText(mSX + dx1, sy, ".", font_nr1);
+#if 1
+    for (j = 0; j < num_dots; j++)
+      DrawText(mSX + dx2 + j * getFontWidth(font_nr3), sy, ".", font_nr3);
+#else
     DrawText(mSX + dx2, sy, ".........................", font_nr3);
+#endif
 
     if (!strEqual(highscore[entry].Name, EMPTY_PLAYER_NAME))
       DrawText(mSX + dx2, sy, highscore[entry].Name, font_nr2);
@@ -4066,7 +4237,9 @@ void HandleHallOfFame(int mx, int my, int dx, int dy, int button)
   if (game_status == GAME_MODE_SCORES)
     PlayMenuSoundIfLoop();
 
+#if 0
   DoAnimation();
+#endif
 }
 
 
@@ -4075,10 +4248,12 @@ void HandleHallOfFame(int mx, int my, int dx, int dy, int button)
 /* ========================================================================= */
 
 static struct TokenInfo *setup_info;
-static int num_setup_info;
+static int num_setup_info;     /* number of setup entries shown on screen */
+static int max_setup_info;     /* total number of setup entries in list */
 
 static char *screen_mode_text;
 static char *window_size_text;
+static char *scaling_type_text;
 static char *scroll_delay_text;
 static char *game_speed_text;
 static char *graphics_set_name;
@@ -4095,7 +4270,7 @@ static void execSetupMain()
   DrawSetupScreen();
 }
 
-static void execSetupGame()
+static void execSetupGame_setGameSpeeds()
 {
   if (game_speeds == NULL)
   {
@@ -4143,6 +4318,62 @@ static void execSetupGame()
 
   /* needed for displaying game speed text instead of identifier */
   game_speed_text = game_speed_current->name;
+}
+
+static void execSetupGame_setScrollDelays()
+{
+  if (scroll_delays == NULL)
+  {
+    int i;
+
+    for (i = 0; scroll_delays_list[i].value != -1; i++)
+    {
+      TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
+      char identifier[32], name[32];
+      int value = scroll_delays_list[i].value;
+      char *text = scroll_delays_list[i].text;
+
+      ti->node_top = &scroll_delays;
+      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, "Scaling Type");
+
+      pushTreeInfo(&scroll_delays, ti);
+    }
+
+    /* sort scaling type values to start with lowest scaling type value */
+    sortTreeInfo(&scroll_delays);
+
+    /* set current scaling type value to configured scaling type value */
+    scroll_delay_current =
+      getTreeInfoFromIdentifier(scroll_delays,i_to_a(setup.scroll_delay_value));
+
+    /* if that fails, set current scaling type to reliable default value */
+    if (scroll_delay_current == NULL)
+      scroll_delay_current =
+       getTreeInfoFromIdentifier(scroll_delays, i_to_a(STD_SCROLL_DELAY));
+
+    /* if that also fails, set current scaling type to first available value */
+    if (scroll_delay_current == NULL)
+      scroll_delay_current = scroll_delays;
+  }
+
+  setup.scroll_delay_value = atoi(scroll_delay_current->identifier);
+
+  /* needed for displaying scaling type text instead of identifier */
+  scroll_delay_text = scroll_delay_current->name;
+}
+
+static void execSetupGame()
+{
+  execSetupGame_setGameSpeeds();
+  execSetupGame_setScrollDelays();
 
   setup_mode = SETUP_MODE_GAME;
 
@@ -4156,6 +4387,13 @@ static void execSetupChooseGameSpeed()
   DrawSetupScreen();
 }
 
+static void execSetupChooseScrollDelay()
+{
+  setup_mode = SETUP_MODE_CHOOSE_SCROLL_DELAY;
+
+  DrawSetupScreen();
+}
+
 static void execSetupEditor()
 {
   setup_mode = SETUP_MODE_EDITOR;
@@ -4248,6 +4486,56 @@ static void execSetupGraphics_setWindowSizes(boolean update_list)
   window_size_text = window_size_current->name;
 }
 
+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)
@@ -4309,81 +4597,53 @@ static void execSetupGraphics_setScreenModes()
   }
 }
 
-static void execSetupGraphics_setScrollDelays()
+static void execSetupGraphics()
 {
-  if (scroll_delays == NULL)
+  if (setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE)
   {
-    int i;
-
-    for (i = 0; scroll_delays_list[i].value != -1; i++)
-    {
-      TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
-      char identifier[32], name[32];
-      int value = scroll_delays_list[i].value;
-      char *text = scroll_delays_list[i].text;
+    // update "setup.window_scaling_percent" from list selection
+    execSetupGraphics_setWindowSizes(FALSE);
+  }
+  else
+  {
+    // update list selection from "setup.window_scaling_percent"
+    execSetupGraphics_setWindowSizes(TRUE);
+  }
 
-      ti->node_top = &scroll_delays;
-      ti->sort_priority = value;
+  execSetupGraphics_setScalingTypes();
+  execSetupGraphics_setScreenModes();
 
-      sprintf(identifier, "%d", value);
-      sprintf(name, "%s", text);
+  setup_mode = SETUP_MODE_GRAPHICS;
 
-      setString(&ti->identifier, identifier);
-      setString(&ti->name, name);
-      setString(&ti->name_sorting, name);
-      setString(&ti->infotext, "Scroll Delay");
+  DrawSetupScreen();
 
-      pushTreeInfo(&scroll_delays, ti);
-    }
+#if defined(TARGET_SDL2)
+  // window scaling may have changed at this point
+  ToggleFullscreenOrChangeWindowScalingIfNeeded();
 
-    /* sort scroll delay values to start with lowest scroll delay value */
-    sortTreeInfo(&scroll_delays);
+  // 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
+}
 
-    /* set current scroll delay value to configured scroll delay value */
-    scroll_delay_current =
-      getTreeInfoFromIdentifier(scroll_delays,i_to_a(setup.scroll_delay_value));
+#if !defined(PLATFORM_ANDROID)
+#if defined(TARGET_SDL2)
+static void execSetupChooseWindowSize()
+{
+#if 0
+  if (!video.window_scaling_available)
+    return;
+#endif
 
-    /* if that fails, set current scroll delay to reliable default value */
-    if (scroll_delay_current == NULL)
-      scroll_delay_current =
-       getTreeInfoFromIdentifier(scroll_delays, i_to_a(STD_SCROLL_DELAY));
-
-    /* if that also fails, set current scroll delay to first available value */
-    if (scroll_delay_current == NULL)
-      scroll_delay_current = scroll_delays;
-  }
-
-  setup.scroll_delay_value = atoi(scroll_delay_current->identifier);
-
-  /* needed for displaying scroll delay text instead of identifier */
-  scroll_delay_text = scroll_delay_current->name;
-}
-
-static void execSetupGraphics()
-{
-  // update "setup.window_scaling_percent" from list selection
-  execSetupGraphics_setWindowSizes(FALSE);
-  // maybe remove non-preset value (if standard value was selected)
-  execSetupGraphics_setWindowSizes(TRUE);
-
-  execSetupGraphics_setScreenModes();
-  execSetupGraphics_setScrollDelays();
-
-  setup_mode = SETUP_MODE_GRAPHICS;
+  setup_mode = SETUP_MODE_CHOOSE_WINDOW_SIZE;
 
   DrawSetupScreen();
 }
 
-#if !defined(PLATFORM_ANDROID)
-#if defined(TARGET_SDL2)
-static void execSetupChooseWindowSize()
+static void execSetupChooseScalingType()
 {
-#if 0
-  if (!video.window_scaling_available)
-    return;
-#endif
-
-  setup_mode = SETUP_MODE_CHOOSE_WINDOW_SIZE;
+  setup_mode = SETUP_MODE_CHOOSE_SCALING_TYPE;
 
   DrawSetupScreen();
 }
@@ -4400,13 +4660,6 @@ static void execSetupChooseScreenMode()
 #endif
 #endif
 
-static void execSetupChooseScrollDelay()
-{
-  setup_mode = SETUP_MODE_CHOOSE_SCROLL_DELAY;
-
-  DrawSetupScreen();
-}
-
 static void execSetupChooseVolumeSimple()
 {
   setup_mode = SETUP_MODE_CHOOSE_VOLUME_SIMPLE;
@@ -4707,6 +4960,10 @@ static struct TokenInfo setup_info_game[] =
   { TYPE_SWITCH,       &setup.autorecord,      "Auto-Record Tapes:"    },
   { TYPE_ENTER_LIST,   execSetupChooseGameSpeed, "Game Speed:"         },
   { TYPE_STRING,       &game_speed_text,       ""                      },
+#if 1
+  { TYPE_ENTER_LIST,   execSetupChooseScrollDelay, "Scroll Delay:"     },
+  { TYPE_STRING,       &scroll_delay_text,     ""                      },
+#endif
   { TYPE_EMPTY,                NULL,                   ""                      },
   { TYPE_LEAVE_MENU,   execSetupMain,          "Back"                  },
 
@@ -4753,6 +5010,10 @@ static struct TokenInfo setup_info_graphics[] =
 #if defined(TARGET_SDL2)
   { TYPE_ENTER_LIST,   execSetupChooseWindowSize, "Window Scaling:"    },
   { TYPE_STRING,       &window_size_text,      ""                      },
+#if 1
+  { TYPE_ENTER_LIST,   execSetupChooseScalingType, "Anti-Aliasing:"    },
+  { TYPE_STRING,       &scaling_type_text,     ""                      },
+#endif
 #else
   { TYPE_ENTER_LIST,   execSetupChooseScreenMode, "Fullscreen Mode:"   },
   { TYPE_STRING,       &screen_mode_text,      ""                      },
@@ -4761,8 +5022,10 @@ static struct TokenInfo setup_info_graphics[] =
 #if 0
   { TYPE_SWITCH,       &setup.scroll_delay,    "Scroll Delay:"         },
 #endif
-  { TYPE_ENTER_LIST,   execSetupChooseScrollDelay, "Scroll Delay Value:" },
+#if 0
+  { TYPE_ENTER_LIST,   execSetupChooseScrollDelay, "Scroll Delay:"     },
   { TYPE_STRING,       &scroll_delay_text,     ""                      },
+#endif
 #if 0
   { TYPE_SWITCH,       &setup.soft_scrolling,  "Soft Scrolling:"       },
 #endif
@@ -5026,6 +5289,123 @@ static int getSetupValueFont(int type, void *value)
     return FONT_VALUE_1;
 }
 
+#if 1
+static void drawSetupValue(int screen_pos, int setup_info_pos_raw)
+{
+  int si_pos = (setup_info_pos_raw < 0 ? screen_pos : setup_info_pos_raw);
+  struct TokenInfo *si = &setup_info[si_pos];
+  boolean font_draw_xoffset_modified = FALSE;
+  int font_draw_xoffset_old = -1;
+  int xoffset = (num_setup_info < max_setup_info ? -1 : 0);
+  int menu_screen_value_xpos = MENU_SCREEN_VALUE_XPOS + xoffset;
+  int menu_screen_max_xpos = MENU_SCREEN_MAX_XPOS + xoffset;
+  int xpos = menu_screen_value_xpos;
+  int ypos = MENU_SCREEN_START_YPOS + screen_pos;
+  int startx = mSX + xpos * 32;
+  int starty = mSY + ypos * 32;
+  int font_nr, font_width;
+#if 0
+  int font_height;
+#endif
+  int type = si->type;
+  void *value = si->value;
+  char *value_string = getSetupValue(type, value);
+#if 1
+  int i;
+#endif
+
+  if (value_string == NULL)
+    return;
+
+  if (type & TYPE_KEY)
+  {
+    xpos = MENU_SCREEN_START_XPOS;
+
+    if (type & TYPE_QUERY)
+      value_string = "<press key>";
+  }
+  else if (type & TYPE_STRING)
+  {
+    int max_value_len = (SCR_FIELDX - 2) * 2;
+
+    xpos = MENU_SCREEN_START_XPOS;
+
+    if (strlen(value_string) > max_value_len)
+      value_string[max_value_len] = '\0';
+  }
+  else if (type & TYPE_YES_NO_AUTO)
+  {
+    xpos = menu_screen_value_xpos - 1;
+  }
+
+  startx = mSX + xpos * 32;
+  starty = mSY + ypos * 32;
+  font_nr = getSetupValueFont(type, value);
+  font_width = getFontWidth(font_nr);
+#if 0
+  font_height = getFontHeight(font_nr);
+#endif
+
+#if 0
+  if (menu_screen_value_xpos < 1 + MAX_MENU_TEXT_LENGTH_BIG)
+    font_nr = ...;
+#endif
+
+  /* downward compatibility correction for Juergen Bonhagen's menu settings */
+  if (setup_mode != SETUP_MODE_INPUT)
+  {
+    int max_menu_text_length_big = (menu_screen_value_xpos -
+                                   MENU_SCREEN_START_XPOS);
+    int max_menu_text_length_medium = max_menu_text_length_big * 2;
+    int check_font_nr = FONT_OPTION_ON; /* known font that needs correction */
+    int font1_xoffset = getFontBitmapInfo(font_nr)->draw_xoffset;
+    int font2_xoffset = getFontBitmapInfo(check_font_nr)->draw_xoffset;
+    int text_startx = mSX + MENU_SCREEN_START_XPOS * 32;
+    int text_font_nr = getSetupTextFont(FONT_MENU_2);
+    int text_font_xoffset = getFontBitmapInfo(text_font_nr)->draw_xoffset;
+    int text_width = max_menu_text_length_medium * getFontWidth(text_font_nr);
+    boolean correct_font_draw_xoffset = FALSE;
+
+    if (xpos == MENU_SCREEN_START_XPOS &&
+       startx + font1_xoffset < text_startx + text_font_xoffset)
+      correct_font_draw_xoffset = TRUE;
+
+    if (xpos == menu_screen_value_xpos &&
+       startx + font2_xoffset < text_startx + text_width + text_font_xoffset)
+      correct_font_draw_xoffset = TRUE;
+
+    /* check if setup value would overlap with setup text when printed */
+    /* (this can happen for extreme/wrong values for font draw offset) */
+    if (correct_font_draw_xoffset)
+    {
+      font_draw_xoffset_old = getFontBitmapInfo(font_nr)->draw_xoffset;
+      font_draw_xoffset_modified = TRUE;
+
+      if (type & TYPE_KEY)
+       getFontBitmapInfo(font_nr)->draw_xoffset += 2 * getFontWidth(font_nr);
+      else if (!(type & TYPE_STRING))
+       getFontBitmapInfo(font_nr)->draw_xoffset = text_font_xoffset + 20 -
+         max_menu_text_length_medium * (16 - getFontWidth(text_font_nr));
+    }
+  }
+
+#if 0
+  DrawBackground(startx, starty, SX + SXSIZE - startx, font_height);
+#else
+  for (i = 0; i <= menu_screen_max_xpos - xpos; i++)
+    DrawText(startx + i * font_width, starty, " ", font_nr);
+#endif
+
+  // printf("::: startx == %d\n", startx);
+
+  DrawText(startx, starty, value_string, font_nr);
+
+  if (font_draw_xoffset_modified)
+    getFontBitmapInfo(font_nr)->draw_xoffset = font_draw_xoffset_old;
+}
+
+#else
+
 static void drawSetupValue(int pos)
 {
   boolean font_draw_xoffset_modified = FALSE;
@@ -5124,6 +5504,48 @@ static void drawSetupValue(int pos)
   if (font_draw_xoffset_modified)
     getFontBitmapInfo(font_nr)->draw_xoffset = font_draw_xoffset_old;
 }
+#endif
+
+#if 1
+static void changeSetupValue(int screen_pos, int setup_info_pos_raw, int dx)
+{
+  int si_pos = (setup_info_pos_raw < 0 ? screen_pos : setup_info_pos_raw);
+  struct TokenInfo *si = &setup_info[si_pos];
+
+  if (si->type & TYPE_BOOLEAN_STYLE)
+  {
+    *(boolean *)si->value ^= TRUE;
+  }
+  else if (si->type & TYPE_YES_NO_AUTO)
+  {
+    *(int *)si->value =
+      (dx == -1 ?
+       (*(int *)si->value == AUTO ? TRUE :
+       *(int *)si->value == TRUE ? FALSE : AUTO) :
+       (*(int *)si->value == TRUE ? AUTO :
+       *(int *)si->value == AUTO ? FALSE : TRUE));
+  }
+  else if (si->type & TYPE_KEY)
+  {
+    Key key;
+
+    si->type |= TYPE_QUERY;
+    drawSetupValue(screen_pos, setup_info_pos_raw);
+    si->type &= ~TYPE_QUERY;
+
+    key = getSetupKey();
+    if (key != KSYM_UNDEFINED)
+      *(Key *)si->value = key;
+  }
+
+  drawSetupValue(screen_pos, setup_info_pos_raw);
+
+  // fullscreen state may have changed at this point
+  if (si->value == &setup.fullscreen)
+    ToggleFullscreenOrChangeWindowScalingIfNeeded();
+}
+
+#else
 
 static void changeSetupValue(int pos, int dx)
 {
@@ -5145,7 +5567,7 @@ static void changeSetupValue(int pos, int dx)
     Key key;
 
     setup_info[pos].type |= TYPE_QUERY;
-    drawSetupValue(pos);
+    drawSetupValue(pos, -1);
     setup_info[pos].type &= ~TYPE_QUERY;
 
     key = getSetupKey();
@@ -5153,9 +5575,36 @@ static void changeSetupValue(int pos, int dx)
       *(Key *)setup_info[pos].value = key;
   }
 
-  drawSetupValue(pos);
+  drawSetupValue(pos, -1);
+
+  // fullscreen state may have changed at this point
+  if (setup_info[pos].value == &setup.fullscreen)
+    ToggleFullscreenOrChangeWindowScalingIfNeeded();
 }
+#endif
+
+#if 1
+static void DrawCursorAndText_Setup(int screen_pos, int setup_info_pos_raw,
+                                   boolean active)
+{
+  int si_pos = (setup_info_pos_raw < 0 ? screen_pos : setup_info_pos_raw);
+  struct TokenInfo *si = &setup_info[si_pos];
+  int xpos = MENU_SCREEN_START_XPOS;
+  int ypos = MENU_SCREEN_START_YPOS + screen_pos;
+  int font_nr = getSetupTextFont(si->type);
 
+  if (setup_info == setup_info_input)
+    font_nr = FONT_MENU_1;
+
+  if (active)
+    font_nr = FONT_ACTIVE(font_nr);
+
+  DrawText(mSX + xpos * 32, mSY + ypos * 32, si->text, font_nr);
+
+  if (si->type & ~TYPE_SKIP_ENTRY)
+    drawCursor(screen_pos, active);
+}
+#else
 static void DrawCursorAndText_Setup(int pos, boolean active)
 {
   int xpos = MENU_SCREEN_START_XPOS;
@@ -5173,6 +5622,58 @@ static void DrawCursorAndText_Setup(int pos, boolean active)
   if (setup_info[pos].type & ~TYPE_SKIP_ENTRY)
     drawCursor(pos, active);
 }
+#endif
+
+static void drawSetupInfoList(struct TokenInfo *setup_info,
+                             int first_entry, int num_page_entries)
+{
+  int i;
+
+  if (num_page_entries > NUM_MENU_ENTRIES_ON_SCREEN)
+    num_page_entries = NUM_MENU_ENTRIES_ON_SCREEN;
+
+  if (num_page_entries > max_setup_info)
+    num_page_entries = max_setup_info;
+
+  if (first_entry + num_page_entries > max_setup_info)
+    first_entry = 0;
+
+#if 1
+  /* clear tree list area, but not title or scrollbar */
+  DrawBackground(mSX, mSY + MENU_SCREEN_START_YPOS * 32,
+                 SC_SCROLLBAR_XPOS + menu.scrollbar_xoffset,
+                 NUM_MENU_ENTRIES_ON_SCREEN * 32);
+#endif
+
+  for (i = 0; i < num_page_entries; i++)
+  {
+    int setup_info_pos = first_entry + i;
+    struct TokenInfo *si = &setup_info[setup_info_pos];
+    void *value_ptr = si->value;
+
+    /* set some entries to "unchangeable" according to other variables */
+    if ((value_ptr == &setup.sound_simple && !audio.sound_available) ||
+       (value_ptr == &setup.sound_loops  && !audio.loops_available) ||
+       (value_ptr == &setup.sound_music  && !audio.music_available) ||
+       (value_ptr == &setup.fullscreen   && !video.fullscreen_available) ||
+       (value_ptr == &screen_mode_text   && !video.fullscreen_available) ||
+       (value_ptr == &window_size_text   && !video.window_scaling_available) ||
+       (value_ptr == &scaling_type_text  && !video.window_scaling_available))
+      si->type |= TYPE_GHOSTED;
+
+    if (si->type & (TYPE_ENTER_MENU|TYPE_ENTER_LIST))
+      initCursor(i, IMG_MENU_BUTTON_ENTER_MENU);
+    else if (si->type & (TYPE_LEAVE_MENU|TYPE_LEAVE_LIST))
+      initCursor(i, IMG_MENU_BUTTON_LEAVE_MENU);
+    else if (si->type & ~TYPE_SKIP_ENTRY)
+      initCursor(i, IMG_MENU_BUTTON);
+
+    DrawCursorAndText_Setup(i, setup_info_pos, FALSE);
+
+    if (si->type & TYPE_VALUE)
+      drawSetupValue(i, setup_info_pos);
+  }
+}
 
 static void DrawSetupScreen_Generic()
 {
@@ -5181,6 +5682,12 @@ static void DrawSetupScreen_Generic()
   int i;
 
   UnmapAllGadgets();
+
+#if 1
+  FreeScreenGadgets();
+  CreateScreenGadgets();
+#endif
+
   CloseDoor(DOOR_CLOSE_2);
 
   if (redraw_mask & REDRAW_ALL)
@@ -5264,6 +5771,22 @@ static void DrawSetupScreen_Generic()
 
   DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, title_string);
 
+#if 1
+
+  num_setup_info = 0;
+  for (i = 0; setup_info[i].type != 0 && i < MAX_MENU_ENTRIES_ON_SCREEN; i++)
+    num_setup_info++;
+
+  max_setup_info = 0;
+  for (i = 0; setup_info[i].type != 0; i++)
+    max_setup_info++;
+
+#if 0
+  drawSetupInfoList(setup_info, 0, NUM_MENU_ENTRIES_ON_SCREEN);
+#endif
+
+#else
+
   num_setup_info = 0;
 #if 1
   for (i = 0; setup_info[i].type != 0 && i < MAX_MENU_ENTRIES_ON_SCREEN; i++)
@@ -5279,7 +5802,8 @@ static void DrawSetupScreen_Generic()
        (value_ptr == &setup.sound_music  && !audio.music_available) ||
        (value_ptr == &setup.fullscreen   && !video.fullscreen_available) ||
        (value_ptr == &screen_mode_text   && !video.fullscreen_available) ||
-       (value_ptr == &window_size_text   && !video.window_scaling_available))
+       (value_ptr == &window_size_text   && !video.window_scaling_available) ||
+       (value_ptr == &scaling_type_text  && !video.window_scaling_available))
       setup_info[i].type |= TYPE_GHOSTED;
 
     if (setup_info[i].type & (TYPE_ENTER_MENU|TYPE_ENTER_LIST))
@@ -5296,6 +5820,7 @@ static void DrawSetupScreen_Generic()
 
     num_setup_info++;
   }
+#endif
 
 #if 0
   DrawTextSCentered(SYSIZE - 20, FONT_TEXT_4,
@@ -5306,6 +5831,10 @@ static void DrawSetupScreen_Generic()
   HandleSetupScreen_Generic(0, 0, 0, 0, MB_MENU_INITIALIZE);
 #endif
 
+#if 1
+  MapScreenGadgets(max_setup_info);
+#endif
+
   if (redraw_all)
     redraw_mask = REDRAW_ALL;
 
@@ -5324,9 +5853,23 @@ static void DrawSetupScreen_Generic()
 void HandleSetupScreen_Generic(int mx, int my, int dx, int dy, int button)
 {
   static int choice_store[MAX_SETUP_MODES];
-  int choice = choice_store[setup_mode];       /* always starts with 0 */
+  static int first_entry_store[MAX_SETUP_MODES];
+  int choice = choice_store[setup_mode];               /* starts with 0 */
+  int first_entry = first_entry_store[setup_mode];     /* starts with 0 */
   int x = 0;
+#if 1
+  int y = choice - first_entry;
+  int y_old = y;
+#else
   int y = choice;
+#endif
+  boolean position_set_by_scrollbar = (dx == 999);
+#if 1
+  int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
+  int num_page_entries;
+
+  num_page_entries = MIN(max_setup_info, NUM_MENU_ENTRIES_ON_SCREEN);
+#endif
 
   if (button == MB_MENU_INITIALIZE)
   {
@@ -5334,21 +5877,56 @@ void HandleSetupScreen_Generic(int mx, int my, int dx, int dy, int button)
     while (choice < num_setup_info &&
           setup_info[choice].type & TYPE_SKIP_ENTRY)
       choice++;
+#if 0
+    choice_store[setup_mode] = choice;
+#endif
+
+#if 1
+    if (position_set_by_scrollbar)
+      first_entry = first_entry_store[setup_mode] = dy;
+    else
+      AdjustScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL, max_setup_info,
+                     NUM_MENU_ENTRIES_ON_SCREEN, first_entry);
+
+    drawSetupInfoList(setup_info, first_entry, NUM_MENU_ENTRIES_ON_SCREEN);
+#endif
+
+#if 1
+    if (choice < first_entry)
+    {
+      choice = first_entry;
+
+      if (setup_info[choice].type & TYPE_SKIP_ENTRY)
+       choice++;
+    }
+    else if (choice > first_entry + num_page_entries - 1)
+    {
+      choice = first_entry + num_page_entries - 1;
+
+      if (setup_info[choice].type & TYPE_SKIP_ENTRY)
+       choice--;
+    }
+
     choice_store[setup_mode] = choice;
 
-    DrawCursorAndText_Setup(choice, TRUE);
+    DrawCursorAndText_Setup(choice - first_entry, choice, TRUE);
+#else
+    DrawCursorAndText_Setup(choice, -1, TRUE);
+#endif
 
     return;
   }
   else if (button == MB_MENU_LEAVE)
   {
+    int i;
+
     PlaySound(SND_MENU_ITEM_SELECTING);
 
-    for (y = 0; y < num_setup_info; y++)
+    for (i = 0; setup_info[i].type != 0; i++)
     {
-      if (setup_info[y].type & TYPE_LEAVE_MENU)
+      if (setup_info[i].type & TYPE_LEAVE_MENU)
       {
-       void (*menu_callback_function)(void) = setup_info[y].value;
+       void (*menu_callback_function)(void) = setup_info[i].value;
 
        FadeSetLeaveMenu();
 
@@ -5366,8 +5944,94 @@ void HandleSetupScreen_Generic(int mx, int my, int dx, int dy, int button)
     x = (mx - mSX) / 32;
     y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS;
   }
+#if 1
+  else if (dx || dy)   /* keyboard or scrollbar/scrollbutton input */
+#else
   else if (dx || dy)   /* keyboard input */
+#endif
   {
+    /* move cursor instead of scrolling when already at start/end of list */
+    if (dy == -1 * SCROLL_LINE && first_entry == 0)
+      dy = -1;
+    else if (dy == +1 * SCROLL_LINE &&
+            first_entry + num_page_entries == max_setup_info)
+      dy = 1;
+
+    /* handle scrolling screen one line or page */
+    if (y + dy < 0 ||
+       y + dy > num_page_entries - 1)
+    {
+      boolean redraw = FALSE;
+
+      if (ABS(dy) == SCROLL_PAGE)
+       step = num_page_entries - 1;
+
+      if (dy < 0 && first_entry > 0)
+      {
+       /* scroll page/line up */
+
+       first_entry -= step;
+       if (first_entry < 0)
+         first_entry = 0;
+
+       redraw = TRUE;
+      }
+      else if (dy > 0 && first_entry + num_page_entries < max_setup_info)
+      {
+       /* scroll page/line down */
+
+       first_entry += step;
+       if (first_entry + num_page_entries > max_setup_info)
+         first_entry = MAX(0, max_setup_info - num_page_entries);
+
+       redraw = TRUE;
+      }
+
+      if (redraw)
+      {
+       choice += first_entry - first_entry_store[setup_mode];
+
+       if (choice < first_entry)
+       {
+         choice = first_entry;
+
+         if (setup_info[choice].type & TYPE_SKIP_ENTRY)
+           choice++;
+       }
+       else if (choice > first_entry + num_page_entries - 1)
+       {
+         choice = first_entry + num_page_entries - 1;
+
+         if (setup_info[choice].type & TYPE_SKIP_ENTRY)
+           choice--;
+       }
+#if 1
+       else if (setup_info[choice].type & TYPE_SKIP_ENTRY)
+       {
+         choice += SIGN(dy);
+
+         if (choice < first_entry ||
+             choice > first_entry + num_page_entries - 1)
+         first_entry += SIGN(dy);
+       }
+#endif
+
+       // printf("::: MARK 1: %d\n", first_entry);
+
+       first_entry_store[setup_mode] = first_entry;
+       choice_store[setup_mode] = choice;
+
+       drawSetupInfoList(setup_info, first_entry, NUM_MENU_ENTRIES_ON_SCREEN);
+
+       DrawCursorAndText_Setup(choice - first_entry, choice, TRUE);
+
+       AdjustScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL, max_setup_info,
+                       NUM_MENU_ENTRIES_ON_SCREEN, first_entry);
+      }
+
+      return;
+    }
+
     if (dx)
     {
       int menu_navigation_type = (dx < 0 ? TYPE_LEAVE : TYPE_ENTER);
@@ -5377,29 +6041,132 @@ void HandleSetupScreen_Generic(int mx, int my, int dx, int dy, int button)
          setup_info[choice].type & TYPE_YES_NO_AUTO)
        button = MB_MENU_CHOICE;
     }
+#if 1
+    else if (dy)
+      y += dy;
+#else
     else if (dy)
       y = choice + dy;
+#endif
 
     /* jump to next non-empty menu entry (up or down) */
+#if 1
+    while (first_entry + y > 0 &&
+          first_entry + y < max_setup_info - 1 &&
+          setup_info[first_entry + y].type & TYPE_SKIP_ENTRY)
+      y += dy;
+#else
     while (y > 0 && y < num_setup_info - 1 &&
-          setup_info[y].type & TYPE_SKIP_ENTRY)
+          setup_info[first_entry + y].type & TYPE_SKIP_ENTRY)
       y += dy;
+#endif
+
+    if (!IN_VIS_FIELD(x, y))
+    {
+      choice += y - y_old;
+#if 1
+      if (choice < first_entry)
+       first_entry = choice;
+      else if (choice > first_entry + num_page_entries - 1)
+       first_entry = choice - num_page_entries + 1;
+#else
+      first_entry += y - y_old;
+#endif
+
+      if (first_entry >= 0 &&
+         first_entry + num_page_entries <= max_setup_info)
+      {
+       first_entry_store[setup_mode] = first_entry;
+
+       if (choice < first_entry)
+         choice = first_entry;
+       else if (choice > first_entry + num_page_entries - 1)
+         choice = first_entry + num_page_entries - 1;
+
+       choice_store[setup_mode] = choice;
+
+       drawSetupInfoList(setup_info, first_entry, NUM_MENU_ENTRIES_ON_SCREEN);
+
+       DrawCursorAndText_Setup(choice - first_entry, choice, TRUE);
+
+       AdjustScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL, max_setup_info,
+                       NUM_MENU_ENTRIES_ON_SCREEN, first_entry);
+      }
+
+      return;
+    }
   }
 
+#if 1
+  if (!anyScrollbarGadgetActive() &&
+      IN_VIS_FIELD(x, y) &&
+      mx < screen_gadget[SCREEN_CTRL_ID_SCROLL_VERTICAL]->x &&
+      y >= 0 && y < num_page_entries)
+#else
   if (IN_VIS_FIELD(x, y) && y >= 0 && y < num_setup_info)
+#endif
   {
+#if 0
+    printf("::: TEST/HandleSetupScreen_Generic [%d, %d, %d, %d]\n", Counter(),
+          button, mx, screen_gadget[SCREEN_CTRL_ID_SCROLL_VERTICAL]->x);
+#endif
+
     if (button)
     {
+#if 1
+      if (first_entry + y != choice &&
+         setup_info[first_entry + y].type & ~TYPE_SKIP_ENTRY)
+      {
+       PlaySound(SND_MENU_ITEM_ACTIVATING);
+
+       DrawCursorAndText_Setup(choice - first_entry, choice, FALSE);
+       DrawCursorAndText_Setup(y, first_entry + y, TRUE);
+
+       choice = choice_store[setup_mode] = first_entry + y;
+      }
+#else
       if (y != choice && setup_info[y].type & ~TYPE_SKIP_ENTRY)
       {
        PlaySound(SND_MENU_ITEM_ACTIVATING);
 
-       DrawCursorAndText_Setup(choice, FALSE);
-       DrawCursorAndText_Setup(y, TRUE);
+       DrawCursorAndText_Setup(choice, -1, FALSE);
+       DrawCursorAndText_Setup(y, -1, TRUE);
 
        choice = choice_store[setup_mode] = y;
       }
+#endif
     }
+#if 1
+    else if (!(setup_info[first_entry + y].type & TYPE_GHOSTED))
+    {
+      PlaySound(SND_MENU_ITEM_SELECTING);
+
+      /* when selecting key headline, execute function for key value change */
+      if (setup_info[first_entry + y].type & TYPE_KEYTEXT &&
+         setup_info[first_entry + y + 1].type & TYPE_KEY)
+       y++;
+
+      /* when selecting string value, execute function for list selection */
+      if (setup_info[first_entry + y].type & TYPE_STRING && y > 0 &&
+         setup_info[first_entry + y - 1].type & TYPE_ENTER_LIST)
+       y--;
+
+      if (setup_info[first_entry + y].type & TYPE_ENTER_OR_LEAVE)
+      {
+       void (*menu_callback_function)(void) =
+         setup_info[first_entry + y].value;
+
+       FadeSetFromType(setup_info[first_entry + y].type);
+
+       menu_callback_function();
+      }
+      else
+      {
+       if (setup_info[first_entry + y].type & TYPE_VALUE)
+         changeSetupValue(y, first_entry + y, dx);
+      }
+    }
+#else
     else if (!(setup_info[y].type & TYPE_GHOSTED))
     {
       PlaySound(SND_MENU_ITEM_SELECTING);
@@ -5428,6 +6195,7 @@ void HandleSetupScreen_Generic(int mx, int my, int dx, int dy, int button)
          changeSetupValue(y, dx);
       }
     }
+#endif
   }
 }
 
@@ -5470,7 +6238,7 @@ void DrawSetupScreen_Input()
     else if (setup_info[i].type & ~TYPE_SKIP_ENTRY)
       initCursor(i, IMG_MENU_BUTTON);
 
-    DrawCursorAndText_Setup(i, FALSE);
+    DrawCursorAndText_Setup(i, -1, FALSE);
   }
 
 #if 0
@@ -5639,7 +6407,7 @@ void HandleSetupScreen_Input(int mx, int my, int dx, int dy, int button)
   {
     drawPlayerSetupInputInfo(input_player_nr, (choice == 2));
 
-    DrawCursorAndText_Setup(choice, TRUE);
+    DrawCursorAndText_Setup(choice, -1, TRUE);
 
     return;
   }
@@ -5684,8 +6452,8 @@ void HandleSetupScreen_Input(int mx, int my, int dx, int dy, int button)
     {
       if (y != choice)
       {
-       DrawCursorAndText_Setup(choice, FALSE);
-       DrawCursorAndText_Setup(y, TRUE);
+       DrawCursorAndText_Setup(choice, -1, FALSE);
+       DrawCursorAndText_Setup(y, -1, TRUE);
 
        drawPlayerSetupInputInfo(input_player_nr, (y == 2));
 
@@ -6113,12 +6881,14 @@ void DrawSetupScreen()
     DrawSetupScreen_Input();
   else if (setup_mode == SETUP_MODE_CHOOSE_GAME_SPEED)
     DrawChooseTree(&game_speed_current);
+  else if (setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY)
+    DrawChooseTree(&scroll_delay_current);
   else if (setup_mode == SETUP_MODE_CHOOSE_SCREEN_MODE)
     DrawChooseTree(&screen_mode_current);
   else if (setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE)
     DrawChooseTree(&window_size_current);
-  else if (setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY)
-    DrawChooseTree(&scroll_delay_current);
+  else if (setup_mode == SETUP_MODE_CHOOSE_SCALING_TYPE)
+    DrawChooseTree(&scaling_type_current);
   else if (setup_mode == SETUP_MODE_CHOOSE_GRAPHICS)
     DrawChooseTree(&artwork.gfx_current);
   else if (setup_mode == SETUP_MODE_CHOOSE_SOUNDS)
@@ -6144,7 +6914,7 @@ void RedrawSetupScreenAfterFullscreenToggle()
   if (setup_mode == SETUP_MODE_GRAPHICS ||
       setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE)
   {
-    // update "setup.window_scaling_percent" from list selection
+    // update list selection from "setup.window_scaling_percent"
     execSetupGraphics_setWindowSizes(TRUE);
 
     DrawSetupScreen();
@@ -6161,12 +6931,14 @@ void HandleSetupScreen(int mx, int my, int dx, int dy, int button)
     HandleSetupScreen_Input(mx, my, dx, dy, button);
   else if (setup_mode == SETUP_MODE_CHOOSE_GAME_SPEED)
     HandleChooseTree(mx, my, dx, dy, button, &game_speed_current);
+  else if (setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY)
+    HandleChooseTree(mx, my, dx, dy, button, &scroll_delay_current);
   else if (setup_mode == SETUP_MODE_CHOOSE_SCREEN_MODE)
     HandleChooseTree(mx, my, dx, dy, button, &screen_mode_current);
   else if (setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE)
     HandleChooseTree(mx, my, dx, dy, button, &window_size_current);
-  else if (setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY)
-    HandleChooseTree(mx, my, dx, dy, button, &scroll_delay_current);
+  else if (setup_mode == SETUP_MODE_CHOOSE_SCALING_TYPE)
+    HandleChooseTree(mx, my, dx, dy, button, &scaling_type_current);
   else if (setup_mode == SETUP_MODE_CHOOSE_GRAPHICS)
     HandleChooseTree(mx, my, dx, dy, button, &artwork.gfx_current);
   else if (setup_mode == SETUP_MODE_CHOOSE_SOUNDS)
@@ -6182,7 +6954,9 @@ void HandleSetupScreen(int mx, int my, int dx, int dy, int button)
   else
     HandleSetupScreen_Generic(mx, my, dx, dy, button);
 
+#if 0
   DoAnimation();
+#endif
 }
 
 void HandleGameActions()
@@ -6205,13 +6979,13 @@ static void getScreenMenuButtonPos(int *x, int *y, int gadget_id)
   {
 #if 1
     case SCREEN_CTRL_ID_PREV_LEVEL:
-      *x = mSX + menu.main.button.prev_level.x;
-      *y = mSY + menu.main.button.prev_level.y;
+      *x = mSX + GDI_ACTIVE_POS(menu.main.button.prev_level.x);
+      *y = mSY + GDI_ACTIVE_POS(menu.main.button.prev_level.y);
       break;
 
     case SCREEN_CTRL_ID_NEXT_LEVEL:
-      *x = mSX + menu.main.button.next_level.x;
-      *y = mSY + menu.main.button.next_level.y;
+      *x = mSX + GDI_ACTIVE_POS(menu.main.button.next_level.x);
+      *y = mSY + GDI_ACTIVE_POS(menu.main.button.next_level.y);
       break;
 #else
     case SCREEN_CTRL_ID_PREV_LEVEL:
@@ -6618,8 +7392,25 @@ void MapScreenMenuGadgets(int screen_mask)
       MapGadget(screen_gadget[menubutton_info[i].gadget_id]);
 }
 
+void MapScreenGadgets(int num_entries)
+{
+  int i;
+
+  if (num_entries <= NUM_MENU_ENTRIES_ON_SCREEN)
+    return;
+
+  for (i = 0; i < NUM_SCREEN_SCROLLBUTTONS; i++)
+    MapGadget(screen_gadget[scrollbutton_info[i].gadget_id]);
+
+  for (i = 0; i < NUM_SCREEN_SCROLLBARS; i++)
+    MapGadget(screen_gadget[scrollbar_info[i].gadget_id]);
+}
+
 void MapScreenTreeGadgets(TreeInfo *ti)
 {
+#if 1
+  MapScreenGadgets(numTreeInfoInGroup(ti));
+#else
   int num_entries = numTreeInfoInGroup(ti);
   int i;
 
@@ -6631,6 +7422,7 @@ void MapScreenTreeGadgets(TreeInfo *ti)
 
   for (i = 0; i < NUM_SCREEN_SCROLLBARS; i++)
     MapGadget(screen_gadget[scrollbar_info[i].gadget_id]);
+#endif
 }
 
 static void HandleScreenGadgets(struct GadgetInfo *gi)