fixed (swapped) editor fonts for CE properties tab buttons
[rocksndiamonds.git] / src / editor.c
index 6a95010a354f054ba20386ed8e4b398cbc6de469..ce97227216f0e26d7a28180a7db03b234bc8d47e 100644 (file)
@@ -67,6 +67,8 @@
 #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)
                                         2 * MINI_TILEY)
 
 #define ED_SETTINGS1_YPOS              MINI_TILEY
-#define ED_SETTINGS2_XPOS              MINI_TILEX
-#define ED_SETTINGS2_YPOS              (ED_SETTINGS1_YPOS + 12 * TILEY - 2)
-
-/* values for counter gadgets */
-#define ED_COUNTER_YSTART              (ED_SETTINGS1_YPOS + 2 * TILEY)
-#define ED_COUNTER_YDISTANCE           (3 * MINI_TILEY)
-#define ED_COUNTER_YPOS(n)             (ED_COUNTER_YSTART +            \
-                                        (n) * ED_COUNTER_YDISTANCE)
-#define ED_COUNTER2_YPOS(n)            (ED_COUNTER_YSTART +            \
-                                        (n) * ED_COUNTER_YDISTANCE - 2)
 
 /* values for element content drawing areas */
 #define ED_AREA_1X1_SETTINGS_XPOS(n)   (ED_ELEMENT_SETTINGS_XPOS(n))
                                            6 * ((n) / 4) * MINI_TILEY)
 
 /* values for scrolling gadgets for drawing area */
-#define ED_SCROLLBUTTON_XPOS           24
-#define ED_SCROLLBUTTON_YPOS           0
-#define ED_SCROLLBAR_XPOS              24
-#define ED_SCROLLBAR_YPOS              64
-
 #define ED_SCROLLBUTTON_XSIZE          16
 #define ED_SCROLLBUTTON_YSIZE          16
 
 #define ED_SCROLL_VERTICAL_YSIZE       (SYSIZE - 4 * ED_SCROLLBUTTON_YSIZE)
 
 /* values for scrolling gadgets for element list */
-#define ED_SCROLLBUTTON2_XPOS          50
-#define ED_SCROLLBUTTON2_YPOS          0
-#define ED_SCROLLBAR2_XPOS             50
-#define ED_SCROLLBAR2_YPOS             20
-
 #define ED_SCROLLBUTTON2_XSIZE         (graphic_info[IMG_EDITOR_PALETTE_SCROLL_UP].width)
 #define ED_SCROLLBUTTON2_YSIZE         (graphic_info[IMG_EDITOR_PALETTE_SCROLL_UP].height)
 
                                         2 * ED_SCROLLBUTTON2_YSIZE)
 
 /* values for checkbutton gadgets */
-#define ED_CHECKBUTTON_XSIZE           ED_BUTTON_COUNT_XSIZE
-#define ED_CHECKBUTTON_YSIZE           ED_BUTTON_COUNT_YSIZE
-#define ED_CHECKBUTTON_UNCHECKED_XPOS  ED_BUTTON_MINUS_XPOS
-#define ED_CHECKBUTTON_CHECKED_XPOS    ED_BUTTON_PLUS_XPOS
-#define ED_CHECKBUTTON_YPOS            (ED_BUTTON_MINUS_YPOS + 22)
-#define ED_RADIOBUTTON_YPOS            (ED_BUTTON_MINUS_YPOS + 44)
-#define ED_STICKYBUTTON_YPOS           (ED_BUTTON_MINUS_YPOS + 66)
-
-/* values for some special graphic buttons */
-#define ED_COPY_CHANGE_PAGE_XPOS       25
-#define ED_COPY_CHANGE_PAGE_YPOS       50
-#define ED_PASTE_CHANGE_PAGE_XPOS      25
-#define ED_PASTE_CHANGE_PAGE_YPOS      70
-
-/* some values for text input, selectbox and counter gadgets */
-#define ED_BUTTON_COUNT_YPOS           60
-#define ED_BUTTON_COUNT_XSIZE          20
-#define ED_BUTTON_COUNT_YSIZE          20
-#define ED_WIN_COUNT_XPOS              (2 + ED_BUTTON_COUNT_XSIZE + 2)
-#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_BUTTON_MINUS_XPOS           2
-#define ED_BUTTON_MINUS_YPOS           ED_BUTTON_COUNT_YPOS
-#define ED_BUTTON_MINUS_XSIZE          ED_BUTTON_COUNT_XSIZE
-#define ED_BUTTON_MINUS_YSIZE          ED_BUTTON_COUNT_YSIZE
-#define ED_BUTTON_PLUS_XPOS            (ED_WIN_COUNT_XPOS +            \
-                                        ED_WIN_COUNT_XSIZE + 2)
-#define ED_BUTTON_PLUS_YPOS            ED_BUTTON_COUNT_YPOS
-#define ED_BUTTON_PLUS_XSIZE           ED_BUTTON_COUNT_XSIZE
-#define ED_BUTTON_PLUS_YSIZE           ED_BUTTON_COUNT_YSIZE
-
-#define ED_SELECTBOX_XPOS              ED_WIN_COUNT_XPOS
-#define ED_SELECTBOX_YPOS              (ED_WIN_COUNT_YPOS +            \
-                                        2 + ED_WIN_COUNT_YSIZE)
-#define ED_SELECTBOX_XSIZE             ED_WIN_COUNT_XSIZE
-#define ED_SELECTBOX_YSIZE             ED_WIN_COUNT_YSIZE
-
-#define ED_SELECTBOX_BUTTON_XSIZE      14
-
-#define ED_TEXTBUTTON_XPOS             ED_WIN_COUNT_XPOS
-#define ED_TEXTBUTTON_YPOS             (ED_WIN_COUNT_YPOS +            \
-                                        4 * (2 + ED_WIN_COUNT_YSIZE))
-#define ED_TEXTBUTTON_INACTIVE_YPOS    ED_TEXTBUTTON_YPOS
-
-#define ED_TEXTBUTTON_TAB_XPOS         ED_WIN_COUNT_XPOS
-#define ED_TEXTBUTTON_TAB_YPOS         (ED_WIN_COUNT_YPOS +            \
-                                        2 * (2 + ED_WIN_COUNT_YSIZE))
-#define ED_TEXTBUTTON_TAB_INACTIVE_YPOS        (ED_WIN_COUNT_YPOS +            \
-                                        3 * (2 + ED_WIN_COUNT_YSIZE))
-
-#define ED_TEXTBUTTON_XSIZE            ED_WIN_COUNT_XSIZE
-#define ED_TEXTBUTTON_YSIZE            ED_WIN_COUNT_YSIZE
+#define ED_CHECKBUTTON_XSIZE           20
+#define ED_CHECKBUTTON_YSIZE           20
 
 /* values for ClearEditorGadgetInfoText() and HandleEditorGadgetInfoText() */
 #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 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                  (SCR_FIELDX)
-#define MAX_ED_FIELDY                  (SCR_FIELDY - 1)
+/* default value for element tile size in drawing area */
+#define DEFAULT_EDITOR_TILESIZE                MINI_TILESIZE
 
 
 /*
@@ -1013,7 +942,7 @@ static struct
   {
     IMG_EDITOR_BUTTON_GFX_ZOOM_LEVEL,          GADGET_ID_ZOOM,
     &editor.button.zoom_level,                 GD_TYPE_NORMAL_BUTTON,
-    "zoom level tile size",                    'z'
+    "zoom level tile size",                    '-'
   },
   {
     IMG_EDITOR_BUTTON_GFX_ROTATE_RIGHT,                GADGET_ID_WRAP_RIGHT,
@@ -1046,7 +975,7 @@ static struct
   {
     IMG_EDITOR_BUTTON_GFX_UNDO,                        GADGET_ID_UNDO,
     &editor.button.undo,                       GD_TYPE_NORMAL_BUTTON,
-    "undo last operation",                     'U'
+    "undo/redo last operation",                        'u'
   },
   {
     IMG_EDITOR_BUTTON_GFX_CONF,                        GADGET_ID_INFO,
@@ -1289,7 +1218,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,
@@ -1297,7 +1226,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,
@@ -1305,7 +1234,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,
@@ -1313,7 +1242,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,
@@ -1321,7 +1250,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,
@@ -1329,7 +1258,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,
@@ -1337,7 +1266,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,
@@ -1345,7 +1274,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,
@@ -1391,7 +1320,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,
@@ -2231,7 +2160,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,
@@ -2239,7 +2168,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,
@@ -2247,7 +2176,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,
@@ -2255,7 +2184,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,
@@ -2263,7 +2192,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,
@@ -2432,7 +2361,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,
@@ -2494,7 +2423,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"
@@ -2515,39 +2444,34 @@ static struct
 
 static struct
 {
-  int gd_x, gd_y;
+  int graphic;
   int x, y;
-  int width, height;
   int gadget_id;
   int gadget_id_align;
   char *text_left, *text_right, *infotext;
 } graphicbutton_info[ED_NUM_GRAPHICBUTTONS] =
 {
   {
-    ED_BUTTON_MINUS_XPOS,              ED_BUTTON_COUNT_YPOS,
+    IMG_EDITOR_COUNTER_DOWN,
     ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(14),
-    ED_BUTTON_COUNT_XSIZE,             ED_BUTTON_COUNT_YSIZE,
     GADGET_ID_PREV_CHANGE_PAGE,                GADGET_ID_NONE,
     NULL, NULL,                                "select previous change page"
   },
   {
-    ED_BUTTON_PLUS_XPOS,               ED_BUTTON_COUNT_YPOS,
+    IMG_EDITOR_COUNTER_UP,
     -1,                                        ED_ELEMENT_SETTINGS_YPOS(14),
-    ED_BUTTON_COUNT_XSIZE,             ED_BUTTON_COUNT_YSIZE,
     GADGET_ID_NEXT_CHANGE_PAGE,                GADGET_ID_SELECT_CHANGE_PAGE,
     NULL, "change page",               "select next change page"
   },
   {
-    ED_COPY_CHANGE_PAGE_XPOS,          ED_COPY_CHANGE_PAGE_YPOS,
+    IMG_EDITOR_BUTTON_GFX_CP_COPY,
     -1,                                        ED_ELEMENT_SETTINGS_YPOS(14),
-    ED_BUTTON_COUNT_XSIZE,             ED_BUTTON_COUNT_YSIZE,
     GADGET_ID_COPY_CHANGE_PAGE,                GADGET_ID_NEXT_CHANGE_PAGE,
     " ", NULL,                         "copy settings from this change page"
   },
   {
-    ED_PASTE_CHANGE_PAGE_XPOS,         ED_PASTE_CHANGE_PAGE_YPOS,
+    IMG_EDITOR_BUTTON_GFX_CP_PASTE,
     -1,                                        ED_ELEMENT_SETTINGS_YPOS(14),
-    ED_BUTTON_COUNT_XSIZE,             ED_BUTTON_COUNT_YSIZE,
     GADGET_ID_PASTE_CHANGE_PAGE,       GADGET_ID_COPY_CHANGE_PAGE,
     NULL, NULL,                                "paste settings to this change page"
   },
@@ -2875,42 +2799,42 @@ static struct
     "use graphic of element:",         "use existing element graphic"
   },
   {
-    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,
@@ -3304,7 +3228,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
@@ -3327,12 +3251,18 @@ static struct
   -----------------------------------------------------------------------------
 */
 
+/* maximal size of level editor drawing area */
+static int MAX_ED_FIELDX, MAX_ED_FIELDY;
+
 /* actual size of level editor drawing area */
 static int ed_fieldx, ed_fieldy;
 
 /* actual position of level editor drawing area in level playfield */
 static int level_xpos = -1, level_ypos = -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)
 
 /* drawing elements on the three mouse buttons */
@@ -3344,7 +3274,10 @@ static int new_element3 = EL_SAND;
 #define BUTTON_ELEMENT(button) ((button) == 1 ? new_element1 : \
                                (button) == 2 ? new_element2 : \
                                (button) == 3 ? new_element3 : EL_EMPTY)
-#define BUTTON_STEPSIZE(button) ((button) == 1 ? 1 : (button) == 2 ? 5 : 10)
+#define BUTTON_STEPSIZE(button) ((button) == 1 ?  1 : \
+                                (button) == 2 ?  5 : \
+                                (button) == 3 ? 10 : \
+                                (button))
 
 /* forward declaration for internal use */
 static void ModifyEditorCounterValue(int, int);
@@ -3389,6 +3322,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;
@@ -5206,8 +5140,8 @@ 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;
@@ -5242,6 +5176,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];
@@ -5259,31 +5208,31 @@ 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;
@@ -5312,7 +5261,6 @@ static void CreateControlButtons()
     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;
@@ -5321,8 +5269,6 @@ static void CreateControlButtons()
     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;
@@ -5364,16 +5310,16 @@ static void CreateControlButtons()
                      GDI_INFO_TEXT, controlbutton_info[i].infotext,
                      GDI_X, x,
                      GDI_Y, y,
-                     GDI_WIDTH, width,
-                     GDI_HEIGHT, height,
+                     GDI_WIDTH, gd->width,
+                     GDI_HEIGHT, gd->height,
                      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_y2,
-                     GDI_ALT_DESIGN_UNPRESSED, gd_bitmap, gd_x1a, gd_y1a,
-                     GDI_ALT_DESIGN_PRESSED, gd_bitmap, gd_x2a, gd_y2a,
+                     GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
+                     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,
@@ -5525,14 +5471,13 @@ static void CreateCounterButtons()
 
     for (j = 0; j < 2; j++)
     {
-      Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
       struct GadgetInfo *gi;
       int id = (j == 0 ?
                counterbutton_info[i].gadget_id_down :
                counterbutton_info[i].gadget_id_up);
-      int gd_xoffset;
-      int gd_x, gd_y, gd_x1, gd_x2, gd_y1, gd_y2;
-      int x_size, y_size;
+      int graphic;
+      struct GraphicInfo *gd;
+      int gd_x1, gd_x2, gd_y1, gd_y2;
       unsigned int event_mask;
       char infotext[max_infotext_len + 1];
 
@@ -5540,12 +5485,9 @@ static void CreateCounterButtons()
 
       if (i == ED_COUNTER_ID_SELECT_LEVEL)
       {
-       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;
+       graphic = (j == 0 ?
+                  IMG_EDITOR_BUTTON_GFX_PREV_LEVEL :
+                  IMG_EDITOR_BUTTON_GFX_NEXT_LEVEL);
 
        event_mask |= GD_EVENT_RELEASED;
 
@@ -5559,25 +5501,21 @@ static void CreateCounterButtons()
          x = DX + editor.button.next_level.x;
          y = DY + editor.button.next_level.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;
-       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_y1 = DOOR_GFX_PAGEY1 + ED_BUTTON_COUNT_YPOS;
-       gd_y2 = gd_y1;
-       x_size = ED_BUTTON_COUNT_XSIZE;
-       y_size = ED_BUTTON_COUNT_YSIZE;
+       graphic = (j == 0 ?
+                  IMG_EDITOR_COUNTER_DOWN :
+                  IMG_EDITOR_COUNTER_UP);
       }
 
+      gd = &graphic_info[graphic];
+
+      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;
+
       sprintf(infotext, "%s counter value by 1, 5 or 10",
              (j == 0 ? "decrease" : "increase"));
 
@@ -5586,12 +5524,12 @@ static void CreateCounterButtons()
                        GDI_INFO_TEXT, infotext,
                        GDI_X, x,
                        GDI_Y, y,
-                       GDI_WIDTH, x_size,
-                       GDI_HEIGHT, y_size,
+                       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_y1,
-                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
+                       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,
@@ -5610,36 +5548,33 @@ 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];
+         graphic = IMG_EDITOR_INPUT_GFX_LEVEL_NUMBER;
 
-         gd_bitmap = gd->bitmap;
+         font_type = FONT_LEVEL_NUMBER;
+         font_type_active = FONT_LEVEL_NUMBER_ACTIVE;
 
          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;
-         font_type_active = FONT_LEVEL_NUMBER_ACTIVE;
        }
        else
        {
-         gd_x = DOOR_GFX_PAGEX4 + ED_WIN_COUNT_XPOS;
-         gd_y = DOOR_GFX_PAGEY1 + ED_WIN_COUNT_YPOS;
+         graphic = IMG_EDITOR_COUNTER_INPUT;
        }
 
+       gd = &graphic_info[graphic];
+
+       gd_x1 = gd->src_x;
+       gd_y1 = gd->src_y;
+       gd_x2 = gd->src_x + gd->active_xoffset;
+       gd_y2 = gd->src_y + gd->active_yoffset;
+
        gi = CreateGadget(GDI_CUSTOM_ID, id,
                          GDI_CUSTOM_TYPE_ID, i,
                          GDI_INFO_TEXT, "enter counter value",
@@ -5652,10 +5587,10 @@ static void CreateCounterButtons()
                          GDI_TEXT_SIZE, 3,     /* minimal counter text size */
                          GDI_TEXT_FONT, font_type,
                          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, border_size, border_size,
-                         GDI_DESIGN_WIDTH, gd_width,
+                         GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
+                         GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
+                         GDI_BORDER_SIZE, gd->border_size, gd->border_size,
+                         GDI_DESIGN_WIDTH, gd->width,
                          GDI_EVENT_MASK, event_mask,
                          GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
                          GDI_CALLBACK_ACTION, HandleCounterButtons,
@@ -5711,7 +5646,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,
@@ -5733,8 +5668,11 @@ static void CreateTextInputGadgets()
 
   for (i = 0; i < ED_NUM_TEXTINPUT; i++)
   {
-    Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
-    int gd_x, gd_y;
+    struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_INPUT_TEXT];
+    int gd_x1 = gd->src_x;
+    int gd_y1 = gd->src_y;
+    int gd_x2 = gd->src_x + gd->active_xoffset;
+    int gd_y2 = gd->src_y + gd->active_yoffset;
     struct GadgetInfo *gi;
     unsigned int event_mask;
     char infotext[MAX_OUTPUT_LINESIZE + 1];
@@ -5742,9 +5680,6 @@ static void CreateTextInputGadgets()
 
     event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
 
-    gd_x = DOOR_GFX_PAGEX4 + ED_WIN_COUNT_XPOS;
-    gd_y = DOOR_GFX_PAGEY1 + ED_WIN_COUNT_YPOS;
-
     sprintf(infotext, "Enter %s", textinput_info[i].infotext);
     infotext[max_infotext_len] = '\0';
 
@@ -5758,10 +5693,10 @@ static void CreateTextInputGadgets()
                      GDI_TEXT_SIZE, textinput_info[i].size,
                      GDI_TEXT_FONT, FONT_INPUT_1,
                      GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_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_DESIGN_WIDTH, ED_WIN_COUNT_XSIZE,
+                     GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
+                     GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
+                     GDI_BORDER_SIZE, gd->border_size, gd->border_size,
+                     GDI_DESIGN_WIDTH, gd->width,
                      GDI_EVENT_MASK, event_mask,
                      GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
                      GDI_CALLBACK_ACTION, HandleTextInputGadgets,
@@ -5781,8 +5716,11 @@ static void CreateTextAreaGadgets()
 
   for (i = 0; i < ED_NUM_TEXTAREAS; i++)
   {
-    Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
-    int gd_x, gd_y;
+    struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_INPUT_TEXTAREA];
+    int gd_x1 = gd->src_x;
+    int gd_y1 = gd->src_y;
+    int gd_x2 = gd->src_x + gd->active_xoffset;
+    int gd_y2 = gd->src_y + gd->active_yoffset;
     struct GadgetInfo *gi;
     unsigned int event_mask;
     char infotext[MAX_OUTPUT_LINESIZE + 1];
@@ -5792,9 +5730,6 @@ static void CreateTextAreaGadgets()
 
     event_mask = GD_EVENT_TEXT_LEAVING;
 
-    gd_x = DOOR_GFX_PAGEX4 + ED_WIN_COUNT_XPOS;
-    gd_y = DOOR_GFX_PAGEY1 + ED_WIN_COUNT_YPOS;
-
     sprintf(infotext, "Enter %s", textarea_info[i].infotext);
     infotext[max_infotext_len] = '\0';
 
@@ -5807,10 +5742,10 @@ static void CreateTextAreaGadgets()
                      GDI_AREA_SIZE, area_xsize, area_ysize,
                      GDI_TEXT_FONT, FONT_INPUT_1,
                      GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_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_DESIGN_WIDTH, ED_WIN_COUNT_XSIZE,
+                     GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
+                     GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
+                     GDI_BORDER_SIZE, gd->border_size, gd->border_size,
+                     GDI_DESIGN_WIDTH, gd->width,
                      GDI_EVENT_MASK, event_mask,
                      GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
                      GDI_CALLBACK_ACTION, HandleTextAreaGadgets,
@@ -5830,8 +5765,13 @@ static void CreateSelectboxGadgets()
 
   for (i = 0; i < ED_NUM_SELECTBOX; i++)
   {
-    Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
-    int gd_x, gd_y;
+    struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_SELECTBOX_INPUT];
+    struct GraphicInfo *gd2 = &graphic_info[IMG_EDITOR_SELECTBOX_BUTTON];
+    int gd_x1 = gd->src_x;
+    int gd_y1 = gd->src_y;
+    int gd_x2 = gd->src_x + gd->active_xoffset;
+    int gd_y2 = gd->src_y + gd->active_yoffset;
+    int selectbox_button_xsize = gd2->width;
     struct GadgetInfo *gi;
     unsigned int event_mask;
     char infotext[MAX_OUTPUT_LINESIZE + 1];
@@ -5856,9 +5796,6 @@ static void CreateSelectboxGadgets()
     event_mask = GD_EVENT_RELEASED |
       GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
 
-    gd_x = DOOR_GFX_PAGEX4 + ED_SELECTBOX_XPOS;
-    gd_y = DOOR_GFX_PAGEY1 + ED_SELECTBOX_YPOS;
-
     /* determine horizontal position to the right of specified gadget */
     if (selectbox_info[i].gadget_id_align != GADGET_ID_NONE)
       x = (right_gadget_border[selectbox_info[i].gadget_id_align] +
@@ -5883,11 +5820,11 @@ static void CreateSelectboxGadgets()
                      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,
-                     GDI_BORDER_SIZE_SELECTBUTTON, ED_SELECTBOX_BUTTON_XSIZE,
-                     GDI_DESIGN_WIDTH, ED_WIN_COUNT_XSIZE,
+                     GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
+                     GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
+                     GDI_BORDER_SIZE, gd->border_size, gd->border_size,
+                     GDI_BORDER_SIZE_SELECTBUTTON, selectbox_button_xsize,
+                     GDI_DESIGN_WIDTH, gd->width,
                      GDI_EVENT_MASK, event_mask,
                      GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
                      GDI_CALLBACK_ACTION, HandleSelectboxGadgets,
@@ -5909,12 +5846,23 @@ static void CreateTextbuttonGadgets()
 
   for (i = 0; i < ED_NUM_TEXTBUTTONS; i++)
   {
-    Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
-    int gd_x1, gd_x2, gd_y1, gd_y2;
+    int id = textbutton_info[i].gadget_id;
+    int graphic =
+      ((id >= GADGET_ID_LEVELINFO_LEVEL && id <= GADGET_ID_LEVELINFO_EDITOR) ||
+       (id >= GADGET_ID_PROPERTIES_INFO && id <= GADGET_ID_PROPERTIES_CHANGE) ?
+       IMG_EDITOR_TABBUTTON : IMG_EDITOR_TEXTBUTTON);
+    struct GraphicInfo *gd = &graphic_info[graphic];
+    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 border_xsize = gd->border_size + gd->draw_xoffset;
+    int border_ysize = gd->border_size;
     struct GadgetInfo *gi;
     unsigned int event_mask;
     char infotext[MAX_OUTPUT_LINESIZE + 1];
-    int id = textbutton_info[i].gadget_id;
     int x = SX + textbutton_info[i].x;
     int y = SY + textbutton_info[i].y;
 
@@ -5923,22 +5871,6 @@ static void CreateTextbuttonGadgets()
 
     event_mask = GD_EVENT_RELEASED;
 
-    if ((id >= GADGET_ID_LEVELINFO_LEVEL && id <= GADGET_ID_LEVELINFO_EDITOR) ||
-       (id >= GADGET_ID_PROPERTIES_INFO && id <= GADGET_ID_PROPERTIES_CHANGE))
-    {
-      gd_x1 = DOOR_GFX_PAGEX4 + ED_TEXTBUTTON_TAB_XPOS;
-      gd_x2 = DOOR_GFX_PAGEX3 + ED_TEXTBUTTON_TAB_XPOS;
-      gd_y1 = DOOR_GFX_PAGEY1 + ED_TEXTBUTTON_TAB_YPOS;
-      gd_y2 = DOOR_GFX_PAGEY1 + ED_TEXTBUTTON_TAB_INACTIVE_YPOS;
-    }
-    else
-    {
-      gd_x1 = DOOR_GFX_PAGEX4 + ED_TEXTBUTTON_XPOS;
-      gd_x2 = DOOR_GFX_PAGEX3 + ED_TEXTBUTTON_XPOS;
-      gd_y1 = DOOR_GFX_PAGEY1 + ED_TEXTBUTTON_YPOS;
-      gd_y2 = DOOR_GFX_PAGEY1 + ED_TEXTBUTTON_INACTIVE_YPOS;
-    }
-
     sprintf(infotext, "%s", textbutton_info[i].infotext);
     infotext[max_infotext_len] = '\0';
 
@@ -5959,13 +5891,13 @@ static void CreateTextbuttonGadgets()
                      GDI_TYPE, GD_TYPE_TEXT_BUTTON,
                      GDI_TEXT_VALUE, textbutton_info[i].text,
                      GDI_TEXT_SIZE, textbutton_info[i].size,
-                     GDI_TEXT_FONT, FONT_INPUT_2_ACTIVE,
-                     GDI_TEXT_FONT_ACTIVE, FONT_INPUT_2,
-                     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_BORDER_SIZE, ED_BORDER_TEXT_XSIZE, ED_BORDER_SIZE,
-                     GDI_DESIGN_WIDTH, ED_WIN_COUNT_XSIZE,
+                     GDI_TEXT_FONT, FONT_INPUT_2,
+                     GDI_TEXT_FONT_ACTIVE, FONT_INPUT_2_ACTIVE,
+                     GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
+                     GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
+                     GDI_ALT_DESIGN_UNPRESSED, gd->bitmap, gd_x1a, gd_y1a,
+                     GDI_BORDER_SIZE, border_xsize, border_ysize,
+                     GDI_DESIGN_WIDTH, gd->width,
                      GDI_DECORATION_SHIFTING, 1, 1,
                      GDI_EVENT_MASK, event_mask,
                      GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
@@ -5983,7 +5915,6 @@ static void CreateTextbuttonGadgets()
 
 static void CreateGraphicbuttonGadgets()
 {
-  Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
   struct GadgetInfo *gi;
   unsigned int event_mask;
   int i;
@@ -5992,27 +5923,16 @@ static void CreateGraphicbuttonGadgets()
   for (i = 0; i < ED_NUM_GRAPHICBUTTONS; i++)
   {
     int id = graphicbutton_info[i].gadget_id;
-    int gd_x1, gd_x2, gd_y1, gd_y2;
     int x = SX + graphicbutton_info[i].x;
     int y = SY + graphicbutton_info[i].y;
+    struct GraphicInfo *gd = &graphic_info[graphicbutton_info[i].graphic];
+    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;
 
     event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
 
-    if (i <= ED_GRAPHICBUTTON_ID_NEXT_CHANGE_PAGE)
-    {
-      gd_x1 = DOOR_GFX_PAGEX4 + graphicbutton_info[i].gd_x;
-      gd_y1 = DOOR_GFX_PAGEY1 + graphicbutton_info[i].gd_y;
-      gd_x2 = DOOR_GFX_PAGEX3 + graphicbutton_info[i].gd_x;
-      gd_y2 = gd_y1;
-    }
-    else       /* (i <= ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE) */
-    {
-      gd_x1 = DOOR_GFX_PAGEX6 + graphicbutton_info[i].gd_x;
-      gd_y1 = DOOR_GFX_PAGEY1 + graphicbutton_info[i].gd_y;
-      gd_x2 = gd_x1 - ED_BUTTON_COUNT_XSIZE;
-      gd_y2 = gd_y1;
-    }
-
     /* determine horizontal position to the right of specified gadget */
     if (graphicbutton_info[i].gadget_id_align != GADGET_ID_NONE)
       x = (right_gadget_border[graphicbutton_info[i].gadget_id_align] +
@@ -6027,12 +5947,12 @@ static void CreateGraphicbuttonGadgets()
                      GDI_INFO_TEXT, graphicbutton_info[i].infotext,
                      GDI_X, x,
                      GDI_Y, y,
-                     GDI_WIDTH, graphicbutton_info[i].width,
-                     GDI_HEIGHT, graphicbutton_info[i].height,
+                     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_y1,
-                     GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
+                     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, HandleGraphicbuttonGadgets,
@@ -6164,31 +6084,29 @@ static void CreateScrollbarGadgets()
 
 static void CreateCheckbuttonGadgets()
 {
-  Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
   struct GadgetInfo *gi;
   unsigned int event_mask;
-  int gd_x1, gd_x2, gd_x3, gd_x4, gd_y;
   int i;
 
   event_mask = GD_EVENT_PRESSED;
 
-  gd_x1 = DOOR_GFX_PAGEX4 + ED_CHECKBUTTON_UNCHECKED_XPOS;
-  gd_x2 = DOOR_GFX_PAGEX3 + ED_CHECKBUTTON_UNCHECKED_XPOS;
-  gd_x3 = DOOR_GFX_PAGEX4 + ED_CHECKBUTTON_CHECKED_XPOS;
-  gd_x4 = DOOR_GFX_PAGEX3 + ED_CHECKBUTTON_CHECKED_XPOS;
-  gd_y  = DOOR_GFX_PAGEY1 + ED_RADIOBUTTON_YPOS;
-
   for (i = 0; i < ED_NUM_CHECKBUTTONS; i++)
   {
     int id = checkbutton_info[i].gadget_id;
+    int graphic = (id == GADGET_ID_STICK_ELEMENT ? IMG_EDITOR_STICKYBUTTON :
+                  IMG_EDITOR_CHECKBOX);
+    struct GraphicInfo *gd = &graphic_info[graphic];
+    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 x = SX + checkbutton_info[i].x;
     int y = SY + checkbutton_info[i].y;
 
-    if (id == GADGET_ID_STICK_ELEMENT)
-      gd_y  = DOOR_GFX_PAGEY1 + ED_STICKYBUTTON_YPOS;
-    else
-      gd_y  = DOOR_GFX_PAGEY1 + ED_CHECKBUTTON_YPOS;
-
     /* determine horizontal position to the right of specified gadget */
     if (checkbutton_info[i].gadget_id_align != GADGET_ID_NONE)
       x = (right_gadget_border[checkbutton_info[i].gadget_id_align] +
@@ -6203,14 +6121,14 @@ static void CreateCheckbuttonGadgets()
                      GDI_INFO_TEXT, checkbutton_info[i].infotext,
                      GDI_X, x,
                      GDI_Y, y,
-                     GDI_WIDTH, ED_CHECKBUTTON_XSIZE,
-                     GDI_HEIGHT, ED_CHECKBUTTON_YSIZE,
+                     GDI_WIDTH, gd->width,
+                     GDI_HEIGHT, gd->height,
                      GDI_TYPE, GD_TYPE_CHECK_BUTTON,
                      GDI_CHECKED, *checkbutton_info[i].value,
-                     GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
-                     GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
-                     GDI_ALT_DESIGN_UNPRESSED, gd_bitmap, gd_x3, gd_y,
-                     GDI_ALT_DESIGN_PRESSED, gd_bitmap, gd_x4, gd_y,
+                     GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
+                     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, HandleCheckbuttons,
@@ -6227,20 +6145,21 @@ static void CreateCheckbuttonGadgets()
 
 static void CreateRadiobuttonGadgets()
 {
-  Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
+  struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_RADIOBUTTON];
+  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;
   struct GadgetInfo *gi;
   unsigned int event_mask;
-  int gd_x1, gd_x2, gd_x3, gd_x4, gd_y;
   int i;
 
   event_mask = GD_EVENT_PRESSED;
 
-  gd_x1 = DOOR_GFX_PAGEX4 + ED_CHECKBUTTON_UNCHECKED_XPOS;
-  gd_x2 = DOOR_GFX_PAGEX3 + ED_CHECKBUTTON_UNCHECKED_XPOS;
-  gd_x3 = DOOR_GFX_PAGEX4 + ED_CHECKBUTTON_CHECKED_XPOS;
-  gd_x4 = DOOR_GFX_PAGEX3 + ED_CHECKBUTTON_CHECKED_XPOS;
-  gd_y  = DOOR_GFX_PAGEY1 + ED_RADIOBUTTON_YPOS;
-
   for (i = 0; i < ED_NUM_RADIOBUTTONS; i++)
   {
     int id = radiobutton_info[i].gadget_id;
@@ -6264,15 +6183,15 @@ static void CreateRadiobuttonGadgets()
                      GDI_INFO_TEXT, radiobutton_info[i].infotext,
                      GDI_X, x,
                      GDI_Y, y,
-                     GDI_WIDTH, ED_CHECKBUTTON_XSIZE,
-                     GDI_HEIGHT, ED_CHECKBUTTON_YSIZE,
+                     GDI_WIDTH, gd->width,
+                     GDI_HEIGHT, gd->height,
                      GDI_TYPE, GD_TYPE_RADIO_BUTTON,
                      GDI_RADIO_NR, radiobutton_info[i].radio_button_nr,
                      GDI_CHECKED, checked,
-                     GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
-                     GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
-                     GDI_ALT_DESIGN_UNPRESSED, gd_bitmap, gd_x3, gd_y,
-                     GDI_ALT_DESIGN_PRESSED, gd_bitmap, gd_x4, gd_y,
+                     GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
+                     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, HandleRadiobuttons,
@@ -6736,6 +6655,8 @@ static void ResetUndoBuffer()
 {
   undo_buffer_position = -1;
   undo_buffer_steps = -1;
+  redo_buffer_steps = 0;
+
   CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
 
   level.changed = FALSE;
@@ -7460,6 +7381,31 @@ 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()
@@ -7476,6 +7422,8 @@ void DrawLevelEd()
   /* needed if different viewport properties defined for editor */
   ChangeViewportPropertiesIfNeeded();
 
+  InitZoomLevelSettings();
+
   playfield_area_changed = DrawingAreaChanged();
 
   OpenDoor(DOOR_OPEN_1 | DOOR_OPEN_2 | DOOR_NO_DELAY);
@@ -7516,8 +7464,10 @@ void DrawLevelEd()
   DrawSpecialEditorDoor();
 
   /* draw new control window */
-  BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
-            DOOR_GFX_PAGEX8, 236, EXSIZE, EYSIZE, EX, EY);
+  BlitBitmap(graphic_info[IMG_BACKGROUND_TOOLBOX].bitmap, drawto,
+            graphic_info[IMG_BACKGROUND_TOOLBOX].src_x,
+            graphic_info[IMG_BACKGROUND_TOOLBOX].src_y,
+            EXSIZE, EYSIZE, EX, EY);
 
   // redraw_mask |= REDRAW_ALL;
 
@@ -7549,52 +7499,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_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_pos[ED_SCROLLBUTTON_ID_AREA_RIGHT].x + xoffset;
-  y = SX + scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_DOWN].y + yoffset;
-
-  ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_RIGHT], GDI_X, x, GDI_END);
-  ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_DOWN], GDI_Y, y, GDI_END);
-
-  width  = scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].width + xoffset;
-  height = scrollbar_pos[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);
@@ -7799,7 +7759,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();
@@ -8085,8 +8045,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;
 
@@ -8098,7 +8060,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);
 }
@@ -8468,6 +8430,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;
@@ -8710,6 +8673,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)
     {
@@ -8760,6 +8725,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);
   }
 }
 
@@ -9394,7 +9378,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,
@@ -10095,10 +10079,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);
@@ -10364,7 +10348,7 @@ static int DrawLevelText(int sx, int sy, char letter, int mode)
       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;
@@ -10395,7 +10379,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;
@@ -10409,7 +10393,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;
 
@@ -10430,7 +10414,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);
 }
@@ -10442,7 +10426,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)
@@ -10451,6 +10435,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:
@@ -10469,13 +10456,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];
@@ -10537,7 +10527,7 @@ static void RandomPlacement(int new_element)
     }
   }
 
-  DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
+  DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
   CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
 }
 
@@ -10556,7 +10546,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);
 }
 
@@ -10789,7 +10779,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;
@@ -10893,6 +10883,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:
@@ -11178,9 +11172,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);
@@ -11197,9 +11191,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);
@@ -11216,9 +11210,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);
@@ -11235,9 +11229,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);
@@ -11246,12 +11240,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:
@@ -11336,7 +11330,19 @@ static void HandleControlButtons(struct GadgetInfo *gi)
       break;
 
     case GADGET_ID_ZOOM:
-      printf("::: zoom button pressed with mouse button %d\n", button);
+      // 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);
+
+      // 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();
+
       break;
 
     case GADGET_ID_CUSTOM_COPY_FROM:
@@ -11355,9 +11361,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("Redo buffer empty!", REQ_CONFIRM);
+
        break;
       }
 
@@ -11367,9 +11384,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++)
@@ -11378,7 +11411,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;
 
@@ -11411,7 +11444,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:
@@ -11612,11 +11645,11 @@ void HandleLevelEditorKeyInput(Key key)
        break;
       case KSYM_Page_Up:
        id = GADGET_ID_SCROLL_LIST_UP;
-       button = MB_RIGHTBUTTON;
+       button = ED_ELEMENTLIST_BUTTONS_VERT - 1;
        break;
       case KSYM_Page_Down:
        id = GADGET_ID_SCROLL_LIST_DOWN;
-       button = MB_RIGHTBUTTON;
+       button = ED_ELEMENTLIST_BUTTONS_VERT - 1;
        break;
 
       case KSYM_Home:
@@ -11698,6 +11731,14 @@ void HandleLevelEditorKeyInput(Key key)
       ClickOnGadget(level_editor_gadget[GADGET_ID_PROPERTIES], button);
     else if (letter == '.')
       ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS], button);
+    else if (letter == 'U')
+      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)
@@ -11763,13 +11804,17 @@ void PrintEditorGadgetInfoText(struct GadgetInfo *gi)
 
     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, " ('%c/Shift-U')", 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);