added key pad '-', '+' and '0' keys to zoom function in level editor
[rocksndiamonds.git] / src / editor.c
index 5752d7420e34397251e9c344aea87e536efd70a8..3baec5725bb4cb8b3da700f7475021ac5c0f88ab 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
-
 /* values for the control window */
-#define ED_CTRL_NO_BUTTONS_GFX_XPOS    6
-#define ED_CTRL_NO_BUTTONS_GFX_YPOS    286
-#define ED_CTRL1_BUTTONS_GFX_YPOS      236
-#define ED_CTRL2_BUTTONS_GFX_YPOS      236
-#define ED_CTRL3_BUTTONS_GFX_YPOS      324
-#define ED_CTRL4_BUTTONS_GFX_XPOS      44
-#define ED_CTRL4_BUTTONS_GFX_YPOS      214
-#define ED_CTRL1_BUTTONS_ALT_GFX_YPOS  142
-#define ED_CTRL3_BUTTONS_ALT_GFX_YPOS  302
-
-#define ED_CTRL1_BUTTON_XSIZE          22
-#define ED_CTRL1_BUTTON_YSIZE          22
-#define ED_CTRL1_BUTTONS_XPOS          6
-#define ED_CTRL1_BUTTONS_YPOS          6
-#define ED_CTRL2_BUTTON_XSIZE          30
-#define ED_CTRL2_BUTTON_YSIZE          20
-#define ED_CTRL2_BUTTONS_XPOS          5
-#define ED_CTRL2_BUTTONS_YPOS          99
-#define ED_CTRL3_BUTTON_XSIZE          22
-#define ED_CTRL3_BUTTON_YSIZE          22
-#define ED_CTRL3_BUTTONS_XPOS          6
-#define ED_CTRL3_BUTTONS_YPOS          6
-#define ED_CTRL4_BUTTON_XSIZE          22
-#define ED_CTRL4_BUTTON_YSIZE          22
-#define ED_CTRL4_BUTTONS_XPOS          6
-#define ED_CTRL4_BUTTONS_YPOS          6
-
 #define ED_CTRL1_BUTTONS_HORIZ         4
 #define ED_CTRL1_BUTTONS_VERT          4
 #define ED_CTRL2_BUTTONS_HORIZ         3
 #define ED_CTRL3_BUTTONS_VERT          1
 #define ED_CTRL4_BUTTONS_HORIZ         2
 #define ED_CTRL4_BUTTONS_VERT          1
+#define ED_CTRL5_BUTTONS_HORIZ         1
+#define ED_CTRL5_BUTTONS_VERT          1
 
 #define ED_NUM_CTRL1_BUTTONS   (ED_CTRL1_BUTTONS_HORIZ * ED_CTRL1_BUTTONS_VERT)
 #define ED_NUM_CTRL2_BUTTONS   (ED_CTRL2_BUTTONS_HORIZ * ED_CTRL2_BUTTONS_VERT)
 #define ED_NUM_CTRL3_BUTTONS   (ED_CTRL3_BUTTONS_HORIZ * ED_CTRL3_BUTTONS_VERT)
 #define ED_NUM_CTRL4_BUTTONS   (ED_CTRL4_BUTTONS_HORIZ * ED_CTRL4_BUTTONS_VERT)
+#define ED_NUM_CTRL5_BUTTONS   (ED_CTRL5_BUTTONS_HORIZ * ED_CTRL5_BUTTONS_VERT)
 #define ED_NUM_CTRL1_2_BUTTONS (ED_NUM_CTRL1_BUTTONS   + ED_NUM_CTRL2_BUTTONS)
 #define ED_NUM_CTRL1_3_BUTTONS (ED_NUM_CTRL1_2_BUTTONS + ED_NUM_CTRL3_BUTTONS)
-#define ED_NUM_CTRL_BUTTONS    (ED_NUM_CTRL1_BUTTONS + \
-                               ED_NUM_CTRL2_BUTTONS +  \
-                               ED_NUM_CTRL3_BUTTONS +  \
-                               ED_NUM_CTRL4_BUTTONS)
+#define ED_NUM_CTRL1_4_BUTTONS (ED_NUM_CTRL1_3_BUTTONS + ED_NUM_CTRL4_BUTTONS)
+#define ED_NUM_CTRL_BUTTONS    (ED_NUM_CTRL1_4_BUTTONS + ED_NUM_CTRL5_BUTTONS)
 
 /* values for the element list */
-#define ED_ELEMENTLIST_XPOS            5
-#define ED_ELEMENTLIST_YPOS            30
-#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_XPOS            (editor.palette.x)
+#define ED_ELEMENTLIST_YPOS            (editor.palette.y)
+#define ED_ELEMENTLIST_XSIZE           (graphic_info[IMG_EDITOR_PALETTE_BUTTON].width)
+#define ED_ELEMENTLIST_YSIZE           (graphic_info[IMG_EDITOR_PALETTE_BUTTON].height)
+#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_BORDER_SIZE                 3
 #define ED_BORDER_TEXT_XSIZE           5
 #define ED_BORDER_AREA_YSIZE           1
+#define ED_ELEMENT_BORDER              8
+#define ED_ELEMENT_BORDER_INPUT                4
 
 #define ED_GADGET_DISTANCE             2
 #define ED_GADGET_TEXT_DISTANCE                (2 * ED_GADGET_DISTANCE)
 #define ED_SCROLLBAR2_XPOS             50
 #define ED_SCROLLBAR2_YPOS             20
 
-#define ED_SCROLLBUTTON2_XSIZE         10
-#define ED_SCROLLBUTTON2_YSIZE         10
+#define ED_SCROLLBUTTON2_XSIZE         (graphic_info[IMG_EDITOR_PALETTE_SCROLL_UP].width)
+#define ED_SCROLLBUTTON2_YSIZE         (graphic_info[IMG_EDITOR_PALETTE_SCROLL_UP].height)
 
-#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 ED_WIN_COUNT_YPOS              ED_BUTTON_COUNT_YPOS
 #define ED_WIN_COUNT_XSIZE             52
 #define ED_WIN_COUNT_YSIZE             ED_BUTTON_COUNT_YSIZE
-#define ED_WIN_COUNT2_XPOS             27
-#define ED_WIN_COUNT2_YPOS             3
-#define ED_WIN_COUNT2_XSIZE            46
-#define ED_WIN_COUNT2_YSIZE            ED_BUTTON_COUNT_YSIZE
 
 #define ED_BUTTON_MINUS_XPOS           2
 #define ED_BUTTON_MINUS_YPOS           ED_BUTTON_COUNT_YPOS
 #define INFOTEXT_XPOS                  SX
 #define INFOTEXT_YPOS                  (SY + SYSIZE - MINI_TILEX + 2)
 #define INFOTEXT_XSIZE                 SXSIZE
-#define INFOTEXT_YSIZE                 MINI_TILEX
+#define INFOTEXT_YSIZE                 MINI_TILEY
 
 
 /*
 #define GADGET_ID_TEXT                 (GADGET_ID_TOOLBOX_FIRST + 7)
 #define GADGET_ID_FLOOD_FILL           (GADGET_ID_TOOLBOX_FIRST + 8)
 #define GADGET_ID_WRAP_LEFT            (GADGET_ID_TOOLBOX_FIRST + 9)
-#define GADGET_ID_PROPERTIES           (GADGET_ID_TOOLBOX_FIRST + 10)
+#define GADGET_ID_ZOOM                 (GADGET_ID_TOOLBOX_FIRST + 10)
 #define GADGET_ID_WRAP_RIGHT           (GADGET_ID_TOOLBOX_FIRST + 11)
 #define GADGET_ID_RANDOM_PLACEMENT     (GADGET_ID_TOOLBOX_FIRST + 12)
 #define GADGET_ID_GRAB_BRUSH           (GADGET_ID_TOOLBOX_FIRST + 13)
 #define GADGET_ID_CUSTOM_COPY          (GADGET_ID_TOOLBOX_FIRST + 25)
 #define GADGET_ID_CUSTOM_PASTE         (GADGET_ID_TOOLBOX_FIRST + 26)
 
+#define GADGET_ID_PROPERTIES           (GADGET_ID_TOOLBOX_FIRST + 27)
+
 /* counter gadget identifiers */
-#define GADGET_ID_COUNTER_FIRST                (GADGET_ID_TOOLBOX_FIRST + 27)
+#define GADGET_ID_COUNTER_FIRST                (GADGET_ID_TOOLBOX_FIRST + 28)
 
 #define GADGET_ID_SELECT_LEVEL_DOWN    (GADGET_ID_COUNTER_FIRST + 0)
 #define GADGET_ID_SELECT_LEVEL_TEXT    (GADGET_ID_COUNTER_FIRST + 1)
 #define ED_MODE_PROPERTIES_CHANGE      ED_TEXTBUTTON_ID_PROPERTIES_CHANGE
 
 /* how many steps can be cancelled */
-#define NUM_UNDO_STEPS                 (10 + 1)
+#define NUM_UNDO_STEPS                 (64 + 1)
 
 /* values for elements with score for certain actions */
 #define MIN_SCORE                      0
 #define RANDOM_USE_PERCENTAGE          0
 #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)
+/* default value for element tile size in drawing area */
+#define DEFAULT_EDITOR_TILESIZE                MINI_TILESIZE
 
 
 /*
 
 static struct
 {
+  int graphic;
+  int gadget_id;
+  struct XY *pos;
+  int gadget_type;
+  char *infotext;
   char shortcut;
-  char *text;
-} control_info[ED_NUM_CTRL_BUTTONS] =
+} controlbutton_info[ED_NUM_CTRL_BUTTONS] =
 {
   /* note: some additional characters are already reserved for "cheat mode"
      shortcuts (":XYZ" style) -- for details, see "events.c" */
 
-  { 's',       "draw single items"                     },
-  { 'd',       "draw connected items"                  },
-  { 'l',       "draw lines"                            },
-  { 'a',       "draw arcs"                             },
-  { 'r',       "draw outline rectangles"               },
-  { 'R',       "draw filled rectangles"                },
-  { '\0',      "wrap (rotate) level up"                },
-  { 't',       "enter text elements"                   },
-  { 'f',       "flood fill"                            },
-  { '\0',      "wrap (rotate) level left"              },
-  { '?',       "properties of drawing element"         },
-  { '\0',      "wrap (rotate) level right"             },
-  { '\0',      "random element placement"              },
-  { 'b',       "grab brush"                            },
-  { '\0',      "wrap (rotate) level down"              },
-  { ',',       "pick drawing element"                  },
-
-  { 'U',       "undo last operation"                   },
-  { 'I',       "properties of level"                   },
-  { 'S',       "save level"                            },
-  { 'C',       "clear level"                           },
-  { 'T',       "test level"                            },
-  { 'E',       "exit level editor"                     },
-
-  { '\0',      "copy settings from other element"      },
-  { '\0',      "copy settings to other element"        },
-  { '\0',      "exchange element with other element"   },
-
-  { '\0',      "copy settings from this element"       },
-  { '\0',      "paste settings to this element"        },
+  /* ---------- toolbox control buttons ------------------------------------ */
+
+  {
+    IMG_EDITOR_BUTTON_GFX_DRAW_SINGLE,         GADGET_ID_SINGLE_ITEMS,
+    &editor.button.draw_single,                        GD_TYPE_RADIO_BUTTON,
+    "draw single items",                       's'
+  },
+  {
+    IMG_EDITOR_BUTTON_GFX_DRAW_CONNECTED,      GADGET_ID_CONNECTED_ITEMS,
+    &editor.button.draw_connected,             GD_TYPE_RADIO_BUTTON,
+    "draw connected items",                    'd'
+  },
+  {
+    IMG_EDITOR_BUTTON_GFX_DRAW_LINE,           GADGET_ID_LINE,
+    &editor.button.draw_line,                  GD_TYPE_RADIO_BUTTON,
+    "draw lines",                              'l'
+  },
+  {
+    IMG_EDITOR_BUTTON_GFX_DRAW_ARC,            GADGET_ID_ARC,
+    &editor.button.draw_arc,                   GD_TYPE_RADIO_BUTTON,
+    "draw arcs",                               'a'
+  },
+  {
+    IMG_EDITOR_BUTTON_GFX_DRAW_RECTANGLE,      GADGET_ID_RECTANGLE,
+    &editor.button.draw_rectangle,             GD_TYPE_RADIO_BUTTON,
+    "draw outline rectangles",                 'r'
+  },
+  {
+    IMG_EDITOR_BUTTON_GFX_DRAW_FILLED_BOX,     GADGET_ID_FILLED_BOX,
+    &editor.button.draw_filled_box,            GD_TYPE_RADIO_BUTTON,
+    "draw filled rectangles",                  'R'
+  },
+  {
+    IMG_EDITOR_BUTTON_GFX_ROTATE_UP,           GADGET_ID_WRAP_UP,
+    &editor.button.rotate_up,                  GD_TYPE_NORMAL_BUTTON,
+    "wrap (rotate) level up",                  0
+  },
+  {
+    IMG_EDITOR_BUTTON_GFX_DRAW_TEXT,           GADGET_ID_TEXT,
+    &editor.button.draw_text,                  GD_TYPE_RADIO_BUTTON,
+    "enter text elements",                     't'
+  },
+  {
+    IMG_EDITOR_BUTTON_GFX_FLOOD_FILL,          GADGET_ID_FLOOD_FILL,
+    &editor.button.flood_fill,                 GD_TYPE_RADIO_BUTTON,
+    "flood fill",                              'f'
+  },
+  {
+    IMG_EDITOR_BUTTON_GFX_ROTATE_LEFT,         GADGET_ID_WRAP_LEFT,
+    &editor.button.rotate_left,                        GD_TYPE_NORMAL_BUTTON,
+    "wrap (rotate) level left",                        0
+  },
+  {
+    IMG_EDITOR_BUTTON_GFX_ZOOM_LEVEL,          GADGET_ID_ZOOM,
+    &editor.button.zoom_level,                 GD_TYPE_NORMAL_BUTTON,
+    "zoom level tile size",                    '-'
+  },
+  {
+    IMG_EDITOR_BUTTON_GFX_ROTATE_RIGHT,                GADGET_ID_WRAP_RIGHT,
+    &editor.button.rotate_right,               GD_TYPE_NORMAL_BUTTON,
+    "wrap (rotate) level right",               0
+  },
+  {
+    IMG_EDITOR_BUTTON_GFX_DRAW_RANDOM,         GADGET_ID_RANDOM_PLACEMENT,
+    &editor.button.draw_random,                        GD_TYPE_NORMAL_BUTTON,
+    "random element placement",                        0
+  },
+  {
+    IMG_EDITOR_BUTTON_GFX_GRAB_BRUSH,          GADGET_ID_GRAB_BRUSH,
+    &editor.button.grab_brush,                 GD_TYPE_RADIO_BUTTON,
+    "grab brush",                              'b'
+  },
+  {
+    IMG_EDITOR_BUTTON_GFX_ROTATE_DOWN,         GADGET_ID_WRAP_DOWN,
+    &editor.button.rotate_down,                        GD_TYPE_NORMAL_BUTTON,
+    "wrap (rotate) level down",                        0
+  },
+  {
+    IMG_EDITOR_BUTTON_GFX_PICK_ELEMENT,                GADGET_ID_PICK_ELEMENT,
+    &editor.button.pick_element,               GD_TYPE_RADIO_BUTTON,
+    "pick drawing element",                    ','
+  },
+
+  /* ---------- level control buttons -------------------------------------- */
+
+  {
+    IMG_EDITOR_BUTTON_GFX_UNDO,                        GADGET_ID_UNDO,
+    &editor.button.undo,                       GD_TYPE_NORMAL_BUTTON,
+    "undo/redo last operation",                        'U'
+  },
+  {
+    IMG_EDITOR_BUTTON_GFX_CONF,                        GADGET_ID_INFO,
+    &editor.button.conf,                       GD_TYPE_NORMAL_BUTTON,
+    "properties of level",                     'I'
+  },
+  {
+    IMG_EDITOR_BUTTON_GFX_SAVE,                        GADGET_ID_SAVE,
+    &editor.button.save,                       GD_TYPE_NORMAL_BUTTON,
+    "save level",                              'S'
+  },
+  {
+    IMG_EDITOR_BUTTON_GFX_CLEAR,               GADGET_ID_CLEAR,
+    &editor.button.clear,                      GD_TYPE_NORMAL_BUTTON,
+    "clear level",                             'C'
+  },
+  {
+    IMG_EDITOR_BUTTON_GFX_TEST,                        GADGET_ID_TEST,
+    &editor.button.test,                       GD_TYPE_NORMAL_BUTTON,
+    "test level",                              'T'
+  },
+  {
+    IMG_EDITOR_BUTTON_GFX_EXIT,                        GADGET_ID_EXIT,
+    &editor.button.exit,                       GD_TYPE_NORMAL_BUTTON,
+    "exit level editor",                       'E'
+  },
+
+  /* ---------- CE and GE control buttons ---------------------------------- */
+
+  {
+    IMG_EDITOR_BUTTON_GFX_CE_COPY_FROM,                GADGET_ID_CUSTOM_COPY_FROM,
+    &editor.button.ce_copy_from,               GD_TYPE_RADIO_BUTTON,
+    "copy settings from other element",                0
+  },
+  {
+    IMG_EDITOR_BUTTON_GFX_CE_COPY_TO,          GADGET_ID_CUSTOM_COPY_TO,
+    &editor.button.ce_copy_to,                 GD_TYPE_RADIO_BUTTON,
+    "copy settings to other element",          0
+  },
+  {
+    IMG_EDITOR_BUTTON_GFX_CE_SWAP,             GADGET_ID_CUSTOM_EXCHANGE,
+    &editor.button.ce_swap,                    GD_TYPE_RADIO_BUTTON,
+    "exchange element with other element",     0
+  },
+  {
+    IMG_EDITOR_BUTTON_GFX_CE_COPY,             GADGET_ID_CUSTOM_COPY,
+    &editor.button.ce_copy,                    GD_TYPE_NORMAL_BUTTON,
+    "copy settings from this element",         0
+  },
+  {
+    IMG_EDITOR_BUTTON_GFX_CE_PASTE,            GADGET_ID_CUSTOM_PASTE,
+    &editor.button.ce_paste,                   GD_TYPE_NORMAL_BUTTON,
+    "paste settings to this element",          0
+  },
+
+  /* ---------- palette control buttons ------------------------------------ */
+
+  {
+    IMG_EDITOR_BUTTON_GFX_PROPERTIES,          GADGET_ID_PROPERTIES,
+    &editor.button.properties,                 GD_TYPE_NORMAL_BUTTON,
+    "properties of drawing element",           'p'
+  }
 };
 
 static int random_placement_value = 10;
@@ -1047,11 +1137,7 @@ static struct
   /* ---------- current level number --------------------------------------- */
 
   {
-#if 1
     -1, -1,    /* these values are not constant, but can change at runtime */
-#else
-    DX + 5 - SX,                       DY + 3 - SY,
-#endif
     1,                                 100,
     GADGET_ID_SELECT_LEVEL_DOWN,       GADGET_ID_SELECT_LEVEL_UP,
     GADGET_ID_SELECT_LEVEL_TEXT,       GADGET_ID_NONE,
@@ -1204,7 +1290,7 @@ static struct
   /* ---------- element settings: configure 1 (custom elements) ------------ */
 
   {
-    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(6),
+    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(5),
     MIN_SCORE,                         MAX_SCORE,
     GADGET_ID_CUSTOM_SCORE_DOWN,       GADGET_ID_CUSTOM_SCORE_UP,
     GADGET_ID_CUSTOM_SCORE_TEXT,       GADGET_ID_NONE,
@@ -1212,7 +1298,7 @@ static struct
     NULL,                              "CE score", " "
   },
   {
-    -1,                                        ED_ELEMENT_SETTINGS_YPOS(6),
+    -1,                                        ED_ELEMENT_SETTINGS_YPOS(5),
     MIN_COLLECT_COUNT,                 MAX_COLLECT_COUNT,
     GADGET_ID_CUSTOM_GEMCOUNT_DOWN,    GADGET_ID_CUSTOM_GEMCOUNT_UP,
     GADGET_ID_CUSTOM_GEMCOUNT_TEXT,    GADGET_ID_CUSTOM_SCORE_UP,
@@ -1220,7 +1306,7 @@ static struct
     NULL,                              "CE count", NULL
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(12),
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(10),
     0,                                 9999,
     GADGET_ID_CUSTOM_VALUE_FIX_DOWN,   GADGET_ID_CUSTOM_VALUE_FIX_UP,
     GADGET_ID_CUSTOM_VALUE_FIX_TEXT,   GADGET_ID_NONE,
@@ -1228,7 +1314,7 @@ static struct
     NULL,                              "CE value", NULL
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(12),
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(10),
     0,                                 9999,
     GADGET_ID_CUSTOM_VALUE_RND_DOWN,   GADGET_ID_CUSTOM_VALUE_RND_UP,
     GADGET_ID_CUSTOM_VALUE_RND_TEXT,   GADGET_ID_CUSTOM_VALUE_FIX_UP,
@@ -1236,7 +1322,7 @@ static struct
     NULL,                              "+random", NULL
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(7),
+    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(6),
     0,                                 999,
     GADGET_ID_PUSH_DELAY_FIX_DOWN,     GADGET_ID_PUSH_DELAY_FIX_UP,
     GADGET_ID_PUSH_DELAY_FIX_TEXT,     GADGET_ID_NONE,
@@ -1244,7 +1330,7 @@ static struct
     NULL,                              "push delay", NULL
   },
   {
-    -1,                                        ED_ELEMENT_SETTINGS_YPOS(7),
+    -1,                                        ED_ELEMENT_SETTINGS_YPOS(6),
     0,                                 999,
     GADGET_ID_PUSH_DELAY_RND_DOWN,     GADGET_ID_PUSH_DELAY_RND_UP,
     GADGET_ID_PUSH_DELAY_RND_TEXT,     GADGET_ID_PUSH_DELAY_FIX_UP,
@@ -1252,7 +1338,7 @@ static struct
     NULL,                              "+random", NULL
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(8),
+    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(7),
     0,                                 999,
     GADGET_ID_DROP_DELAY_FIX_DOWN,     GADGET_ID_DROP_DELAY_FIX_UP,
     GADGET_ID_DROP_DELAY_FIX_TEXT,     GADGET_ID_NONE,
@@ -1260,7 +1346,7 @@ static struct
     NULL,                              "drop delay", NULL
   },
   {
-    -1,                                        ED_ELEMENT_SETTINGS_YPOS(8),
+    -1,                                        ED_ELEMENT_SETTINGS_YPOS(7),
     0,                                 999,
     GADGET_ID_DROP_DELAY_RND_DOWN,     GADGET_ID_DROP_DELAY_RND_UP,
     GADGET_ID_DROP_DELAY_RND_TEXT,     GADGET_ID_DROP_DELAY_FIX_UP,
@@ -1306,7 +1392,7 @@ static struct
   /* ---------- element settings: configure (group elements) --------------- */
 
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(5),
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(3),
     MIN_ELEMENTS_IN_GROUP,             MAX_ELEMENTS_IN_GROUP,
     GADGET_ID_GROUP_CONTENT_DOWN,      GADGET_ID_GROUP_CONTENT_UP,
     GADGET_ID_GROUP_CONTENT_TEXT,      GADGET_ID_NONE,
@@ -2146,7 +2232,7 @@ static struct
   /* ---------- element settings: configure 1 (custom elements) ------------ */
 
   {
-    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(3),
+    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(2),
     GADGET_ID_CUSTOM_ACCESS_TYPE,      GADGET_ID_NONE,
     -1,
     options_access_type,
@@ -2154,7 +2240,7 @@ static struct
     NULL, NULL,                                "type of access to this field"
   },
   {
-    -1,                                        ED_ELEMENT_SETTINGS_YPOS(3),
+    -1,                                        ED_ELEMENT_SETTINGS_YPOS(2),
     GADGET_ID_CUSTOM_ACCESS_LAYER,     GADGET_ID_CUSTOM_ACCESS_TYPE,
     -1,
     options_access_layer,
@@ -2162,7 +2248,7 @@ static struct
     NULL, NULL,                                "layer of access for this field"
   },
   {
-    -1,                                        ED_ELEMENT_SETTINGS_YPOS(3),
+    -1,                                        ED_ELEMENT_SETTINGS_YPOS(2),
     GADGET_ID_CUSTOM_ACCESS_PROTECTED, GADGET_ID_CUSTOM_ACCESS_LAYER,
     -1,
     options_access_protected,
@@ -2170,7 +2256,7 @@ static struct
     NULL, NULL,                                "protected access for this field"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(4),
+    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(3),
     GADGET_ID_CUSTOM_ACCESS_DIRECTION, GADGET_ID_NONE,
     -1,
     options_access_direction,
@@ -2178,7 +2264,7 @@ static struct
     "from", NULL,                      "access direction for this field"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(5),
+    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(4),
     GADGET_ID_CUSTOM_WALK_TO_ACTION,   GADGET_ID_NONE,
     -1,
     options_walk_to_action,
@@ -2347,7 +2433,7 @@ static struct
   /* ---------- element settings: configure (group elements) --------------- */
 
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(6),
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(4),
     GADGET_ID_GROUP_CHOICE_MODE,       GADGET_ID_NONE,
     -1,
     options_group_choice_mode,
@@ -2409,7 +2495,7 @@ static struct
     NULL, NULL,                                "Configure custom element change pages"
   },
   {
-    -1,                                        ED_ELEMENT_SETTINGS_YPOS(2),
+    -1,                                        ED_ELEMENT_SETTINGS_YPOS(14),
     GADGET_ID_SAVE_AS_TEMPLATE,                GADGET_ID_CUSTOM_USE_TEMPLATE,
     -1,                                        "Save",
     " ", "As Template",                        "Save current settings as new template"
@@ -2470,61 +2556,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,
-#if 1
-    -1, -1,    /* these values are not constant, but can change at runtime */
-#else
-    ED_SCROLL_UP_XPOS,      ED_SCROLL_UP_YPOS,
-#endif
+    IMG_EDITOR_PLAYFIELD_SCROLL_UP,
     GADGET_ID_SCROLL_UP,
     "scroll level editing area up"
   },
   {
-    ED_SCROLLBUTTON_XPOS,   ED_SCROLLBUTTON_YPOS + 1 * ED_SCROLLBUTTON_YSIZE,
-#if 1
-    -1, -1,    /* these values are not constant, but can change at runtime */
-#else
-    ED_SCROLL_DOWN_XPOS,    ED_SCROLL_DOWN_YPOS,
-#endif
+    IMG_EDITOR_PLAYFIELD_SCROLL_DOWN,
     GADGET_ID_SCROLL_DOWN,
     "scroll level editing area down"
   },
   {
-    ED_SCROLLBUTTON_XPOS,   ED_SCROLLBUTTON_YPOS + 2 * ED_SCROLLBUTTON_YSIZE,
-#if 1
-    -1, -1,    /* these values are not constant, but can change at runtime */
-#else
-    ED_SCROLL_LEFT_XPOS,    ED_SCROLL_LEFT_YPOS,
-#endif
+    IMG_EDITOR_PLAYFIELD_SCROLL_LEFT,
     GADGET_ID_SCROLL_LEFT,
     "scroll level editing area left"
   },
   {
-    ED_SCROLLBUTTON_XPOS,   ED_SCROLLBUTTON_YPOS + 3 * ED_SCROLLBUTTON_YSIZE,
-#if 1
-    -1, -1,    /* these values are not constant, but can change at runtime */
-#else
-    ED_SCROLL_RIGHT_XPOS,   ED_SCROLL_RIGHT_YPOS,
-#endif
+    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')"
   },
@@ -2532,68 +2600,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,
-#if 1
-    -1, -1,    /* these values are not constant, but can change at runtime */
-    -1, -1,    /* these values are not constant, but can change at runtime */
-    -1, -1,    /* these values are not constant, but can change at runtime */
-    -1, -1,    /* these values are not constant, but can change at runtime */
-#else
-    SX + ED_SCROLL_HORIZONTAL_XPOS,    SY + ED_SCROLL_HORIZONTAL_YPOS,
-    ED_SCROLL_HORIZONTAL_XSIZE,                ED_SCROLL_HORIZONTAL_YSIZE,
-    SX,                                        SY,
-    SXSIZE,                            SYSIZE,
-#endif
+    IMG_EDITOR_PLAYFIELD_SCROLLBAR,
     GD_TYPE_SCROLLBAR_HORIZONTAL,
     GADGET_ID_SCROLL_HORIZONTAL,
     "scroll level editing area horizontally"
   },
   {
-    ED_SCROLLBAR_XPOS,                 ED_SCROLLBAR_YPOS,
-#if 1
-    -1, -1,    /* these values are not constant, but can change at runtime */
-    -1, -1,    /* these values are not constant, but can change at runtime */
-    -1, -1,    /* these values are not constant, but can change at runtime */
-    -1, -1,    /* these values are not constant, but can change at runtime */
-#else
-    SX + ED_SCROLL_VERTICAL_XPOS,      SY + ED_SCROLL_VERTICAL_YPOS,
-    ED_SCROLL_VERTICAL_XSIZE,          ED_SCROLL_VERTICAL_YSIZE,
-    SX,                                        SY,
-    SXSIZE,                            SYSIZE,
-#endif
+    IMG_EDITOR_PLAYFIELD_SCROLLBAR,
     GD_TYPE_SCROLLBAR_VERTICAL,
     GADGET_ID_SCROLL_VERTICAL,
     "scroll level editing area vertically"
   },
   {
-    ED_SCROLLBAR2_XPOS,                        ED_SCROLLBAR2_YPOS,
-#if 1
-    -1, -1,    /* these values are not constant, but can change at runtime */
-    ED_SCROLL2_VERTICAL_XSIZE,         ED_SCROLL2_VERTICAL_YSIZE,
-    -1, -1,    /* these values are not constant, but can change at runtime */
-#else
-    DX + ED_SCROLL2_VERTICAL_XPOS,     DY + ED_SCROLL2_VERTICAL_YPOS,
-    ED_SCROLL2_VERTICAL_XSIZE,         ED_SCROLL2_VERTICAL_YSIZE,
-    DX,                                        DY,
-#endif
-    DXSIZE,                            DYSIZE,
+    IMG_EDITOR_PALETTE_SCROLLBAR,
     GD_TYPE_SCROLLBAR_VERTICAL,
     GADGET_ID_SCROLL_LIST_VERTICAL,
     "scroll element list vertically"
   }
 };
 
+
 static struct
 {
   int x, y;
@@ -2710,7 +2751,7 @@ static struct
     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),
@@ -2831,53 +2872,46 @@ 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),
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(14),
     GADGET_ID_CUSTOM_USE_TEMPLATE,     GADGET_ID_NONE,
     &level.use_custom_template,
     NULL,
     "use template",                    "use template for custom properties"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(3),
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(2),
     GADGET_ID_CUSTOM_ACCESSIBLE,       GADGET_ID_NONE,
     &custom_element_properties[EP_ACCESSIBLE],
     NULL,
     NULL,                              "player can walk to or pass this field"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(10),
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(9),
     GADGET_ID_CUSTOM_GRAV_REACHABLE,   GADGET_ID_NONE,
     &custom_element_properties[EP_GRAVITY_REACHABLE],
     NULL,
     "reachable despite gravity",       "player can walk/dig despite gravity"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(13),
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(11),
     GADGET_ID_CUSTOM_USE_LAST_VALUE,   GADGET_ID_NONE,
     &custom_element.use_last_ce_value,
     NULL,
     "use last CE value after change",  "use last CE value after change"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(5),
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(4),
     GADGET_ID_CUSTOM_WALK_TO_OBJECT,   GADGET_ID_NONE,
     &custom_element_properties[EP_WALK_TO_OBJECT],
     NULL,
     NULL,                              "player can dig/collect/push element"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(9),
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(8),
     GADGET_ID_CUSTOM_INDESTRUCTIBLE,   GADGET_ID_NONE,
     &custom_element_properties[EP_INDESTRUCTIBLE],
     NULL,
@@ -3033,11 +3067,7 @@ static struct
     0,                                 0,
     GADGET_ID_DRAWING_LEVEL,           GADGET_ID_NONE,
     NULL,
-#if 1
     -1, -1,    /* these values are not constant, but can change at runtime */
-#else
-    MAX_ED_FIELDX, MAX_ED_FIELDY,
-#endif
     NULL, NULL, NULL,                  NULL
   },
 
@@ -3275,7 +3305,7 @@ static struct
   /* ---------- group element content -------------------------------------- */
 
   {
-    ED_AREA_1X1_SETTINGS_XPOS(0),      ED_AREA_1X1_SETTINGS_YPOS(4),
+    ED_AREA_1X1_SETTINGS_XPOS(0),      ED_AREA_1X1_SETTINGS_YPOS(2),
     GADGET_ID_GROUP_CONTENT,           GADGET_ID_NONE,
     &group_element_info.element[0],    MAX_ELEMENTS_IN_GROUP, 1,
     "content:", NULL, NULL,            NULL
@@ -3298,21 +3328,19 @@ static struct
   -----------------------------------------------------------------------------
 */
 
+/* maximal size of level editor drawing area */
+static int MAX_ED_FIELDX, MAX_ED_FIELDY;
+
 /* actual size of level editor drawing area */
-#if 1
 static int ed_fieldx, ed_fieldy;
-#else
-static int ed_fieldx = MAX_ED_FIELDX - 1, ed_fieldy = MAX_ED_FIELDY - 1;
-#endif
 
 /* actual position of level editor drawing area in level playfield */
 static int level_xpos = -1, level_ypos = -1;
 
-#if 1
+/* actual tile size used to display level editor playfield */
+static int ed_tilesize = DEFAULT_EDITOR_TILESIZE;
+
 #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;
@@ -3353,8 +3381,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;
@@ -3366,6 +3396,7 @@ static short UndoBuffer[NUM_UNDO_STEPS][MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 static short IntelliDrawBuffer[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 static int undo_buffer_position = 0;
 static int undo_buffer_steps = 0;
+static int redo_buffer_steps = 0;
 
 static int edit_mode;
 static int edit_mode_levelinfo;
@@ -4065,13 +4096,13 @@ static int editor_el_chars[] =
   EL_CHAR('^'),
   EL_CHAR('_'),
 
-  EL_CHAR('©'),
-  EL_CHAR('Ä'),
-  EL_CHAR('Ö'),
-  EL_CHAR('Ãœ'),
+  EL_CHAR(CHAR_BYTE_COPYRIGHT),
+  EL_CHAR(CHAR_BYTE_UMLAUT_A),
+  EL_CHAR(CHAR_BYTE_UMLAUT_O),
+  EL_CHAR(CHAR_BYTE_UMLAUT_U),
 
-  EL_CHAR('°'),
-  EL_CHAR('®'),
+  EL_CHAR(CHAR_BYTE_DEGREE),
+  EL_CHAR(CHAR_BYTE_REGISTERED),
   EL_CHAR(FONT_ASCII_CURSOR),
   EL_CHAR(FONT_ASCII_BUTTON),
 
@@ -4175,13 +4206,13 @@ static int editor_el_steel_chars[] =
   EL_STEEL_CHAR('^'),
   EL_STEEL_CHAR('_'),
 
-  EL_STEEL_CHAR('©'),
-  EL_STEEL_CHAR('Ä'),
-  EL_STEEL_CHAR('Ö'),
-  EL_STEEL_CHAR('Ãœ'),
+  EL_STEEL_CHAR(CHAR_BYTE_COPYRIGHT),
+  EL_STEEL_CHAR(CHAR_BYTE_UMLAUT_A),
+  EL_STEEL_CHAR(CHAR_BYTE_UMLAUT_O),
+  EL_STEEL_CHAR(CHAR_BYTE_UMLAUT_U),
 
-  EL_STEEL_CHAR('°'),
-  EL_STEEL_CHAR('®'),
+  EL_STEEL_CHAR(CHAR_BYTE_DEGREE),
+  EL_STEEL_CHAR(CHAR_BYTE_REGISTERED),
   EL_STEEL_CHAR(FONT_ASCII_CURSOR),
   EL_STEEL_CHAR(FONT_ASCII_BUTTON),
 
@@ -4656,11 +4687,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 */
 
@@ -4854,27 +4885,47 @@ static char *getElementInfoText(int element)
   return info_text;
 }
 
-char *getElementDescriptionFilename(int element)
+static char *getElementDescriptionFilenameExt(char *basename)
 {
-  char *docs_dir = options.docs_directory;
   char *elements_subdir = "elements";
+  static char *elements_subdir2 = NULL;
   static char *filename = NULL;
-  char basename[MAX_FILENAME_LEN];
+
+  if (elements_subdir2 == NULL)
+    elements_subdir2 = getPath2(DOCS_DIRECTORY, elements_subdir);
 
   checked_free(filename);
 
-  /* 1st try: look for element description file for exactly this element */
-  sprintf(basename, "%s.txt", element_info[element].token_name);
-  filename = getPath3(docs_dir, elements_subdir, basename);
+  /* 1st try: look for element description in current level set directory */
+  filename = getPath3(getCurrentLevelDir(), elements_subdir2, basename);
   if (fileExists(filename))
     return filename;
 
   free(filename);
 
+  /* 2nd try: look for element description in the game's base directory */
+  filename = getPath3(options.docs_directory, elements_subdir, basename);
+  if (fileExists(filename))
+    return filename;
+
+  return NULL;
+}
+
+char *getElementDescriptionFilename(int element)
+{
+  char basename[MAX_FILENAME_LEN];
+  char *filename;
+
+  /* 1st try: look for element description file for exactly this element */
+  sprintf(basename, "%s.txt", element_info[element].token_name);
+  filename = getElementDescriptionFilenameExt(basename);
+  if (filename != NULL)
+    return filename;
+
   /* 2nd try: look for element description file for this element's class */
   sprintf(basename, "%s.txt", element_info[element].class_name);
-  filename = getPath3(docs_dir, elements_subdir, basename);
-  if (fileExists(filename))
+  filename = getElementDescriptionFilenameExt(basename);
+  if (filename != NULL)
     return filename;
 
   return NULL;
@@ -4993,7 +5044,9 @@ static void ReinitializeElementList()
     {
       if (setup.editor.el_headlines)
       {
-       num_editor_elements += *editor_elements_info[i].headline_list_size;
+       // required for correct padding of palette headline buttons
+       if (*editor_elements_info[i].headline_list_size > 0)
+         num_editor_elements += editor.palette.cols;
 
        for (j = 0; j < *editor_elements_info[i].headline_list_size; j++)
        {
@@ -5007,7 +5060,13 @@ static void ReinitializeElementList()
       if (found_inactive_cascade)
        continue;
 
-      num_editor_elements += *editor_elements_info[i].element_list_size;
+      // required for correct padding of palette element buttons
+      int element_list_size = *editor_elements_info[i].element_list_size;
+      int element_rows =
+       (element_list_size + editor.palette.cols - 1) / editor.palette.cols;
+      int element_buttons = editor.palette.cols * element_rows;
+
+      num_editor_elements += element_buttons;
     }
   }
 
@@ -5031,9 +5090,16 @@ static void ReinitializeElementList()
     {
       if (setup.editor.el_headlines)
       {
-       for (j = 0; j < *editor_elements_info[i].headline_list_size; j++)
+       // required for correct padding of palette headline buttons
+       int headline_size = (*editor_elements_info[i].headline_list_size > 0 ?
+                            editor.palette.cols : 0);
+
+       for (j = 0; j < headline_size; j++)
        {
-         int element = (*editor_elements_info[i].headline_list)[j];
+         // use empty elements for padding of palette headline buttons
+         int element = (j < *editor_elements_info[i].headline_list_size ?
+                        (*editor_elements_info[i].headline_list)[j] :
+                        editor_el_empty[0]);
 
          editor_elements[pos++] = element;
 
@@ -5045,8 +5111,19 @@ static void ReinitializeElementList()
       if (found_inactive_cascade)
        continue;
 
-      for (j = 0; j < *editor_elements_info[i].element_list_size; j++)
+      // required for correct padding of palette element buttons
+      int element_list_size = *editor_elements_info[i].element_list_size;
+      int element_rows =
+       (element_list_size + editor.palette.cols - 1) / editor.palette.cols;
+      int element_buttons = editor.palette.cols * element_rows;
+
+      // copy all elements from element list
+      for (j = 0; j < element_list_size; j++)
        editor_elements[pos++] = (*editor_elements_info[i].element_list)[j];
+
+      // use empty elements for padding of palette element buttons
+      for (j = 0; j < element_buttons - element_list_size; j++)
+       editor_elements[pos++] = editor_el_empty[0];
     }
   }
 
@@ -5137,13 +5214,13 @@ static void DrawElementBorder(int dest_x, int dest_y, int width, int height,
     (input ? IMG_EDITOR_ELEMENT_BORDER_INPUT : IMG_EDITOR_ELEMENT_BORDER);
   Bitmap *src_bitmap;
   int src_x, src_y;
-  int bx = (input ? 4 : 8);
-  int by = (input ? 4 : 8);
+  int bx = (input ? ED_ELEMENT_BORDER_INPUT : ED_ELEMENT_BORDER);
+  int by = (input ? ED_ELEMENT_BORDER_INPUT : ED_ELEMENT_BORDER);
   int bx2 = TILEX - bx;
   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);
@@ -5173,6 +5250,21 @@ static void DrawElementBorder(int dest_x, int dest_y, int width, int height,
   ClearRectangle(drawto, dest_x - 1, dest_y - 1, width + 2, height + 2);
 }
 
+static void DrawEditorElement(int x, int y, int element)
+{
+  DrawSizedElement(x, y, element, ed_tilesize);
+}
+
+static void DrawEditorElementOrWall(int x, int y, int scroll_x, int scroll_y)
+{
+  DrawSizedElementOrWall(x, y, scroll_x, scroll_y, ed_tilesize);
+}
+
+static void DrawEditorLevel(int size_x, int size_y, int scroll_x, int scroll_y)
+{
+  DrawSizedLevel(size_x, size_y, scroll_x, scroll_y, ed_tilesize);
+}
+
 static void DrawDrawingArea(int id)
 {
   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
@@ -5190,80 +5282,86 @@ static void DrawDrawingArea(int id)
                         el2edimg(value[x * area_ysize + y]));
 }
 
-static void ScrollMiniLevel(int from_x, int from_y, int scroll)
+static void ScrollEditorLevel(int from_x, int from_y, int scroll)
 {
   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);
 
   BlitBitmap(drawto, 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));
+            SX + (dx == -1 ? ed_tilesize : 0),
+            SY + (dy == -1 ? ed_tilesize : 0),
+            (ed_fieldx * ed_tilesize) - (dx != 0 ? ed_tilesize : 0),
+            (ed_fieldy * ed_tilesize) - (dy != 0 ? ed_tilesize : 0),
+            SX + (dx == +1 ? ed_tilesize : 0),
+            SY + (dy == +1 ? ed_tilesize : 0));
 
   if (dx)
   {
     x = (dx == 1 ? 0 : ed_fieldx - 1);
     for (y = 0; y < ed_fieldy; y++)
-      DrawMiniElementOrWall(x, y, from_x, from_y);
+      DrawEditorElementOrWall(x, y, from_x, from_y);
   }
   else if (dy)
   {
     y = (dy == 1 ? 0 : ed_fieldy - 1);
     for (x = 0; x < ed_fieldx; x++)
-      DrawMiniElementOrWall(x, y, from_x, from_y);
+      DrawEditorElementOrWall(x, y, from_x, from_y);
   }
 
   redraw_mask |= REDRAW_FIELD;
   BackToFront();
 }
 
+void getElementListGraphicSource(int element, Bitmap **bitmap, int *x, int *y)
+{
+  int graphic = el2edimg(element);
+  int tile_size = (editor.palette.tile_size >= TILESIZE ? TILESIZE :
+                  MINI_TILESIZE);
+
+  getSizedGraphicSource(graphic, 0, tile_size, bitmap, x, y);
+}
+
 static void CreateControlButtons()
 {
-  Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
   struct GadgetInfo *gi;
-  unsigned long event_mask;
   int i;
 
   /* create toolbox buttons */
   for (i = 0; i < ED_NUM_CTRL_BUTTONS; i++)
   {
-    int id = i;
-    int width, height;
-    int gd_xoffset, gd_yoffset;
-    int gd_x1, gd_x2, gd_y1, gd_y2;
-    int button_type;
-    int radio_button_nr;
-    boolean checked;
-
-    if (id == GADGET_ID_SINGLE_ITEMS ||
-       id == GADGET_ID_CONNECTED_ITEMS ||
-       id == GADGET_ID_LINE ||
-       id == GADGET_ID_ARC ||
-       id == GADGET_ID_TEXT ||
-       id == GADGET_ID_RECTANGLE ||
-       id == GADGET_ID_FILLED_BOX ||
-       id == GADGET_ID_FLOOD_FILL ||
-       id == GADGET_ID_GRAB_BRUSH ||
-       id == GADGET_ID_PICK_ELEMENT ||
-       id == GADGET_ID_CUSTOM_COPY_FROM ||
-       id == GADGET_ID_CUSTOM_COPY_TO ||
-       id == GADGET_ID_CUSTOM_EXCHANGE)
+    int id = controlbutton_info[i].gadget_id;
+    int type = controlbutton_info[i].gadget_type;
+    int graphic = controlbutton_info[i].graphic;
+    struct XY *pos = controlbutton_info[i].pos;
+    struct GraphicInfo *gd = &graphic_info[graphic];
+    Bitmap *gd_bitmap = gd->bitmap;
+    int gd_x1 = gd->src_x;
+    int gd_y1 = gd->src_y;
+    int gd_x2 = gd->src_x + gd->pressed_xoffset;
+    int gd_y2 = gd->src_y + gd->pressed_yoffset;
+    int gd_x1a = gd->src_x + gd->active_xoffset;
+    int gd_y1a = gd->src_y + gd->active_yoffset;
+    int gd_x2a = gd->src_x + gd->active_xoffset + gd->pressed_xoffset;
+    int gd_y2a = gd->src_y + gd->active_yoffset + gd->pressed_yoffset;
+    int width  = gd->width;
+    int height = gd->height;
+    int x = pos->x;
+    int y = pos->y;
+    unsigned int event_mask;
+    int radio_button_nr = RADIO_NR_NONE;
+    boolean checked = FALSE;
+
+    if (type == GD_TYPE_RADIO_BUTTON)
     {
-      button_type = GD_TYPE_RADIO_BUTTON;
-      radio_button_nr = RADIO_NR_DRAWING_TOOLBOX;
-      checked = (id == drawing_function ? TRUE : FALSE);
       event_mask = GD_EVENT_PRESSED;
+      radio_button_nr = RADIO_NR_DRAWING_TOOLBOX;
+
+      if (id == drawing_function)
+       checked = TRUE;
     }
     else
     {
-      button_type = GD_TYPE_NORMAL_BUTTON;
-      radio_button_nr = RADIO_NR_NONE;
-      checked = FALSE;
-
       if (id == GADGET_ID_WRAP_LEFT ||
          id == GADGET_ID_WRAP_RIGHT ||
          id == GADGET_ID_WRAP_UP ||
@@ -5273,82 +5371,32 @@ static void CreateControlButtons()
        event_mask = GD_EVENT_RELEASED;
     }
 
-    if (id < ED_NUM_CTRL1_BUTTONS)
-    {
-      int x = i % ED_CTRL1_BUTTONS_HORIZ;
-      int y = i / ED_CTRL1_BUTTONS_HORIZ;
-
-      gd_xoffset = ED_CTRL1_BUTTONS_XPOS + x * ED_CTRL1_BUTTON_XSIZE;
-      gd_yoffset = ED_CTRL1_BUTTONS_YPOS + y * ED_CTRL1_BUTTON_YSIZE;
-      width  = ED_CTRL1_BUTTON_XSIZE;
-      height = ED_CTRL1_BUTTON_YSIZE;
-
-      gd_x1 = DOOR_GFX_PAGEX8 + gd_xoffset;
-      gd_x2 = DOOR_GFX_PAGEX7 + gd_xoffset;
-      gd_y1 = DOOR_GFX_PAGEY1 + ED_CTRL1_BUTTONS_GFX_YPOS     + gd_yoffset;
-      gd_y2 = DOOR_GFX_PAGEY1 + ED_CTRL1_BUTTONS_ALT_GFX_YPOS + gd_yoffset;
-    }
-    else if (id < ED_NUM_CTRL1_2_BUTTONS)
+    if (id == GADGET_ID_PROPERTIES)
     {
-      int x = (i - ED_NUM_CTRL1_BUTTONS) % ED_CTRL2_BUTTONS_HORIZ;
-      int y = (i - ED_NUM_CTRL1_BUTTONS) / ED_CTRL2_BUTTONS_HORIZ;
-
-      gd_xoffset = ED_CTRL2_BUTTONS_XPOS + x * ED_CTRL2_BUTTON_XSIZE;
-      gd_yoffset = ED_CTRL2_BUTTONS_YPOS + y * ED_CTRL2_BUTTON_YSIZE;
-      width  = ED_CTRL2_BUTTON_XSIZE;
-      height = ED_CTRL2_BUTTON_YSIZE;
-
-      gd_x1 = DOOR_GFX_PAGEX8 + gd_xoffset;
-      gd_x2 = DOOR_GFX_PAGEX7 + gd_xoffset;
-      gd_y1 = DOOR_GFX_PAGEY1 + ED_CTRL2_BUTTONS_GFX_YPOS + gd_yoffset;
-      gd_y2 = 0;       /* no alternative graphic for these buttons */
-    }
-    else if (id < ED_NUM_CTRL1_3_BUTTONS)
-    {
-      int x = (i - ED_NUM_CTRL1_2_BUTTONS) % ED_CTRL3_BUTTONS_HORIZ + 1;
-      int y = (i - ED_NUM_CTRL1_2_BUTTONS) / ED_CTRL3_BUTTONS_HORIZ;
-
-      gd_xoffset = ED_CTRL3_BUTTONS_XPOS + x * ED_CTRL3_BUTTON_XSIZE;
-      gd_yoffset = ED_CTRL3_BUTTONS_YPOS + y * ED_CTRL3_BUTTON_YSIZE;
-      width  = ED_CTRL3_BUTTON_XSIZE;
-      height = ED_CTRL3_BUTTON_YSIZE;
-
-      gd_x1 = DOOR_GFX_PAGEX6 + gd_xoffset;
-      gd_x2 = DOOR_GFX_PAGEX5 + gd_xoffset;
-      gd_y1 = DOOR_GFX_PAGEY1 + ED_CTRL3_BUTTONS_GFX_YPOS     + gd_yoffset;
-      gd_y2 = DOOR_GFX_PAGEY1 + ED_CTRL3_BUTTONS_ALT_GFX_YPOS + gd_yoffset;
+      x += DX;
+      y += DY;
     }
     else
     {
-      int x = (i - ED_NUM_CTRL1_3_BUTTONS) % ED_CTRL4_BUTTONS_HORIZ;
-      int y = (i - ED_NUM_CTRL1_3_BUTTONS) / ED_CTRL4_BUTTONS_HORIZ + 3;
-
-      gd_xoffset = ED_CTRL4_BUTTONS_XPOS + x * ED_CTRL4_BUTTON_XSIZE;
-      gd_yoffset = ED_CTRL4_BUTTONS_YPOS + y * ED_CTRL4_BUTTON_YSIZE;
-      width  = ED_CTRL4_BUTTON_XSIZE;
-      height = ED_CTRL4_BUTTON_YSIZE;
-
-      gd_x1 = DOOR_GFX_PAGEX6 + ED_CTRL4_BUTTONS_GFX_XPOS + gd_xoffset;
-      gd_x2 = DOOR_GFX_PAGEX5 + ED_CTRL4_BUTTONS_GFX_XPOS + gd_xoffset;
-      gd_y1 = DOOR_GFX_PAGEY1 + ED_CTRL4_BUTTONS_GFX_YPOS + gd_yoffset;
-      gd_y2 = 0;       /* no alternative graphic for these buttons */
+      x += EX;
+      y += EY;
     }
 
     gi = CreateGadget(GDI_CUSTOM_ID, id,
                      GDI_CUSTOM_TYPE_ID, i,
-                     GDI_INFO_TEXT, control_info[i].text,
-                     GDI_X, EX + gd_xoffset,
-                     GDI_Y, EY + gd_yoffset,
+                     GDI_INFO_TEXT, controlbutton_info[i].infotext,
+                     GDI_X, x,
+                     GDI_Y, y,
                      GDI_WIDTH, width,
                      GDI_HEIGHT, height,
-                     GDI_TYPE, button_type,
+                     GDI_TYPE, type,
                      GDI_STATE, GD_BUTTON_UNPRESSED,
                      GDI_RADIO_NR, radio_button_nr,
                      GDI_CHECKED, checked,
                      GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
-                     GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y1,
-                     GDI_ALT_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y2,
-                     GDI_ALT_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
+                     GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
+                     GDI_ALT_DESIGN_UNPRESSED, gd_bitmap, gd_x1a, gd_y1a,
+                     GDI_ALT_DESIGN_PRESSED, gd_bitmap, gd_x2a, gd_y2a,
                      GDI_EVENT_MASK, event_mask,
                      GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
                      GDI_CALLBACK_ACTION, HandleControlButtons,
@@ -5361,49 +5409,46 @@ static void CreateControlButtons()
   }
 
   /* these values are not constant, but can change at runtime */
-  scrollbutton_info[ED_SCROLLBUTTON_ID_AREA_UP].x    = ED_SCROLL_UP_XPOS;
-  scrollbutton_info[ED_SCROLLBUTTON_ID_AREA_UP].y    = ED_SCROLL_UP_YPOS;
-  scrollbutton_info[ED_SCROLLBUTTON_ID_AREA_DOWN].x  = ED_SCROLL_DOWN_XPOS;
-  scrollbutton_info[ED_SCROLLBUTTON_ID_AREA_DOWN].y  = ED_SCROLL_DOWN_YPOS;
-  scrollbutton_info[ED_SCROLLBUTTON_ID_AREA_LEFT].x  = ED_SCROLL_LEFT_XPOS;
-  scrollbutton_info[ED_SCROLLBUTTON_ID_AREA_LEFT].y  = ED_SCROLL_LEFT_YPOS;
-  scrollbutton_info[ED_SCROLLBUTTON_ID_AREA_RIGHT].x = ED_SCROLL_RIGHT_XPOS;
-  scrollbutton_info[ED_SCROLLBUTTON_ID_AREA_RIGHT].y = ED_SCROLL_RIGHT_YPOS;
+  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 x, y, width, height;
-    int gd_x1, gd_x2, gd_y1, gd_y2;
-
-    x = scrollbutton_info[i].x;
-    y = scrollbutton_info[i].y;
-
-    event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
+    int graphic = scrollbutton_info[i].graphic;
+    struct GraphicInfo *gd = &graphic_info[graphic];
+    Bitmap *gd_bitmap = gd->bitmap;
+    int gd_x1 = gd->src_x;
+    int gd_y1 = gd->src_y;
+    int gd_x2 = gd->src_x + gd->pressed_xoffset;
+    int gd_y2 = gd->src_y + gd->pressed_yoffset;
+    int width  = gd->width;
+    int height = gd->height;
+    int x = scrollbutton_pos[i].x;
+    int y = scrollbutton_pos[i].y;
+    unsigned int event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
 
     if (id == GADGET_ID_SCROLL_LIST_UP ||
        id == GADGET_ID_SCROLL_LIST_DOWN)
     {
       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;
     }
     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;
     }
 
     gi = CreateGadget(GDI_CUSTOM_ID, id,
@@ -5431,42 +5476,43 @@ static void CreateControlButtons()
   /* create buttons for element list */
   for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
   {
+    int id = GADGET_ID_ELEMENTLIST_FIRST + i;
+    int graphic = IMG_EDITOR_PALETTE_BUTTON;
+    struct GraphicInfo *gd = &graphic_info[graphic];
+    Bitmap *gd_bitmap = gd->bitmap;
     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 x = i % ED_ELEMENTLIST_BUTTONS_HORIZ;
-    int y = i / ED_ELEMENTLIST_BUTTONS_HORIZ;
-    int id = GADGET_ID_ELEMENTLIST_FIRST + i;
+    int gd_x1 = gd->src_x;
+    int gd_y1 = gd->src_y;
+    int gd_x2 = gd->src_x + gd->pressed_xoffset;
+    int gd_y2 = gd->src_y + gd->pressed_yoffset;
+    int xx = i % ED_ELEMENTLIST_BUTTONS_HORIZ;
+    int yy = i / ED_ELEMENTLIST_BUTTONS_HORIZ;
+    int x = DX + ED_ELEMENTLIST_XPOS + xx * gd->width;
+    int y = DY + ED_ELEMENTLIST_YPOS + yy * gd->height;
     int element = editor_elements[i];
+    int tile_size = (editor.palette.tile_size >= TILESIZE ? TILESIZE :
+                    MINI_TILESIZE);
+    unsigned int event_mask = GD_EVENT_RELEASED;
 
-    event_mask = GD_EVENT_RELEASED;
-
-    gd_xoffset = ED_ELEMENTLIST_XPOS + x * ED_ELEMENTLIST_XSIZE;
-    gd_yoffset = ED_ELEMENTLIST_YPOS + y * ED_ELEMENTLIST_YSIZE;
-
-    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;
-
-    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;
+    getElementListGraphicSource(element, &deco_bitmap, &deco_x, &deco_y);
+    deco_xpos = (gd->width  - tile_size) / 2;
+    deco_ypos = (gd->height - tile_size) / 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_X, x,
+                     GDI_Y, y,
+                     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,
+                     GDI_DECORATION_SIZE, tile_size, tile_size,
                      GDI_DECORATION_SHIFTING, 1, 1,
                      GDI_EVENT_MASK, event_mask,
                      GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
@@ -5485,10 +5531,6 @@ 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;
@@ -5512,37 +5554,49 @@ 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;
 
-       if (j == 1)
-         x += 2 * ED_GADGET_DISTANCE;
-       y += ED_GADGET_DISTANCE;
+       if (j == 0)
+       {
+         x = DX + editor.button.prev_level.x;
+         y = DY + editor.button.prev_level.y;
+       }
+       else
+       {
+         x = DX + editor.button.next_level.x;
+         y = DY + editor.button.next_level.y;
+       }
 
-       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;
       }
@@ -5559,8 +5613,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,
@@ -5580,24 +5634,28 @@ static void CreateCounterButtons()
        int font_type = FONT_INPUT_1;
        int font_type_active = FONT_INPUT_1_ACTIVE;
        int gd_width = ED_WIN_COUNT_XSIZE;
+       int border_size = ED_BORDER_SIZE;
 
        id = counterbutton_info[i].gadget_id_text;
        event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
 
        if (i == ED_COUNTER_ID_SELECT_LEVEL)
        {
+         int graphic = IMG_EDITOR_INPUT_GFX_LEVEL_NUMBER;
+         struct GraphicInfo *gd = &graphic_info[graphic];
+
+         gd_bitmap = gd->bitmap;
+
+         x = DX + editor.input.level_number.x;
+         y = DY + editor.input.level_number.y;
+
+         gd_x = gd->src_x;
+         gd_y = gd->src_y;
+         gd_width = gd->width;
+         border_size = gd->border_size;
+
          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;
-
-         gd_x = DOOR_GFX_PAGEX6 + ED_WIN_COUNT2_XPOS;
-         gd_y = DOOR_GFX_PAGEY1 + ED_WIN_COUNT2_YPOS;
-         gd_width = ED_WIN_COUNT2_XSIZE;
        }
        else
        {
@@ -5619,7 +5677,7 @@ static void CreateCounterButtons()
                          GDI_TEXT_FONT_ACTIVE, font_type_active,
                          GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x, gd_y,
                          GDI_DESIGN_PRESSED, gd_bitmap, gd_x, gd_y,
-                         GDI_BORDER_SIZE, ED_BORDER_SIZE, ED_BORDER_SIZE,
+                         GDI_BORDER_SIZE, border_size, border_size,
                          GDI_DESIGN_WIDTH, gd_width,
                          GDI_EVENT_MASK, event_mask,
                          GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
@@ -5650,7 +5708,7 @@ static void CreateDrawingAreas()
   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;
@@ -5676,7 +5734,7 @@ static void CreateDrawingAreas()
                      GDI_Y, y,
                      GDI_TYPE, GD_TYPE_DRAWING_AREA,
                      GDI_AREA_SIZE, area_xsize, area_ysize,
-                     GDI_ITEM_SIZE, MINI_TILEX, MINI_TILEY,
+                     GDI_ITEM_SIZE, ed_tilesize, ed_tilesize,
                      GDI_EVENT_MASK, event_mask,
                      GDI_CALLBACK_INFO, HandleDrawingAreaInfo,
                      GDI_CALLBACK_ACTION, HandleDrawingAreas,
@@ -5701,7 +5759,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;
 
@@ -5749,7 +5807,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;
@@ -5798,7 +5856,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;
@@ -5843,9 +5901,11 @@ static void CreateSelectboxGadgets()
                      GDI_Y, y,
                      GDI_TYPE, GD_TYPE_SELECTBOX,
                      GDI_SELECTBOX_OPTIONS, selectbox_info[i].options,
+                     GDI_SELECTBOX_CHAR_UNSELECTABLE, '[',
                      GDI_TEXT_SIZE, selectbox_info[i].size,
                      GDI_TEXT_FONT, FONT_INPUT_1,
                      GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_ACTIVE,
+                     GDI_TEXT_FONT_UNSELECTABLE, FONT_TEXT_1,
                      GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x, gd_y,
                      GDI_DESIGN_PRESSED, gd_bitmap, gd_x, gd_y,
                      GDI_BORDER_SIZE, ED_BORDER_SIZE, ED_BORDER_SIZE,
@@ -5875,7 +5935,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;
@@ -5948,7 +6008,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 */
@@ -6015,47 +6075,55 @@ static void CreateScrollbarGadgets()
   int i;
 
   /* these values are not constant, but can change at runtime */
-  scrollbar_info[ED_SCROLLBAR_ID_AREA_HORIZONTAL].x =
+  scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].x =
     SX + ED_SCROLL_HORIZONTAL_XPOS;
-  scrollbar_info[ED_SCROLLBAR_ID_AREA_HORIZONTAL].y =
+  scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].y =
     SY + ED_SCROLL_HORIZONTAL_YPOS;
-  scrollbar_info[ED_SCROLLBAR_ID_AREA_HORIZONTAL].width =
+  scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].width =
     ED_SCROLL_HORIZONTAL_XSIZE;
-  scrollbar_info[ED_SCROLLBAR_ID_AREA_HORIZONTAL].height =
+  scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].height =
     ED_SCROLL_HORIZONTAL_YSIZE;
-  scrollbar_info[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_x      = SX;
-  scrollbar_info[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_y      = SY;
-  scrollbar_info[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_width  = SXSIZE;
-  scrollbar_info[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_height = SYSIZE;
+  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_info[ED_SCROLLBAR_ID_AREA_VERTICAL].x =
+  scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].x =
     SX + ED_SCROLL_VERTICAL_XPOS;
-  scrollbar_info[ED_SCROLLBAR_ID_AREA_VERTICAL].y =
+  scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].y =
     SY + ED_SCROLL_VERTICAL_YPOS;
-  scrollbar_info[ED_SCROLLBAR_ID_AREA_VERTICAL].width =
+  scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].width =
     ED_SCROLL_VERTICAL_XSIZE;
-  scrollbar_info[ED_SCROLLBAR_ID_AREA_VERTICAL].height =
+  scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].height =
     ED_SCROLL_VERTICAL_YSIZE;
-  scrollbar_info[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_x      = SX;
-  scrollbar_info[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_y      = SY;
-  scrollbar_info[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_width  = SXSIZE;
-  scrollbar_info[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_height = SYSIZE;
+  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_info[ED_SCROLLBAR_ID_LIST_VERTICAL].x =
+  scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].x =
     DX + ED_SCROLL2_VERTICAL_XPOS;
-  scrollbar_info[ED_SCROLLBAR_ID_LIST_VERTICAL].y =
+  scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].y =
     DY + ED_SCROLL2_VERTICAL_YPOS;
-  scrollbar_info[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_x = DX;
-  scrollbar_info[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_y = DY;
+  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)
     {
@@ -6081,27 +6149,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,
@@ -6122,7 +6189,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;
 
@@ -6185,7 +6252,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;
 
@@ -6254,6 +6321,18 @@ void CreateLevelEditorGadgets()
   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();
@@ -6277,12 +6356,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)
@@ -6347,6 +6433,9 @@ static void MapControlButtons()
   for (i = 0; i < ED_NUM_CTRL1_2_BUTTONS; i++)
     MapGadget(level_editor_gadget[i]);
 
+  /* map toolbox buttons (element properties button) */
+  MapGadget(level_editor_gadget[ED_NUM_CTRL1_4_BUTTONS]);
+
   /* map buttons to select elements */
   for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
     MapGadget(level_editor_gadget[GADGET_ID_ELEMENTLIST_FIRST + i]);
@@ -6604,26 +6693,27 @@ static void UnmapLevelEditorToolboxCustomGadgets()
 
 static void MapOrUnmapLevelEditorToolboxDrawingGadgets(boolean map)
 {
-  Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
   int i;
 
   for (i = 0; i < ED_NUM_CTRL1_BUTTONS; i++)
   {
     if (i != GADGET_ID_SINGLE_ITEMS &&
-       i != GADGET_ID_PROPERTIES &&
        i != GADGET_ID_PICK_ELEMENT)
     {
       struct GadgetInfo *gi = level_editor_gadget[i];
 
       if (map)
+      {
        MapGadget(gi);
+      }
       else
       {
+       int graphic = IMG_EDITOR_NO_TOOLBOX_BUTTON;
+       struct GraphicInfo *gd = &graphic_info[graphic];
+
        UnmapGadget(gi);
 
-       BlitBitmap(gd_bitmap, drawto,
-                  DOOR_GFX_PAGEX6 + ED_CTRL_NO_BUTTONS_GFX_XPOS,
-                  DOOR_GFX_PAGEY1 + ED_CTRL_NO_BUTTONS_GFX_YPOS,
+       BlitBitmap(gd->bitmap, drawto, gd->src_x, gd->src_y,
                   gi->width, gi->height, gi->x, gi->y);
 
        redraw_mask |= REDRAW_DOOR_3;
@@ -6647,12 +6737,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]);
 }
 
@@ -6660,7 +6751,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]);
 }
 
@@ -6668,6 +6759,8 @@ static void ResetUndoBuffer()
 {
   undo_buffer_position = -1;
   undo_buffer_steps = -1;
+  redo_buffer_steps = 0;
+
   CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
 
   level.changed = FALSE;
@@ -6691,13 +6784,6 @@ static boolean LevelChanged()
   boolean field_changed = FALSE;
   int x, y;
 
-#if 1
-  /* changed read-only levels can now be saved in personal level set */
-#else
-  if (leveldir_current->readonly)
-    return FALSE;
-#endif
-
   for (y = 0; y < lev_fieldy; y++) 
     for (x = 0; x < lev_fieldx; x++)
       if (Feld[x][y] != level.field[x][y])
@@ -6728,8 +6814,8 @@ static boolean PrepareSavingIntoPersonalLevelSet()
     return TRUE;
   }
 
-  if (!Request("This level is read only ! "
-              "Save into personal level set ?", REQ_ASK))
+  if (!Request("This level is read only! "
+              "Save into personal level set?", REQ_ASK))
     return FALSE;
 
   // "cd" to personal level set dir (for writing copy the first time)
@@ -7007,13 +7093,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;
   }
@@ -7238,7 +7324,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],
@@ -7399,22 +7485,52 @@ void CheckElementDescriptions()
       Error(ERR_WARN, "no element description for element '%s'", EL_NAME(i));
 }
 
+static int getMaxEdFieldX(boolean has_scrollbar)
+{
+  int scrollbar_width = (has_scrollbar ? ED_SCROLLBUTTON_XSIZE : 0);
+  int sxsize = SXSIZE - scrollbar_width;
+  int max_ed_fieldx = sxsize / ed_tilesize;
+
+  return max_ed_fieldx;
+}
+
+static int getMaxEdFieldY(boolean has_scrollbar)
+{
+  int infotext_height = INFOTEXT_YSIZE;
+  int scrollbar_height = (has_scrollbar ? ED_SCROLLBUTTON_YSIZE : 0);
+  int sysize = SYSIZE - scrollbar_height - infotext_height;
+  int max_ed_fieldy = sysize / ed_tilesize;
+
+  return max_ed_fieldy;
+}
+
+void InitZoomLevelSettings()
+{
+  MAX_ED_FIELDX = getMaxEdFieldX(FALSE);
+  MAX_ED_FIELDY = getMaxEdFieldY(FALSE);
+}
+
+static boolean playfield_area_changed = FALSE;
+
 void DrawLevelEd()
 {
   StopAnimation();
 
   CloseDoor(DOOR_CLOSE_ALL);
 
-#if 1
   FadeOut(REDRAW_FIELD);
-#endif
 
-#if 1
+  /* 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();
-#endif
 
-  OpenDoor(DOOR_OPEN_2 | DOOR_NO_DELAY);
+  InitZoomLevelSettings();
+
+  playfield_area_changed = DrawingAreaChanged();
+
+  OpenDoor(DOOR_OPEN_1 | DOOR_OPEN_2 | DOOR_NO_DELAY);
 
 #if DEBUG
   CheckElementDescriptions();
@@ -7439,13 +7555,14 @@ void DrawLevelEd()
     level_ypos = -1;
   }
 
-  /* 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);
+  /* needed for gadgets drawn on background (like palette scrollbar) */
+  SetDoorBackgroundImage(IMG_UNDEFINED);
 
-#if 0
-  printf("::: %d, %d  /  %d, %d\n", VX, VY, EX, EY);
-#endif
+  /* copy default editor door content to main double buffer */
+  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();
@@ -7454,46 +7571,25 @@ void DrawLevelEd()
   BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
             DOOR_GFX_PAGEX8, 236, EXSIZE, EYSIZE, EX, EY);
 
-  redraw_mask |= REDRAW_ALL;
+  // redraw_mask |= REDRAW_ALL;
 
-#if 1
   FreeLevelEditorGadgets();
   CreateLevelEditorGadgets();
-#endif
 
   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()
@@ -7505,54 +7601,62 @@ static void AdjustDrawingAreaGadgets()
   boolean horizontal_scrollbar_needed;
   boolean vertical_scrollbar_needed;
   int x, y, width, height;
-  int xoffset, yoffset;
 
   /* check if we need any scrollbars */
   horizontal_scrollbar_needed = (ed_xsize > max_ed_fieldx);
-  vertical_scrollbar_needed = (ed_ysize > max_ed_fieldy);
+  vertical_scrollbar_needed   = (ed_ysize > max_ed_fieldy);
 
   /* check if we have a smaller editor field because of scrollbars */
-  if (horizontal_scrollbar_needed)
-    max_ed_fieldy = MAX_ED_FIELDY - 1;
-  if (vertical_scrollbar_needed)
-    max_ed_fieldx = MAX_ED_FIELDX - 1;
+  max_ed_fieldx = getMaxEdFieldX(vertical_scrollbar_needed);
+  max_ed_fieldy = getMaxEdFieldY(horizontal_scrollbar_needed);
 
   /* check again if we now need more scrollbars because of less space */
   horizontal_scrollbar_needed = (ed_xsize > max_ed_fieldx);
-  vertical_scrollbar_needed = (ed_ysize > max_ed_fieldy);
+  vertical_scrollbar_needed   = (ed_ysize > max_ed_fieldy);
 
   /* check if editor field gets even smaller after adding new scrollbars */
-  if (horizontal_scrollbar_needed)
-    max_ed_fieldy = MAX_ED_FIELDY - 1;
-  if (vertical_scrollbar_needed)
-    max_ed_fieldx = MAX_ED_FIELDX - 1;
+  max_ed_fieldx = getMaxEdFieldX(vertical_scrollbar_needed);
+  max_ed_fieldy = getMaxEdFieldY(horizontal_scrollbar_needed);
 
-  ed_fieldx = (ed_xsize < MAX_ED_FIELDX ? ed_xsize : max_ed_fieldx);
-  ed_fieldy = (ed_ysize < MAX_ED_FIELDY ? ed_ysize : max_ed_fieldy);
+  ed_fieldx = (ed_xsize > max_ed_fieldx ? max_ed_fieldx : ed_xsize);
+  ed_fieldy = (ed_ysize > max_ed_fieldy ? max_ed_fieldy : ed_ysize);
 
+  x = SX + ed_fieldx * ed_tilesize;
+  y = SY + ed_fieldy * ed_tilesize;
+
+  width  = ed_fieldx * ed_tilesize - 2 * ED_SCROLLBUTTON_XSIZE;
+  height = ed_fieldy * ed_tilesize - 2 * ED_SCROLLBUTTON_YSIZE;
+
+  /* adjust drawing area gadget */
   ModifyGadget(level_editor_gadget[GADGET_ID_DRAWING_LEVEL],
-              GDI_WIDTH, ed_fieldx * MINI_TILEX,
-              GDI_HEIGHT, ed_fieldy * MINI_TILEY,
               GDI_AREA_SIZE, ed_fieldx, ed_fieldy,
+              GDI_ITEM_SIZE, ed_tilesize, ed_tilesize,
               GDI_END);
 
-  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;
-
-  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;
-
+  /* adjust horizontal scrollbar gadgets */
+  ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LEFT],
+              GDI_Y, y,
+              GDI_END);
+  ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_RIGHT],
+              GDI_X, x - ED_SCROLLBUTTON_XSIZE,
+              GDI_Y, y,
+              GDI_END);
   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL],
+              GDI_Y, y,
               GDI_WIDTH, width,
               GDI_SCROLLBAR_ITEMS_VISIBLE, ed_fieldx,
               GDI_END);
+
+  /* adjust vertical scrollbar gadgets */
+  ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_UP],
+              GDI_X, x,
+              GDI_END);
+  ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_DOWN],
+              GDI_X, x,
+              GDI_Y, y - ED_SCROLLBUTTON_YSIZE,
+              GDI_END);
   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL],
+              GDI_X, x,
               GDI_HEIGHT, height,
               GDI_SCROLLBAR_ITEMS_VISIBLE, ed_fieldy,
               GDI_END);
@@ -7696,39 +7800,41 @@ static void ModifyEditorElementList()
 
     UnmapGadget(gi);
 
-    getMiniGraphicSource(el2edimg(element), &gd->bitmap, &gd->x, &gd->y);
+    getElementListGraphicSource(element, &gd->bitmap, &gd->x, &gd->y);
+
     ModifyGadget(gi, GDI_INFO_TEXT, getElementInfoText(element), GDI_END);
 
     MapGadget(gi);
   }
 }
 
+static void DrawDrawingElement(int element, struct EditorPaletteElementInfo *e)
+{
+  int graphic = el2edimg(element);
+  int tile_size = (e->tile_size >= TILESIZE ? TILESIZE : MINI_TILESIZE);
+
+  DrawSizedGraphicExt(drawto, DX + e->x, DY + e->y, graphic, 0, tile_size);
+}
+
 static void PickDrawingElement(int button, int element)
 {
+  struct
+  {
+    int *new_element;
+    struct EditorPaletteElementInfo *e;
+  } de, drawing_elements[] =
+  {
+    { &new_element1,   &editor.palette.element_left    },
+    { &new_element2,   &editor.palette.element_middle  },
+    { &new_element3,   &editor.palette.element_right   },
+  };
+
   if (button < 1 || button > 3)
     return;
 
-  if (button == 1)
-  {
-    new_element1 = element;
-    DrawMiniGraphicExt(drawto,
-                      DX + ED_WIN_MB_LEFT_XPOS, DY + ED_WIN_MB_LEFT_YPOS,
-                      el2edimg(new_element1));
-  }
-  else if (button == 2)
-  {
-    new_element2 = element;
-    DrawMiniGraphicExt(drawto,
-                      DX + ED_WIN_MB_MIDDLE_XPOS, DY + ED_WIN_MB_MIDDLE_YPOS,
-                      el2edimg(new_element2));
-  }
-  else
-  {
-    new_element3 = element;
-    DrawMiniGraphicExt(drawto,
-                      DX + ED_WIN_MB_RIGHT_XPOS, DY + ED_WIN_MB_RIGHT_YPOS,
-                      el2edimg(new_element3));
-  }
+  de = drawing_elements[button - 1];
+
+  DrawDrawingElement((*de.new_element = element), de.e);
 
   redraw_mask |= REDRAW_DOOR_1;
 }
@@ -7747,7 +7853,7 @@ static void DrawDrawingWindow()
   SetMainBackgroundImage(IMG_UNDEFINED);
   ClearField();
 
-  UnmapLevelEditorWindowGadgets();
+  UnmapLevelEditorFieldGadgets();
   UnmapLevelEditorToolboxCustomGadgets();
 
   AdjustDrawingAreaGadgets();
@@ -7755,7 +7861,7 @@ static void DrawDrawingWindow()
   AdjustEditorScrollbar(GADGET_ID_SCROLL_HORIZONTAL);
   AdjustEditorScrollbar(GADGET_ID_SCROLL_VERTICAL);
 
-  DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
+  DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
 
   MapMainDrawingArea();
   MapLevelEditorToolboxDrawingGadgets();
@@ -7778,10 +7884,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++)
@@ -7801,19 +7903,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()
@@ -7825,10 +7919,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 */
@@ -7862,19 +7952,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()
@@ -7918,24 +8000,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();
 
@@ -8077,8 +8147,10 @@ static void DrawGroupElementArea(int element)
 {
   int num_elements = group_element_info.num_elements;
   int id = ED_DRAWING_ID_GROUP_CONTENT;
-  int sx = SX + drawingarea_info[id].x - MINI_TILEX / 2;
-  int sy = SY + drawingarea_info[id].y - MINI_TILEY / 2;
+  int bx = ED_ELEMENT_BORDER_INPUT;
+  int by = ED_ELEMENT_BORDER_INPUT;
+  int sx = SX + drawingarea_info[id].x - bx;
+  int sy = SY + drawingarea_info[id].y - by;
   int xsize = MAX_ELEMENTS_IN_GROUP;
   int ysize = 1;
 
@@ -8090,7 +8162,7 @@ static void DrawGroupElementArea(int element)
   ModifyEditorDrawingArea(id, num_elements, 1);
 
   /* delete content areas in case of reducing number of them */
-  DrawBackground(sx, sy, (xsize + 1) * MINI_TILEX, (ysize + 1) * MINI_TILEY);
+  DrawBackground(sx, sy, xsize * MINI_TILEX + 2*bx, ysize * MINI_TILEY + 2*by);
 
   MapDrawingArea(id);
 }
@@ -8171,9 +8243,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, 0, -1, TRUE, FALSE, FALSE);
+                     max_lines_drawable, 0, -1, TRUE, FALSE, FALSE);
 }
 
 static void DrawPropertiesInfo()
@@ -8237,8 +8313,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;
@@ -8456,6 +8532,7 @@ static boolean checkPropertiesConfig(int element)
 
 static void DrawPropertiesConfig()
 {
+  boolean draw_footer_line = FALSE;
   int max_num_element_counters = 4;
   int num_element_counters = 0;
   int i;
@@ -8698,6 +8775,8 @@ static void DrawPropertiesConfig()
 
       /* draw drawing area gadgets */
       MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC);
+
+      draw_footer_line = TRUE;
     }
     else if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2)
     {
@@ -8748,6 +8827,25 @@ static void DrawPropertiesConfig()
 
     /* draw drawing area gadgets */
     MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC);
+
+    draw_footer_line = TRUE;
+  }
+
+  /* draw little footer border line above CE/GE use/save template gadgets */
+  if (draw_footer_line)
+  {
+    struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_PROPERTIES_INFO];
+    struct GadgetDesign *gd = &gd_gi1->alt_design[GD_BUTTON_UNPRESSED];
+    int gd_x = gd->x + gd_gi1->border.width / 2;
+    int gd_y = gd->y + gd_gi1->height - 1;
+    Pixel tab_color = GetPixel(gd->bitmap, gd_x, gd_y);
+
+    if (tab_color != BLACK_PIXEL)              /* black => transparent */
+      FillRectangle(drawto,
+                   SX + ED_ELEMENT_SETTINGS_XPOS(0),
+                   SY + ED_ELEMENT_SETTINGS_YPOS(14) - MINI_TILEY / 2,
+                   getTabulatorBarWidth(), ED_GADGET_DISTANCE,
+                   tab_color);
   }
 }
 
@@ -8812,7 +8910,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)
@@ -8884,7 +8982,7 @@ static void DrawPropertiesWindow()
 
   CopyElementPropertiesToEditor(properties_element);
 
-  UnmapLevelEditorWindowGadgets();
+  UnmapLevelEditorFieldGadgets();
   UnmapLevelEditorToolboxDrawingGadgets();
   UnmapLevelEditorToolboxCustomGadgets();
 
@@ -8895,12 +8993,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 */
 
@@ -9387,7 +9480,7 @@ static void SetElementSimple(int x, int y, int element, boolean change_level)
     Feld[x][y] = element;
 
   if (IN_ED_FIELD(sx, sy))
-    DrawMiniElement(sx, sy, element);
+    DrawEditorElement(sx, sy, element);
 }
 
 static void MergeAndCloseNeighbourElements(int x1, int y1, int *element1,
@@ -10088,10 +10181,10 @@ static void DrawAreaBorder(int from_x, int from_y, int to_x, int to_y)
   if (from_y > to_y)
     swap_numbers(&from_y, &to_y);
 
-  from_sx = SX + from_x * MINI_TILEX;
-  from_sy = SY + from_y * MINI_TILEY;
-  to_sx = SX + to_x * MINI_TILEX + MINI_TILEX - 1;
-  to_sy = SY + to_y * MINI_TILEY + MINI_TILEY - 1;
+  from_sx = SX + from_x * ed_tilesize;
+  from_sy = SY + from_y * ed_tilesize;
+  to_sx = SX + (to_x + 1) * ed_tilesize - 1;
+  to_sy = SY + (to_y + 1) * ed_tilesize - 1;
 
   DrawSimpleWhiteLine(drawto, from_sx, from_sy, to_sx, from_sy);
   DrawSimpleWhiteLine(drawto, to_sx, from_sy, to_sx, to_sy);
@@ -10124,11 +10217,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)
 {
-#if 1
   static short brush_buffer[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-#else
-  static short brush_buffer[MAX_ED_FIELDX][MAX_ED_FIELDY];
-#endif
   static int brush_width, brush_height;
   static int last_cursor_x = -1, last_cursor_y = -1;
   static boolean delete_old_brush;
@@ -10159,7 +10248,10 @@ static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y,
        else if (element >= NUM_FILE_ELEMENTS)
          element_mapped = EL_UNKNOWN;
 
-       printf("%c%03d", (mode == CB_DUMP_BRUSH ? '`' : '¸'), element_mapped);
+       // dump brush as level sketch text for the R'n'D forum:
+       // - large tiles: `xxx (0x60 ASCII)
+       // - small tiles: Â¸xxx (0xb8 ISO-8859-1, 0xc2b8 UTF-8)
+       printf("%s%03d", (mode == CB_DUMP_BRUSH ? "`" : "¸"), element_mapped);
       }
 
       printf("\n");
@@ -10309,7 +10401,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;
@@ -10318,11 +10410,11 @@ static int DrawLevelText(int sx, int sy, char letter, int mode)
   /* map lower case letters to upper case and convert special characters */
   if (letter >= 'a' && letter <= 'z')
     letter_element = EL_CHAR_ASCII0 + letter + (int)('A' - 'a');
-  else if (letter == 'ä' || letter == 'Ä')
+  else if (letter == CHAR_BYTE_UMLAUT_a || letter == CHAR_BYTE_UMLAUT_A)
     letter_element = EL_CHAR_AUMLAUT;
-  else if (letter == 'ö' || letter == 'Ö')
+  else if (letter == CHAR_BYTE_UMLAUT_o || letter == CHAR_BYTE_UMLAUT_O)
     letter_element = EL_CHAR_OUMLAUT;
-  else if (letter == 'ü' || letter == 'Ãœ')
+  else if (letter == CHAR_BYTE_UMLAUT_u || letter == CHAR_BYTE_UMLAUT_U)
     letter_element = EL_CHAR_UUMLAUT;
   else if (letter == '^')
     letter_element = EL_CHAR_COPYRIGHT;
@@ -10351,13 +10443,14 @@ 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;
 
     case TEXT_SETCURSOR:
-      DrawMiniElement(last_sx, last_sy, Feld[lx][ly]);
+      DrawEditorElement(last_sx, last_sy, Feld[lx][ly]);
       DrawAreaBorder(sx, sy, sx, sy);
       last_sx = sx;
       last_sy = sy;
@@ -10366,6 +10459,10 @@ static int DrawLevelText(int sx, int sy, char letter, int mode)
     case TEXT_WRITECHAR:
       if (letter_element >= EL_CHAR_START && letter_element <= EL_CHAR_END)
       {
+       if (new_element1 >= EL_STEEL_CHAR_START &&
+           new_element1 <= EL_STEEL_CHAR_END)
+         letter_element = letter_element - EL_CHAR_START + EL_STEEL_CHAR_START;
+
        delete_buffer[sx - start_sx] = Feld[lx][ly];
        Feld[lx][ly] = letter_element;
 
@@ -10384,7 +10481,7 @@ static int DrawLevelText(int sx, int sy, char letter, int mode)
       if (sx > start_sx)
       {
        Feld[lx - 1][ly] = delete_buffer[sx - start_sx - 1];
-       DrawMiniElement(sx - 1, sy, Feld[lx - 1][ly]);
+       DrawEditorElement(sx - 1, sy, Feld[lx - 1][ly]);
        DrawLevelText(sx - 1, sy, 0, TEXT_SETCURSOR);
       }
       break;
@@ -10398,7 +10495,7 @@ static int DrawLevelText(int sx, int sy, char letter, int mode)
 
     case TEXT_END:
       CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
-      DrawMiniElement(sx, sy, Feld[lx][ly]);
+      DrawEditorElement(sx, sy, Feld[lx][ly]);
       typing = FALSE;
       break;
 
@@ -10419,7 +10516,7 @@ static void SetTextCursor(int unused_sx, int unused_sy, int sx, int sy,
   int ly = sy + level_ypos;
 
   if (element == -1)
-    DrawMiniElement(sx, sy, Feld[lx][ly]);
+    DrawEditorElement(sx, sy, Feld[lx][ly]);
   else
     DrawAreaBorder(sx, sy, sx, sy);
 }
@@ -10431,7 +10528,7 @@ static void CheckLevelBorderElement(boolean redraw_playfield)
   SetBorderElement();
 
   if (redraw_playfield && BorderElement != last_border_element)
-    DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
+    DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
 }
 
 static void CopyLevelToUndoBuffer(int mode)
@@ -10440,6 +10537,9 @@ static void CopyLevelToUndoBuffer(int mode)
   boolean new_undo_buffer_position = TRUE;
   int x, y;
 
+  if (undo_buffer_steps == 0)
+    accumulated_undo = FALSE;
+
   switch (mode)
   {
     case UNDO_IMMEDIATE:
@@ -10458,13 +10558,16 @@ static void CopyLevelToUndoBuffer(int mode)
 
   if (new_undo_buffer_position)
   {
-    /* new position in undo buffer ring */
+    /* advance position in undo buffer ring */
     undo_buffer_position = (undo_buffer_position + 1) % NUM_UNDO_STEPS;
 
     if (undo_buffer_steps < NUM_UNDO_STEPS - 1)
       undo_buffer_steps++;
   }
 
+  /* always reset redo buffer when storing level change into undo buffer */
+  redo_buffer_steps = 0;
+
   for (x = 0; x < lev_fieldx; x++)
     for (y = 0; y < lev_fieldy; y++)
       UndoBuffer[undo_buffer_position][x][y] = Feld[x][y];
@@ -10482,9 +10585,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++)
@@ -10509,11 +10610,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
   {
@@ -10526,17 +10623,13 @@ 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--;
       }
     }
   }
 
-  DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
+  DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
   CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
 }
 
@@ -10555,7 +10648,7 @@ void WrapLevel(int dx, int dy)
       Feld[x][y] =
        FieldBackup[(x + wrap_dx) % lev_fieldx][(y + wrap_dy) % lev_fieldy];
 
-  DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
+  DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
   CopyLevelToUndoBuffer(UNDO_ACCUMULATE);
 }
 
@@ -10649,10 +10742,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)
@@ -10660,50 +10749,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
@@ -10717,10 +10776,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);
@@ -10822,7 +10881,7 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
       if (button_press_event && Feld[lx][ly] != new_element)
       {
        FloodFill(lx, ly, new_element);
-       DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
+       DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
        CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
       }
       break;
@@ -10866,7 +10925,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)
@@ -10926,6 +10985,10 @@ static void HandleCounterButtons(struct GadgetInfo *gi)
     case ED_COUNTER_ID_LEVEL_YSIZE:
       lev_fieldx = level.fieldx;
       lev_fieldy = level.fieldy;
+
+      /* check if resizing of level results in change of border border */
+      SetBorderElement();
+
       break;
 
     default:
@@ -10961,14 +11024,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;
 }
@@ -11039,11 +11097,11 @@ static void HandleTextbuttonGadgets(struct GadgetInfo *gi)
     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);
@@ -11159,7 +11217,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);
@@ -11191,7 +11249,6 @@ static void HandleControlButtons(struct GadgetInfo *gi)
 
   if (id < ED_NUM_CTRL1_BUTTONS &&
       id != GADGET_ID_SINGLE_ITEMS &&
-      id != GADGET_ID_PROPERTIES &&
       id != GADGET_ID_PICK_ELEMENT &&
       edit_mode != ED_MODE_DRAWING &&
       drawing_function != GADGET_ID_PICK_ELEMENT &&
@@ -11217,9 +11274,9 @@ static void HandleControlButtons(struct GadgetInfo *gi)
        if (level_xpos < -1)
          level_xpos = -1;
        if (button == 1)
-         ScrollMiniLevel(level_xpos, level_ypos, ED_SCROLL_RIGHT);
+         ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_RIGHT);
        else
-         DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
+         DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
 
        ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL],
                     GDI_SCROLLBAR_ITEM_POSITION, level_xpos + 1, GDI_END);
@@ -11236,9 +11293,9 @@ static void HandleControlButtons(struct GadgetInfo *gi)
        if (level_xpos > lev_fieldx - ed_fieldx + 1)
          level_xpos = lev_fieldx - ed_fieldx + 1;
        if (button == 1)
-         ScrollMiniLevel(level_xpos, level_ypos, ED_SCROLL_LEFT);
+         ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_LEFT);
        else
-         DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
+         DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
 
        ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL],
                     GDI_SCROLLBAR_ITEM_POSITION, level_xpos + 1, GDI_END);
@@ -11255,9 +11312,9 @@ static void HandleControlButtons(struct GadgetInfo *gi)
        if (level_ypos < -1)
          level_ypos = -1;
        if (button == 1)
-         ScrollMiniLevel(level_xpos, level_ypos, ED_SCROLL_DOWN);
+         ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_DOWN);
        else
-         DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
+         DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
 
        ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL],
                     GDI_SCROLLBAR_ITEM_POSITION, level_ypos + 1, GDI_END);
@@ -11274,9 +11331,9 @@ static void HandleControlButtons(struct GadgetInfo *gi)
        if (level_ypos > lev_fieldy - ed_fieldy + 1)
          level_ypos = lev_fieldy - ed_fieldy + 1;
        if (button == 1)
-         ScrollMiniLevel(level_xpos, level_ypos, ED_SCROLL_UP);
+         ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_UP);
        else
-         DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
+         DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
 
        ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL],
                     GDI_SCROLLBAR_ITEM_POSITION, level_ypos + 1, GDI_END);
@@ -11285,12 +11342,12 @@ static void HandleControlButtons(struct GadgetInfo *gi)
 
     case GADGET_ID_SCROLL_HORIZONTAL:
       level_xpos = gi->event.item_position - 1;
-      DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
+      DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
       break;
 
     case GADGET_ID_SCROLL_VERTICAL:
       level_ypos = gi->event.item_position - 1;
-      DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
+      DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
       break;
 
     case GADGET_ID_SCROLL_LIST_UP:
@@ -11317,6 +11374,27 @@ static void HandleControlButtons(struct GadgetInfo *gi)
 
       break;
 
+    case GADGET_ID_PROPERTIES:
+      if (edit_mode != ED_MODE_PROPERTIES)
+      {
+       properties_element = new_element;
+       DrawPropertiesWindow();
+       edit_mode = ED_MODE_PROPERTIES;
+
+       last_level_drawing_function = drawing_function;
+       ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS],
+                     MB_LEFTBUTTON);
+      }
+      else
+      {
+       DrawDrawingWindow();
+       edit_mode = ED_MODE_DRAWING;
+
+       ClickOnGadget(level_editor_gadget[last_level_drawing_function],
+                     MB_LEFTBUTTON);
+      }
+      break;
+
     case GADGET_ID_WRAP_LEFT:
       WrapLevel(-step, 0);
       break;
@@ -11353,25 +11431,20 @@ static void HandleControlButtons(struct GadgetInfo *gi)
       RandomPlacement(new_element);
       break;
 
-    case GADGET_ID_PROPERTIES:
-      if (edit_mode != ED_MODE_PROPERTIES)
-      {
-       properties_element = new_element;
-       DrawPropertiesWindow();
-       edit_mode = ED_MODE_PROPERTIES;
+    case GADGET_ID_ZOOM:
+      // zoom level editor tile size in or out (or reset to default size)
+      ed_tilesize = (button == 1 ? ed_tilesize / 2 :
+                    button == 2 ? DEFAULT_EDITOR_TILESIZE :
+                    button == 3 ? ed_tilesize * 2 : ed_tilesize);
 
-       last_level_drawing_function = drawing_function;
-       ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS],
-                     MB_LEFTBUTTON);
-      }
-      else
-      {
+      // limit zoom level by upper and lower bound
+      ed_tilesize = MIN(MAX(MICRO_TILESIZE, ed_tilesize), TILESIZE);
+
+      InitZoomLevelSettings();
+
+      if (edit_mode == ED_MODE_DRAWING)
        DrawDrawingWindow();
-       edit_mode = ED_MODE_DRAWING;
 
-       ClickOnGadget(level_editor_gadget[last_level_drawing_function],
-                     MB_LEFTBUTTON);
-      }
       break;
 
     case GADGET_ID_CUSTOM_COPY_FROM:
@@ -11390,9 +11463,20 @@ static void HandleControlButtons(struct GadgetInfo *gi)
       break;
 
     case GADGET_ID_UNDO:
-      if (undo_buffer_steps == 0)
+      if (button == 1 && undo_buffer_steps == 0)
+      {
+       Request("Undo buffer empty!", REQ_CONFIRM);
+
+       break;
+      }
+      else if (button == 2)
+      {
+       break;
+      }
+      else if (button == 3 && redo_buffer_steps == 0)
       {
-       Request("Undo buffer empty !", REQ_CONFIRM);
+       Request("Redo buffer empty!", REQ_CONFIRM);
+
        break;
       }
 
@@ -11402,9 +11486,25 @@ static void HandleControlButtons(struct GadgetInfo *gi)
        edit_mode = ED_MODE_DRAWING;
       }
 
-      undo_buffer_position =
-       (undo_buffer_position - 1 + NUM_UNDO_STEPS) % NUM_UNDO_STEPS;
-      undo_buffer_steps--;
+      if (button == 1)
+      {
+       /* undo */
+
+       undo_buffer_position =
+         (undo_buffer_position - 1 + NUM_UNDO_STEPS) % NUM_UNDO_STEPS;
+
+       undo_buffer_steps--;
+       redo_buffer_steps++;
+      }
+      else
+      {
+       /* redo */
+
+       undo_buffer_position = (undo_buffer_position + 1) % NUM_UNDO_STEPS;
+
+       undo_buffer_steps++;
+       redo_buffer_steps--;
+      }
 
       for (x = 0; x < lev_fieldx; x++)
        for (y = 0; y < lev_fieldy; y++)
@@ -11413,7 +11513,7 @@ static void HandleControlButtons(struct GadgetInfo *gi)
       /* check if undo operation forces change of border style */
       CheckLevelBorderElement(FALSE);
 
-      DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
+      DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
 
       break;
 
@@ -11446,7 +11546,7 @@ static void HandleControlButtons(struct GadgetInfo *gi)
 
       CopyLevelToUndoBuffer(GADGET_ID_CLEAR);
 
-      DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
+      DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
       break;
 
     case GADGET_ID_SAVE:
@@ -11466,7 +11566,7 @@ static void HandleControlButtons(struct GadgetInfo *gi)
       new_level = !fileExists(level_filename);
 
       if (new_level ||
-         Request("Save this level and kill the old ?", REQ_ASK))
+         Request("Save this level and kill the old?", REQ_ASK))
       {
        if (leveldir_former->readonly)
          ModifyLevelInfoForSavingIntoPersonalLevelSet(leveldir_former->name);
@@ -11482,10 +11582,10 @@ static void HandleControlButtons(struct GadgetInfo *gi)
 
          if (leveldir_former->readonly)
            sprintf(level_saved_msg,
-                   "Level saved as level %d into personal level set !",
+                   "Level saved as level %d into personal level set!",
                    level_nr);
          else
-           strcpy(level_saved_msg, "Level saved !");
+           strcpy(level_saved_msg, "Level saved!");
 
          Request(level_saved_msg, REQ_CONFIRM);
        }
@@ -11512,11 +11612,10 @@ static void HandleControlButtons(struct GadgetInfo *gi)
 
       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);
 
-#if 0
-      DrawCompleteVideoDisplay();
-#endif
+      // redraw_mask = REDRAW_ALL;
 
       level_editor_test_game = TRUE;
 
@@ -11728,15 +11827,27 @@ void HandleLevelEditorKeyInput(Key key)
 
     if (id != GADGET_ID_NONE)
       ClickOnGadget(level_editor_gadget[id], button);
+    else if (letter >= '1' && letter <= '3')
+      ClickOnGadget(level_editor_gadget[GADGET_ID_PROPERTIES], letter - '0');
+    else if (letter == '?')
+      ClickOnGadget(level_editor_gadget[GADGET_ID_PROPERTIES], button);
     else if (letter == '.')
       ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS], button);
+    else if (letter == 'R')
+      ClickOnGadget(level_editor_gadget[GADGET_ID_UNDO], 3);
+    else if (key == KSYM_KP_Subtract)
+      ClickOnGadget(level_editor_gadget[GADGET_ID_ZOOM], 1);
+    else if (key == KSYM_KP_0 || letter == '0')
+      ClickOnGadget(level_editor_gadget[GADGET_ID_ZOOM], 2);
+    else if (key == KSYM_KP_Add || letter == '+')
+      ClickOnGadget(level_editor_gadget[GADGET_ID_ZOOM], 3);
     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++)
-       if (letter && letter == control_info[i].shortcut)
+       if (letter && letter == controlbutton_info[i].shortcut)
          if (!anyTextGadgetActive())
            ClickOnGadget(level_editor_gadget[i], button);
   }
@@ -11744,8 +11855,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;
 
@@ -11791,17 +11902,21 @@ void PrintEditorGadgetInfoText(struct GadgetInfo *gi)
 
   if (gi->custom_id < ED_NUM_CTRL_BUTTONS)
   {
-    int key = control_info[gi->custom_id].shortcut;
+    int key = controlbutton_info[gi->custom_id].shortcut;
 
     if (key)
     {
-      if (gi->custom_id == GADGET_ID_SINGLE_ITEMS)     /* special case 1 */
+      if (gi->custom_id == GADGET_ID_SINGLE_ITEMS)
        sprintf(shortcut, " ('.' or '%c')", key);
-      else if (gi->custom_id == GADGET_ID_PICK_ELEMENT)        /* special case 2 */
+      else if (gi->custom_id == GADGET_ID_PICK_ELEMENT)
        sprintf(shortcut, " ('%c' or 'Ctrl')", key);
-      else if (gi->custom_id == GADGET_ID_TEST)                /* special case 3 */
+      else if (gi->custom_id == GADGET_ID_TEST)
        sprintf(shortcut, " ('Enter' or 'Shift-%c')", key);
-      else                                             /* normal case */
+      else if (gi->custom_id == GADGET_ID_UNDO)
+       sprintf(shortcut, " ('Shift-%c/R')", key);
+      else if (gi->custom_id == GADGET_ID_ZOOM)
+       sprintf(shortcut, " ('%c', '0', '+')", key);
+      else
        sprintf(shortcut, " ('%s%c')",
                (key >= 'A' && key <= 'Z' ? "Shift-" : ""), key);
 
@@ -11991,30 +12106,24 @@ 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);
+    if (!global.use_envelope_request)
+    {
+      CloseDoor(DOOR_CLOSE_1);
+      OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
+    }
   }
 }