rnd-19990220-1-src
[rocksndiamonds.git] / src / editor.c
index 9df186776b76713a89461b6aa0dcbd0f685b12b6..d5233e26d3aeafa7e2c16f6eabba878f0ff5ba19 100644 (file)
 #define MIN_SCORE                      0
 #define MAX_SCORE                      255
 
-/* values for elements with content */
-#define MIN_ELEM_CONTENT               1
-#define MAX_ELEM_CONTENT               8
-
 /* values for the control window */
 #define ED_CTRL_BUTTONS_GFX_YPOS       236
 #define ED_CTRL_BUTTONS_ALT_GFX_YPOS   142
 #define GADGET_ID_LEVEL_TIMESCORE_DOWN 43
 #define GADGET_ID_LEVEL_TIMESCORE_TEXT 44
 #define GADGET_ID_LEVEL_TIMESCORE_UP   45
+#define GADGET_ID_SELECT_LEVEL_DOWN    46
+#define GADGET_ID_SELECT_LEVEL_TEXT    47
+#define GADGET_ID_SELECT_LEVEL_UP      48
 
 /* drawing area identifiers */
-#define GADGET_ID_DRAWING_LEVEL        46
-#define GADGET_ID_ELEM_CONTENT_0       47
-#define GADGET_ID_ELEM_CONTENT_1       48
-#define GADGET_ID_ELEM_CONTENT_2       49
-#define GADGET_ID_ELEM_CONTENT_3       50
-#define GADGET_ID_ELEM_CONTENT_4       51
-#define GADGET_ID_ELEM_CONTENT_5       52
-#define GADGET_ID_ELEM_CONTENT_6       53
-#define GADGET_ID_ELEM_CONTENT_7       54
-#define GADGET_ID_AMOEBA_CONTENT       55
+#define GADGET_ID_DRAWING_LEVEL                49
+#define GADGET_ID_ELEM_CONTENT_0       50
+#define GADGET_ID_ELEM_CONTENT_1       51
+#define GADGET_ID_ELEM_CONTENT_2       52
+#define GADGET_ID_ELEM_CONTENT_3       53
+#define GADGET_ID_ELEM_CONTENT_4       54
+#define GADGET_ID_ELEM_CONTENT_5       55
+#define GADGET_ID_ELEM_CONTENT_6       56
+#define GADGET_ID_ELEM_CONTENT_7       57
+#define GADGET_ID_AMOEBA_CONTENT       58
 
 /* text input identifiers */
-#define GADGET_ID_LEVEL_NAME           56
-#define GADGET_ID_LEVEL_AUTHOR         57
+#define GADGET_ID_LEVEL_NAME           59
+#define GADGET_ID_LEVEL_AUTHOR         60
 
 /* gadgets for scrolling of drawing area */
-#define GADGET_ID_SCROLL_UP            58
-#define GADGET_ID_SCROLL_DOWN          59
-#define GADGET_ID_SCROLL_LEFT          60
-#define GADGET_ID_SCROLL_RIGHT         61
-#define GADGET_ID_SCROLL_HORIZONTAL    62
-#define GADGET_ID_SCROLL_VERTICAL      63
+#define GADGET_ID_SCROLL_UP            61
+#define GADGET_ID_SCROLL_DOWN          62
+#define GADGET_ID_SCROLL_LEFT          63
+#define GADGET_ID_SCROLL_RIGHT         64
+#define GADGET_ID_SCROLL_HORIZONTAL    65
+#define GADGET_ID_SCROLL_VERTICAL      66
 
 /* gadgets for scrolling element list */
-#define GADGET_ID_ELEMENTLIST_UP       64
-#define GADGET_ID_ELEMENTLIST_DOWN     65
+#define GADGET_ID_ELEMENTLIST_UP       67
+#define GADGET_ID_ELEMENTLIST_DOWN     68
 
 /* gadgets for buttons in element list */
-#define GADGET_ID_ELEMENTLIST_FIRST    66
-#define GADGET_ID_ELEMENTLIST_LAST     105
+#define GADGET_ID_ELEMENTLIST_FIRST    69
+#define GADGET_ID_ELEMENTLIST_LAST     108
 
 /* buttons for level settings */
-#define GADGET_ID_RANDOM_PERCENTAGE    106
-#define GADGET_ID_RANDOM_QUANTITY      107
-#define GADGET_ID_RANDOM_RESTRICTED    108
-#define GADGET_ID_DOUBLE_SPEED         109
-#define GADGET_ID_GRAVITY              110
-#define GADGET_ID_STICK_ELEMENT                111
+#define GADGET_ID_RANDOM_PERCENTAGE    109
+#define GADGET_ID_RANDOM_QUANTITY      110
+#define GADGET_ID_RANDOM_RESTRICTED    111
+#define GADGET_ID_DOUBLE_SPEED         112
+#define GADGET_ID_GRAVITY              113
+#define GADGET_ID_STICK_ELEMENT                114
 
 /* another drawing area for random placement */
-#define GADGET_ID_RANDOM_BACKGROUND    112
+#define GADGET_ID_RANDOM_BACKGROUND    115
 
-#define NUM_EDITOR_GADGETS             113
+#define NUM_EDITOR_GADGETS             116
 
 /* radio button numbers */
 #define RADIO_NR_NONE                  0
 #define ED_COUNTER_ID_LEVEL_TIMELIMIT  5
 #define ED_COUNTER_ID_LEVEL_TIMESCORE  6
 #define ED_COUNTER_ID_LEVEL_RANDOM     7
+#define ED_COUNTER_ID_SELECT_LEVEL     8
 
-#define ED_NUM_COUNTERBUTTONS          8
+#define ED_NUM_COUNTERBUTTONS          9
 
 #define ED_COUNTER_ID_LEVEL_FIRST      ED_COUNTER_ID_LEVEL_XSIZE
 #define ED_COUNTER_ID_LEVEL_LAST       ED_COUNTER_ID_LEVEL_RANDOM
@@ -380,15 +380,15 @@ static struct
   { 'E', "exit level editor" }
 };
 
-/* pointers to counter values */
-static int *gadget_elem_score_value = NULL;
-static int *gadget_elem_content_value = NULL;
-static int *gadget_level_xsize_value = NULL;
-static int *gadget_level_ysize_value = NULL;
-static int *gadget_level_random_value = NULL;
-static int *gadget_level_collect_value = NULL;
-static int *gadget_level_timelimit_value = NULL;
-static int *gadget_level_timescore_value = NULL;
+/* values for random placement */
+#define RANDOM_USE_PERCENTAGE          0
+#define RANDOM_USE_QUANTITY            1
+
+static int random_placement_value = 10;
+static int random_placement_method = RANDOM_USE_QUANTITY;
+static int random_placement_background_element = EL_ERDREICH;
+static boolean random_placement_background_restricted = FALSE;
+static boolean stick_element_properties_window = FALSE;
 
 static struct
 {
@@ -396,7 +396,7 @@ static struct
   int min_value, max_value;
   int gadget_id_down, gadget_id_up;
   int gadget_id_text;
-  int **counter_value;
+  int *value;
   char *infotext_above, *infotext_right;
 } counterbutton_info[ED_NUM_COUNTERBUTTONS] =
 {
@@ -405,15 +405,15 @@ static struct
     MIN_SCORE,                         MAX_SCORE,
     GADGET_ID_ELEM_SCORE_DOWN,         GADGET_ID_ELEM_SCORE_UP,
     GADGET_ID_ELEM_SCORE_TEXT,
-    &gadget_elem_score_value,
+    NULL,                              /* will be set when used */
     "element score",                   NULL
   },
   {
     ED_COUNT_ELEM_CONTENT_XPOS,                ED_COUNT_ELEM_CONTENT_YPOS,
-    MIN_ELEM_CONTENT,                  MAX_ELEM_CONTENT,
+    MIN_ELEMENT_CONTENTS,              MAX_ELEMENT_CONTENTS,
     GADGET_ID_ELEM_CONTENT_DOWN,       GADGET_ID_ELEM_CONTENT_UP,
     GADGET_ID_ELEM_CONTENT_TEXT,
-    &gadget_elem_content_value,
+    &level.num_yam_contents,
     "element content",                 NULL
   },
   {
@@ -421,7 +421,7 @@ static struct
     MIN_LEV_FIELDX,                    MAX_LEV_FIELDX,
     GADGET_ID_LEVEL_XSIZE_DOWN,                GADGET_ID_LEVEL_XSIZE_UP,
     GADGET_ID_LEVEL_XSIZE_TEXT,
-    &gadget_level_xsize_value,
+    &level.fieldx,
     "playfield size",                  "width",
   },
   {
@@ -429,7 +429,7 @@ static struct
     MIN_LEV_FIELDY,                    MAX_LEV_FIELDY,
     GADGET_ID_LEVEL_YSIZE_DOWN,                GADGET_ID_LEVEL_YSIZE_UP,
     GADGET_ID_LEVEL_YSIZE_TEXT,
-    &gadget_level_ysize_value,
+    &level.fieldy,
     NULL,                              "height",
   },
   {
@@ -437,7 +437,7 @@ static struct
     0,                                 999,
     GADGET_ID_LEVEL_COLLECT_DOWN,      GADGET_ID_LEVEL_COLLECT_UP,
     GADGET_ID_LEVEL_COLLECT_TEXT,
-    &gadget_level_collect_value,
+    &level.gems_needed,
     "number of emeralds to collect",   NULL
   },
   {
@@ -445,7 +445,7 @@ static struct
     0,                                 999,
     GADGET_ID_LEVEL_TIMELIMIT_DOWN,    GADGET_ID_LEVEL_TIMELIMIT_UP,
     GADGET_ID_LEVEL_TIMELIMIT_TEXT,
-    &gadget_level_timelimit_value,
+    &level.time,
     "time available to solve level",   "(0 => no time limit)"
   },
   {
@@ -453,7 +453,7 @@ static struct
     0,                                 255,
     GADGET_ID_LEVEL_TIMESCORE_DOWN,    GADGET_ID_LEVEL_TIMESCORE_UP,
     GADGET_ID_LEVEL_TIMESCORE_TEXT,
-    &gadget_level_timescore_value,
+    &level.score[SC_ZEITBONUS],
     "score for each 10 seconds left",  NULL
   },
   {
@@ -461,8 +461,16 @@ static struct
     1,                                 100,
     GADGET_ID_LEVEL_RANDOM_DOWN,       GADGET_ID_LEVEL_RANDOM_UP,
     GADGET_ID_LEVEL_RANDOM_TEXT,
-    &gadget_level_random_value,
+    &random_placement_value,
     "random element placement",                "in"
+  },
+  {
+    DX - SX - 1,                       0 - SY + 31,
+    1,                                 100,
+    GADGET_ID_SELECT_LEVEL_DOWN,       GADGET_ID_SELECT_LEVEL_UP,
+    GADGET_ID_SELECT_LEVEL_TEXT,
+    &level_nr,
+    NULL,                              NULL
   }
 };
 
@@ -565,16 +573,6 @@ static struct
   }
 };
 
-/* values for random placement */
-#define RANDOM_USE_PERCENTAGE          0
-#define RANDOM_USE_QUANTITY            1
-
-static int random_placement_value = 10;
-static int random_placement_method = RANDOM_USE_QUANTITY;
-static int random_placement_background_element = EL_ERDREICH;
-static boolean random_placement_background_restricted = FALSE;
-static boolean stick_element_properties_window = FALSE;
-
 static struct
 {
   int x, y;
@@ -655,17 +653,22 @@ static int new_element3 = EL_ERDREICH;
 #define BUTTON_ELEMENT(button) (button == 1 ? new_element1 : \
                                button == 2 ? new_element2 : \
                                button == 3 ? new_element3 : EL_LEERRAUM)
+#define BUTTON_STEPSIZE(button) (button == 1 ? 1 : button == 2 ? 5 : 10)
 
 /* forward declaration for internal use */
+static void ModifyEditorCounter(int, int);
+static void ModifyEditorCounterLimits(int, int, int);
 static void DrawDrawingWindow();
 static void DrawLevelInfoWindow();
 static void DrawPropertiesWindow();
 static void CopyLevelToUndoBuffer(int);
-static void HandleControlButtons(struct GadgetInfo *);
-static void HandleCounterButtons(struct GadgetInfo *);
 static void HandleDrawingAreas(struct GadgetInfo *);
-static void HandleDrawingAreaInfo(struct GadgetInfo *);
+static void HandleCounterButtons(struct GadgetInfo *);
 static void HandleTextInputGadgets(struct GadgetInfo *);
+static void HandleRadiobuttons(struct GadgetInfo *);
+static void HandleCheckbuttons(struct GadgetInfo *);
+static void HandleControlButtons(struct GadgetInfo *);
+static void HandleDrawingAreaInfo(struct GadgetInfo *);
 
 static struct GadgetInfo *level_editor_gadget[NUM_EDITOR_GADGETS];
 
@@ -674,7 +677,7 @@ static int last_drawing_function = GADGET_ID_SINGLE_ITEMS;
 static boolean draw_with_brush = FALSE;
 static int properties_element = 0;
 
-static short ElementContent[MAX_ELEM_CONTENT][3][3];
+static short ElementContent[MAX_ELEMENT_CONTENTS][3][3];
 static short FieldBackup[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 static short UndoBuffer[NUM_UNDO_STEPS][MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 static int undo_buffer_position = 0;
@@ -1178,6 +1181,7 @@ static void CreateControlButtons()
     gd_y2  = DOOR_GFX_PAGEY1 + ED_CTRL_BUTTONS_ALT_GFX_YPOS + gd_yoffset;
 
     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,
@@ -1235,9 +1239,10 @@ static void CreateControlButtons()
       gd_y1 = DOOR_GFX_PAGEY1 + scrollbutton_info[i].ypos;
       gd_x2 = gd_x1 - ED_SCROLLBUTTON_XSIZE;
       gd_y2 = gd_y1;
-   }
+    }
 
     gi = CreateGadget(GDI_CUSTOM_ID, id,
+                     GDI_CUSTOM_TYPE_ID, i,
                      GDI_INFO_TEXT, scrollbutton_info[i].infotext,
                      GDI_X, x,
                      GDI_Y, y,
@@ -1283,6 +1288,7 @@ static void CreateControlButtons()
     deco_ypos = (ED_ELEMENTLIST_YSIZE - MINI_TILEY) / 2;
 
     gi = CreateGadget(GDI_CUSTOM_ID, id,
+                     GDI_CUSTOM_TYPE_ID, i,
                      GDI_INFO_TEXT, element_info[editor_element[i]],
                      GDI_X, DX + gd_xoffset,
                      GDI_Y, DY + gd_yoffset,
@@ -1326,25 +1332,50 @@ static void CreateCounterButtons()
                counterbutton_info[i].gadget_id_up);
       int gd_xoffset;
       int gd_x, gd_x1, gd_x2, gd_y;
+      int x_size, y_size;
       unsigned long event_mask;
       char infotext[MAX_INFOTEXT_LEN + 1];
 
       event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
 
-      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;
+      if (i == ED_COUNTER_ID_SELECT_LEVEL)
+      {
+       int sid = (j == 0 ?
+                  ED_SCROLLBUTTON_ID_AREA_LEFT :
+                  ED_SCROLLBUTTON_ID_AREA_RIGHT);
+
+       event_mask |= GD_EVENT_RELEASED;
+
+       if (j == 1)
+         xpos += ED_GADGET_DISTANCE;
+       ypos += ED_GADGET_DISTANCE;
+
+       gd_x1 = DOOR_GFX_PAGEX8 + scrollbutton_info[sid].xpos;
+       gd_x2 = gd_x1 - ED_SCROLLBUTTON_XSIZE;
+       gd_y  = DOOR_GFX_PAGEY1 + scrollbutton_info[sid].ypos;
+       x_size = ED_SCROLLBUTTON_XSIZE;
+       y_size = ED_SCROLLBUTTON_YSIZE;
+      }
+      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;
+       x_size = ED_BUTTON_COUNT_XSIZE;
+       y_size = ED_BUTTON_COUNT_YSIZE;
+      }
 
       sprintf(infotext, "%s counter value by 1, 5 or 10",
              (j == 0 ? "decrease" : "increase"));
 
       gi = CreateGadget(GDI_CUSTOM_ID, id,
+                       GDI_CUSTOM_TYPE_ID, i,
                        GDI_INFO_TEXT, infotext,
                        GDI_X, xpos,
                        GDI_Y, ypos,
-                       GDI_WIDTH, ED_BUTTON_COUNT_XSIZE,
-                       GDI_HEIGHT, ED_BUTTON_COUNT_YSIZE,
+                       GDI_WIDTH, x_size,
+                       GDI_HEIGHT, y_size,
                        GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
                        GDI_STATE, GD_BUTTON_UNPRESSED,
                        GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y,
@@ -1364,10 +1395,22 @@ static void CreateCounterButtons()
        id = counterbutton_info[i].gadget_id_text;
        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;
+       if (i == ED_COUNTER_ID_SELECT_LEVEL)
+       {
+         xpos += ED_GADGET_DISTANCE;
+         ypos -= ED_GADGET_DISTANCE;
+
+         gd_x = DOOR_GFX_PAGEX4 + ED_WIN_COUNT_XPOS;
+         gd_y = DOOR_GFX_PAGEY1 + ED_WIN_COUNT_YPOS;
+       }
+       else
+       {
+         gd_x = DOOR_GFX_PAGEX4 + ED_WIN_COUNT_XPOS;
+         gd_y = DOOR_GFX_PAGEY1 + ED_WIN_COUNT_YPOS;
+       }
 
        gi = CreateGadget(GDI_CUSTOM_ID, id,
+                         GDI_CUSTOM_TYPE_ID, i,
                          GDI_INFO_TEXT, "enter counter value",
                          GDI_X, xpos,
                          GDI_Y, ypos,
@@ -1423,13 +1466,14 @@ static void CreateDrawingAreas()
   level_editor_gadget[id] = gi;
 
   /* ... up to eight areas for element content ... */
-  for (i=0; i<MAX_ELEM_CONTENT; i++)
+  for (i=0; i<MAX_ELEMENT_CONTENTS; i++)
   {
     int gx = SX + ED_AREA_ELEM_CONTENT_XPOS + 5 * (i % 4) * MINI_TILEX;
     int gy = SX + ED_AREA_ELEM_CONTENT_YPOS + 6 * (i / 4) * MINI_TILEY;
 
     id = GADGET_ID_ELEM_CONTENT_0 + i;
     gi = CreateGadget(GDI_CUSTOM_ID, id,
+                     GDI_CUSTOM_TYPE_ID, i,
                      GDI_X, gx,
                      GDI_Y, gy,
                      GDI_WIDTH, 3 * MINI_TILEX,
@@ -1509,6 +1553,7 @@ static void CreateTextInputGadgets()
     infotext[MAX_INFOTEXT_LEN] = '\0';
 
     gi = CreateGadget(GDI_CUSTOM_ID, id,
+                     GDI_CUSTOM_TYPE_ID, i,
                      GDI_INFO_TEXT, infotext,
                      GDI_X, SX + textinput_info[i].x,
                      GDI_Y, SY + textinput_info[i].y,
@@ -1563,6 +1608,7 @@ static void CreateScrollbarGadgets()
     gd_y2 = DOOR_GFX_PAGEY1 + scrollbar_info[i].ypos;
 
     gi = CreateGadget(GDI_CUSTOM_ID, id,
+                     GDI_CUSTOM_TYPE_ID, i,
                      GDI_INFO_TEXT, scrollbar_info[i].infotext,
                      GDI_X, SX + scrollbar_info[i].x,
                      GDI_Y, SY + scrollbar_info[i].y,
@@ -1612,6 +1658,7 @@ static void CreateCheckbuttonGadgets()
       (*radiobutton_info[i].value == radiobutton_info[i].checked_value);
 
     gi = CreateGadget(GDI_CUSTOM_ID, id,
+                     GDI_CUSTOM_TYPE_ID, i,
                      GDI_INFO_TEXT, radiobutton_info[i].infotext,
                      GDI_X, SX + radiobutton_info[i].x,
                      GDI_Y, SY + radiobutton_info[i].y,
@@ -1625,7 +1672,7 @@ static void CreateCheckbuttonGadgets()
                      GDI_ALT_DESIGN_UNPRESSED, gd_pixmap, gd_x3, gd_y,
                      GDI_ALT_DESIGN_PRESSED, gd_pixmap, gd_x4, gd_y,
                      GDI_EVENT_MASK, event_mask,
-                     GDI_CALLBACK_ACTION, HandleControlButtons,
+                     GDI_CALLBACK_ACTION, HandleRadiobuttons,
                      GDI_END);
 
     if (gi == NULL)
@@ -1644,6 +1691,7 @@ static void CreateCheckbuttonGadgets()
       gd_y  = DOOR_GFX_PAGEY1 + ED_CHECKBUTTON_YPOS;
 
     gi = CreateGadget(GDI_CUSTOM_ID, id,
+                     GDI_CUSTOM_TYPE_ID, i,
                      GDI_INFO_TEXT, checkbutton_info[i].infotext,
                      GDI_X, SX + checkbutton_info[i].x,
                      GDI_Y, SY + checkbutton_info[i].y,
@@ -1656,7 +1704,7 @@ static void CreateCheckbuttonGadgets()
                      GDI_ALT_DESIGN_UNPRESSED, gd_pixmap, gd_x3, gd_y,
                      GDI_ALT_DESIGN_PRESSED, gd_pixmap, gd_x4, gd_y,
                      GDI_EVENT_MASK, event_mask,
-                     GDI_CALLBACK_ACTION, HandleControlButtons,
+                     GDI_CALLBACK_ACTION, HandleCheckbuttons,
                      GDI_END);
 
     if (gi == NULL)
@@ -1676,23 +1724,35 @@ void CreateLevelEditorGadgets()
   CreateCheckbuttonGadgets();
 }
 
+static void MapCounterButtons(int id)
+{
+  MapGadget(level_editor_gadget[counterbutton_info[id].gadget_id_down]);
+  MapGadget(level_editor_gadget[counterbutton_info[id].gadget_id_text]);
+  MapGadget(level_editor_gadget[counterbutton_info[id].gadget_id_up]);
+}
+
 static void MapControlButtons()
 {
+  int counter_id;
   int i;
 
+  /* map toolbox buttons */
   for (i=0; i<ED_NUM_CTRL_BUTTONS; i++)
     MapGadget(level_editor_gadget[i]);
+
+  /* map buttons to select elements */
   for (i=0; i<ED_NUM_ELEMENTLIST_BUTTONS; i++)
     MapGadget(level_editor_gadget[GADGET_ID_ELEMENTLIST_FIRST + i]);
   MapGadget(level_editor_gadget[GADGET_ID_ELEMENTLIST_UP]);
   MapGadget(level_editor_gadget[GADGET_ID_ELEMENTLIST_DOWN]);
-}
 
-static void MapCounterButtons(int id)
-{
-  MapGadget(level_editor_gadget[counterbutton_info[id].gadget_id_down]);
-  MapGadget(level_editor_gadget[counterbutton_info[id].gadget_id_text]);
-  MapGadget(level_editor_gadget[counterbutton_info[id].gadget_id_up]);
+  /* map buttons to select level */
+  counter_id = ED_COUNTER_ID_SELECT_LEVEL;
+  ModifyEditorCounterLimits(counter_id,
+                           leveldir[leveldir_nr].first_level,
+                           leveldir[leveldir_nr].last_level);
+  ModifyEditorCounter(counter_id, *counterbutton_info[counter_id].value);
+  MapCounterButtons(counter_id);
 }
 
 static void MapDrawingArea(int id)
@@ -1756,7 +1816,7 @@ void UnmapLevelEditorWindowGadgets()
   int i;
 
   for (i=0; i<NUM_EDITOR_GADGETS; i++)
-    if (level_editor_gadget[i]->x < DX)
+    if (level_editor_gadget[i]->x < SX + SXSIZE)
       UnmapGadget(level_editor_gadget[i]);
 }
 
@@ -1768,10 +1828,53 @@ void UnmapLevelEditorGadgets()
     UnmapGadget(level_editor_gadget[i]);
 }
 
-void DrawLevelEd()
+static void ResetUndoBuffer()
+{
+  undo_buffer_position = -1;
+  undo_buffer_steps = -1;
+  CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
+}
+
+static void DrawEditModeWindow()
+{
+  if (edit_mode == ED_MODE_INFO)
+    DrawLevelInfoWindow();
+  else if (edit_mode == ED_MODE_PROPERTIES)
+    DrawPropertiesWindow();
+  else /* edit_mode == ED_MODE_DRAWING */
+    DrawDrawingWindow();
+}
+
+static boolean LevelChanged()
+{
+  boolean level_changed = FALSE;
+  int x, y;
+
+  for(y=0; y<lev_fieldy; y++) 
+    for(x=0; x<lev_fieldx; x++)
+      if (Feld[x][y] != Ur[x][y])
+       level_changed = TRUE;
+
+  return level_changed;
+}
+
+static boolean LevelContainsPlayer()
 {
-  edit_mode = ED_MODE_DRAWING;
+  boolean player_found = FALSE;
+  int x, y;
 
+  for(y=0; y<lev_fieldy; y++) 
+    for(x=0; x<lev_fieldx; x++)
+      if (Feld[x][y] == EL_SPIELFIGUR ||
+         Feld[x][y] == EL_SPIELER1 ||
+         Feld[x][y] == EL_SP_MURPHY) 
+       player_found = TRUE;
+
+  return player_found;
+}
+
+void DrawLevelEd()
+{
   CloseDoor(DOOR_CLOSE_ALL);
   OpenDoor(DOOR_OPEN_2 | DOOR_NO_DELAY);
 
@@ -1791,11 +1894,11 @@ void DrawLevelEd()
   }
   else
   {
+    edit_mode = ED_MODE_DRAWING;
+
+    ResetUndoBuffer();
     level_xpos = -1;
     level_ypos = -1;
-    undo_buffer_position = -1;
-    undo_buffer_steps = -1;
-    CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
   }
 
   /* copy default editor door content to main double buffer */
@@ -1833,10 +1936,7 @@ void DrawLevelEd()
            DY + ED_WIN_LEVELNR_YPOS);
 
   /* draw bigger door */
-  XCopyArea(display, pix[PIX_DOOR], drawto, gc,
-           DOOR_GFX_PAGEX7, 0,
-           108, 64,
-           EX - 4, EY - 12);
+  DrawSpecialEditorDoor();
 
   /* draw new control window */
   XCopyArea(display, pix[PIX_DOOR], drawto, gc,
@@ -1852,8 +1952,16 @@ void DrawLevelEd()
   XCopyArea(display, drawto, pix[PIX_DB_DOOR], gc,
            DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
 
+  /*
   DrawDrawingWindow();
+  */
+
+  DrawEditModeWindow();
+
+  /*
   FadeToFront();
+  */
+
 
   OpenDoor(DOOR_OPEN_1);
 
@@ -1862,6 +1970,41 @@ void DrawLevelEd()
   */
 }
 
+void SelectNewLevelToEdit(struct GadgetInfo *gi)
+{
+  int gadget_id = gi->custom_id;
+  int counter_id = gi->custom_type_id;
+  int button = gi->event.button;
+  int *counter_value = counterbutton_info[counter_id].value;
+  int step = BUTTON_STEPSIZE(button) *
+    (gadget_id == counterbutton_info[counter_id].gadget_id_down ? -1 : +1);
+  int old_counter_value = *counter_value;
+  boolean released = (gi->event.type == GD_EVENT_RELEASED);
+
+  if (LevelChanged())
+  {
+    if (gi->event.type == GD_EVENT_PRESSED)
+      return;
+
+    if (!Request("Level has changed! Discard changes ?", REQ_ASK))
+    {
+      ModifyEditorCounter(counter_id, old_counter_value);
+      return;
+    }
+  }
+  else if (released)
+    return;
+
+  if (gadget_id == counterbutton_info[counter_id].gadget_id_text)
+    *counter_value = gi->text.number_value;
+  else
+    ModifyEditorCounter(counter_id, *counter_value + step);
+
+  LoadLevel(level_nr);
+  ResetUndoBuffer();
+  DrawEditModeWindow();
+}
+
 static void AdjustDrawingAreaGadgets()
 {
   int ed_xsize = lev_fieldx + 2;
@@ -1976,7 +2119,7 @@ static void ModifyEditorTextInput(int textinput_id, char *new_text)
 
 static void ModifyEditorCounter(int counter_id, int new_value)
 {
-  int *counter_value = *counterbutton_info[counter_id].counter_value;
+  int *counter_value = counterbutton_info[counter_id].value;
   int gadget_id = counterbutton_info[counter_id].gadget_id_text;
   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
 
@@ -1986,6 +2129,14 @@ static void ModifyEditorCounter(int counter_id, int new_value)
     *counter_value = gi->text.number_value;
 }
 
+static void ModifyEditorCounterLimits(int counter_id, int min, int max)
+{
+  int gadget_id = counterbutton_info[counter_id].gadget_id_text;
+  struct GadgetInfo *gi = level_editor_gadget[gadget_id];
+
+  ModifyGadget(gi, GDI_NUMBER_MIN, min, GDI_NUMBER_MAX, max, GDI_END);
+}
+
 static void PickDrawingElement(int button, int element)
 {
   if (button < 1 || button > 3)
@@ -2080,13 +2231,6 @@ static void DrawLevelInfoWindow()
   DrawText(SX + ED_SETTINGS2_XPOS, SY + ED_SETTINGS2_YPOS,
           "Editor Settings", FS_BIG, FC_YELLOW);
 
-  gadget_level_xsize_value = &lev_fieldx;
-  gadget_level_ysize_value = &lev_fieldy;
-  gadget_level_random_value = &random_placement_value;
-  gadget_level_collect_value = &level.edelsteine;
-  gadget_level_timelimit_value = &level.time;
-  gadget_level_timescore_value = &level.score[10];
-
   /* draw counter gadgets */
   for (i=ED_COUNTER_ID_LEVEL_FIRST; i<=ED_COUNTER_ID_LEVEL_LAST; i++)
   {
@@ -2110,7 +2254,7 @@ static void DrawLevelInfoWindow()
       DrawTextF(x, y, font_color, infotext);
     }
 
-    ModifyEditorCounter(i, **counterbutton_info[i].counter_value);
+    ModifyEditorCounter(i, *counterbutton_info[i].value);
     MapCounterButtons(i);
   }
 
@@ -2168,7 +2312,7 @@ static void DrawAmoebaContentArea()
   int font_color = FC_GREEN;
   int x, y;
 
-  ElementContent[0][0][0] = level.amoebe_inhalt;
+  ElementContent[0][0][0] = level.amoeba_content;
 
   /* draw decorative border for the object */
   for (y=0; y<2; y++)
@@ -2194,7 +2338,7 @@ static void DrawAmoebaContentArea()
 
 static void DrawElementContentAreas()
 {
-  int *num_areas = &MampferMax;
+  int counter_id = ED_COUNTER_ID_ELEM_CONTENT;
   int area_x = ED_AREA_ELEM_CONTENT_XPOS / MINI_TILEX;
   int area_y = ED_AREA_ELEM_CONTENT_YPOS / MINI_TILEY;
   int area_sx = SX + ED_AREA_ELEM_CONTENT_XPOS;
@@ -2204,22 +2348,21 @@ static void DrawElementContentAreas()
   int font_color = FC_GREEN;
   int i, x, y;
 
-  for (i=0; i<MAX_ELEM_CONTENT; i++)
+  for (i=0; i<MAX_ELEMENT_CONTENTS; i++)
     for (y=0; y<3; y++)
       for (x=0; x<3; x++)
-       ElementContent[i][x][y] = level.mampfer_inhalt[i][x][y];
+       ElementContent[i][x][y] = level.yam_content[i][x][y];
 
-  for (i=0; i<MAX_ELEM_CONTENT; i++)
+  for (i=0; i<MAX_ELEMENT_CONTENTS; i++)
     UnmapDrawingArea(GADGET_ID_ELEM_CONTENT_0 + i);
 
   /* display counter to choose number of element content areas */
-  gadget_elem_content_value = num_areas;
-
-  x = counterbutton_info[ED_COUNTER_ID_ELEM_CONTENT].x + xoffset_right;
-  y = counterbutton_info[ED_COUNTER_ID_ELEM_CONTENT].y + yoffset_right;
+  x = counterbutton_info[counter_id].x + xoffset_right;
+  y = counterbutton_info[counter_id].y + yoffset_right;
   DrawTextF(x, y, font_color, "number of content areas");
-  ModifyEditorCounter(ED_COUNTER_ID_ELEM_CONTENT, *gadget_elem_content_value);
-  MapCounterButtons(ED_COUNTER_ID_ELEM_CONTENT);
+
+  ModifyEditorCounter(counter_id, *counterbutton_info[counter_id].value);
+  MapCounterButtons(counter_id);
 
   /* delete content areas in case of reducing number of them */
   XFillRectangle(display, backbuffer, gc,
@@ -2227,7 +2370,7 @@ static void DrawElementContentAreas()
                 SXSIZE, 12 * MINI_TILEY);
 
   /* draw some decorative border for the objects */
-  for (i=0; i<*num_areas; i++)
+  for (i=0; i<level.num_yam_contents; i++)
   {
     for (y=0; y<4; y++)
       for (x=0; x<4; x++)
@@ -2252,7 +2395,7 @@ static void DrawElementContentAreas()
   DrawText(area_sx + (5 * 4 - 1) * MINI_TILEX, area_sy + 2 * MINI_TILEY + 1,
           "smashed", FS_SMALL, font_color);
 
-  for (i=0; i<*num_areas; i++)
+  for (i=0; i<level.num_yam_contents; i++)
   {
     for (y=0; y<3; y++)
       for (x=0; x<3; x++)
@@ -2264,7 +2407,7 @@ static void DrawElementContentAreas()
              font_color, "%d", i + 1);
   }
 
-  for (i=0; i<*num_areas; i++)
+  for (i=0; i<level.num_yam_contents; i++)
     MapDrawingArea(GADGET_ID_ELEM_CONTENT_0 + i);
 }
 
@@ -2276,6 +2419,7 @@ static void DrawElementContentAreas()
 
 static void DrawPropertiesWindow()
 {
+  int counter_id = ED_COUNTER_ID_ELEM_SCORE;
   int num_elements_in_level;
   float percentage;
   int xoffset_right = counter_xsize;
@@ -2289,55 +2433,55 @@ static void DrawPropertiesWindow()
   static struct
   {
     int element;
-    int *counter_value;
+    int *value;
     char *text;
   } elements_with_counter[] =
   {
-    { EL_EDELSTEIN,    &level.score[0],        TEXT_COLLECTING },
-    { EL_EDELSTEIN_BD, &level.score[0],        TEXT_COLLECTING },
-    { EL_EDELSTEIN_GELB,&level.score[0],       TEXT_COLLECTING },
-    { EL_EDELSTEIN_ROT,        &level.score[0],        TEXT_COLLECTING },
-    { EL_EDELSTEIN_LILA,&level.score[0],       TEXT_COLLECTING },
-    { EL_DIAMANT,      &level.score[1],        TEXT_COLLECTING },
-    { EL_KAEFER_R,     &level.score[2],        TEXT_SMASHING },
-    { EL_KAEFER_O,     &level.score[2],        TEXT_SMASHING },
-    { EL_KAEFER_L,     &level.score[2],        TEXT_SMASHING },
-    { EL_KAEFER_U,     &level.score[2],        TEXT_SMASHING },
-    { EL_BUTTERFLY_R,  &level.score[2],        TEXT_SMASHING },
-    { EL_BUTTERFLY_O,  &level.score[2],        TEXT_SMASHING },
-    { EL_BUTTERFLY_L,  &level.score[2],        TEXT_SMASHING },
-    { EL_BUTTERFLY_U,  &level.score[2],        TEXT_SMASHING },
-    { EL_FLIEGER_R,    &level.score[3],        TEXT_SMASHING },
-    { EL_FLIEGER_O,    &level.score[3],        TEXT_SMASHING },
-    { EL_FLIEGER_L,    &level.score[3],        TEXT_SMASHING },
-    { EL_FLIEGER_U,    &level.score[3],        TEXT_SMASHING },
-    { EL_FIREFLY_R,    &level.score[3],        TEXT_SMASHING },
-    { EL_FIREFLY_O,    &level.score[3],        TEXT_SMASHING },
-    { EL_FIREFLY_L,    &level.score[3],        TEXT_SMASHING },
-    { EL_FIREFLY_U,    &level.score[3],        TEXT_SMASHING },
-    { EL_MAMPFER,      &level.score[4],        TEXT_SMASHING },
-    { EL_MAMPFER2,     &level.score[4],        TEXT_SMASHING },
-    { EL_ROBOT,                &level.score[5],        TEXT_SMASHING },
-    { EL_PACMAN_R,     &level.score[6],        TEXT_SMASHING },
-    { EL_PACMAN_O,     &level.score[6],        TEXT_SMASHING },
-    { EL_PACMAN_L,     &level.score[6],        TEXT_SMASHING },
-    { EL_PACMAN_U,     &level.score[6],        TEXT_SMASHING },
-    { EL_KOKOSNUSS,    &level.score[7],        TEXT_CRACKING },
-    { EL_DYNAMIT_AUS,  &level.score[8],        TEXT_COLLECTING },
-    { EL_SCHLUESSEL1,  &level.score[9],        TEXT_COLLECTING },
-    { EL_SCHLUESSEL2,  &level.score[9],        TEXT_COLLECTING },
-    { EL_SCHLUESSEL3,  &level.score[9],        TEXT_COLLECTING },
-    { EL_SCHLUESSEL4,  &level.score[9],        TEXT_COLLECTING },
-    { EL_EM_KEY_1_FILE,        &level.score[9],        TEXT_COLLECTING },
-    { EL_EM_KEY_2_FILE,        &level.score[9],        TEXT_COLLECTING },
-    { EL_EM_KEY_3_FILE,        &level.score[9],        TEXT_COLLECTING },
-    { EL_EM_KEY_4_FILE,        &level.score[9],        TEXT_COLLECTING },
-    { EL_AMOEBE_NASS,  &level.tempo_amoebe,    TEXT_SPEED },
-    { EL_AMOEBE_NORM,  &level.tempo_amoebe,    TEXT_SPEED },
-    { EL_AMOEBE_VOLL,  &level.tempo_amoebe,    TEXT_SPEED },
-    { EL_AMOEBE_BD,    &level.tempo_amoebe,    TEXT_SPEED },
-    { EL_SIEB_INAKTIV, &level.dauer_sieb,      TEXT_DURATION },
-    { EL_ABLENK_AUS,   &level.dauer_ablenk,    TEXT_DURATION },
+    { EL_EDELSTEIN,    &level.score[SC_EDELSTEIN],     TEXT_COLLECTING },
+    { EL_EDELSTEIN_BD, &level.score[SC_EDELSTEIN],     TEXT_COLLECTING },
+    { EL_EDELSTEIN_GELB,&level.score[SC_EDELSTEIN],    TEXT_COLLECTING },
+    { EL_EDELSTEIN_ROT,        &level.score[SC_EDELSTEIN],     TEXT_COLLECTING },
+    { EL_EDELSTEIN_LILA,&level.score[SC_EDELSTEIN],    TEXT_COLLECTING },
+    { EL_DIAMANT,      &level.score[SC_DIAMANT],       TEXT_COLLECTING },
+    { EL_KAEFER_R,     &level.score[SC_KAEFER],        TEXT_SMASHING },
+    { EL_KAEFER_O,     &level.score[SC_KAEFER],        TEXT_SMASHING },
+    { EL_KAEFER_L,     &level.score[SC_KAEFER],        TEXT_SMASHING },
+    { EL_KAEFER_U,     &level.score[SC_KAEFER],        TEXT_SMASHING },
+    { EL_BUTTERFLY_R,  &level.score[SC_KAEFER],        TEXT_SMASHING },
+    { EL_BUTTERFLY_O,  &level.score[SC_KAEFER],        TEXT_SMASHING },
+    { EL_BUTTERFLY_L,  &level.score[SC_KAEFER],        TEXT_SMASHING },
+    { EL_BUTTERFLY_U,  &level.score[SC_KAEFER],        TEXT_SMASHING },
+    { EL_FLIEGER_R,    &level.score[SC_FLIEGER],       TEXT_SMASHING },
+    { EL_FLIEGER_O,    &level.score[SC_FLIEGER],       TEXT_SMASHING },
+    { EL_FLIEGER_L,    &level.score[SC_FLIEGER],       TEXT_SMASHING },
+    { EL_FLIEGER_U,    &level.score[SC_FLIEGER],       TEXT_SMASHING },
+    { EL_FIREFLY_R,    &level.score[SC_FLIEGER],       TEXT_SMASHING },
+    { EL_FIREFLY_O,    &level.score[SC_FLIEGER],       TEXT_SMASHING },
+    { EL_FIREFLY_L,    &level.score[SC_FLIEGER],       TEXT_SMASHING },
+    { EL_FIREFLY_U,    &level.score[SC_FLIEGER],       TEXT_SMASHING },
+    { EL_MAMPFER,      &level.score[SC_MAMPFER],       TEXT_SMASHING },
+    { EL_MAMPFER2,     &level.score[SC_MAMPFER],       TEXT_SMASHING },
+    { EL_ROBOT,                &level.score[SC_ROBOT],         TEXT_SMASHING },
+    { EL_PACMAN_R,     &level.score[SC_PACMAN],        TEXT_SMASHING },
+    { EL_PACMAN_O,     &level.score[SC_PACMAN],        TEXT_SMASHING },
+    { EL_PACMAN_L,     &level.score[SC_PACMAN],        TEXT_SMASHING },
+    { EL_PACMAN_U,     &level.score[SC_PACMAN],        TEXT_SMASHING },
+    { EL_KOKOSNUSS,    &level.score[SC_KOKOSNUSS],     TEXT_CRACKING },
+    { EL_DYNAMIT_AUS,  &level.score[SC_DYNAMIT],       TEXT_COLLECTING },
+    { EL_SCHLUESSEL1,  &level.score[SC_SCHLUESSEL],    TEXT_COLLECTING },
+    { EL_SCHLUESSEL2,  &level.score[SC_SCHLUESSEL],    TEXT_COLLECTING },
+    { EL_SCHLUESSEL3,  &level.score[SC_SCHLUESSEL],    TEXT_COLLECTING },
+    { EL_SCHLUESSEL4,  &level.score[SC_SCHLUESSEL],    TEXT_COLLECTING },
+    { EL_EM_KEY_1_FILE,        &level.score[SC_SCHLUESSEL],    TEXT_COLLECTING },
+    { EL_EM_KEY_2_FILE,        &level.score[SC_SCHLUESSEL],    TEXT_COLLECTING },
+    { EL_EM_KEY_3_FILE,        &level.score[SC_SCHLUESSEL],    TEXT_COLLECTING },
+    { EL_EM_KEY_4_FILE,        &level.score[SC_SCHLUESSEL],    TEXT_COLLECTING },
+    { EL_AMOEBE_NASS,  &level.amoeba_speed,            TEXT_SPEED },
+    { EL_AMOEBE_NORM,  &level.amoeba_speed,            TEXT_SPEED },
+    { EL_AMOEBE_VOLL,  &level.amoeba_speed,            TEXT_SPEED },
+    { EL_AMOEBE_BD,    &level.amoeba_speed,            TEXT_SPEED },
+    { EL_SIEB_INAKTIV, &level.time_magic_wall,         TEXT_DURATION },
+    { EL_ABLENK_AUS,   &level.time_wheel,              TEXT_DURATION },
     { -1, NULL, NULL }
   };
 
@@ -2394,14 +2538,14 @@ static void DrawPropertiesWindow()
   {
     if (elements_with_counter[i].element == properties_element)
     {
-      int x = counterbutton_info[ED_COUNTER_ID_ELEM_SCORE].x + xoffset_right;
-      int y = counterbutton_info[ED_COUNTER_ID_ELEM_SCORE].y + yoffset_right;
-
-      gadget_elem_score_value = elements_with_counter[i].counter_value;
+      int x = counterbutton_info[counter_id].x + xoffset_right;
+      int y = counterbutton_info[counter_id].y + yoffset_right;
 
+      counterbutton_info[counter_id].value = elements_with_counter[i].value;
       DrawTextF(x, y, font_color, elements_with_counter[i].text);
-      ModifyEditorCounter(ED_COUNTER_ID_ELEM_SCORE, *gadget_elem_score_value);
-      MapCounterButtons(ED_COUNTER_ID_ELEM_SCORE);
+
+      ModifyEditorCounter(counter_id,  *counterbutton_info[counter_id].value);
+      MapCounterButtons(counter_id);
       break;
     }
   }
@@ -2970,7 +3114,7 @@ static void CopyLevelToUndoBuffer(int mode)
     for(y=0; y<lev_fieldy; y++)
       UndoBuffer[undo_buffer_position][x][y] = Feld[x][y];
 
-  /* check if change of border style was forced by drawing operation */
+  /* check if drawing operation forces change of border style */
   last_border_element = BorderElement;
   SetBorderElement();
   if (BorderElement != last_border_element)
@@ -3176,12 +3320,12 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
                           el2gfx(new_element));
 
        if (id == GADGET_ID_AMOEBA_CONTENT)
-         level.amoebe_inhalt = new_element;
+         level.amoeba_content = new_element;
        else if (id == GADGET_ID_RANDOM_BACKGROUND)
          random_placement_background_element = new_element;
        else if (id >= GADGET_ID_ELEM_CONTENT_0 &&
                 id <= GADGET_ID_ELEM_CONTENT_7)
-         level.mampfer_inhalt[id - GADGET_ID_ELEM_CONTENT_0][sx][sy] =
+         level.yam_content[id - GADGET_ID_ELEM_CONTENT_0][sx][sy] =
            new_element;
       }
       break;
@@ -3289,130 +3433,54 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
 
 static void HandleCounterButtons(struct GadgetInfo *gi)
 {
-  int id = gi->custom_id;
+  int gadget_id = gi->custom_id;
+  int counter_id = gi->custom_type_id;
   int button = gi->event.button;
-  int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
+  int *counter_value = counterbutton_info[counter_id].value;
+  int step = BUTTON_STEPSIZE(button) *
+    (gadget_id == counterbutton_info[counter_id].gadget_id_down ? -1 : +1);
 
-  switch (id)
+  if (counter_id == ED_COUNTER_ID_SELECT_LEVEL)
   {
-    case GADGET_ID_ELEM_SCORE_DOWN:
-    case GADGET_ID_ELEM_SCORE_UP:
-      step *= (id == GADGET_ID_ELEM_SCORE_DOWN ? -1 : 1);
-      ModifyEditorCounter(ED_COUNTER_ID_ELEM_SCORE,
-                         *gadget_elem_score_value + step);
-      break;
-    case GADGET_ID_ELEM_SCORE_TEXT:
-      *gadget_elem_score_value = gi->text.number_value;
-      break;
-
-    case GADGET_ID_ELEM_CONTENT_DOWN:
-    case GADGET_ID_ELEM_CONTENT_UP:
-      step *= (id == GADGET_ID_ELEM_CONTENT_DOWN ? -1 : 1);
-      ModifyEditorCounter(ED_COUNTER_ID_ELEM_CONTENT,
-                         *gadget_elem_content_value + step);
-      DrawElementContentAreas();
-      break;
-    case GADGET_ID_ELEM_CONTENT_TEXT:
-      *gadget_elem_content_value = gi->text.number_value;
-      DrawElementContentAreas();
-      break;
-
-    case GADGET_ID_LEVEL_XSIZE_DOWN:
-    case GADGET_ID_LEVEL_XSIZE_UP:
-      step *= (id == GADGET_ID_LEVEL_XSIZE_DOWN ? -1 : 1);
-      ModifyEditorCounter(ED_COUNTER_ID_LEVEL_XSIZE,
-                         *gadget_level_xsize_value + step);
-      level.fieldx = lev_fieldx;
-      break;
-    case GADGET_ID_LEVEL_XSIZE_TEXT:
-      *gadget_level_xsize_value = gi->text.number_value;
-      level.fieldx = lev_fieldx;
-      break;
-
-    case GADGET_ID_LEVEL_YSIZE_DOWN:
-    case GADGET_ID_LEVEL_YSIZE_UP:
-      step *= (id == GADGET_ID_LEVEL_YSIZE_DOWN ? -1 : 1);
-      ModifyEditorCounter(ED_COUNTER_ID_LEVEL_YSIZE,
-                         *gadget_level_ysize_value + step);
-      level.fieldy = lev_fieldy;
-      break;
-    case GADGET_ID_LEVEL_YSIZE_TEXT:
-      *gadget_level_ysize_value = gi->text.number_value;
-      level.fieldy = lev_fieldy;
-      break;
-
-    case GADGET_ID_LEVEL_RANDOM_DOWN:
-    case GADGET_ID_LEVEL_RANDOM_UP:
-      step *= (id == GADGET_ID_LEVEL_RANDOM_DOWN ? -1 : 1);
-      ModifyEditorCounter(ED_COUNTER_ID_LEVEL_RANDOM,
-                         *gadget_level_random_value + step);
-      break;
-    case GADGET_ID_LEVEL_RANDOM_TEXT:
-      *gadget_level_random_value = gi->text.number_value;
-      break;
-
-    case GADGET_ID_LEVEL_COLLECT_DOWN:
-    case GADGET_ID_LEVEL_COLLECT_UP:
-      step *= (id == GADGET_ID_LEVEL_COLLECT_DOWN ? -1 : 1);
-      ModifyEditorCounter(ED_COUNTER_ID_LEVEL_COLLECT,
-                         *gadget_level_collect_value + step);
-      break;
-    case GADGET_ID_LEVEL_COLLECT_TEXT:
-      *gadget_level_collect_value = gi->text.number_value;
-      break;
-
-    case GADGET_ID_LEVEL_TIMELIMIT_DOWN:
-    case GADGET_ID_LEVEL_TIMELIMIT_UP:
-      step *= (id == GADGET_ID_LEVEL_TIMELIMIT_DOWN ? -1 : 1);
-      ModifyEditorCounter(ED_COUNTER_ID_LEVEL_TIMELIMIT,
-                         *gadget_level_timelimit_value + step);
-      break;
-    case GADGET_ID_LEVEL_TIMELIMIT_TEXT:
-      *gadget_level_timelimit_value = gi->text.number_value;
-      break;
-
-    case GADGET_ID_LEVEL_TIMESCORE_DOWN:
-    case GADGET_ID_LEVEL_TIMESCORE_UP:
-      step *= (id == GADGET_ID_LEVEL_TIMESCORE_DOWN ? -1 : 1);
-      ModifyEditorCounter(ED_COUNTER_ID_LEVEL_TIMESCORE,
-                         *gadget_level_timescore_value + step);
-      break;
-    case GADGET_ID_LEVEL_TIMESCORE_TEXT:
-      *gadget_level_timescore_value = gi->text.number_value;
-      break;
-
-    default:
-      break;
+    SelectNewLevelToEdit(gi);
+    return;
   }
+
+  if (gadget_id == counterbutton_info[counter_id].gadget_id_text)
+    *counter_value = gi->text.number_value;
+  else
+    ModifyEditorCounter(counter_id, *counter_value + step);
+
+  if (counter_id == ED_COUNTER_ID_ELEM_CONTENT)
+    DrawElementContentAreas();
+  else if (counter_id == ED_COUNTER_ID_LEVEL_XSIZE)
+    lev_fieldx = level.fieldx;
+  else if (counter_id == ED_COUNTER_ID_LEVEL_YSIZE)
+    lev_fieldy = level.fieldy;
 }
 
 static void HandleTextInputGadgets(struct GadgetInfo *gi)
 {
-  int id = gi->custom_id;
-
-  switch (id)
-  {
-    case GADGET_ID_LEVEL_NAME:
-      strcpy(level.name, gi->text.value);
-      break;
+  strcpy(textinput_info[gi->custom_type_id].value, gi->text.value);
+}
 
-    case GADGET_ID_LEVEL_AUTHOR:
-      strcpy(level.author, gi->text.value);
-      break;
+static void HandleRadiobuttons(struct GadgetInfo *gi)
+{
+  *radiobutton_info[gi->custom_type_id].value =
+    radiobutton_info[gi->custom_type_id].checked_value;
+}
 
-    default:
-      break;
-  }
+static void HandleCheckbuttons(struct GadgetInfo *gi)
+{
+  *checkbutton_info[gi->custom_type_id].value ^= TRUE;
 }
 
 static void HandleControlButtons(struct GadgetInfo *gi)
 {
   int id = gi->custom_id;
   int button = gi->event.button;
-  int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
+  int step = BUTTON_STEPSIZE(button);
   int new_element = BUTTON_ELEMENT(button);
-  int player_present = FALSE;
-  int level_changed = FALSE;
   int i, x, y;
 
   if (edit_mode == ED_MODE_DRAWING && drawing_function == GADGET_ID_TEXT)
@@ -3640,19 +3708,7 @@ static void HandleControlButtons(struct GadgetInfo *gi)
        break;
       }
 
-      for(y=0; y<lev_fieldy; y++) 
-       for(x=0; x<lev_fieldx; x++)
-         if (Feld[x][y] != Ur[x][y])
-           level_changed = TRUE;
-
-      for(y=0; y<lev_fieldy; y++) 
-       for(x=0; x<lev_fieldx; x++)
-         if (Feld[x][y] == EL_SPIELFIGUR ||
-             Feld[x][y] == EL_SPIELER1 ||
-             Feld[x][y] == EL_SP_MURPHY) 
-           player_present = TRUE;
-
-      if (!player_present)
+      if (!LevelContainsPlayer)
        Request("No Level without Gregor Mc Duffin please !", REQ_CONFIRM);
       else
       {
@@ -3667,14 +3723,7 @@ static void HandleControlButtons(struct GadgetInfo *gi)
       break;
 
     case GADGET_ID_TEST:
-      for(y=0; y<lev_fieldy; y++) 
-       for(x=0; x<lev_fieldx; x++)
-         if (Feld[x][y] == EL_SPIELFIGUR ||
-             Feld[x][y] == EL_SPIELER1 ||
-             Feld[x][y] == EL_SP_MURPHY) 
-           player_present = TRUE;
-
-      if (!player_present)
+      if (!LevelContainsPlayer)
        Request("No Level without Gregor Mc Duffin please !", REQ_CONFIRM);
       else
       {
@@ -3687,13 +3736,7 @@ static void HandleControlButtons(struct GadgetInfo *gi)
            Ur[x][y] = Feld[x][y];
 
        UnmapLevelEditorGadgets();
-
-       /* draw smaller door */
-       XCopyArea(display, pix[PIX_DOOR], drawto, gc,
-                 DOOR_GFX_PAGEX7, 64,
-                 108, 64,
-                 EX - 4, EY - 12);
-       redraw_mask |= REDRAW_ALL;
+       UndrawSpecialEditorDoor();
 
        CloseDoor(DOOR_CLOSE_ALL);
 
@@ -3710,12 +3753,7 @@ static void HandleControlButtons(struct GadgetInfo *gi)
       break;
 
     case GADGET_ID_EXIT:
-      for(y=0; y<lev_fieldy; y++) 
-       for(x=0; x<lev_fieldx; x++)
-         if (Feld[x][y] != Ur[x][y])
-           level_changed = TRUE;
-
-      if (!level_changed ||
+      if (!LevelChanged() ||
          Request("Level has changed! Exit without saving ?",
                  REQ_ASK | REQ_STAY_OPEN))
       {
@@ -3725,13 +3763,6 @@ static void HandleControlButtons(struct GadgetInfo *gi)
        CloseDoor(DOOR_CLOSE_ALL);
        */
 
-       /* draw smaller door */
-       XCopyArea(display, pix[PIX_DOOR], drawto, gc,
-                 DOOR_GFX_PAGEX7, 64,
-                 108, 64,
-                 EX - 4, EY - 12);
-       redraw_mask |= REDRAW_ALL;
-
        game_status = MAINMENU;
        DrawMainMenu();
       }
@@ -3745,32 +3776,6 @@ static void HandleControlButtons(struct GadgetInfo *gi)
       }
       break;
 
-    case GADGET_ID_RANDOM_PERCENTAGE:
-      *radiobutton_info[ED_RADIOBUTTON_ID_PERCENTAGE].value =
-       radiobutton_info[ED_RADIOBUTTON_ID_PERCENTAGE].checked_value;
-      break;
-
-    case GADGET_ID_RANDOM_QUANTITY:
-      *radiobutton_info[ED_RADIOBUTTON_ID_QUANTITY].value =
-       radiobutton_info[ED_RADIOBUTTON_ID_QUANTITY].checked_value;
-      break;
-
-    case GADGET_ID_RANDOM_RESTRICTED:
-      *checkbutton_info[ED_CHECKBUTTON_ID_RANDOM_RESTRICTED].value ^= TRUE;
-      break;
-
-    case GADGET_ID_DOUBLE_SPEED:
-      *checkbutton_info[ED_CHECKBUTTON_ID_DOUBLE_SPEED].value ^= TRUE;
-      break;
-
-    case GADGET_ID_GRAVITY:
-      *checkbutton_info[ED_CHECKBUTTON_ID_GRAVITY].value ^= TRUE;
-      break;
-
-    case GADGET_ID_STICK_ELEMENT:
-      *checkbutton_info[ED_CHECKBUTTON_ID_STICK_ELEMENT].value ^= TRUE;
-      break;
-
     default:
       if (id >= GADGET_ID_ELEMENTLIST_FIRST &&
          id <= GADGET_ID_ELEMENTLIST_LAST)