major cleanup of preprocessor hell
[rocksndiamonds.git] / src / editor.c
index a75d128500553814e1de836731ed2a16af5d4355..f39eb4e4ca4cdd4646ebb97b7dc07b583cb62fbe 100644 (file)
@@ -1,15 +1,13 @@
-/***********************************************************
-* Rocks'n'Diamonds -- McDuffin Strikes Back!               *
-*----------------------------------------------------------*
-* (c) 1995-2006 Artsoft Entertainment                      *
-*               Holger Schemel                             *
-*               Detmolder Strasse 189                      *
-*               33604 Bielefeld                            *
-*               Germany                                    *
-*               e-mail: info@artsoft.org                   *
-*----------------------------------------------------------*
-* editor.c                                                 *
-***********************************************************/
+// ============================================================================
+// Rocks'n'Diamonds - McDuffin Strikes Back!
+// ----------------------------------------------------------------------------
+// (c) 1995-2014 by Artsoft Entertainment
+//                         Holger Schemel
+//                 info@artsoft.org
+//                 http://www.artsoft.org/
+// ----------------------------------------------------------------------------
+// editor.c
+// ============================================================================
 
 #include <math.h>
 
 */
 
 /* positions in the level editor */
-#define ED_WIN_MB_LEFT_XPOS            6
-#define ED_WIN_MB_LEFT_YPOS            258
-#define ED_WIN_MB_MIDDLE_XPOS          42
-#define ED_WIN_MB_MIDDLE_YPOS          ED_WIN_MB_LEFT_YPOS
-#define ED_WIN_MB_RIGHT_XPOS           78
-#define ED_WIN_MB_RIGHT_YPOS           ED_WIN_MB_LEFT_YPOS
+#define ED_WIN_MB_LEFT_XPOS            (editor.palette.element_left.x)
+#define ED_WIN_MB_LEFT_YPOS            (editor.palette.element_left.y)
+#define ED_WIN_MB_MIDDLE_XPOS          (editor.palette.element_middle.x)
+#define ED_WIN_MB_MIDDLE_YPOS          (editor.palette.element_middle.y)
+#define ED_WIN_MB_RIGHT_XPOS           (editor.palette.element_right.x)
+#define ED_WIN_MB_RIGHT_YPOS           (editor.palette.element_right.y)
 
 /* values for the control window */
 #define ED_CTRL_NO_BUTTONS_GFX_XPOS    6
                                ED_NUM_CTRL4_BUTTONS)
 
 /* values for the element list */
-#define ED_ELEMENTLIST_XPOS            5
-#define ED_ELEMENTLIST_YPOS            30
+#define ED_ELEMENTLIST_XPOS            (editor.palette.x)
+#define ED_ELEMENTLIST_YPOS            (editor.palette.y)
 #define ED_ELEMENTLIST_XSIZE           20
 #define ED_ELEMENTLIST_YSIZE           20
-#define ED_ELEMENTLIST_BUTTONS_HORIZ   4
-#define ED_ELEMENTLIST_BUTTONS_VERT    11
+#define ED_ELEMENTLIST_BUTTONS_HORIZ   (editor.palette.cols)
+#define ED_ELEMENTLIST_BUTTONS_VERT    (editor.palette.rows)
 #define ED_NUM_ELEMENTLIST_BUTTONS     (ED_ELEMENTLIST_BUTTONS_HORIZ * \
                                         ED_ELEMENTLIST_BUTTONS_VERT)
 
 #define ED_SCROLLBUTTON2_XSIZE         10
 #define ED_SCROLLBUTTON2_YSIZE         10
 
-#define ED_SCROLL2_UP_XPOS             85
-#define ED_SCROLL2_UP_YPOS             30
+#define ED_SCROLL2_UP_XPOS             (ED_ELEMENTLIST_XPOS +          \
+                                        ED_ELEMENTLIST_BUTTONS_HORIZ * \
+                                        ED_ELEMENTLIST_XSIZE)
+#define ED_SCROLL2_UP_YPOS             ED_ELEMENTLIST_YPOS
 #define ED_SCROLL2_DOWN_XPOS           ED_SCROLL2_UP_XPOS
 #define ED_SCROLL2_DOWN_YPOS           (ED_SCROLL2_UP_YPOS +           \
                                         ED_ELEMENTLIST_BUTTONS_VERT *  \
 #define GADGET_ID_RANDOM_BALL_CONTENT  (GADGET_ID_CHECKBUTTON_FIRST + 8)
 #define GADGET_ID_INITIAL_BALL_STATE   (GADGET_ID_CHECKBUTTON_FIRST + 9)
 #define GADGET_ID_GROW_INTO_DIGGABLE   (GADGET_ID_CHECKBUTTON_FIRST + 10)
-#define GADGET_ID_CONTINUOUS_SNAPPING  (GADGET_ID_CHECKBUTTON_FIRST + 11)
-#define GADGET_ID_BLOCK_SNAP_FIELD     (GADGET_ID_CHECKBUTTON_FIRST + 12)
-#define GADGET_ID_BLOCK_LAST_FIELD     (GADGET_ID_CHECKBUTTON_FIRST + 13)
-#define GADGET_ID_SP_BLOCK_LAST_FIELD  (GADGET_ID_CHECKBUTTON_FIRST + 14)
-#define GADGET_ID_INSTANT_RELOCATION   (GADGET_ID_CHECKBUTTON_FIRST + 15)
-#define GADGET_ID_SHIFTED_RELOCATION   (GADGET_ID_CHECKBUTTON_FIRST + 16)
-#define GADGET_ID_USE_START_ELEMENT    (GADGET_ID_CHECKBUTTON_FIRST + 17)
-#define GADGET_ID_USE_ARTWORK_ELEMENT  (GADGET_ID_CHECKBUTTON_FIRST + 18)
-#define GADGET_ID_USE_EXPLOSION_ELEMENT        (GADGET_ID_CHECKBUTTON_FIRST + 19)
-#define GADGET_ID_INITIAL_GRAVITY      (GADGET_ID_CHECKBUTTON_FIRST + 20)
-#define GADGET_ID_USE_INITIAL_INVENTORY        (GADGET_ID_CHECKBUTTON_FIRST + 21)
-#define GADGET_ID_CAN_PASS_TO_WALKABLE (GADGET_ID_CHECKBUTTON_FIRST + 22)
-#define GADGET_ID_CAN_FALL_INTO_ACID   (GADGET_ID_CHECKBUTTON_FIRST + 23)
-#define GADGET_ID_CAN_MOVE_INTO_ACID   (GADGET_ID_CHECKBUTTON_FIRST + 24)
-#define GADGET_ID_DONT_COLLIDE_WITH    (GADGET_ID_CHECKBUTTON_FIRST + 25)
-#define GADGET_ID_ENVELOPE_AUTOWRAP    (GADGET_ID_CHECKBUTTON_FIRST + 26)
-#define GADGET_ID_ENVELOPE_CENTERED    (GADGET_ID_CHECKBUTTON_FIRST + 27)
-#define GADGET_ID_CUSTOM_INDESTRUCTIBLE        (GADGET_ID_CHECKBUTTON_FIRST + 28)
-#define GADGET_ID_CUSTOM_CAN_EXPLODE   (GADGET_ID_CHECKBUTTON_FIRST + 29)
-#define GADGET_ID_CUSTOM_EXPLODE_FIRE  (GADGET_ID_CHECKBUTTON_FIRST + 30)
-#define GADGET_ID_CUSTOM_EXPLODE_SMASH (GADGET_ID_CHECKBUTTON_FIRST + 31)
-#define GADGET_ID_CUSTOM_EXPLODE_IMPACT        (GADGET_ID_CHECKBUTTON_FIRST + 32)
-#define GADGET_ID_CUSTOM_WALK_TO_OBJECT        (GADGET_ID_CHECKBUTTON_FIRST + 33)
-#define GADGET_ID_CUSTOM_DEADLY                (GADGET_ID_CHECKBUTTON_FIRST + 34)
-#define GADGET_ID_CUSTOM_CAN_MOVE      (GADGET_ID_CHECKBUTTON_FIRST + 35)
-#define GADGET_ID_CUSTOM_CAN_FALL      (GADGET_ID_CHECKBUTTON_FIRST + 36)
-#define GADGET_ID_CUSTOM_CAN_SMASH     (GADGET_ID_CHECKBUTTON_FIRST + 37)
-#define GADGET_ID_CUSTOM_SLIPPERY      (GADGET_ID_CHECKBUTTON_FIRST + 38)
-#define GADGET_ID_CUSTOM_ACCESSIBLE    (GADGET_ID_CHECKBUTTON_FIRST + 39)
-#define GADGET_ID_CUSTOM_GRAV_REACHABLE        (GADGET_ID_CHECKBUTTON_FIRST + 40)
-#define GADGET_ID_CUSTOM_USE_LAST_VALUE        (GADGET_ID_CHECKBUTTON_FIRST + 41)
-#define GADGET_ID_CUSTOM_USE_GRAPHIC   (GADGET_ID_CHECKBUTTON_FIRST + 42)
-#define GADGET_ID_CUSTOM_USE_TEMPLATE  (GADGET_ID_CHECKBUTTON_FIRST + 43)
-#define GADGET_ID_CUSTOM_CAN_CHANGE    (GADGET_ID_CHECKBUTTON_FIRST + 44)
-#define GADGET_ID_CHANGE_USE_CONTENT   (GADGET_ID_CHECKBUTTON_FIRST + 45)
-#define GADGET_ID_CHANGE_USE_EXPLOSION (GADGET_ID_CHECKBUTTON_FIRST + 46)
-#define GADGET_ID_CHANGE_ONLY_COMPLETE (GADGET_ID_CHECKBUTTON_FIRST + 47)
-#define GADGET_ID_CHANGE_USE_RANDOM    (GADGET_ID_CHECKBUTTON_FIRST + 48)
-#define GADGET_ID_CHANGE_HAS_ACTION    (GADGET_ID_CHECKBUTTON_FIRST + 49)
-#define GADGET_ID_CHANGE_DELAY         (GADGET_ID_CHECKBUTTON_FIRST + 50)
-#define GADGET_ID_CHANGE_BY_DIRECT_ACT (GADGET_ID_CHECKBUTTON_FIRST + 51)
-#define GADGET_ID_CHANGE_BY_OTHER_ACT  (GADGET_ID_CHECKBUTTON_FIRST + 52)
+#define GADGET_ID_AUTO_EXIT_SOKOBAN    (GADGET_ID_CHECKBUTTON_FIRST + 11)
+#define GADGET_ID_CONTINUOUS_SNAPPING  (GADGET_ID_CHECKBUTTON_FIRST + 12)
+#define GADGET_ID_BLOCK_SNAP_FIELD     (GADGET_ID_CHECKBUTTON_FIRST + 13)
+#define GADGET_ID_BLOCK_LAST_FIELD     (GADGET_ID_CHECKBUTTON_FIRST + 14)
+#define GADGET_ID_SP_BLOCK_LAST_FIELD  (GADGET_ID_CHECKBUTTON_FIRST + 15)
+#define GADGET_ID_INSTANT_RELOCATION   (GADGET_ID_CHECKBUTTON_FIRST + 16)
+#define GADGET_ID_SHIFTED_RELOCATION   (GADGET_ID_CHECKBUTTON_FIRST + 17)
+#define GADGET_ID_USE_START_ELEMENT    (GADGET_ID_CHECKBUTTON_FIRST + 18)
+#define GADGET_ID_USE_ARTWORK_ELEMENT  (GADGET_ID_CHECKBUTTON_FIRST + 19)
+#define GADGET_ID_USE_EXPLOSION_ELEMENT        (GADGET_ID_CHECKBUTTON_FIRST + 20)
+#define GADGET_ID_INITIAL_GRAVITY      (GADGET_ID_CHECKBUTTON_FIRST + 21)
+#define GADGET_ID_USE_INITIAL_INVENTORY        (GADGET_ID_CHECKBUTTON_FIRST + 22)
+#define GADGET_ID_CAN_PASS_TO_WALKABLE (GADGET_ID_CHECKBUTTON_FIRST + 23)
+#define GADGET_ID_CAN_FALL_INTO_ACID   (GADGET_ID_CHECKBUTTON_FIRST + 24)
+#define GADGET_ID_CAN_MOVE_INTO_ACID   (GADGET_ID_CHECKBUTTON_FIRST + 25)
+#define GADGET_ID_DONT_COLLIDE_WITH    (GADGET_ID_CHECKBUTTON_FIRST + 26)
+#define GADGET_ID_ENVELOPE_AUTOWRAP    (GADGET_ID_CHECKBUTTON_FIRST + 27)
+#define GADGET_ID_ENVELOPE_CENTERED    (GADGET_ID_CHECKBUTTON_FIRST + 28)
+#define GADGET_ID_CUSTOM_INDESTRUCTIBLE        (GADGET_ID_CHECKBUTTON_FIRST + 29)
+#define GADGET_ID_CUSTOM_CAN_EXPLODE   (GADGET_ID_CHECKBUTTON_FIRST + 30)
+#define GADGET_ID_CUSTOM_EXPLODE_FIRE  (GADGET_ID_CHECKBUTTON_FIRST + 31)
+#define GADGET_ID_CUSTOM_EXPLODE_SMASH (GADGET_ID_CHECKBUTTON_FIRST + 32)
+#define GADGET_ID_CUSTOM_EXPLODE_IMPACT        (GADGET_ID_CHECKBUTTON_FIRST + 33)
+#define GADGET_ID_CUSTOM_WALK_TO_OBJECT        (GADGET_ID_CHECKBUTTON_FIRST + 34)
+#define GADGET_ID_CUSTOM_DEADLY                (GADGET_ID_CHECKBUTTON_FIRST + 35)
+#define GADGET_ID_CUSTOM_CAN_MOVE      (GADGET_ID_CHECKBUTTON_FIRST + 36)
+#define GADGET_ID_CUSTOM_CAN_FALL      (GADGET_ID_CHECKBUTTON_FIRST + 37)
+#define GADGET_ID_CUSTOM_CAN_SMASH     (GADGET_ID_CHECKBUTTON_FIRST + 38)
+#define GADGET_ID_CUSTOM_SLIPPERY      (GADGET_ID_CHECKBUTTON_FIRST + 39)
+#define GADGET_ID_CUSTOM_ACCESSIBLE    (GADGET_ID_CHECKBUTTON_FIRST + 40)
+#define GADGET_ID_CUSTOM_GRAV_REACHABLE        (GADGET_ID_CHECKBUTTON_FIRST + 41)
+#define GADGET_ID_CUSTOM_USE_LAST_VALUE        (GADGET_ID_CHECKBUTTON_FIRST + 42)
+#define GADGET_ID_CUSTOM_USE_GRAPHIC   (GADGET_ID_CHECKBUTTON_FIRST + 43)
+#define GADGET_ID_CUSTOM_USE_TEMPLATE  (GADGET_ID_CHECKBUTTON_FIRST + 44)
+#define GADGET_ID_CUSTOM_CAN_CHANGE    (GADGET_ID_CHECKBUTTON_FIRST + 45)
+#define GADGET_ID_CHANGE_USE_CONTENT   (GADGET_ID_CHECKBUTTON_FIRST + 46)
+#define GADGET_ID_CHANGE_USE_EXPLOSION (GADGET_ID_CHECKBUTTON_FIRST + 47)
+#define GADGET_ID_CHANGE_ONLY_COMPLETE (GADGET_ID_CHECKBUTTON_FIRST + 48)
+#define GADGET_ID_CHANGE_USE_RANDOM    (GADGET_ID_CHECKBUTTON_FIRST + 49)
+#define GADGET_ID_CHANGE_HAS_ACTION    (GADGET_ID_CHECKBUTTON_FIRST + 50)
+#define GADGET_ID_CHANGE_DELAY         (GADGET_ID_CHECKBUTTON_FIRST + 51)
+#define GADGET_ID_CHANGE_BY_DIRECT_ACT (GADGET_ID_CHECKBUTTON_FIRST + 52)
+#define GADGET_ID_CHANGE_BY_OTHER_ACT  (GADGET_ID_CHECKBUTTON_FIRST + 53)
 
 /* gadgets for buttons in element list */
-#define GADGET_ID_ELEMENTLIST_FIRST    (GADGET_ID_CHECKBUTTON_FIRST + 53)
+#define GADGET_ID_ELEMENTLIST_FIRST    (GADGET_ID_CHECKBUTTON_FIRST + 54)
 #define GADGET_ID_ELEMENTLIST_LAST     (GADGET_ID_ELEMENTLIST_FIRST +  \
                                        ED_NUM_ELEMENTLIST_BUTTONS - 1)
 
 #define ED_CHECKBUTTON_ID_RANDOM_BALL_CONTENT  6
 #define ED_CHECKBUTTON_ID_INITIAL_BALL_STATE   7
 #define ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE   8
-#define ED_CHECKBUTTON_ID_CONTINUOUS_SNAPPING  9
-#define ED_CHECKBUTTON_ID_BLOCK_SNAP_FIELD     10
-#define ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD     11
-#define ED_CHECKBUTTON_ID_SP_BLOCK_LAST_FIELD  12
-#define ED_CHECKBUTTON_ID_INSTANT_RELOCATION   13
-#define ED_CHECKBUTTON_ID_SHIFTED_RELOCATION   14
-#define ED_CHECKBUTTON_ID_USE_START_ELEMENT    15
-#define ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT  16
-#define ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT        17
-#define ED_CHECKBUTTON_ID_INITIAL_GRAVITY      18
-#define ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY        19
-#define ED_CHECKBUTTON_ID_CAN_PASS_TO_WALKABLE 20
-#define ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID   21
-#define ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID   22
-#define ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH    23
-#define ED_CHECKBUTTON_ID_ENVELOPE_AUTOWRAP    24
-#define ED_CHECKBUTTON_ID_ENVELOPE_CENTERED    25
-#define ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC   26
-#define ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE  27
-#define ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE    28
-#define ED_CHECKBUTTON_ID_CUSTOM_GRAV_REACHABLE        29
-#define ED_CHECKBUTTON_ID_CUSTOM_USE_LAST_VALUE        30
-#define ED_CHECKBUTTON_ID_CUSTOM_WALK_TO_OBJECT        31
-#define ED_CHECKBUTTON_ID_CUSTOM_INDESTRUCTIBLE        32
-#define ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE      33
-#define ED_CHECKBUTTON_ID_CUSTOM_CAN_FALL      34
-#define ED_CHECKBUTTON_ID_CUSTOM_CAN_SMASH     35
-#define ED_CHECKBUTTON_ID_CUSTOM_SLIPPERY      36
-#define ED_CHECKBUTTON_ID_CUSTOM_DEADLY                37
-#define ED_CHECKBUTTON_ID_CUSTOM_CAN_EXPLODE   38
-#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_FIRE  39
-#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_SMASH 40
-#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT        41
-#define ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE    42
-#define ED_CHECKBUTTON_ID_CHANGE_DELAY         43
-#define ED_CHECKBUTTON_ID_CHANGE_BY_DIRECT_ACT 44
-#define ED_CHECKBUTTON_ID_CHANGE_BY_OTHER_ACT  45
-#define ED_CHECKBUTTON_ID_CHANGE_USE_EXPLOSION 46
-#define ED_CHECKBUTTON_ID_CHANGE_USE_CONTENT   47
-#define ED_CHECKBUTTON_ID_CHANGE_ONLY_COMPLETE 48
-#define ED_CHECKBUTTON_ID_CHANGE_USE_RANDOM    49
-#define ED_CHECKBUTTON_ID_CHANGE_HAS_ACTION    50
-
-#define ED_NUM_CHECKBUTTONS                    51
+#define ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN    9
+#define ED_CHECKBUTTON_ID_CONTINUOUS_SNAPPING  10
+#define ED_CHECKBUTTON_ID_BLOCK_SNAP_FIELD     11
+#define ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD     12
+#define ED_CHECKBUTTON_ID_SP_BLOCK_LAST_FIELD  13
+#define ED_CHECKBUTTON_ID_INSTANT_RELOCATION   14
+#define ED_CHECKBUTTON_ID_SHIFTED_RELOCATION   15
+#define ED_CHECKBUTTON_ID_USE_START_ELEMENT    16
+#define ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT  17
+#define ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT        18
+#define ED_CHECKBUTTON_ID_INITIAL_GRAVITY      19
+#define ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY        20
+#define ED_CHECKBUTTON_ID_CAN_PASS_TO_WALKABLE 21
+#define ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID   22
+#define ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID   23
+#define ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH    24
+#define ED_CHECKBUTTON_ID_ENVELOPE_AUTOWRAP    25
+#define ED_CHECKBUTTON_ID_ENVELOPE_CENTERED    26
+#define ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC   27
+#define ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE  28
+#define ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE    29
+#define ED_CHECKBUTTON_ID_CUSTOM_GRAV_REACHABLE        30
+#define ED_CHECKBUTTON_ID_CUSTOM_USE_LAST_VALUE        31
+#define ED_CHECKBUTTON_ID_CUSTOM_WALK_TO_OBJECT        32
+#define ED_CHECKBUTTON_ID_CUSTOM_INDESTRUCTIBLE        33
+#define ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE      34
+#define ED_CHECKBUTTON_ID_CUSTOM_CAN_FALL      35
+#define ED_CHECKBUTTON_ID_CUSTOM_CAN_SMASH     36
+#define ED_CHECKBUTTON_ID_CUSTOM_SLIPPERY      37
+#define ED_CHECKBUTTON_ID_CUSTOM_DEADLY                38
+#define ED_CHECKBUTTON_ID_CUSTOM_CAN_EXPLODE   39
+#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_FIRE  40
+#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_SMASH 41
+#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT        42
+#define ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE    43
+#define ED_CHECKBUTTON_ID_CHANGE_DELAY         44
+#define ED_CHECKBUTTON_ID_CHANGE_BY_DIRECT_ACT 45
+#define ED_CHECKBUTTON_ID_CHANGE_BY_OTHER_ACT  46
+#define ED_CHECKBUTTON_ID_CHANGE_USE_EXPLOSION 47
+#define ED_CHECKBUTTON_ID_CHANGE_USE_CONTENT   48
+#define ED_CHECKBUTTON_ID_CHANGE_ONLY_COMPLETE 49
+#define ED_CHECKBUTTON_ID_CHANGE_USE_RANDOM    50
+#define ED_CHECKBUTTON_ID_CHANGE_HAS_ACTION    51
+
+#define ED_NUM_CHECKBUTTONS                    52
 
 #define ED_CHECKBUTTON_ID_EDITOR_FIRST ED_CHECKBUTTON_ID_RANDOM_RESTRICTED
 #define ED_CHECKBUTTON_ID_EDITOR_LAST  ED_CHECKBUTTON_ID_RANDOM_RESTRICTED
 #define RANDOM_USE_QUANTITY            1
 
 /* maximal size of level editor drawing area */
-#define MAX_ED_FIELDX          (2 * SCR_FIELDX)
-#define MAX_ED_FIELDY          (2 * SCR_FIELDY - 1)
+#define MAX_ED_FIELDX                  (SCR_FIELDX)
+#define MAX_ED_FIELDY                  (SCR_FIELDY - 1)
 
 
 /*
@@ -1045,7 +1047,7 @@ static struct
   /* ---------- current level number --------------------------------------- */
 
   {
-    DX + 5 - SX,                       DY + 3 - SY,
+    -1, -1,    /* these values are not constant, but can change at runtime */
     1,                                 100,
     GADGET_ID_SELECT_LEVEL_DOWN,       GADGET_ID_SELECT_LEVEL_UP,
     GADGET_ID_SELECT_LEVEL_TEXT,       GADGET_ID_NONE,
@@ -2464,45 +2466,43 @@ static struct
 
 static struct
 {
-  int gd_x, gd_y;
   int x, y;
+} scrollbutton_pos[ED_NUM_SCROLLBUTTONS];
+
+static struct
+{
+  int graphic;
   int gadget_id;
   char *infotext;
 } scrollbutton_info[ED_NUM_SCROLLBUTTONS] =
 {
   {
-    ED_SCROLLBUTTON_XPOS,   ED_SCROLLBUTTON_YPOS + 0 * ED_SCROLLBUTTON_YSIZE,
-    ED_SCROLL_UP_XPOS,      ED_SCROLL_UP_YPOS,
+    IMG_EDITOR_PLAYFIELD_SCROLL_UP,
     GADGET_ID_SCROLL_UP,
     "scroll level editing area up"
   },
   {
-    ED_SCROLLBUTTON_XPOS,   ED_SCROLLBUTTON_YPOS + 1 * ED_SCROLLBUTTON_YSIZE,
-    ED_SCROLL_DOWN_XPOS,    ED_SCROLL_DOWN_YPOS,
+    IMG_EDITOR_PLAYFIELD_SCROLL_DOWN,
     GADGET_ID_SCROLL_DOWN,
     "scroll level editing area down"
   },
   {
-    ED_SCROLLBUTTON_XPOS,   ED_SCROLLBUTTON_YPOS + 2 * ED_SCROLLBUTTON_YSIZE,
-    ED_SCROLL_LEFT_XPOS,    ED_SCROLL_LEFT_YPOS,
+    IMG_EDITOR_PLAYFIELD_SCROLL_LEFT,
     GADGET_ID_SCROLL_LEFT,
     "scroll level editing area left"
   },
   {
-    ED_SCROLLBUTTON_XPOS,   ED_SCROLLBUTTON_YPOS + 3 * ED_SCROLLBUTTON_YSIZE,
-    ED_SCROLL_RIGHT_XPOS,   ED_SCROLL_RIGHT_YPOS,
+    IMG_EDITOR_PLAYFIELD_SCROLL_RIGHT,
     GADGET_ID_SCROLL_RIGHT,
     "scroll level editing area right"
   },
   {
-    ED_SCROLLBUTTON2_XPOS,  ED_SCROLLBUTTON2_YPOS + 0 * ED_SCROLLBUTTON2_YSIZE,
-    ED_SCROLL2_UP_XPOS,     ED_SCROLL2_UP_YPOS,
+    IMG_EDITOR_PALETTE_SCROLL_UP,
     GADGET_ID_SCROLL_LIST_UP,
     "scroll element list up ('Page Up')"
   },
   {
-    ED_SCROLLBUTTON2_XPOS,  ED_SCROLLBUTTON2_YPOS + 1 * ED_SCROLLBUTTON2_YSIZE,
-    ED_SCROLL2_DOWN_XPOS,   ED_SCROLL2_DOWN_YPOS,
+    IMG_EDITOR_PALETTE_SCROLL_DOWN,
     GADGET_ID_SCROLL_LIST_DOWN,
     "scroll element list down ('Page Down')"
   },
@@ -2510,63 +2510,41 @@ static struct
 
 static struct
 {
-  int gd_x, gd_y;
   int x, y;
   int width, height;
   int wheel_x, wheel_y;
   int wheel_width, wheel_height;
+} scrollbar_pos[ED_NUM_SCROLLBARS];
+
+static struct
+{
+  int graphic;
   int type;
   int gadget_id;
   char *infotext;
 } scrollbar_info[ED_NUM_SCROLLBARS] =
 {
   {
-    ED_SCROLLBAR_XPOS,                 ED_SCROLLBAR_YPOS,
-    SX + ED_SCROLL_HORIZONTAL_XPOS,    SY + ED_SCROLL_HORIZONTAL_YPOS,
-    ED_SCROLL_HORIZONTAL_XSIZE,                ED_SCROLL_HORIZONTAL_YSIZE,
-#if 1
-    SX,                                        SY,
-    SXSIZE,                            SYSIZE,
-#else
-    0,                                 0,
-    SX + SXSIZE + SX,                  WIN_YSIZE,
-#endif
+    IMG_EDITOR_PLAYFIELD_SCROLLBAR,
     GD_TYPE_SCROLLBAR_HORIZONTAL,
     GADGET_ID_SCROLL_HORIZONTAL,
     "scroll level editing area horizontally"
   },
   {
-    ED_SCROLLBAR_XPOS,                 ED_SCROLLBAR_YPOS,
-    SX + ED_SCROLL_VERTICAL_XPOS,      SY + ED_SCROLL_VERTICAL_YPOS,
-    ED_SCROLL_VERTICAL_XSIZE,          ED_SCROLL_VERTICAL_YSIZE,
-#if 1
-    SX,                                        SY,
-    SXSIZE,                            SYSIZE,
-#else
-    0,                                 0,
-    SX + SXSIZE + SX,                  WIN_YSIZE,
-#endif
+    IMG_EDITOR_PLAYFIELD_SCROLLBAR,
     GD_TYPE_SCROLLBAR_VERTICAL,
     GADGET_ID_SCROLL_VERTICAL,
     "scroll level editing area vertically"
   },
   {
-    ED_SCROLLBAR2_XPOS,                        ED_SCROLLBAR2_YPOS,
-    DX + ED_SCROLL2_VERTICAL_XPOS,     DY + ED_SCROLL2_VERTICAL_YPOS,
-    ED_SCROLL2_VERTICAL_XSIZE,         ED_SCROLL2_VERTICAL_YSIZE,
-#if 1
-    DX,                                        DY,
-    DXSIZE,                            DYSIZE,
-#else
-    SX + SXSIZE + SX,                  0,
-    WIN_XSIZE - (SX + SXSIZE + SX),    WIN_YSIZE,
-#endif
+    IMG_EDITOR_PALETTE_SCROLLBAR,
     GD_TYPE_SCROLLBAR_VERTICAL,
     GADGET_ID_SCROLL_LIST_VERTICAL,
     "scroll element list vertically"
   }
 };
 
+
 static struct
 {
   int x, y;
@@ -2671,12 +2649,19 @@ static struct
     NULL,
     "can grow into anything diggable", "grow into more than just sand"
   },
+  {
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(0),
+    GADGET_ID_AUTO_EXIT_SOKOBAN,       GADGET_ID_NONE,
+    &level.auto_exit_sokoban,
+    NULL,
+    "exit level if all fields solved", "automatically finish Sokoban levels"
+  },
   {
     ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(8),
     GADGET_ID_CONTINUOUS_SNAPPING,     GADGET_ID_NONE,
     &level.continuous_snapping,
     NULL,
-    "continuos snapping",              "use snapping without releasing key"
+    "continuous snapping",             "use snapping without releasing key"
   },
   {
     ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(7),
@@ -2797,15 +2782,8 @@ static struct
     ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(1),
     GADGET_ID_CUSTOM_USE_GRAPHIC,      GADGET_ID_NONE,
     &custom_element.use_gfx_element,
-
-    /* !!! add separate "use existing element sound" !!! */
-#if 0
-    NULL,
-    "use graphic/sound of element:",   "use existing graphic and sound"
-#else
     NULL,
     "use graphic of element:",         "use existing element graphic"
-#endif
   },
   {
     ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(2),
@@ -2998,7 +2976,8 @@ static struct
   {
     0,                                 0,
     GADGET_ID_DRAWING_LEVEL,           GADGET_ID_NONE,
-    NULL,                              MAX_ED_FIELDX, MAX_ED_FIELDY,
+    NULL,
+    -1, -1,    /* these values are not constant, but can change at runtime */
     NULL, NULL, NULL,                  NULL
   },
 
@@ -3260,16 +3239,12 @@ static struct
 */
 
 /* actual size of level editor drawing area */
-static int ed_fieldx = MAX_ED_FIELDX - 1, ed_fieldy = MAX_ED_FIELDY - 1;
+static int ed_fieldx, ed_fieldy;
 
 /* actual position of level editor drawing area in level playfield */
 static int level_xpos = -1, level_ypos = -1;
 
-#if 1
 #define IN_ED_FIELD(x,y)       IN_FIELD(x, y, ed_fieldx, ed_fieldy)
-#else
-#define IN_ED_FIELD(x,y)  ((x)>=0 && (x)<ed_fieldx && (y)>=0 &&(y)<ed_fieldy)
-#endif
 
 /* drawing elements on the three mouse buttons */
 static int new_element1 = EL_WALL;
@@ -3310,8 +3285,10 @@ static void HandleControlButtons(struct GadgetInfo *);
 static void HandleDrawingAreaInfo(struct GadgetInfo *);
 static void PrintEditorGadgetInfoText(struct GadgetInfo *);
 
-static struct GadgetInfo *level_editor_gadget[NUM_EDITOR_GADGETS];
-static int right_gadget_border[NUM_EDITOR_GADGETS];
+static int num_editor_gadgets = 0;     /* dynamically determined */
+
+static struct GadgetInfo **level_editor_gadget = NULL;
+static int *right_gadget_border = NULL;
 
 static int drawing_function = GADGET_ID_SINGLE_ITEMS;
 static int last_drawing_function = GADGET_ID_SINGLE_ITEMS;
@@ -3705,6 +3682,16 @@ static int editor_el_supaplex[] =
   EL_SP_GRAVITY_PORT_UP,
   EL_SP_GRAVITY_PORT_DOWN,
 
+  EL_SP_GRAVITY_ON_PORT_LEFT,
+  EL_SP_GRAVITY_ON_PORT_RIGHT,
+  EL_SP_GRAVITY_ON_PORT_UP,
+  EL_SP_GRAVITY_ON_PORT_DOWN,
+
+  EL_SP_GRAVITY_OFF_PORT_LEFT,
+  EL_SP_GRAVITY_OFF_PORT_RIGHT,
+  EL_SP_GRAVITY_OFF_PORT_UP,
+  EL_SP_GRAVITY_OFF_PORT_DOWN,
+
   EL_SP_HARDWARE_GRAY,
   EL_SP_HARDWARE_GREEN,
   EL_SP_HARDWARE_BLUE,
@@ -4603,11 +4590,11 @@ static int *editor_el_dynamic_ptr = NULL;
 static int num_editor_hl_dynamic = SIZEOF_ARRAY_INT(editor_hl_dynamic);
 static int num_editor_el_dynamic = 0;
 
-static int editor_hl_empty[] = { };
-static int editor_el_empty[ED_NUM_ELEMENTLIST_BUTTONS];
+static int editor_hl_empty[] = { EL_EMPTY };
+static int *editor_el_empty = NULL;    /* dynamically allocated */
 
 static int *editor_hl_empty_ptr = editor_hl_empty;
-static int *editor_el_empty_ptr = editor_el_empty;
+static int *editor_el_empty_ptr = NULL;
 static int num_editor_hl_empty = 0;
 static int num_editor_el_empty = 0;    /* dynamically determined, if needed */
 
@@ -5090,7 +5077,7 @@ static void DrawElementBorder(int dest_x, int dest_y, int width, int height,
   int by2 = TILEY - by;
   int i;
 
-  getGraphicSource(border_graphic, 0, &src_bitmap, &src_x, &src_y);
+  getFixedGraphicSource(border_graphic, 0, &src_bitmap, &src_x, &src_y);
 
   BlitBitmap(src_bitmap, drawto, src_x, src_y,
             bx, by, dest_x - bx, dest_y - by);
@@ -5139,38 +5126,10 @@ static void DrawDrawingArea(int id)
 
 static void ScrollMiniLevel(int from_x, int from_y, int scroll)
 {
-#if 0
-  /* (directly solved in BlitBitmap() now) */
-  static Bitmap *tmp_backbuffer = NULL;
-#endif
   int x, y;
   int dx = (scroll == ED_SCROLL_LEFT ? -1 : scroll == ED_SCROLL_RIGHT ? 1 : 0);
   int dy = (scroll == ED_SCROLL_UP   ? -1 : scroll == ED_SCROLL_DOWN  ? 1 : 0);
 
-#if 0
-  /* (directly solved in BlitBitmap() now) */
-  if (tmp_backbuffer == NULL)
-    tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
-
-  /* needed when blitting directly to same bitmap -- should not be needed with
-     recent SDL libraries, but apparently does not work in 1.2.11 directly */
-  BlitBitmap(drawto, tmp_backbuffer,
-            SX + (dx == -1 ? MINI_TILEX : 0),
-            SY + (dy == -1 ? MINI_TILEY : 0),
-            (ed_fieldx * MINI_TILEX) - (dx != 0 ? MINI_TILEX : 0),
-            (ed_fieldy * MINI_TILEY) - (dy != 0 ? MINI_TILEY : 0),
-            SX + (dx == +1 ? MINI_TILEX : 0),
-            SY + (dy == +1 ? MINI_TILEY : 0));
-  BlitBitmap(tmp_backbuffer, drawto,
-            SX + (dx == +1 ? MINI_TILEX : 0),
-            SY + (dy == +1 ? MINI_TILEY : 0),
-            (ed_fieldx * MINI_TILEX) - (dx != 0 ? MINI_TILEX : 0),
-            (ed_fieldy * MINI_TILEY) - (dy != 0 ? MINI_TILEY : 0),
-            SX + (dx == +1 ? MINI_TILEX : 0),
-            SY + (dy == +1 ? MINI_TILEY : 0));
-
-#else
-
   BlitBitmap(drawto, drawto,
             SX + (dx == -1 ? MINI_TILEX : 0),
             SY + (dy == -1 ? MINI_TILEY : 0),
@@ -5178,7 +5137,6 @@ static void ScrollMiniLevel(int from_x, int from_y, int scroll)
             (ed_fieldy * MINI_TILEY) - (dy != 0 ? MINI_TILEY : 0),
             SX + (dx == +1 ? MINI_TILEX : 0),
             SY + (dy == +1 ? MINI_TILEY : 0));
-#endif
 
   if (dx)
   {
@@ -5201,7 +5159,7 @@ static void CreateControlButtons()
 {
   Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
   struct GadgetInfo *gi;
-  unsigned long event_mask;
+  unsigned int event_mask;
   int i;
 
   /* create toolbox buttons */
@@ -5336,15 +5294,31 @@ static void CreateControlButtons()
     level_editor_gadget[id] = gi;
   }
 
+  /* these values are not constant, but can change at runtime */
+  scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_UP].x    = ED_SCROLL_UP_XPOS;
+  scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_UP].y    = ED_SCROLL_UP_YPOS;
+  scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_DOWN].x  = ED_SCROLL_DOWN_XPOS;
+  scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_DOWN].y  = ED_SCROLL_DOWN_YPOS;
+  scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_LEFT].x  = ED_SCROLL_LEFT_XPOS;
+  scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_LEFT].y  = ED_SCROLL_LEFT_YPOS;
+  scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_RIGHT].x = ED_SCROLL_RIGHT_XPOS;
+  scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_RIGHT].y = ED_SCROLL_RIGHT_YPOS;
+  scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_UP].x    = ED_SCROLL2_UP_XPOS;
+  scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_UP].y    = ED_SCROLL2_UP_YPOS;
+  scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_DOWN].x  = ED_SCROLL2_DOWN_XPOS;
+  scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_DOWN].y  = ED_SCROLL2_DOWN_YPOS;
+
   /* create buttons for scrolling of drawing area and element list */
   for (i = 0; i < ED_NUM_SCROLLBUTTONS; i++)
   {
     int id = scrollbutton_info[i].gadget_id;
+    int graphic = scrollbutton_info[i].graphic;
+    struct GraphicInfo *gd = &graphic_info[graphic];
     int x, y, width, height;
     int gd_x1, gd_x2, gd_y1, gd_y2;
 
-    x = scrollbutton_info[i].x;
-    y = scrollbutton_info[i].y;
+    x = scrollbutton_pos[i].x;
+    y = scrollbutton_pos[i].y;
 
     event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
 
@@ -5353,23 +5327,23 @@ static void CreateControlButtons()
     {
       x += DX;
       y += DY;
-      width = ED_SCROLLBUTTON2_XSIZE;
-      height = ED_SCROLLBUTTON2_YSIZE;
-      gd_x1 = DOOR_GFX_PAGEX8 + scrollbutton_info[i].gd_x;
-      gd_y1 = DOOR_GFX_PAGEY1 + scrollbutton_info[i].gd_y;
-      gd_x2 = gd_x1 - ED_SCROLLBUTTON2_XSIZE;
-      gd_y2 = gd_y1;
+      width  = gd->width;
+      height = gd->height;
+      gd_x1 = gd->src_x;
+      gd_y1 = gd->src_y;
+      gd_x2 = gd->src_x + gd->pressed_xoffset;
+      gd_y2 = gd->src_y + gd->pressed_yoffset;
     }
     else
     {
       x += SX;
       y += SY;
-      width = ED_SCROLLBUTTON_XSIZE;
-      height = ED_SCROLLBUTTON_YSIZE;
-      gd_x1 = DOOR_GFX_PAGEX8 + scrollbutton_info[i].gd_x;
-      gd_y1 = DOOR_GFX_PAGEY1 + scrollbutton_info[i].gd_y;
-      gd_x2 = gd_x1 - ED_SCROLLBUTTON_XSIZE;
-      gd_y2 = gd_y1;
+      width  = gd->width;
+      height = gd->height;
+      gd_x1 = gd->src_x;
+      gd_y1 = gd->src_y;
+      gd_x2 = gd->src_x + gd->pressed_xoffset;
+      gd_y2 = gd->src_y + gd->pressed_yoffset;
     }
 
     gi = CreateGadget(GDI_CUSTOM_ID, id,
@@ -5397,10 +5371,11 @@ static void CreateControlButtons()
   /* create buttons for element list */
   for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
   {
+    struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_PALETTE_BUTTON];
     Bitmap *deco_bitmap;
     int deco_x, deco_y, deco_xpos, deco_ypos;
     int gd_xoffset, gd_yoffset;
-    int gd_x1, gd_x2, gd_y;
+    int gd_x1, gd_y1, gd_x2, gd_y2;
     int x = i % ED_ELEMENTLIST_BUTTONS_HORIZ;
     int y = i / ED_ELEMENTLIST_BUTTONS_HORIZ;
     int id = GADGET_ID_ELEMENTLIST_FIRST + i;
@@ -5408,28 +5383,29 @@ static void CreateControlButtons()
 
     event_mask = GD_EVENT_RELEASED;
 
-    gd_xoffset = ED_ELEMENTLIST_XPOS + x * ED_ELEMENTLIST_XSIZE;
-    gd_yoffset = ED_ELEMENTLIST_YPOS + y * ED_ELEMENTLIST_YSIZE;
+    gd_xoffset = ED_ELEMENTLIST_XPOS + x * gd->width;
+    gd_yoffset = ED_ELEMENTLIST_YPOS + y * gd->height;
 
-    gd_x1 = DOOR_GFX_PAGEX6 + ED_ELEMENTLIST_XPOS + ED_ELEMENTLIST_XSIZE;
-    gd_x2 = DOOR_GFX_PAGEX6 + ED_ELEMENTLIST_XPOS;
-    gd_y  = DOOR_GFX_PAGEY1 + ED_ELEMENTLIST_YPOS;
+    gd_x1 = gd->src_x;
+    gd_y1 = gd->src_y;
+    gd_x2 = gd->src_x + gd->pressed_xoffset;
+    gd_y2 = gd->src_y + gd->pressed_yoffset;
 
     getMiniGraphicSource(el2edimg(element), &deco_bitmap, &deco_x, &deco_y);
-    deco_xpos = (ED_ELEMENTLIST_XSIZE - MINI_TILEX) / 2;
-    deco_ypos = (ED_ELEMENTLIST_YSIZE - MINI_TILEY) / 2;
+    deco_xpos = (gd->width  - MINI_TILEX) / 2;
+    deco_ypos = (gd->height - MINI_TILEY) / 2;
 
     gi = CreateGadget(GDI_CUSTOM_ID, id,
                      GDI_CUSTOM_TYPE_ID, i,
                      GDI_INFO_TEXT, getElementInfoText(element),
                      GDI_X, DX + gd_xoffset,
                      GDI_Y, DY + gd_yoffset,
-                     GDI_WIDTH, ED_ELEMENTLIST_XSIZE,
-                     GDI_HEIGHT, ED_ELEMENTLIST_YSIZE,
+                     GDI_WIDTH, gd->width,
+                     GDI_HEIGHT, gd->height,
                      GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
                      GDI_STATE, GD_BUTTON_UNPRESSED,
-                     GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
-                     GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
+                     GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
+                     GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
                      GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
                      GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
                      GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
@@ -5451,6 +5427,10 @@ static void CreateCounterButtons()
   int max_infotext_len = getMaxInfoTextLength();
   int i;
 
+  /* these values are not constant, but can change at runtime */
+  counterbutton_info[ED_COUNTER_ID_SELECT_LEVEL].x = DX + 5 - SX;
+  counterbutton_info[ED_COUNTER_ID_SELECT_LEVEL].y = DY + 3 - SY;
+
   for (i = 0; i < ED_NUM_COUNTERBUTTONS; i++)
   {
     int j;
@@ -5474,18 +5454,21 @@ static void CreateCounterButtons()
                counterbutton_info[i].gadget_id_down :
                counterbutton_info[i].gadget_id_up);
       int gd_xoffset;
-      int gd_x, gd_x1, gd_x2, gd_y;
+      int gd_x, gd_y, gd_x1, gd_x2, gd_y1, gd_y2;
       int x_size, y_size;
-      unsigned long event_mask;
+      unsigned int event_mask;
       char infotext[max_infotext_len + 1];
 
       event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
 
       if (i == ED_COUNTER_ID_SELECT_LEVEL)
       {
-       int sid = (j == 0 ?
-                  ED_SCROLLBUTTON_ID_AREA_LEFT :
-                  ED_SCROLLBUTTON_ID_AREA_RIGHT);
+       int graphic = (j == 0 ?
+                      IMG_EDITOR_BUTTON_GFX_PREV_LEVEL :
+                      IMG_EDITOR_BUTTON_GFX_NEXT_LEVEL);
+       struct GraphicInfo *gd = &graphic_info[graphic];
+
+       gd_bitmap = gd->bitmap;
 
        event_mask |= GD_EVENT_RELEASED;
 
@@ -5493,18 +5476,20 @@ static void CreateCounterButtons()
          x += 2 * ED_GADGET_DISTANCE;
        y += ED_GADGET_DISTANCE;
 
-       gd_x1 = DOOR_GFX_PAGEX8 + scrollbutton_info[sid].gd_x;
-       gd_x2 = gd_x1 - ED_SCROLLBUTTON_XSIZE;
-       gd_y  = DOOR_GFX_PAGEY1 + scrollbutton_info[sid].gd_y;
-       x_size = ED_SCROLLBUTTON_XSIZE;
-       y_size = ED_SCROLLBUTTON_YSIZE;
+       gd_x1 = gd->src_x;
+       gd_y1 = gd->src_y;
+       gd_x2 = gd->src_x + gd->pressed_xoffset;
+       gd_y2 = gd->src_y + gd->pressed_yoffset;
+       x_size = gd->width;
+       y_size = gd->height;
       }
       else
       {
        gd_xoffset = (j == 0 ? ED_BUTTON_MINUS_XPOS : ED_BUTTON_PLUS_XPOS);
        gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
        gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
-       gd_y  = DOOR_GFX_PAGEY1 + ED_BUTTON_COUNT_YPOS;
+       gd_y1 = DOOR_GFX_PAGEY1 + ED_BUTTON_COUNT_YPOS;
+       gd_y2 = gd_y1;
        x_size = ED_BUTTON_COUNT_XSIZE;
        y_size = ED_BUTTON_COUNT_YSIZE;
       }
@@ -5521,8 +5506,8 @@ static void CreateCounterButtons()
                        GDI_HEIGHT, y_size,
                        GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
                        GDI_STATE, GD_BUTTON_UNPRESSED,
-                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
-                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
+                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
+                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
                        GDI_EVENT_MASK, event_mask,
                        GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
                        GDI_CALLBACK_ACTION, HandleCounterButtons,
@@ -5549,11 +5534,7 @@ static void CreateCounterButtons()
        if (i == ED_COUNTER_ID_SELECT_LEVEL)
        {
          font_type = FONT_LEVEL_NUMBER;
-#if 1
          font_type_active = FONT_LEVEL_NUMBER_ACTIVE;
-#else
-         font_type_active = FONT_LEVEL_NUMBER;
-#endif
          x += 2 * ED_GADGET_DISTANCE;
          y -= ED_GADGET_DISTANCE;
 
@@ -5605,10 +5586,14 @@ static void CreateDrawingAreas()
 {
   int i;
 
+  /* these values are not constant, but can change at runtime */
+  drawingarea_info[ED_DRAWING_ID_DRAWING_LEVEL].area_xsize = MAX_ED_FIELDX;
+  drawingarea_info[ED_DRAWING_ID_DRAWING_LEVEL].area_ysize = MAX_ED_FIELDY;
+
   for (i = 0; i < ED_NUM_DRAWING_AREAS; i++)
   {
     struct GadgetInfo *gi;
-    unsigned long event_mask;
+    unsigned int event_mask;
     int id = drawingarea_info[i].gadget_id;
     int x = SX + drawingarea_info[i].x;
     int y = SY + drawingarea_info[i].y;
@@ -5659,7 +5644,7 @@ static void CreateTextInputGadgets()
     Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
     int gd_x, gd_y;
     struct GadgetInfo *gi;
-    unsigned long event_mask;
+    unsigned int event_mask;
     char infotext[MAX_OUTPUT_LINESIZE + 1];
     int id = textinput_info[i].gadget_id;
 
@@ -5707,7 +5692,7 @@ static void CreateTextAreaGadgets()
     Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
     int gd_x, gd_y;
     struct GadgetInfo *gi;
-    unsigned long event_mask;
+    unsigned int event_mask;
     char infotext[MAX_OUTPUT_LINESIZE + 1];
     int id = textarea_info[i].gadget_id;
     int area_xsize = textarea_info[i].xsize;
@@ -5756,7 +5741,7 @@ static void CreateSelectboxGadgets()
     Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
     int gd_x, gd_y;
     struct GadgetInfo *gi;
-    unsigned long event_mask;
+    unsigned int event_mask;
     char infotext[MAX_OUTPUT_LINESIZE + 1];
     int id = selectbox_info[i].gadget_id;
     int x = SX + selectbox_info[i].x;
@@ -5833,7 +5818,7 @@ static void CreateTextbuttonGadgets()
     Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
     int gd_x1, gd_x2, gd_y1, gd_y2;
     struct GadgetInfo *gi;
-    unsigned long event_mask;
+    unsigned int event_mask;
     char infotext[MAX_OUTPUT_LINESIZE + 1];
     int id = textbutton_info[i].gadget_id;
     int x = SX + textbutton_info[i].x;
@@ -5906,7 +5891,7 @@ static void CreateGraphicbuttonGadgets()
 {
   Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
   struct GadgetInfo *gi;
-  unsigned long event_mask;
+  unsigned int event_mask;
   int i;
 
   /* create buttons for scrolling of drawing area and element list */
@@ -5972,14 +5957,56 @@ static void CreateScrollbarGadgets()
 {
   int i;
 
+  /* these values are not constant, but can change at runtime */
+  scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].x =
+    SX + ED_SCROLL_HORIZONTAL_XPOS;
+  scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].y =
+    SY + ED_SCROLL_HORIZONTAL_YPOS;
+  scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].width =
+    ED_SCROLL_HORIZONTAL_XSIZE;
+  scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].height =
+    ED_SCROLL_HORIZONTAL_YSIZE;
+  scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_x      = SX;
+  scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_y      = SY;
+  scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_width  = SXSIZE;
+  scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_height = SYSIZE;
+
+  scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].x =
+    SX + ED_SCROLL_VERTICAL_XPOS;
+  scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].y =
+    SY + ED_SCROLL_VERTICAL_YPOS;
+  scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].width =
+    ED_SCROLL_VERTICAL_XSIZE;
+  scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].height =
+    ED_SCROLL_VERTICAL_YSIZE;
+  scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_x      = SX;
+  scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_y      = SY;
+  scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_width  = SXSIZE;
+  scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_height = SYSIZE;
+
+  scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].x =
+    DX + ED_SCROLL2_VERTICAL_XPOS;
+  scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].y =
+    DY + ED_SCROLL2_VERTICAL_YPOS;
+  scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].width =
+    ED_SCROLL2_VERTICAL_XSIZE;
+  scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].height =
+    ED_SCROLL2_VERTICAL_YSIZE;
+  scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_x = DX;
+  scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_y = DY;
+  scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_width  = DXSIZE;
+  scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_height = DYSIZE;
+
   for (i = 0; i < ED_NUM_SCROLLBARS; i++)
   {
     int id = scrollbar_info[i].gadget_id;
-    Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
+    int graphic = scrollbar_info[i].graphic;
+    struct GraphicInfo *gd = &graphic_info[graphic];
+    Bitmap *gd_bitmap = gd->bitmap;
     int gd_x1, gd_x2, gd_y1, gd_y2;
     struct GadgetInfo *gi;
     int items_max, items_visible, item_position;
-    unsigned long event_mask;
+    unsigned int event_mask;
 
     if (i == ED_SCROLLBAR_ID_LIST_VERTICAL)
     {
@@ -6005,27 +6032,26 @@ static void CreateScrollbarGadgets()
 
     event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS;
 
-    gd_x1 = DOOR_GFX_PAGEX8 + scrollbar_info[i].gd_x;
-    gd_x2 = (gd_x1 - (scrollbar_info[i].type == GD_TYPE_SCROLLBAR_HORIZONTAL ?
-                     scrollbar_info[i].height : scrollbar_info[i].width));
-    gd_y1 = DOOR_GFX_PAGEY1 + scrollbar_info[i].gd_y;
-    gd_y2 = DOOR_GFX_PAGEY1 + scrollbar_info[i].gd_y;
+    gd_x1 = gd->src_x;
+    gd_y1 = gd->src_y;
+    gd_x2 = gd->src_x + gd->pressed_xoffset;
+    gd_y2 = gd->src_y + gd->pressed_yoffset;
 
     gi = CreateGadget(GDI_CUSTOM_ID, id,
                      GDI_CUSTOM_TYPE_ID, i,
                      GDI_INFO_TEXT, scrollbar_info[i].infotext,
-                     GDI_X, scrollbar_info[i].x,
-                     GDI_Y, scrollbar_info[i].y,
-                     GDI_WIDTH, scrollbar_info[i].width,
-                     GDI_HEIGHT, scrollbar_info[i].height,
+                     GDI_X, scrollbar_pos[i].x,
+                     GDI_Y, scrollbar_pos[i].y,
+                     GDI_WIDTH, scrollbar_pos[i].width,
+                     GDI_HEIGHT, scrollbar_pos[i].height,
                      GDI_TYPE, scrollbar_info[i].type,
                      GDI_SCROLLBAR_ITEMS_MAX, items_max,
                      GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
                      GDI_SCROLLBAR_ITEM_POSITION, item_position,
-                     GDI_WHEEL_AREA_X, scrollbar_info[i].wheel_x,
-                     GDI_WHEEL_AREA_Y, scrollbar_info[i].wheel_y,
-                     GDI_WHEEL_AREA_WIDTH, scrollbar_info[i].wheel_width,
-                     GDI_WHEEL_AREA_HEIGHT, scrollbar_info[i].wheel_height,
+                     GDI_WHEEL_AREA_X, scrollbar_pos[i].wheel_x,
+                     GDI_WHEEL_AREA_Y, scrollbar_pos[i].wheel_y,
+                     GDI_WHEEL_AREA_WIDTH, scrollbar_pos[i].wheel_width,
+                     GDI_WHEEL_AREA_HEIGHT, scrollbar_pos[i].wheel_height,
                      GDI_STATE, GD_BUTTON_UNPRESSED,
                      GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
                      GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
@@ -6046,7 +6072,7 @@ static void CreateCheckbuttonGadgets()
 {
   Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
   struct GadgetInfo *gi;
-  unsigned long event_mask;
+  unsigned int event_mask;
   int gd_x1, gd_x2, gd_x3, gd_x4, gd_y;
   int i;
 
@@ -6109,7 +6135,7 @@ static void CreateRadiobuttonGadgets()
 {
   Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
   struct GadgetInfo *gi;
-  unsigned long event_mask;
+  unsigned int event_mask;
   int gd_x1, gd_x2, gd_x3, gd_x4, gd_y;
   int i;
 
@@ -6174,6 +6200,22 @@ void CreateLevelEditorGadgets()
   /* setting 'game_status' is needed to get the right fonts for the editor */
   game_status = GAME_MODE_EDITOR;
 
+  /* these values are not constant, but can change at runtime */
+  ed_fieldx = MAX_ED_FIELDX - 1;
+  ed_fieldy = MAX_ED_FIELDY - 1;
+
+  num_editor_gadgets = NUM_EDITOR_GADGETS;
+
+  // printf("::: allocating %d gadgets ...\n", num_editor_gadgets);
+
+  level_editor_gadget =
+    checked_calloc(num_editor_gadgets * sizeof(struct GadgetInfo *));
+  right_gadget_border =
+    checked_calloc(num_editor_gadgets * sizeof(int));
+
+  editor_el_empty = checked_calloc(ED_NUM_ELEMENTLIST_BUTTONS * sizeof(int));
+  editor_el_empty_ptr = editor_el_empty;
+
   ReinitializeElementList();
 
   CreateControlButtons();
@@ -6197,12 +6239,19 @@ void FreeLevelEditorGadgets()
 {
   int i;
 
-  for (i = 0; i < NUM_EDITOR_GADGETS; i++)
+  // printf("::: freeing %d gadgets ...\n", num_editor_gadgets);
+
+  for (i = 0; i < num_editor_gadgets; i++)
   {
     FreeGadget(level_editor_gadget[i]);
 
     level_editor_gadget[i] = NULL;
   }
+
+  checked_free(level_editor_gadget);
+  checked_free(right_gadget_border);
+
+  checked_free(editor_el_empty);
 }
 
 static void MapCounterButtons(int id)
@@ -6567,12 +6616,13 @@ static void UnmapDrawingArea(int id)
   UnmapGadget(level_editor_gadget[drawingarea_info[id].gadget_id]);
 }
 
-static void UnmapLevelEditorWindowGadgets()
+static void UnmapLevelEditorFieldGadgets()
 {
   int i;
 
-  for (i = 0; i < NUM_EDITOR_GADGETS; i++)
-    if (level_editor_gadget[i]->x < SX + SXSIZE)
+  for (i = 0; i < num_editor_gadgets; i++)
+    if (IN_GFX_FIELD_FULL(level_editor_gadget[i]->x,
+                         level_editor_gadget[i]->y))
       UnmapGadget(level_editor_gadget[i]);
 }
 
@@ -6580,7 +6630,7 @@ void UnmapLevelEditorGadgets()
 {
   int i;
 
-  for (i = 0; i < NUM_EDITOR_GADGETS; i++)
+  for (i = 0; i < num_editor_gadgets; i++)
     UnmapGadget(level_editor_gadget[i]);
 }
 
@@ -6611,9 +6661,6 @@ static boolean LevelChanged()
   boolean field_changed = FALSE;
   int x, y;
 
-  if (leveldir_current->readonly)
-    return FALSE;
-
   for (y = 0; y < lev_fieldy; y++) 
     for (x = 0; x < lev_fieldx; x++)
       if (Feld[x][y] != level.field[x][y])
@@ -6622,21 +6669,151 @@ static boolean LevelChanged()
   return (level.changed || field_changed);
 }
 
-static boolean LevelContainsPlayer()
+static boolean PrepareSavingIntoPersonalLevelSet()
 {
-  boolean player_found = FALSE;
-  int x, y;
+  static LevelDirTree *last_copied_leveldir = NULL;
+  static LevelDirTree *last_written_leveldir = NULL;
+  static int last_copied_level_nr = -1;
+  static int last_written_level_nr = -1;
+  LevelDirTree *leveldir_former = leveldir_current;
+  int level_nr_former = level_nr;
+  int new_level_nr;
+
+  // remember last mod/save so that for current session, we write
+  // back to the same personal copy, asking only about overwrite.
+  if (leveldir_current == last_copied_leveldir &&
+      level_nr == last_copied_level_nr)
+  {
+    // "cd" to personal level set dir (as used when writing last copy)
+    leveldir_current = last_written_leveldir;
+    level_nr = last_written_level_nr;
 
-  return TRUE;         /* !!! CURRENTLY DEACTIVATED !!! */
+    return TRUE;
+  }
+
+  if (!Request("This level is read only! "
+              "Save into personal level set?", REQ_ASK))
+    return FALSE;
 
-  for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
+  // "cd" to personal level set dir (for writing copy the first time)
+  leveldir_current =
+    getTreeInfoFromIdentifier(leveldir_first, getLoginName());
+
+  // find unused level number
+  for (new_level_nr = leveldir_current->first_level; ; new_level_nr++)
   {
-    if (Feld[x][y] == EL_PLAYER_1 ||
-       Feld[x][y] == EL_SP_MURPHY) 
-      player_found = TRUE;
+    static char *level_filename = NULL;
+
+    setString(&level_filename, getDefaultLevelFilename(new_level_nr));
+
+    if (!fileExists(level_filename))
+      break;
   }
 
-  return player_found;
+  last_copied_leveldir = leveldir_former;
+  last_copied_level_nr = level_nr_former;
+
+  last_written_leveldir = leveldir_current;
+  last_written_level_nr = level_nr = new_level_nr;
+
+  return TRUE;
+}
+
+static void ModifyLevelInfoForSavingIntoPersonalLevelSet(char *former_name)
+{
+  static char *filename_levelinfo = NULL, *mod_name = NULL;
+  FILE *file;
+
+  // annotate this copy-and-mod in personal levelinfo.conf
+  setString(&filename_levelinfo,
+           getPath2(getCurrentLevelDir(), LEVELINFO_FILENAME));
+
+  if ((file = fopen(filename_levelinfo, MODE_APPEND)))
+  {
+    fprintf(file, "\n");
+    fprintf(file, "# level %d was modified from:\n", level_nr);
+    fprintf(file, "# - previous level set name:    %s\n",
+           former_name);
+    fprintf(file, "# - level within previous set:  %d \"%s\"\n",
+           level.file_info.nr, level.name);
+    fprintf(file, "# - previous author:            %s\n",
+           level.author);
+    fprintf(file, "# - previous save date:         ");
+
+    if (level.creation_date.src == DATE_SRC_LEVELFILE)
+    {
+      fprintf(file, "%04d-%02d-%02d\n",
+             level.creation_date.year,
+             level.creation_date.month,
+             level.creation_date.day);
+    }
+    else
+    {
+      fprintf(file, "not recorded\n");
+    }
+
+    fclose(file);
+  }
+
+  if (level_nr > leveldir_current->last_level)
+  {
+    static char *temp_levelinfo = NULL;
+    FILE *temp_file = NULL;
+    char line[MAX_LINE_LEN];
+
+    setString(&temp_levelinfo,
+             getPath2(getCurrentLevelDir(),
+                      getStringCat2(LEVELINFO_FILENAME, ".new")));
+
+    if ((file = fopen(filename_levelinfo, MODE_READ)) &&
+       (temp_file = fopen(temp_levelinfo, MODE_WRITE)))
+    {
+      while (fgets(line, MAX_LINE_LEN, file))
+      {
+       if (!strPrefix(line, "levels:"))
+         fputs(line, temp_file);
+       else
+         fprintf(temp_file, "%-32s%d\n", "levels:", level_nr + 9);
+      }
+    }
+
+    if (temp_file)
+      fclose(temp_file);
+
+    if (file)
+      fclose(file);
+
+    // needs error handling; also, ok on dos/win?
+    unlink(filename_levelinfo);
+    rename(temp_levelinfo, filename_levelinfo);
+  }
+
+  // else: allow the save even if annotation failed
+
+  // now... spray graffiti on the old level vital statistics
+  // user can change these; just trying to set a good baseline
+
+  // don't truncate names for fear of making offensive or silly:
+  // long-named original author only recorded in levelinfo.conf.
+  // try to fit "Joe after Bob", "Joe (ed.)", then just "Joe"
+  if (!strEqual(level.author, leveldir_current->author))
+  {
+    setString(&mod_name, getStringCat3(leveldir_current->author,
+                                      " after ", level.author));
+
+    if (strlen(mod_name) > MAX_LEVEL_AUTHOR_LEN)
+      setString(&mod_name,
+               getStringCat2(leveldir_current->author, " (ed.)"));
+
+    if (strlen(mod_name) > MAX_LEVEL_AUTHOR_LEN)
+      setString(&mod_name, leveldir_current->author);
+
+    strncpy(level.author, mod_name, MAX_LEVEL_AUTHOR_LEN);
+
+    // less worried about truncation here
+    setString(&mod_name, getStringCat2("Mod: ", level.name));
+    strncpy(level.name, mod_name, MAX_LEVEL_NAME_LEN);
+  }
 }
 
 static void CopyPlayfield(short src[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
@@ -6793,13 +6970,13 @@ static boolean CopyCustomElement(int element_old, int element_new,
   }
   else if (IS_CUSTOM_ELEMENT(element_old) && !IS_CUSTOM_ELEMENT(element_new))
   {
-    Request("Please choose custom element !", REQ_CONFIRM);
+    Request("Please choose custom element!", REQ_CONFIRM);
 
     return FALSE;
   }
   else if (IS_GROUP_ELEMENT(element_old) && !IS_GROUP_ELEMENT(element_new))
   {
-    Request("Please choose group element !", REQ_CONFIRM);
+    Request("Please choose group element!", REQ_CONFIRM);
 
     return FALSE;
   }
@@ -7024,7 +7201,7 @@ static void CopyCustomElementPropertiesToGame(int element)
 
   if (level.use_custom_template)
   {
-    if (Request("Copy and modify level template ?", REQ_ASK))
+    if (Request("Copy and modify level template?", REQ_ASK))
     {
       level.use_custom_template = FALSE;
       ModifyGadget(level_editor_gadget[GADGET_ID_CUSTOM_USE_TEMPLATE],
@@ -7185,17 +7362,36 @@ void CheckElementDescriptions()
       Error(ERR_WARN, "no element description for element '%s'", EL_NAME(i));
 }
 
+static boolean playfield_area_changed = FALSE;
+
 void DrawLevelEd()
 {
+  int old_sx = SX;
+  int old_sy = SY;
+  int old_sxsize = SXSIZE;
+  int old_sysize = SYSIZE;
+
   StopAnimation();
 
   CloseDoor(DOOR_CLOSE_ALL);
 
-#if 1
   FadeOut(REDRAW_FIELD);
-#endif
 
-  OpenDoor(DOOR_OPEN_2 | DOOR_NO_DELAY);
+  /* needed after playing if editor playfield area has different size */
+  ClearRectangle(drawto, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
+
+  /* needed if different viewport properties defined for editor */
+  ChangeViewportPropertiesIfNeeded();
+
+  if (old_sx != SX ||
+      old_sy != SY ||
+      old_sxsize != SXSIZE ||
+      old_sysize != SYSIZE)
+    playfield_area_changed = TRUE;
+  else
+    playfield_area_changed = FALSE;
+
+  OpenDoor(DOOR_OPEN_1 | DOOR_OPEN_2 | DOOR_NO_DELAY);
 
 #if DEBUG
   CheckElementDescriptions();
@@ -7221,8 +7417,10 @@ void DrawLevelEd()
   }
 
   /* copy default editor door content to main double buffer */
-  BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
-            DOOR_GFX_PAGEX6, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DX, DY);
+  BlitBitmap(graphic_info[IMG_BACKGROUND_PALETTE].bitmap, drawto,
+            graphic_info[IMG_BACKGROUND_PALETTE].src_x,
+            graphic_info[IMG_BACKGROUND_PALETTE].src_y,
+            DXSIZE, DYSIZE, DX, DY);
 
   /* draw bigger door */
   DrawSpecialEditorDoor();
@@ -7233,39 +7431,23 @@ void DrawLevelEd()
 
   redraw_mask |= REDRAW_ALL;
 
+  FreeLevelEditorGadgets();
+  CreateLevelEditorGadgets();
+
   ReinitializeElementList();           /* update dynamic level element list */
   ReinitializeElementListButtons();    /* custom element may look different */
 
   InitElementPropertiesGfxElement();
 
-#if 1
   UnmapAllGadgets();
-#else
-  UnmapTapeButtons();
-#endif
   MapControlButtons();
 
-#if 0
-  FadeOut(REDRAW_FIELD);
-#endif
-
   DrawEditModeWindow();
 
-#if 1
-  FadeIn(REDRAW_FIELD);
-#endif
+  FadeIn(playfield_area_changed ? REDRAW_ALL : REDRAW_FIELD);
 
   /* copy actual editor door content to door double buffer for OpenDoor() */
-  BlitBitmap(drawto, bitmap_db_door,
-            DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
-
-#if 1
-  /* draw new control window (with border) to window */
-  redraw_mask |= REDRAW_ALL;
-  BackToFront();
-#endif
-
-  OpenDoor(DOOR_OPEN_1);
+  BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
 }
 
 static void AdjustDrawingAreaGadgets()
@@ -7311,14 +7493,14 @@ static void AdjustDrawingAreaGadgets()
   xoffset = (ed_fieldx == MAX_ED_FIELDX ? ED_SCROLLBUTTON_XSIZE : 0);
   yoffset = (ed_fieldy == MAX_ED_FIELDY ? ED_SCROLLBUTTON_YSIZE : 0);
 
-  x = SX + scrollbutton_info[ED_SCROLLBUTTON_ID_AREA_RIGHT].x + xoffset;
-  y = SX + scrollbutton_info[ED_SCROLLBUTTON_ID_AREA_DOWN].y + yoffset;
+  x = SX + scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_RIGHT].x + xoffset;
+  y = SX + scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_DOWN].y + yoffset;
 
   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_RIGHT], GDI_X, x, GDI_END);
   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_DOWN], GDI_Y, y, GDI_END);
 
-  width = scrollbar_info[ED_SCROLLBAR_ID_AREA_HORIZONTAL].width + xoffset;
-  height = scrollbar_info[ED_SCROLLBAR_ID_AREA_VERTICAL].height + yoffset;
+  width  = scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].width + xoffset;
+  height = scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].height + yoffset;
 
   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL],
               GDI_WIDTH, width,
@@ -7519,7 +7701,7 @@ static void DrawDrawingWindow()
   SetMainBackgroundImage(IMG_UNDEFINED);
   ClearField();
 
-  UnmapLevelEditorWindowGadgets();
+  UnmapLevelEditorFieldGadgets();
   UnmapLevelEditorToolboxCustomGadgets();
 
   AdjustDrawingAreaGadgets();
@@ -7550,10 +7732,6 @@ static void DrawLevelInfoTabulatorGadgets()
   Pixel tab_color = GetPixel(gd->bitmap, gd_x, gd_y);
   int id_first = ED_TEXTBUTTON_ID_LEVELINFO_LEVEL;
   int id_last  = ED_TEXTBUTTON_ID_LEVELINFO_EDITOR;
-#if 1
-#else
-  int max_tabs = 2;
-#endif
   int i;
 
   for (i = id_first; i <= id_last; i++)
@@ -7573,19 +7751,11 @@ static void DrawLevelInfoTabulatorGadgets()
     MapTextbuttonGadget(i);
   }
 
-#if 1
   /* draw little border line below tabulator buttons */
   if (tab_color != BLACK_PIXEL)                        /* black => transparent */
     FillRectangle(drawto, gd_gi1->x, gd_gi1->y + gd_gi1->height + 1,
                  getTabulatorBarWidth(), ED_GADGET_DISTANCE,
                  tab_color);
-#else
-  /* draw little border line below tabulator buttons */
-  if (tab_color != BLACK_PIXEL)                        /* black => transparent */
-    FillRectangle(drawto, gd_gi1->x, gd_gi1->y + gd_gi1->height + 1,
-                 max_tabs * gd_gi1->width + (max_tabs -1) * ED_GADGET_DISTANCE,
-                 ED_GADGET_DISTANCE, tab_color);
-#endif
 }
 
 static void DrawPropertiesTabulatorGadgets()
@@ -7597,10 +7767,6 @@ static void DrawPropertiesTabulatorGadgets()
   Pixel tab_color = GetPixel(gd->bitmap, gd_x, gd_y);
   int id_first = ED_TEXTBUTTON_ID_PROPERTIES_INFO;
   int id_last  = ED_TEXTBUTTON_ID_PROPERTIES_CONFIG;
-#if 1
-#else
-  int max_tabs = 4;
-#endif
   int i;
 
   /* draw two config tabulators for player elements */
@@ -7634,19 +7800,11 @@ static void DrawPropertiesTabulatorGadgets()
     MapTextbuttonGadget(i);
   }
 
-#if 1
   /* draw little border line below tabulator buttons */
   if (tab_color != BLACK_PIXEL)                        /* black => transparent */
     FillRectangle(drawto, gd_gi1->x, gd_gi1->y + gd_gi1->height + 1,
                  getTabulatorBarWidth(), ED_GADGET_DISTANCE,
                  tab_color);
-#else
-  /* draw little border line below tabulator buttons */
-  if (tab_color != BLACK_PIXEL)                        /* black => transparent */
-    FillRectangle(drawto, gd_gi1->x, gd_gi1->y + gd_gi1->height + 1,
-                 max_tabs * gd_gi1->width + (max_tabs -1) * ED_GADGET_DISTANCE,
-                 ED_GADGET_DISTANCE, tab_color);
-#endif
 }
 
 static void DrawLevelInfoLevel()
@@ -7690,24 +7848,12 @@ static void DrawLevelInfoWindow()
 {
   stick_element_properties_window = FALSE;
 
-  UnmapLevelEditorWindowGadgets();
+  UnmapLevelEditorFieldGadgets();
 
   SetMainBackgroundImage(IMG_BACKGROUND_EDITOR);
   ClearField();
 
-#if 1
-#if 1
   DrawTextSCentered(ED_SETTINGS1_YPOS, FONT_TITLE_1, "Global Settings");
-#else
-  DrawTextSCentered(ED_SETTINGS1_YPOS, FONT_TITLE_1, "Level Settings");
-  DrawTextSCentered(ED_SETTINGS2_YPOS, FONT_TITLE_1, "Editor Settings");
-#endif
-#else
-  DrawText(SX + ED_SETTINGS2_XPOS, SY + ED_SETTINGS1_YPOS,
-          "Level Settings", FONT_TITLE_1);
-  DrawText(SX + ED_SETTINGS2_XPOS, SY + ED_SETTINGS2_YPOS,
-          "Editor Settings", FONT_TITLE_1);
-#endif
 
   DrawLevelInfoTabulatorGadgets();
 
@@ -7943,9 +8089,13 @@ static int PrintElementDescriptionFromFile(char *filename, int start_line)
   int sy = SY + pad_y + start_line * font_height;
   int max_chars_per_line = (SXSIZE - 2 * pad_x) / font_width;
   int max_lines_per_screen = (SYSIZE - pad_y) / font_height - 1;
+  int max_lines_drawable = max_lines_per_screen - start_line;
+
+  if (start_line >= max_lines_per_screen)
+    return FALSE;
 
   return DrawTextFile(sx, sy, filename, font_nr, max_chars_per_line, -1,
-                     max_lines_per_screen, -1, TRUE, FALSE, FALSE);
+                     max_lines_drawable, 0, -1, TRUE, FALSE, FALSE);
 }
 
 static void DrawPropertiesInfo()
@@ -8009,8 +8159,8 @@ static void DrawPropertiesInfo()
     { -1,                      NULL                                    }
   };
   char *filename = getElementDescriptionFilename(properties_element);
-  char *percentage_text = "In this level:";
-  char *properties_text = "Standard properties:";
+  char *percentage_text = "In this level: ";
+  char *properties_text = "Standard properties: ";
   float percentage;
   int num_elements_in_level;
   int num_standard_properties = 0;
@@ -8213,7 +8363,10 @@ static boolean checkPropertiesConfig(int element)
       HAS_EDITOR_CONTENT(element) ||
       CAN_GROW(element) ||
       COULD_MOVE_INTO_ACID(element) ||
-      MAYBE_DONT_COLLIDE_WITH(element))
+      MAYBE_DONT_COLLIDE_WITH(element) ||
+      element == EL_SOKOBAN_OBJECT ||
+      element == EL_SOKOBAN_FIELD_EMPTY ||
+      element == EL_SOKOBAN_FIELD_FULL)
     return TRUE;
   else
     for (i = 0; elements_with_counter[i].element != -1; i++)
@@ -8407,6 +8560,11 @@ static void DrawPropertiesConfig()
     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE);
   }
 
+  if (properties_element == EL_SOKOBAN_OBJECT ||
+      properties_element == EL_SOKOBAN_FIELD_EMPTY ||
+      properties_element == EL_SOKOBAN_FIELD_FULL)
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN);
+
   if (IS_ENVELOPE(properties_element))
   {
     int counter1_id = ED_COUNTER_ID_ENVELOPE_XSIZE;
@@ -8576,7 +8734,7 @@ static void DrawEditorElementAnimation(int x, int y)
               ANIM_MODE(graphic) == ANIM_CE_SCORE ?
               custom_element.collect_score_initial : FrameCounter);
 
-  DrawGraphicAnimationExt(drawto, x, y, graphic, frame, NO_MASKING);
+  DrawFixedGraphicAnimationExt(drawto, x, y, graphic, frame, NO_MASKING);
 }
 
 static void DrawEditorElementName(int x, int y, int element)
@@ -8648,7 +8806,7 @@ static void DrawPropertiesWindow()
 
   CopyElementPropertiesToEditor(properties_element);
 
-  UnmapLevelEditorWindowGadgets();
+  UnmapLevelEditorFieldGadgets();
   UnmapLevelEditorToolboxDrawingGadgets();
   UnmapLevelEditorToolboxCustomGadgets();
 
@@ -8659,12 +8817,7 @@ static void DrawPropertiesWindow()
   SetMainBackgroundImage(IMG_BACKGROUND_EDITOR);
   ClearField();
 
-#if 1
   DrawTextSCentered(ED_SETTINGS1_YPOS, FONT_TITLE_1, "Element Settings");
-#else
-  DrawText(SX + ED_SETTINGS2_XPOS, SY + ED_SETTINGS1_YPOS,
-          "Element Settings", FONT_TITLE_1);
-#endif
 
   FrameCounter = 0;    /* restart animation frame counter */
 
@@ -9593,20 +9746,6 @@ static void SetElementIntelliDraw(int x, int y, int new_element,
        EL_SP_GRAVITY_PORT_LEFT
       },
 
-      {
-       EL_MOLE_UP,
-       EL_MOLE_RIGHT,
-       EL_MOLE_DOWN,
-       EL_MOLE_LEFT
-      },
-
-      {
-       EL_BALLOON_SWITCH_UP,
-       EL_BALLOON_SWITCH_RIGHT,
-       EL_BALLOON_SWITCH_DOWN,
-       EL_BALLOON_SWITCH_LEFT
-      },
-
       {
        EL_SP_GRAVITY_ON_PORT_UP,
        EL_SP_GRAVITY_ON_PORT_RIGHT,
@@ -9621,6 +9760,20 @@ static void SetElementIntelliDraw(int x, int y, int new_element,
        EL_SP_GRAVITY_OFF_PORT_LEFT
       },
 
+      {
+       EL_MOLE_UP,
+       EL_MOLE_RIGHT,
+       EL_MOLE_DOWN,
+       EL_MOLE_LEFT
+      },
+
+      {
+       EL_BALLOON_SWITCH_UP,
+       EL_BALLOON_SWITCH_RIGHT,
+       EL_BALLOON_SWITCH_DOWN,
+       EL_BALLOON_SWITCH_LEFT
+      },
+
       {
        -1,
        -1,
@@ -9888,7 +10041,7 @@ static void SelectArea(int from_x, int from_y, int to_x, int to_y,
 static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y,
                         int button, int mode)
 {
-  static short brush_buffer[MAX_ED_FIELDX][MAX_ED_FIELDY];
+  static short brush_buffer[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
   static int brush_width, brush_height;
   static int last_cursor_x = -1, last_cursor_y = -1;
   static boolean delete_old_brush;
@@ -10069,7 +10222,7 @@ static void FloodFill(int from_x, int from_y, int fill_element)
 static int DrawLevelText(int sx, int sy, char letter, int mode)
 {
   static short delete_buffer[MAX_LEV_FIELDX];
-  static int start_sx, start_sy;
+  static int start_sx;
   static int last_sx, last_sy;
   static boolean typing = FALSE;
   int letter_element = EL_CHAR_ASCII0 + letter;
@@ -10111,8 +10264,9 @@ static int DrawLevelText(int sx, int sy, char letter, int mode)
        DrawLevelText(0, 0, 0, TEXT_END);
 
       typing = TRUE;
-      start_sx = last_sx = sx;
-      start_sy = last_sy = sy;
+      start_sx = sx;
+      last_sx = sx;
+      last_sy = sy;
       DrawLevelText(sx, sy, 0, TEXT_SETCURSOR);
       break;
 
@@ -10242,9 +10396,7 @@ static void RandomPlacement(int new_element)
   int num_percentage, num_elements;
   int x, y;
 
-#if 1
   ResetIntelliDraw();
-#endif
 
   /* determine number of free positions for randomly placing the new element */
   for (x = 0; x < lev_fieldx; x++) for (y = 0; y < lev_fieldy; y++)
@@ -10269,11 +10421,7 @@ static void RandomPlacement(int new_element)
     for (x = 0; x < lev_fieldx; x++)
       for (y = 0; y < lev_fieldy; y++)
        if (free_position[x][y])
-#if 1
          SetElement(x, y, new_element);
-#else
-         Feld[x][y] = new_element;
-#endif
   }
   else
   {
@@ -10286,11 +10434,7 @@ static void RandomPlacement(int new_element)
       if (free_position[x][y])
       {
        free_position[x][y] = FALSE;
-#if 1
        SetElement(x, y, new_element);
-#else
-       Feld[x][y] = new_element;
-#endif
        num_elements--;
       }
     }
@@ -10409,10 +10553,6 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
          if (edit_mode == ED_MODE_DRAWING && draw_with_brush &&
              !inside_drawing_area)
            DeleteBrushFromCursor();
-
-#if 0
-         ResetIntelliDraw();
-#endif
        }
 
        if (!button || button_release_event)
@@ -10420,50 +10560,20 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
 
        if (draw_with_brush)
        {
-#if 0
-         if (!button_release_event)
-#endif
-           CopyBrushToLevel(sx, sy, button);
+         CopyBrushToLevel(sx, sy, button);
        }
-#if 1
        else
-#else
-       else if (new_element != Feld[lx][ly])
-#endif
        {
          if (new_element == EL_PLAYER_1)
          {
            /* remove player at old position */
            for (y = 0; y < lev_fieldy; y++)
-           {
              for (x = 0; x < lev_fieldx; x++)
-             {
                if (Feld[x][y] == EL_PLAYER_1)
-               {
-#if 1
                  SetElement(x, y, EL_EMPTY);
-#else
-                 Feld[x][y] = EL_EMPTY;
-#if 1
-                 if (IN_ED_FIELD(x - level_xpos, y - level_ypos))
-                   DrawMiniElement(x - level_xpos, y - level_ypos, EL_EMPTY);
-#else
-                 if (x - level_xpos >= 0 && x - level_xpos < ed_fieldx &&
-                     y - level_ypos >= 0 && y - level_ypos < ed_fieldy)
-                   DrawMiniElement(x - level_xpos, y - level_ypos, EL_EMPTY);
-#endif
-#endif
-               }
-             }
-           }
          }
 
-#if 1
          SetElementButton(lx, ly, new_element, button);
-#else
-         Feld[lx][ly] = new_element;
-         DrawMiniElement(sx, sy, new_element);
-#endif
        }
       }
       else
@@ -10477,10 +10587,10 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
                             gi->y + sy * MINI_TILEY,
                             el2edimg(new_element));
        else
-         DrawGraphicExt(drawto,
-                        gi->x + sx * TILEX,
-                        gi->y + sy * TILEY,
-                        el2img(new_element), 0);
+         DrawFixedGraphicExt(drawto,
+                             gi->x + sx * TILEX,
+                             gi->y + sy * TILEY,
+                             el2img(new_element), 0);
 
        if (id == GADGET_ID_CUSTOM_GRAPHIC)
          new_element = GFX_ELEMENT(new_element);
@@ -10626,7 +10736,7 @@ static void HandleCounterButtons(struct GadgetInfo *gi)
     if ((level_changed && pressed) || (!level_changed && released))
       return;
 
-    if (level_changed && !Request("Level has changed ! Discard changes ?",
+    if (level_changed && !Request("Level has changed! Discard changes?",
                                  REQ_ASK))
     {
       if (gadget_id == counterbutton_info[counter_id].gadget_id_text)
@@ -10721,14 +10831,9 @@ static void HandleTextAreaGadgets(struct GadgetInfo *gi)
 {
   int type_id = gi->custom_type_id;
 
-#if 1
   strncpy(textarea_info[type_id].value, gi->textarea.value,
          MAX_ENVELOPE_TEXT_LEN);
   textarea_info[type_id].value[MAX_ENVELOPE_TEXT_LEN] = '\0';
-#else
-  /* !!! BUGGY !!! MAX_ENVELOPE_TEXT_LEN != MAX_GADGET_TEXTSIZE !!! */
-  strcpy(textarea_info[type_id].value, gi->textarea.value);
-#endif
 
   level.changed = TRUE;
 }
@@ -10792,12 +10897,21 @@ static void HandleTextbuttonGadgets(struct GadgetInfo *gi)
     char *template_filename = getDefaultLevelFilename(-1);
     boolean new_template = !fileExists(template_filename);
 
+    /* backup original "level.field" (needed to track playfield changes) */
+    CopyPlayfield(level.field, FieldBackup);
+
+    /* "SaveLevelTemplate()" uses "level.field", so copy editor playfield */
+    CopyPlayfield(Feld, level.field);
+
     if (new_template ||
-       Request("Save this template and kill the old ?", REQ_ASK))
+       Request("Save this template and kill the old?", REQ_ASK))
       SaveLevelTemplate();
 
     if (new_template)
-      Request("Template saved !", REQ_CONFIRM);
+      Request("Template saved!", REQ_CONFIRM);
+
+    /* restore original "level.field" (needed to track playfield changes) */
+    CopyPlayfield(FieldBackup, level.field);
   }
   else if (type_id == ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE &&
           custom_element.num_change_pages < MAX_CHANGE_PAGES)
@@ -10910,7 +11024,7 @@ static void HandleCheckbuttons(struct GadgetInfo *gi)
 
     if (level.use_custom_template && !fileExists(template_filename))
     {
-      Request("No level template found !", REQ_CONFIRM);
+      Request("No level template found!", REQ_CONFIRM);
 
       level.use_custom_template = FALSE;
       ModifyGadget(gi, GDI_CHECKED, FALSE, GDI_END);
@@ -11143,7 +11257,7 @@ static void HandleControlButtons(struct GadgetInfo *gi)
     case GADGET_ID_UNDO:
       if (undo_buffer_steps == 0)
       {
-       Request("Undo buffer empty !", REQ_CONFIRM);
+       Request("Undo buffer empty!", REQ_CONFIRM);
        break;
       }
 
@@ -11201,60 +11315,77 @@ static void HandleControlButtons(struct GadgetInfo *gi)
       break;
 
     case GADGET_ID_SAVE:
-      if (leveldir_current->readonly)
-      {
-       Request("This level is read only !", REQ_CONFIRM);
+    {
+      /* saving read-only levels into personal level set modifies global vars
+        "leveldir_current" and "level_nr"; restore them after saving level */
+      LevelDirTree *leveldir_former = leveldir_current;
+      int level_nr_former = level_nr;
+      char *level_filename;
+      boolean new_level;
+
+      if (leveldir_current->readonly &&
+         !PrepareSavingIntoPersonalLevelSet())
        break;
-      }
 
-      if (!LevelContainsPlayer())
-       Request("No Level without Gregor Mc Duffin please !", REQ_CONFIRM);
-      else
+      level_filename = getDefaultLevelFilename(level_nr);
+      new_level = !fileExists(level_filename);
+
+      if (new_level ||
+         Request("Save this level and kill the old?", REQ_ASK))
       {
-       char *level_filename = getDefaultLevelFilename(level_nr);
-       boolean new_level = !fileExists(level_filename);
+       if (leveldir_former->readonly)
+         ModifyLevelInfoForSavingIntoPersonalLevelSet(leveldir_former->name);
 
-       if (new_level ||
-           Request("Save this level and kill the old ?", REQ_ASK))
-       {
-         CopyPlayfield(Feld, level.field);
+       CopyPlayfield(Feld, level.field);
+       SaveLevel(level_nr);
 
-         SaveLevel(level_nr);
-       }
+       level.changed = FALSE;
 
        if (new_level)
-         Request("Level saved !", REQ_CONFIRM);
+       {
+         char level_saved_msg[64];
 
-       level.changed = FALSE;
+         if (leveldir_former->readonly)
+           sprintf(level_saved_msg,
+                   "Level saved as level %d into personal level set!",
+                   level_nr);
+         else
+           strcpy(level_saved_msg, "Level saved!");
+
+         Request(level_saved_msg, REQ_CONFIRM);
+       }
       }
+
+      /* "cd" back to copied-from levelset (in case of saved read-only level) */
+      leveldir_current = leveldir_former;
+      level_nr = level_nr_former;
+
       break;
+    }
 
     case GADGET_ID_TEST:
-      if (!LevelContainsPlayer())
-       Request("No Level without Gregor Mc Duffin please !", REQ_CONFIRM);
-      else
-      {
-       if (LevelChanged())
-         level.game_version = GAME_VERSION_ACTUAL;
+      if (LevelChanged())
+       level.game_version = GAME_VERSION_ACTUAL;
 
-       CopyPlayfield(level.field, FieldBackup);
-       CopyPlayfield(Feld, level.field);
+      CopyPlayfield(level.field, FieldBackup);
+      CopyPlayfield(Feld, level.field);
 
-       CopyNativeLevel_RND_to_Native(&level);
+      CopyNativeLevel_RND_to_Native(&level);
 
-       UnmapLevelEditorGadgets();
-       UndrawSpecialEditorDoor();
+      UnmapLevelEditorGadgets();
+      UndrawSpecialEditorDoor();
 
-       CloseDoor(DOOR_CLOSE_ALL);
+      CloseDoor(DOOR_CLOSE_ALL);
 
-       BackToFront();          /* force redraw of undrawn special door */
+      /* needed before playing if editor playfield area has different size */
+      ClearRectangle(drawto, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
 
-       DrawCompleteVideoDisplay();
+      redraw_mask = REDRAW_ALL;
 
-       level_editor_test_game = TRUE;
+      level_editor_test_game = TRUE;
+
+      StartGameActions(FALSE, setup.autorecord, level.random_seed);
 
-       StartGameActions(FALSE, setup.autorecord, level.random_seed);
-      }
       break;
 
     case GADGET_ID_EXIT:
@@ -11463,7 +11594,9 @@ void HandleLevelEditorKeyInput(Key key)
       ClickOnGadget(level_editor_gadget[id], button);
     else if (letter == '.')
       ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS], button);
-    else if (key == KSYM_Return || key == setup.shortcut.toggle_pause)
+    else if (key == KSYM_Return ||
+            key == KSYM_space ||
+            key == setup.shortcut.toggle_pause)
       ClickOnGadget(level_editor_gadget[GADGET_ID_TEST], button);
     else
       for (i = 0; i < ED_NUM_CTRL_BUTTONS; i++)
@@ -11475,8 +11608,8 @@ void HandleLevelEditorKeyInput(Key key)
 
 void HandleLevelEditorIdle()
 {
-  static unsigned long action_delay = 0;
-  unsigned long action_delay_value = GameFrameDelay;
+  static unsigned int action_delay = 0;
+  unsigned int action_delay_value = GameFrameDelay;
   int xpos = 1, ypos = 2;
   int i;
 
@@ -11722,30 +11855,20 @@ void RequestExitLevelEditor(boolean ask_if_level_has_changed,
 {
   if (!ask_if_level_has_changed ||
       !LevelChanged() ||
-      Request("Level has changed ! Exit without saving ?",
+      Request("Level has changed! Exit without saving?",
              REQ_ASK | REQ_STAY_OPEN))
   {
-    CloseDoor(DOOR_CLOSE_1);
     SetDoorState(DOOR_CLOSE_2);
 
-#if 1
     if (quick_quit)
       FadeSkipNextFadeIn();
-#else
-    if (quick_quit)
-      fading = fading_none;
-#endif
 
     game_status = GAME_MODE_MAIN;
-#if 1
-    DrawAndFadeInMainMenu(REDRAW_FIELD);
-#else
-    DrawMainMenu();
-#endif
+
+    DrawAndFadeInMainMenu(playfield_area_changed ? REDRAW_ALL : REDRAW_FIELD);
   }
   else
   {
-    CloseDoor(DOOR_CLOSE_1);
     OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
   }
 }