added doing 'redo' by pressing 'undo' button with Ctrl or Shift key
[rocksndiamonds.git] / src / editor.c
index 65b0ce2b0deb2927080e2933d6399c1abf876837..5a3d5cfa7f6a451ae55b54c8f5c5d0420284fae4 100644 (file)
@@ -5022,6 +5022,23 @@ static int num_editor_elements = 0;      /* dynamically determined */
 
 static boolean setup_editor_cascade_never = FALSE;
 
+static boolean setup_editor_el_players                 = TRUE;
+static boolean setup_editor_el_boulderdash             = TRUE;
+static boolean setup_editor_el_emerald_mine            = TRUE;
+static boolean setup_editor_el_emerald_mine_club       = TRUE;
+static boolean setup_editor_el_more                    = TRUE;
+static boolean setup_editor_el_sokoban                 = TRUE;
+static boolean setup_editor_el_supaplex                        = TRUE;
+static boolean setup_editor_el_diamond_caves           = TRUE;
+static boolean setup_editor_el_dx_boulderdash          = TRUE;
+static boolean setup_editor_el_mirror_magic            = TRUE;
+static boolean setup_editor_el_deflektor               = TRUE;
+static boolean setup_editor_el_chars                   = TRUE;
+static boolean setup_editor_el_steel_chars             = TRUE;
+static boolean setup_editor_el_custom                  = TRUE;
+static boolean setup_editor_el_user_defined            = TRUE;
+static boolean setup_editor_el_dynamic                 = TRUE;
+
 static int editor_hl_unused[] = { EL_EMPTY };
 static int *editor_hl_unused_ptr = editor_hl_unused;
 static int num_editor_hl_unused = 0;
@@ -5042,109 +5059,109 @@ static struct
 editor_elements_info[] =
 {
   {
-    &setup.editor.el_classic,
+    &setup_editor_el_players,
     &setup_editor_cascade_never,
     &editor_hl_unused_ptr,             &num_editor_hl_unused,
     &editor_el_players_ptr,            &num_editor_el_players
   },
   {
-    &setup.editor.el_classic,
+    &setup_editor_el_boulderdash,
     &setup.editor_cascade.el_bd,
     &editor_hl_boulderdash_ptr,                &num_editor_hl_boulderdash,
     &editor_el_boulderdash_ptr,                &num_editor_el_boulderdash
   },
   {
-    &setup.editor.el_classic,
+    &setup_editor_el_emerald_mine,
     &setup.editor_cascade.el_em,
     &editor_hl_emerald_mine_ptr,       &num_editor_hl_emerald_mine,
     &editor_el_emerald_mine_ptr,       &num_editor_el_emerald_mine
   },
   {
-    &setup.editor.el_classic,
+    &setup_editor_el_emerald_mine_club,
     &setup.editor_cascade.el_emc,
     &editor_hl_emerald_mine_club_ptr,  &num_editor_hl_emerald_mine_club,
     &editor_el_emerald_mine_club_ptr,  &num_editor_el_emerald_mine_club
   },
   {
-    &setup.editor.el_classic,
+    &setup_editor_el_more,
     &setup.editor_cascade.el_rnd,
     &editor_hl_rnd_ptr,                        &num_editor_hl_rnd,
     &editor_el_rnd_ptr,                        &num_editor_el_rnd
   },
   {
-    &setup.editor.el_classic,
+    &setup_editor_el_sokoban,
     &setup.editor_cascade.el_sb,
     &editor_hl_sokoban_ptr,            &num_editor_hl_sokoban,
     &editor_el_sokoban_ptr,            &num_editor_el_sokoban
   },
   {
-    &setup.editor.el_classic,
+    &setup_editor_el_supaplex,
     &setup.editor_cascade.el_sp,
     &editor_hl_supaplex_ptr,           &num_editor_hl_supaplex,
     &editor_el_supaplex_ptr,           &num_editor_el_supaplex
   },
   {
-    &setup.editor.el_classic,
+    &setup_editor_el_diamond_caves,
     &setup.editor_cascade.el_dc,
     &editor_hl_diamond_caves_ptr,      &num_editor_hl_diamond_caves,
     &editor_el_diamond_caves_ptr,      &num_editor_el_diamond_caves
   },
   {
-    &setup.editor.el_classic,
+    &setup_editor_el_dx_boulderdash,
     &setup.editor_cascade.el_dx,
     &editor_hl_dx_boulderdash_ptr,     &num_editor_hl_dx_boulderdash,
     &editor_el_dx_boulderdash_ptr,     &num_editor_el_dx_boulderdash
   },
   {
-    &setup.editor.el_classic,
+    &setup_editor_el_mirror_magic,
     &setup.editor_cascade.el_mm,
     &editor_hl_mirror_magic_ptr,       &num_editor_hl_mirror_magic,
     &editor_el_mirror_magic_ptr,       &num_editor_el_mirror_magic
   },
   {
-    &setup.editor.el_classic,
+    &setup_editor_el_deflektor,
     &setup.editor_cascade.el_df,
     &editor_hl_deflektor_ptr,          &num_editor_hl_deflektor,
     &editor_el_deflektor_ptr,          &num_editor_el_deflektor
   },
   {
-    &setup.editor.el_classic,
+    &setup_editor_el_chars,
     &setup.editor_cascade.el_chars,
     &editor_hl_chars_ptr,              &num_editor_hl_chars,
     &editor_el_chars_ptr,              &num_editor_el_chars
   },
   {
-    &setup.editor.el_classic,
+    &setup_editor_el_steel_chars,
     &setup.editor_cascade.el_steel_chars,
     &editor_hl_steel_chars_ptr,                &num_editor_hl_steel_chars,
     &editor_el_steel_chars_ptr,                &num_editor_el_steel_chars
   },
   {
-    &setup.editor.el_custom,
+    &setup_editor_el_custom,
     &setup.editor_cascade.el_ce,
     &editor_hl_custom_ptr,             &num_editor_hl_custom,
     &editor_el_custom_ptr,             &num_editor_el_custom
   },
   {
-    &setup.editor.el_custom,
+    &setup_editor_el_custom,
     &setup.editor_cascade.el_ge,
     &editor_hl_group_ptr,              &num_editor_hl_group,
     &editor_el_group_ptr,              &num_editor_el_group
   },
   {
-    &setup.editor.el_custom,
+    &setup_editor_el_custom,
     &setup.editor_cascade.el_ref,
     &editor_hl_reference_ptr,          &num_editor_hl_reference,
     &editor_el_reference_ptr,          &num_editor_el_reference
   },
   {
-    &setup.editor.el_user_defined,
+    &setup_editor_el_user_defined,
     &setup.editor_cascade.el_user,
     &editor_hl_user_defined_ptr,       &num_editor_hl_user_defined,
     &editor_el_user_defined_ptr,       &num_editor_el_user_defined
   },
   {
-    &setup.editor.el_dynamic,
+    &setup_editor_el_dynamic,
     &setup.editor_cascade.el_dynamic,
     &editor_hl_dynamic_ptr,            &num_editor_hl_dynamic,
     &editor_el_dynamic_ptr,            &num_editor_el_dynamic,
@@ -5309,12 +5326,122 @@ static void InitDynamicEditorElementList(int **elements, int *num_elements)
     (*elements)[(*num_elements)++] = EL_EMPTY;
 }
 
+static void ReinitializeElementList_EnableSections()
+{
+  /* default: enable all element sections */
+
+  setup_editor_el_players              = TRUE;
+  setup_editor_el_boulderdash          = TRUE;
+  setup_editor_el_emerald_mine         = TRUE;
+  setup_editor_el_emerald_mine_club    = TRUE;
+  setup_editor_el_more                 = TRUE;
+  setup_editor_el_sokoban              = TRUE;
+  setup_editor_el_supaplex             = TRUE;
+  setup_editor_el_diamond_caves                = TRUE;
+  setup_editor_el_dx_boulderdash       = TRUE;
+  setup_editor_el_mirror_magic         = TRUE;
+  setup_editor_el_deflektor            = TRUE;
+  setup_editor_el_chars                        = TRUE;
+  setup_editor_el_steel_chars          = TRUE;
+
+  setup_editor_el_custom               = TRUE;
+  setup_editor_el_user_defined         = TRUE;
+  setup_editor_el_dynamic              = TRUE;
+
+  /* now disable all element sections not to be displayed */
+
+  if (!setup.editor.el_classic)
+  {
+    setup_editor_el_players            = FALSE;
+    setup_editor_el_boulderdash                = FALSE;
+    setup_editor_el_emerald_mine       = FALSE;
+    setup_editor_el_emerald_mine_club  = FALSE;
+    setup_editor_el_more               = FALSE;
+    setup_editor_el_sokoban            = FALSE;
+    setup_editor_el_supaplex           = FALSE;
+    setup_editor_el_diamond_caves      = FALSE;
+    setup_editor_el_dx_boulderdash     = FALSE;
+    setup_editor_el_mirror_magic       = FALSE;
+    setup_editor_el_deflektor          = FALSE;
+    setup_editor_el_chars              = FALSE;
+    setup_editor_el_steel_chars                = FALSE;
+  }
+
+  if (!setup.editor.el_custom)
+  {
+    setup_editor_el_custom             = FALSE;
+  }
+
+  if (!setup.editor.el_user_defined)
+  {
+    setup_editor_el_user_defined       = FALSE;
+  }
+
+  if (!setup.editor.el_dynamic)
+  {
+    setup_editor_el_dynamic            = FALSE;
+  }
+
+  if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
+  {
+    setup_editor_el_mirror_magic       = FALSE;
+    setup_editor_el_deflektor          = FALSE;
+  }
+  else if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
+  {
+    setup_editor_el_boulderdash                = FALSE;
+    setup_editor_el_more               = FALSE;
+    setup_editor_el_sokoban            = FALSE;
+    setup_editor_el_supaplex           = FALSE;
+    setup_editor_el_dx_boulderdash     = FALSE;
+    setup_editor_el_mirror_magic       = FALSE;
+    setup_editor_el_deflektor          = FALSE;
+    setup_editor_el_steel_chars                = FALSE;
+
+    setup_editor_el_custom             = FALSE;
+  }
+  else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
+  {
+    setup_editor_el_players            = FALSE;
+    setup_editor_el_boulderdash                = FALSE;
+    setup_editor_el_emerald_mine       = FALSE;
+    setup_editor_el_emerald_mine_club  = FALSE;
+    setup_editor_el_more               = FALSE;
+    setup_editor_el_sokoban            = FALSE;
+    setup_editor_el_diamond_caves      = FALSE;
+    setup_editor_el_dx_boulderdash     = FALSE;
+    setup_editor_el_mirror_magic       = FALSE;
+    setup_editor_el_deflektor          = FALSE;
+    setup_editor_el_chars              = FALSE;
+    setup_editor_el_steel_chars                = FALSE;
+
+    setup_editor_el_custom             = FALSE;
+  }
+  else if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
+  {
+    setup_editor_el_players            = FALSE;
+    setup_editor_el_boulderdash                = FALSE;
+    setup_editor_el_emerald_mine       = FALSE;
+    setup_editor_el_emerald_mine_club  = FALSE;
+    setup_editor_el_more               = FALSE;
+    setup_editor_el_sokoban            = FALSE;
+    setup_editor_el_supaplex           = FALSE;
+    setup_editor_el_diamond_caves      = FALSE;
+    setup_editor_el_dx_boulderdash     = FALSE;
+    setup_editor_el_steel_chars                = FALSE;
+
+    setup_editor_el_custom             = FALSE;
+  }
+}
+
 static void ReinitializeElementList()
 {
   static boolean initialization_needed = TRUE;
   int pos = 0;
   int i, j;
 
+  ReinitializeElementList_EnableSections();
+
   if (initialization_needed)
   {
     LoadSetup_EditorCascade();         /* load last editor cascade state */
@@ -5594,6 +5721,11 @@ static void DrawEditorElement(int x, int y, int element)
   DrawSizedElement(x, y, element, ed_tilesize);
 }
 
+static void DrawEditorElementThruMask(int x, int y, int element)
+{
+  DrawSizedElementThruMask(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);
@@ -6080,7 +6212,7 @@ static void CreateDrawingAreas()
 
     event_mask =
       GD_EVENT_PRESSED | GD_EVENT_RELEASED | GD_EVENT_MOVING |
-      GD_EVENT_OFF_BORDERS;
+      GD_EVENT_OFF_BORDERS | GD_EVENT_PIXEL_PRECISE;
 
     /* determine horizontal position to the right of specified gadget */
     if (drawingarea_info[i].gadget_id_align != GADGET_ID_NONE)
@@ -8304,6 +8436,9 @@ static void PickDrawingElement(int button, int element)
   if (button < 1 || button > 3)
     return;
 
+  if (IS_MM_WALL(element))
+    element = map_mm_wall_element(element);
+
   de = drawing_elements[button - 1];
 
   *de.new_element = element;   // update global drawing element variable
@@ -10009,10 +10144,32 @@ static int getClosedChip(int x, int y)
   return getChipFromOpenDirectionNotEmpty(direction_new, element_old);
 }
 
-static void SetElementSimple(int x, int y, int element, boolean change_level)
+static void SetElementSimpleExt(int x, int y, int dx, int dy, int element,
+                               boolean change_level)
 {
   int sx = x - level_xpos;
   int sy = y - level_ypos;
+  int old_element = Feld[x][y];
+  unsigned int new_bitmask = (dx + 1) << (dy * 2);
+  boolean draw_masked = FALSE;
+
+  if (IS_MM_WALL_EDITOR(element))
+  {
+    element = map_mm_wall_element_editor(element) | new_bitmask;
+
+    if (IS_MM_WALL(old_element))
+      element |= MM_WALL_BITS(old_element);
+
+    if (!change_level)
+      draw_masked = TRUE;
+  }
+  else if (IS_MM_WALL(old_element) && element == EL_EMPTY)
+  {
+    int element_changed = old_element & ~new_bitmask;
+
+    if (MM_WALL_BITS(element_changed) != 0)
+      element = element_changed;
+  }
 
   IntelliDrawBuffer[x][y] = element;
 
@@ -10020,7 +10177,17 @@ static void SetElementSimple(int x, int y, int element, boolean change_level)
     Feld[x][y] = element;
 
   if (IN_ED_FIELD(sx, sy))
-    DrawEditorElement(sx, sy, element);
+  {
+    if (draw_masked)
+      DrawEditorElementThruMask(sx, sy, element);
+    else
+      DrawEditorElement(sx, sy, element);
+  }
+}
+
+static void SetElementSimple(int x, int y, int element, boolean change_level)
+{
+  SetElementSimpleExt(x, y, 0, 0, element, change_level);
 }
 
 static void MergeAndCloseNeighbourElements(int x1, int y1, int *element1,
@@ -10540,33 +10707,71 @@ static void ResetIntelliDraw()
   SetElementIntelliDraw(-1, -1, EL_UNDEFINED, FALSE, -1);
 }
 
-static void SetElementExt(int x, int y, int element, boolean change_level,
-                         int button)
+static void SetElementExt(int x, int y, int dx, int dy, int element,
+                         boolean change_level, int button)
 {
   if (element < 0)
     SetElementSimple(x, y, Feld[x][y], change_level);
-  else if (GetKeyModState() & KMOD_Shift)
+  else if (GetKeyModState() & KMOD_Shift && !IS_MM_WALL_EDITOR(element))
     SetElementIntelliDraw(x, y, element, change_level, button);
   else
-    SetElementSimple(x, y, element, change_level);
+    SetElementSimpleExt(x, y, dx, dy, element, change_level);
 }
 
 static void SetElement(int x, int y, int element)
 {
-  SetElementExt(x, y, element, TRUE, -1);
+  SetElementExt(x, y, 0, 0, element, TRUE, -1);
 }
 
-static void SetElementButton(int x, int y, int element, int button)
+static void SetElementButton(int x, int y, int dx, int dy, int element,
+                            int button)
 {
-  SetElementExt(x, y, element, TRUE, button);
+  SetElementExt(x, y, dx, dy, element, TRUE, button);
 }
 
-static void DrawLineElement(int sx, int sy, int element, boolean change_level)
+static void SetElementHiRes(int sx2, int sy2, int element, boolean change_level)
 {
-  int lx = sx + level_xpos;
-  int ly = sy + level_ypos;
+  int lx = sx2 / 2 + level_xpos;
+  int ly = sy2 / 2 + level_ypos;
+  int dx = sx2 % 2;
+  int dy = sy2 % 2;
+
+  SetElementExt(lx, ly, dx, dy, element, change_level, -1);
+}
+
+static void SetLevelElementHiRes(int lx2, int ly2, int element)
+{
+  int lx = lx2 / 2;
+  int ly = ly2 / 2;
+  int dx = lx2 % 2;
+  int dy = ly2 % 2;
 
-  SetElementExt(lx, ly, element, change_level, -1);
+  SetElementExt(lx, ly, dx, dy, element, TRUE, -1);
+}
+
+static int getLevelElementHiRes(int lx2, int ly2)
+{
+  int lx = lx2 / 2;
+  int ly = ly2 / 2;
+  int dx = lx2 % 2;
+  int dy = ly2 % 2;
+  int element = Feld[lx][ly];
+  unsigned int bitmask = (dx + 1) << (dy * 2);
+
+  if (IS_MM_WALL(element))
+  {
+    if (element & bitmask)
+      return map_mm_wall_element(element);
+    else
+      return EL_EMPTY;
+  }
+
+  return element;
+}
+
+static void DrawLineElement(int sx2, int sy2, int element, boolean change_level)
+{
+  SetElementHiRes(sx2, sy2, element, change_level);
 }
 
 static void DrawLine(int from_x, int from_y, int to_x, int to_y,
@@ -10654,32 +10859,32 @@ static void DrawArcExt(int from_x, int from_y, int to_x2, int to_y2,
 
   for (x = 0; x <= radius; x++)
   {
-    int sx, sy, lx, ly;
+    int sx2, sy2, lx, ly;
 
     y = (int)(sqrt((float)(radius * radius - x * x)) + 0.5);
 
-    sx = from_x + x * (from_x < to_x2 ? +1 : -1);
-    sy = from_y + y * (from_y < to_y2 ? +1 : -1);
-    lx = sx + level_xpos;
-    ly = sy + level_ypos;
+    sx2 = from_x + x * (from_x < to_x2 ? +1 : -1);
+    sy2 = from_y + y * (from_y < to_y2 ? +1 : -1);
+    lx = sx2 / 2 + level_xpos;
+    ly = sy2 / 2 + level_ypos;
 
-    if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
-      DrawLineElement(sx, sy, element, change_level);
+    if (IN_ED_FIELD(sx2 / 2, sy2 / 2) && IN_LEV_FIELD(lx, ly))
+      DrawLineElement(sx2, sy2, element, change_level);
   }
 
   for (y = 0; y <= radius; y++)
   {
-    int sx, sy, lx, ly;
+    int sx2, sy2, lx, ly;
 
     x = (int)(sqrt((float)(radius * radius - y * y)) + 0.5);
 
-    sx = from_x + x * (from_x < to_x2 ? +1 : -1);
-    sy = from_y + y * (from_y < to_y2 ? +1 : -1);
-    lx = sx + level_xpos;
-    ly = sy + level_ypos;
+    sx2 = from_x + x * (from_x < to_x2 ? +1 : -1);
+    sy2 = from_y + y * (from_y < to_y2 ? +1 : -1);
+    lx = sx2 / 2 + level_xpos;
+    ly = sy2 / 2 + level_ypos;
 
-    if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
-      DrawLineElement(sx, sy, element, change_level);
+    if (IN_ED_FIELD(sx2 / 2, sy2 / 2) && IN_LEV_FIELD(lx, ly))
+      DrawLineElement(sx2, sy2, element, change_level);
   }
 }
 
@@ -10737,11 +10942,17 @@ static void DrawAreaBorder(int from_x, int from_y, int to_x, int to_y)
     redraw_mask |= REDRAW_FIELD;
 }
 
+static void DrawAreaBox(int from_x, int from_y, int to_x, int to_y,
+                       int element, boolean change_level)
+{
+  DrawBox(from_x * 2, from_y * 2, to_x * 2, to_y * 2, element, change_level);
+}
+
 static void SelectArea(int from_x, int from_y, int to_x, int to_y,
                       int element, boolean change_level)
 {
   if (element == -1 || change_level)
-    DrawBox(from_x, from_y, to_x, to_y, -1, FALSE);
+    DrawAreaBox(from_x, from_y, to_x, to_y, -1, FALSE);
   else
     DrawAreaBorder(from_x, from_y, to_x, to_y);
 }
@@ -10754,6 +10965,11 @@ static void SelectArea(int from_x, int from_y, int to_x, int to_y,
 #define CB_DUMP_BRUSH          4
 #define CB_DUMP_BRUSH_SMALL    5
 
+static void DrawBrushElement(int sx, int sy, int element, boolean change_level)
+{
+  DrawLineElement(sx * 2, sy * 2, element, change_level);
+}
+
 static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y,
                         int button, int mode)
 {
@@ -10826,7 +11042,7 @@ static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y,
        brush_buffer[x][y] = Feld[from_lx + x][from_ly + y];
 
        if (button != 1)
-         DrawLineElement(from_x + x, from_y + y, new_element, TRUE);
+         DrawBrushElement(from_x + x, from_y + y, new_element, TRUE);
       }
     }
 
@@ -10879,7 +11095,7 @@ static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y,
          else if (sy > border_to_y)
            border_to_y = sy;
 
-         DrawLineElement(sx, sy, element, change_level);
+         DrawBrushElement(sx, sy, element, change_level);
        }
       }
     }
@@ -10929,6 +11145,28 @@ static void FloodFill(int from_x, int from_y, int fill_element)
   FloodFillLevel(from_x, from_y, fill_element, Feld, lev_fieldx, lev_fieldy);
 }
 
+static void FloodFillWall_MM(int from_sx2, int from_sy2, int fill_element)
+{
+  int from_x = from_sx2 + 2 * level_xpos;
+  int from_y = from_sy2 + 2 * level_ypos;
+  int max_fillx = lev_fieldx * 2;
+  int max_filly = lev_fieldy * 2;
+  short FillFeld[max_fillx][max_filly];
+  int x, y;
+
+  for (x = 0; x < max_fillx; x++)
+    for (y = 0; y < max_filly; y++)
+      FillFeld[x][y] = getLevelElementHiRes(x, y);
+
+  FloodFillLevelExt(from_x, from_y, fill_element, max_fillx, max_filly,
+                   FillFeld, max_fillx, max_filly);
+
+  for (x = 0; x < max_fillx; x++)
+    for (y = 0; y < max_filly; y++)
+      if (FillFeld[x][y] == fill_element)
+       SetLevelElementHiRes(x, y, FillFeld[x][y]);
+}
+
 /* values for DrawLevelText() modes */
 #define TEXT_INIT              0
 #define TEXT_SETCURSOR         1
@@ -11195,6 +11433,8 @@ void WrapLevel(int dx, int dy)
 static void HandleDrawingAreas(struct GadgetInfo *gi)
 {
   static boolean started_inside_drawing_area = FALSE;
+  static int last_sx = -1, last_sy = -1;
+  static int last_sx2 = -1, last_sy2 = -1;
   int id = gi->custom_id;
   int type_id = gi->custom_type_id;
   boolean button_press_event;
@@ -11208,14 +11448,16 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
   int min_sx = 0, min_sy = 0;
   int max_sx = gi->drawing.area_xsize - 1, max_sy = gi->drawing.area_ysize - 1;
   int item_xsize = gi->drawing.item_xsize, item_ysize = gi->drawing.item_ysize;
+  int mini_item_xsize = item_xsize / 2, mini_item_ysize = item_ysize / 2;
+  int sx2 = gi->event.mx / mini_item_xsize;
+  int sy2 = gi->event.my / mini_item_ysize;
+  int dx = sx2 % 2;
+  int dy = sy2 % 2;
   int lx = 0, ly = 0;
   int min_lx = 0, min_ly = 0;
   int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
   int x, y;
 
-  /* handle info callback for each invocation of action callback */
-  gi->callback_info(gi);
-
   button_press_event = (gi->event.type == GD_EVENT_PRESSED);
   button_release_event = (gi->event.type == GD_EVENT_RELEASED);
 
@@ -11241,6 +11483,39 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
     sy = ly - level_ypos;
   }
 
+  /* also correct MM wall-sized (double) drawing area positions accordingly */
+  if (sx2 / 2 < sx || sx2 / 2 > sx)
+  {
+    sx2 = sx * 2;
+    dx = (sx2 / 2 < sx ? 0 : 1);
+  }
+  if (sy2 / 2 < sy || sy2 / 2 > sy)
+  {
+    sy2 = sy * 2;
+    dy = (sy2 / 2 < sy ? 0 : 1);
+  }
+
+  if (button_release_event)
+  {
+    last_sx = -1;
+    last_sy = -1;
+    last_sx2 = -1;
+    last_sy2 = -1;
+  }
+  else if (!button_press_event)
+  {
+    /* prevent handling events for every pixel position when moving mouse */
+    if ((sx == last_sx && sy == last_sy &&
+        !IS_MM_WALL_EDITOR(new_element) && new_element != EL_EMPTY) ||
+       (sx2 == last_sx2 && sy2 == last_sy2))
+      return;
+  }
+
+  last_sx = sx;
+  last_sy = sy;
+  last_sx2 = sx2;
+  last_sy2 = sy2;
+
   if (button_press_event)
     started_inside_drawing_area = inside_drawing_area;
 
@@ -11253,6 +11528,9 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
   if (!button && !button_release_event)
     return;
 
+  /* handle info callback for each invocation of action callback */
+  gi->callback_info(gi);
+
   /* automatically switch to 'single item' drawing mode, if needed */
   actual_drawing_function =
     (draw_level || drawing_function == GADGET_ID_PICK_ELEMENT ?
@@ -11303,7 +11581,7 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
                  SetElement(x, y, EL_EMPTY);
          }
 
-         SetElementButton(lx, ly, new_element, button);
+         SetElementButton(lx, ly, dx, dy, new_element, button);
        }
       }
       else if (!button_release_event)
@@ -11347,6 +11625,9 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
 
        if (button)
        {
+         sx = sx2;
+         sy = sy2;
+
          if (!button_press_event)
            DrawLine(last_sx, last_sy, sx, sy, new_element, TRUE);
 
@@ -11360,6 +11641,9 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
     case GADGET_ID_ARC:
     case GADGET_ID_RECTANGLE:
     case GADGET_ID_FILLED_BOX:
+      sx = sx2;
+      sy = sy2;
+      /* FALLTHROUGH */
     case GADGET_ID_GRAB_BRUSH:
     case GADGET_ID_TEXT:
       {
@@ -11410,6 +11694,8 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
        else if (last_sx != sx || last_sy != sy)
        {
          draw_func(start_sx, start_sy, last_sx, last_sy, -1, FALSE);
+          if (IS_MM_WALL_EDITOR(new_element))  /* clear wall background */
+            draw_func(start_sx, start_sy, sx, sy, EL_EMPTY, FALSE);
          draw_func(start_sx, start_sy, sx, sy, new_element, FALSE);
          last_sx = sx;
          last_sy = sy;
@@ -11420,7 +11706,11 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
     case GADGET_ID_FLOOD_FILL:
       if (button_press_event && Feld[lx][ly] != new_element)
       {
-       FloodFill(lx, ly, new_element);
+       if (IS_MM_WALL_EDITOR(new_element))
+         FloodFillWall_MM(sx2, sy2, new_element);
+       else
+         FloodFill(lx, ly, new_element);
+
        DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
        CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
       }
@@ -11616,6 +11906,12 @@ static void HandleSelectboxGadgets(struct GadgetInfo *gi)
 
     level.changed = TRUE;
   }
+  else if (type_id == ED_SELECTBOX_ID_GAME_ENGINE_TYPE)
+  {
+    /* update element selection list */
+    ReinitializeElementList();
+    ModifyEditorElementList();
+  }
 }
 
 static void HandleTextbuttonGadgets(struct GadgetInfo *gi)
@@ -12121,8 +12417,13 @@ static void HandleControlButtons(struct GadgetInfo *gi)
       InitZoomLevelSettings();
 
       if (edit_mode == ED_MODE_DRAWING)
+      {
        DrawDrawingWindow();
 
+       /* redraw zoom gadget info text */
+       PrintEditorGadgetInfoText(level_editor_gadget[id]);
+      }
+
       break;
 
     case GADGET_ID_CUSTOM_COPY_FROM:
@@ -12141,6 +12442,9 @@ static void HandleControlButtons(struct GadgetInfo *gi)
       break;
 
     case GADGET_ID_UNDO:
+      if (button == 1 && GetKeyModState() & (KMOD_Shift|KMOD_Control))
+       button = 3;
+
       if (button == 1 && undo_buffer_steps == 0)
       {
        Request("Undo buffer empty!", REQ_CONFIRM);
@@ -12608,7 +12912,7 @@ void PrintEditorGadgetInfoText(struct GadgetInfo *gi)
       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);
+       sprintf(shortcut, " ('%c', '0', '-')", key);
       else
        sprintf(shortcut, " ('%s%c')",
                (key >= 'A' && key <= 'Z' ? "Shift-" : ""), key);