added option to rotate newly created gray ball content for MM engine
[rocksndiamonds.git] / src / editor.c
index 833dce2ec7996d81f106a9d3522178bb274753bc..c0fc04466e000ece5d8a5de2f9a75314f08214c7 100644 (file)
@@ -459,6 +459,9 @@ enum
   GADGET_ID_INVENTORY_SIZE_DOWN,
   GADGET_ID_INVENTORY_SIZE_TEXT,
   GADGET_ID_INVENTORY_SIZE_UP,
+  GADGET_ID_MM_BALL_CONTENT_DOWN,
+  GADGET_ID_MM_BALL_CONTENT_TEXT,
+  GADGET_ID_MM_BALL_CONTENT_UP,
   GADGET_ID_CUSTOM_SCORE_DOWN,
   GADGET_ID_CUSTOM_SCORE_TEXT,
   GADGET_ID_CUSTOM_SCORE_UP,
@@ -539,6 +542,7 @@ enum
   GADGET_ID_ARTWORK_ELEMENT,
   GADGET_ID_EXPLOSION_ELEMENT,
   GADGET_ID_INVENTORY_CONTENT,
+  GADGET_ID_MM_BALL_CONTENT,
   GADGET_ID_CUSTOM_GRAPHIC,
   GADGET_ID_CUSTOM_CONTENT,
   GADGET_ID_CUSTOM_MOVE_ENTER,
@@ -570,6 +574,7 @@ enum
   GADGET_ID_LEVELSET_SAVE_MODE,
   GADGET_ID_WIND_DIRECTION,
   GADGET_ID_PLAYER_SPEED,
+  GADGET_ID_MM_BALL_CHOICE_MODE,
   GADGET_ID_CUSTOM_WALK_TO_ACTION,
   GADGET_ID_CUSTOM_EXPLOSION_TYPE,
   GADGET_ID_CUSTOM_DEADLINESS,
@@ -682,6 +687,7 @@ enum
   GADGET_ID_DF_LASER_RED,
   GADGET_ID_DF_LASER_GREEN,
   GADGET_ID_DF_LASER_BLUE,
+  GADGET_ID_ROTATE_MM_BALL_CONTENT,
   GADGET_ID_CUSTOM_INDESTRUCTIBLE,
   GADGET_ID_CUSTOM_CAN_EXPLODE,
   GADGET_ID_CUSTOM_EXPLODE_FIRE,
@@ -750,6 +756,7 @@ enum
   ED_COUNTER_ID_ENVELOPE_XSIZE,
   ED_COUNTER_ID_ENVELOPE_YSIZE,
   ED_COUNTER_ID_INVENTORY_SIZE,
+  ED_COUNTER_ID_MM_BALL_CONTENT,
   ED_COUNTER_ID_CUSTOM_SCORE,
   ED_COUNTER_ID_CUSTOM_GEMCOUNT,
   ED_COUNTER_ID_CUSTOM_VALUE_FIX,
@@ -856,6 +863,7 @@ enum
   ED_SELECTBOX_ID_LEVELSET_SAVE_MODE,
   ED_SELECTBOX_ID_WIND_DIRECTION,
   ED_SELECTBOX_ID_PLAYER_SPEED,
+  ED_SELECTBOX_ID_MM_BALL_CHOICE_MODE,
   ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE,
   ED_SELECTBOX_ID_CUSTOM_ACCESS_LAYER,
   ED_SELECTBOX_ID_CUSTOM_ACCESS_PROTECTED,
@@ -993,6 +1001,7 @@ enum
   ED_CHECKBUTTON_ID_DF_LASER_RED,
   ED_CHECKBUTTON_ID_DF_LASER_GREEN,
   ED_CHECKBUTTON_ID_DF_LASER_BLUE,
+  ED_CHECKBUTTON_ID_ROTATE_MM_BALL_CONTENT,
   ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC,
   ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1,
   ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE,
@@ -1079,6 +1088,7 @@ enum
   ED_DRAWING_ID_ARTWORK_ELEMENT,
   ED_DRAWING_ID_EXPLOSION_ELEMENT,
   ED_DRAWING_ID_INVENTORY_CONTENT,
+  ED_DRAWING_ID_MM_BALL_CONTENT,
   ED_DRAWING_ID_CUSTOM_GRAPHIC,
   ED_DRAWING_ID_CUSTOM_CONTENT,
   ED_DRAWING_ID_CUSTOM_MOVE_ENTER,
@@ -1533,6 +1543,14 @@ static struct
     &level.initial_inventory_size[0],
     NULL,                              NULL, "number of inventory elements"
   },
+  {
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(3),
+    MIN_ELEMENTS_IN_GROUP,             MAX_MM_BALL_CONTENTS,
+    GADGET_ID_MM_BALL_CONTENT_DOWN,    GADGET_ID_MM_BALL_CONTENT_UP,
+    GADGET_ID_MM_BALL_CONTENT_TEXT,    GADGET_ID_NONE,
+    &level.num_mm_ball_contents,
+    NULL,                              NULL, "number of content elements"
+  },
 
   // ---------- element settings: configure 1 (custom elements) ---------------
 
@@ -1743,7 +1761,7 @@ static struct
   int gadget_id;
   int xsize, ysize;
   char *value;
-  char *text_above, *infotext;
+  char *text_above, *text_above_cropped, *infotext;
 } textarea_info[ED_NUM_TEXTAREAS] =
 {
   {
@@ -1751,7 +1769,7 @@ static struct
     GADGET_ID_ENVELOPE_INFO,
     MAX_ENVELOPE_XSIZE, MAX_ENVELOPE_YSIZE,
     NULL,
-    "Envelope Content:", "Envelope Content"
+    "Envelope Content:", "Envelope Content (cropped):", "Envelope Content"
   }
 };
 
@@ -2555,6 +2573,14 @@ static struct
     &level.initial_player_stepsize[0],
     NULL, "initial player speed:", NULL,       "initial player speed"
   },
+  {
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(4),
+    GADGET_ID_MM_BALL_CHOICE_MODE,     GADGET_ID_NONE,
+    -1,
+    options_group_choice_mode,
+    &level.mm_ball_choice_mode,
+    NULL, "choice type:", NULL,                "type of content choice"
+  },
 
   // ---------- element settings: configure 1 (custom elements) ---------------
 
@@ -3354,6 +3380,13 @@ static struct
     NULL, NULL,
     "blue",                            "use blue color components in laser"
   },
+  {
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(5),
+    GADGET_ID_ROTATE_MM_BALL_CONTENT,  GADGET_ID_NONE,
+    &level.rotate_mm_ball_content,
+    NULL, NULL,
+    "randomly rotate created content", "randomly rotate newly created content"
+  },
 
   // ---------- element settings: configure 1 (custom elements) ---------------
 
@@ -3740,6 +3773,16 @@ static struct
     NULL, NULL, NULL, NULL,            "content for initial inventory"
   },
 
+  // ---------- gray ball content -----------------------------------------
+
+  {
+    ED_AREA_1X1_SETTINGS_XPOS(0),      ED_AREA_1X1_SETTINGS_YPOS(2),
+    ED_AREA_1X1_SETTINGS_XOFF,         ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_MM_BALL_CONTENT,         GADGET_ID_NONE,
+    &level.mm_ball_content[0],         MAX_MM_BALL_CONTENTS, 1,
+    "content:", NULL, NULL, NULL,      "content for gray ball"
+  },
+
   // ---------- element settings: configure 1 (custom elements) ---------------
 
   // ---------- custom graphic ------------------------------------------------
@@ -4610,7 +4653,12 @@ static int editor_el_mirror_magic[] =
   EL_MM_WOODEN_GRID_FIXED_1,
   EL_MM_WOODEN_GRID_FIXED_2,
   EL_MM_WOODEN_GRID_FIXED_3,
-  EL_MM_WOODEN_GRID_FIXED_4
+  EL_MM_WOODEN_GRID_FIXED_4,
+
+  EL_MM_ENVELOPE_1,
+  EL_MM_ENVELOPE_2,
+  EL_MM_ENVELOPE_3,
+  EL_MM_ENVELOPE_4
 };
 static int *editor_hl_mirror_magic_ptr = editor_hl_mirror_magic;
 static int *editor_el_mirror_magic_ptr = editor_el_mirror_magic;
@@ -5892,10 +5940,10 @@ static void ReinitializeElementList(void)
   // determine size of element list
   for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
   {
-    boolean found_inactive_cascade = FALSE;
-
     if (*editor_elements_info[i].setup_value)
     {
+      boolean found_inactive_cascade = FALSE;
+
       if (setup.editor.el_headlines)
       {
        // required for correct padding of palette headline buttons
@@ -6502,11 +6550,9 @@ static void CreateCounterButtons(void)
       int graphic;
       struct GraphicInfo *gd;
       int gd_x1, gd_x2, gd_y1, gd_y2;
-      unsigned int event_mask;
+      unsigned int event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
       char infotext[max_infotext_len + 1];
 
-      event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
-
       if (i == ED_COUNTER_ID_SELECT_LEVEL)
       {
        graphic = (j == 0 ?
@@ -6646,7 +6692,6 @@ static void CreateDrawingAreas(void)
   for (i = 0; i < ED_NUM_DRAWING_AREAS; i++)
   {
     struct GadgetInfo *gi;
-    unsigned int event_mask;
     int id = drawingarea_info[i].gadget_id;
     int x = SX + ED_AREA_SETTINGS_X(drawingarea_info[i]);
     int y = SY + ED_AREA_SETTINGS_Y(drawingarea_info[i]);
@@ -6654,8 +6699,7 @@ static void CreateDrawingAreas(void)
     int area_ysize = drawingarea_info[i].area_ysize;
     int item_size = (id == GADGET_ID_DRAWING_LEVEL ?
                     ed_tilesize : ED_DRAWINGAREA_TILE_SIZE);
-
-    event_mask =
+    unsigned int event_mask =
       GD_EVENT_PRESSED | GD_EVENT_RELEASED | GD_EVENT_MOVING |
       GD_EVENT_OFF_BORDERS | GD_EVENT_PIXEL_PRECISE;
 
@@ -6702,7 +6746,7 @@ static void CreateTextInputGadgets(void)
     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;
+    unsigned int event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
     char infotext[MAX_OUTPUT_LINESIZE + 1];
     int id = textinput_info[i].gadget_id;
     int x, y;
@@ -6729,8 +6773,6 @@ static void CreateTextInputGadgets(void)
       y = ED_SETTINGS_Y(textinput_info[i].y);
     }
 
-    event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
-
     sprintf(infotext, "Enter %s", textinput_info[i].infotext);
     infotext[max_infotext_len] = '\0';
 
@@ -6773,14 +6815,12 @@ static void CreateTextAreaGadgets(void)
     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;
+    unsigned int event_mask = GD_EVENT_TEXT_LEAVING;
     char infotext[MAX_OUTPUT_LINESIZE + 1];
     int id = textarea_info[i].gadget_id;
     int area_xsize = textarea_info[i].xsize;
     int area_ysize = textarea_info[i].ysize;
 
-    event_mask = GD_EVENT_TEXT_LEAVING;
-
     sprintf(infotext, "Enter %s", textarea_info[i].infotext);
     infotext[max_infotext_len] = '\0';
 
@@ -6824,11 +6864,12 @@ static void CreateSelectboxGadgets(void)
     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];
     int id = selectbox_info[i].gadget_id;
     int x = SX + ED_SETTINGS_X(selectbox_info[i].x);
     int y = SY + ED_SETTINGS_Y(selectbox_info[i].y);
+    unsigned int event_mask =
+      GD_EVENT_RELEASED | GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
 
     if (selectbox_info[i].size == -1)  // dynamically determine size
     {
@@ -6844,9 +6885,6 @@ static void CreateSelectboxGadgets(void)
       selectbox_info[i].size++;                // add one character empty space
     }
 
-    event_mask = GD_EVENT_RELEASED |
-      GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
-
     // 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] +
@@ -6915,7 +6953,7 @@ static void CreateTextbuttonGadgets(void)
     int border_xsize = gd->border_size + gd->draw_xoffset;
     int border_ysize = gd->border_size;
     struct GadgetInfo *gi;
-    unsigned int event_mask;
+    unsigned int event_mask = GD_EVENT_RELEASED;
     char infotext[MAX_OUTPUT_LINESIZE + 1];
     int x = SX + ED_SETTINGS_X(textbutton_info[i].x);
     int y = SY + ED_SETTINGS_Y(textbutton_info[i].y);
@@ -6923,8 +6961,6 @@ static void CreateTextbuttonGadgets(void)
     if (textbutton_info[i].size == -1) // dynamically determine size
       textbutton_info[i].size = strlen(textbutton_info[i].text);
 
-    event_mask = GD_EVENT_RELEASED;
-
     sprintf(infotext, "%s", textbutton_info[i].infotext);
     infotext[max_infotext_len] = '\0';
 
@@ -6977,7 +7013,6 @@ static void CreateTextbuttonGadgets(void)
 static void CreateGraphicbuttonGadgets(void)
 {
   struct GadgetInfo *gi;
-  unsigned int event_mask;
   int i;
 
   // create buttons for scrolling of drawing area and element list
@@ -6992,8 +7027,7 @@ static void CreateGraphicbuttonGadgets(void)
     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;
+    unsigned int event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
 
     // determine horizontal position to the right of specified gadget
     if (graphicbutton_info[i].gadget_id_align != GADGET_ID_NONE)
@@ -7085,7 +7119,7 @@ static void CreateScrollbarGadgets(void)
     int gd_y2 = gd->src_y + gd->pressed_yoffset;
     struct GadgetInfo *gi;
     int items_max, items_visible, item_position;
-    unsigned int event_mask;
+    unsigned int event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS;
 
     if (i == ED_SCROLLBAR_ID_LIST_VERTICAL)
     {
@@ -7109,8 +7143,6 @@ static void CreateScrollbarGadgets(void)
       }
     }
 
-    event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS;
-
     gi = CreateGadget(GDI_CUSTOM_ID, id,
                      GDI_CUSTOM_TYPE_ID, i,
                      GDI_IMAGE_ID, graphic,
@@ -7146,11 +7178,8 @@ static void CreateScrollbarGadgets(void)
 static void CreateCheckbuttonGadgets(void)
 {
   struct GadgetInfo *gi;
-  unsigned int event_mask;
   int i;
 
-  event_mask = GD_EVENT_PRESSED;
-
   for (i = 0; i < ED_NUM_CHECKBUTTONS; i++)
   {
     int id = checkbutton_info[i].gadget_id;
@@ -7167,6 +7196,7 @@ static void CreateCheckbuttonGadgets(void)
     int gd_y2a = gd->src_y + gd->active_yoffset + gd->pressed_yoffset;
     int x = SX + ED_SETTINGS_X(checkbutton_info[i].x);
     int y = SY + ED_SETTINGS_Y(checkbutton_info[i].y);
+    unsigned int event_mask = GD_EVENT_PRESSED;
 
     // determine horizontal position to the right of specified gadget
     if (checkbutton_info[i].gadget_id_align != GADGET_ID_NONE)
@@ -7218,16 +7248,14 @@ static void CreateRadiobuttonGadgets(void)
   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 i;
 
-  event_mask = GD_EVENT_PRESSED;
-
   for (i = 0; i < ED_NUM_RADIOBUTTONS; i++)
   {
     int id = radiobutton_info[i].gadget_id;
     int x = SX + ED_SETTINGS_X(radiobutton_info[i].x);
     int y = SY + ED_SETTINGS_Y(radiobutton_info[i].y);
+    unsigned int event_mask = GD_EVENT_PRESSED;
 
     int checked =
       (*radiobutton_info[i].value == radiobutton_info[i].checked_value);
@@ -7296,6 +7324,8 @@ void CreateLevelEditorGadgets(void)
 
   use_permanent_palette = !editor.palette.show_as_separate_screen;
 
+  InitGadgetScreenBorders(-1, INFOTEXT_YPOS);
+
   ReinitializeElementList();
 
   CreateControlButtons();
@@ -7488,9 +7518,13 @@ static void MapTextAreaGadget(int id)
   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
   int x_above = ED_SETTINGS_X(textarea_info[id].x);
   int y_above = ED_SETTINGS_Y(textarea_info[id].y) - yoffset_above;
+  char *text_above = textarea_info[id].text_above;
+
+  if (gi->textarea.cropped && textarea_info[id].text_above_cropped)
+    text_above = textarea_info[id].text_above_cropped;
 
-  if (textarea_info[id].text_above)
-    DrawTextS(x_above, y_above, font_nr, textarea_info[id].text_above);
+  if (text_above)
+    DrawTextS(x_above, y_above, font_nr, text_above);
 
   ModifyGadget(gi, GDI_TEXT_VALUE, textarea_info[id].value, GDI_END);
 
@@ -9512,7 +9546,7 @@ static void DrawMagicBallContentAreas(void)
   DrawText(x, y + 2 * tilesize, "active",    font_nr);
 }
 
-static void DrawAndroidElementArea(int element)
+static void DrawAndroidElementArea(void)
 {
   int id = ED_DRAWING_ID_ANDROID_CONTENT;
   int num_elements = level.num_android_clone_elements;
@@ -9540,7 +9574,7 @@ static void DrawAndroidElementArea(int element)
   MapDrawingArea(id);
 }
 
-static void DrawGroupElementArea(int element)
+static void DrawGroupElementArea(void)
 {
   int id = ED_DRAWING_ID_GROUP_CONTENT;
   int num_elements = group_element_info.num_elements;
@@ -9597,13 +9631,40 @@ static void DrawPlayerInitialInventoryArea(int element)
   MapDrawingArea(id);
 }
 
+static void DrawMMBallContentArea(void)
+{
+  int id = ED_DRAWING_ID_MM_BALL_CONTENT;
+  int num_elements = level.num_mm_ball_contents;
+  int border_size = ED_DRAWINGAREA_BORDER_SIZE;
+  int sx = SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size;
+  int sy = SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size;
+  int xsize = MAX_MM_BALL_CONTENTS;
+  int ysize = 1;
+
+  if (drawingarea_info[id].text_left != NULL)
+    sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left);
+
+  UnmapDrawingArea(id);
+
+  ModifyEditorDrawingArea(id, num_elements, 1);
+
+  // delete content areas in case of reducing number of them
+  DrawBackground(sx, sy,
+                xsize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
+                ysize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size);
+
+  MapDrawingArea(id);
+}
+
 static void DrawEnvelopeTextArea(int envelope_nr)
 {
   int id = ED_TEXTAREA_ID_ENVELOPE_INFO;
   struct GadgetInfo *gi = level_editor_gadget[textarea_info[id].gadget_id];
 
   UnmapGadget(gi);
-  DrawBackground(gi->x, gi->y, gi->width, gi->height);
+
+  DrawBackground(gi->x, gi->y,
+                gi->textarea.crop_width, gi->textarea.crop_height);
 
   if (envelope_nr != -1)
     textarea_info[id].value = level.envelope[envelope_nr].text;
@@ -9923,6 +9984,7 @@ static boolean checkPropertiesConfig(int element)
       IS_EMPTY_ELEMENT(element) ||
       IS_BALLOON_ELEMENT(element) ||
       IS_ENVELOPE(element) ||
+      IS_MM_ENVELOPE(element) ||
       IS_MM_MCDUFFIN(element) ||
       IS_DF_LASER(element) ||
       IS_PLAYER_ELEMENT(element) ||
@@ -10079,7 +10141,15 @@ static void DrawPropertiesConfig(void)
       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INITIAL_BALL_ACTIVE);
     }
     else if (properties_element == EL_EMC_ANDROID)
-      DrawAndroidElementArea(properties_element);
+      DrawAndroidElementArea();
+    else if (properties_element == EL_MM_GRAY_BALL)
+    {
+      MapCounterButtons(ED_COUNTER_ID_MM_BALL_CONTENT);
+      MapSelectboxGadget(ED_SELECTBOX_ID_MM_BALL_CHOICE_MODE);
+      MapCheckbuttonGadget(ED_CHECKBUTTON_ID_ROTATE_MM_BALL_CONTENT);
+
+      DrawMMBallContentArea();
+    }
   }
 
   if (IS_PLAYER_ELEMENT(properties_element))
@@ -10220,13 +10290,14 @@ static void DrawPropertiesConfig(void)
   if (IS_BALLOON_ELEMENT(properties_element))
     MapSelectboxGadget(ED_SELECTBOX_ID_WIND_DIRECTION);
 
-  if (IS_ENVELOPE(properties_element))
+  if (IS_ENVELOPE(properties_element) ||
+      IS_MM_ENVELOPE(properties_element))
   {
     int counter1_id = ED_COUNTER_ID_ENVELOPE_XSIZE;
     int counter2_id = ED_COUNTER_ID_ENVELOPE_YSIZE;
     int button1_id = ED_CHECKBUTTON_ID_ENVELOPE_AUTOWRAP;
     int button2_id = ED_CHECKBUTTON_ID_ENVELOPE_CENTERED;
-    int envelope_nr = properties_element - EL_ENVELOPE_1;
+    int envelope_nr = ENVELOPE_NR(properties_element);
 
     counterbutton_info[counter1_id].value = &level.envelope[envelope_nr].xsize;
     counterbutton_info[counter2_id].value = &level.envelope[envelope_nr].ysize;
@@ -10334,7 +10405,7 @@ static void DrawPropertiesConfig(void)
     MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1);
 
     // draw drawing area gadgets
-    DrawGroupElementArea(properties_element);
+    DrawGroupElementArea();
 
     // draw text input gadgets
     MapTextInputGadget(ED_TEXTINPUT_ID_ELEMENT_NAME);
@@ -10451,12 +10522,12 @@ static void DrawEditorElementName(int x, int y, int font_nr)
   int font_height = getFontHeight(font_nr);
   int max_text_width = SXSIZE - x - ED_ELEMENT_SETTINGS_X(0);
   int max_chars_per_line = max_text_width / font_width;
-  char buffer[max_chars_per_line + 1];
 
   if (strlen(element_name) <= max_chars_per_line)
     DrawTextS(x, y, font_nr, element_name);
   else
   {
+    char buffer[max_chars_per_line + 1];
     int next_pos = max_chars_per_line;
 
     strncpy(buffer, element_name, max_chars_per_line);
@@ -12621,7 +12692,7 @@ static int DrawLevelText(int sx, int sy, char letter, int mode)
   static int start_sx;
   static int last_sx, last_sy;
   static boolean typing = FALSE;
-  int letter_element = EL_CHAR_ASCII0 + letter;
+  int letter_element;
   int lx = 0, ly = 0;
 
   // map lower case letters to upper case and convert special characters
@@ -12924,8 +12995,6 @@ static void CopyLevelTemplateToUserLevelSet(char *levelset_subdir)
 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;
@@ -12945,8 +13014,6 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
   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;
 
   button_press_event = (gi->event.type == GD_EVENT_PRESSED);
@@ -12958,6 +13025,9 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
 
   if (draw_level)
   {
+    int min_lx = 0, min_ly = 0;
+    int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
+
     // get positions inside level field
     lx = sx + level_xpos;
     ly = sy + level_ypos;
@@ -12986,15 +13056,12 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
     sy2 = sy * 2 + dy;
   }
 
-  if (button_release_event)
-  {
-    last_sx = -1;
-    last_sy = -1;
-    last_sx2 = -1;
-    last_sy2 = -1;
-  }
-  else if (!button_press_event)
+  if (!button_press_event && !button_release_event)
   {
+    static int last_sx = -1;
+    static int last_sy = -1;
+    static int last_sx2 = -1;
+    static int last_sy2 = -1;
     int old_element = (IN_LEV_FIELD(lx, ly) ? Tile[lx][ly] : EL_UNDEFINED);
     boolean hires_drawing = (level.game_engine_type == GAME_ENGINE_TYPE_MM &&
                             isHiresTileElement(old_element) &&
@@ -13004,12 +13071,12 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
     if ((sx == last_sx && sy == last_sy && !hires_drawing) ||
        (sx2 == last_sx2 && sy2 == last_sy2))
       return;
-  }
 
-  last_sx = sx;
-  last_sy = sy;
-  last_sx2 = sx2;
-  last_sy2 = sy2;
+    last_sx = sx;
+    last_sy = sy;
+    last_sx2 = sx2;
+    last_sy2 = sy2;
+  }
 
   if (button_press_event)
     started_inside_drawing_area = inside_drawing_area;
@@ -13020,9 +13087,6 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
   if (!IS_VALID_BUTTON(button))
     return;
 
-  if (!button && !button_release_event)
-    return;
-
   // handle info callback for each invocation of action callback
   gi->callback_info(gi);
 
@@ -13058,10 +13122,9 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
          if (edit_mode == ED_MODE_DRAWING && draw_with_brush &&
              !inside_drawing_area)
            DeleteBrushFromCursor();
-       }
 
-       if (!button || button_release_event)
          break;
+       }
 
        if (draw_with_brush)
        {
@@ -13146,22 +13209,19 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
        if (button_release_event)
          CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
 
-       if (button)
-       {
-         SetDrawModeHiRes(new_element);
+       SetDrawModeHiRes(new_element);
 
-         if (getDrawModeHiRes())
-         {
-           sx = sx2;
-           sy = sy2;
-         }
+       if (getDrawModeHiRes())
+       {
+         sx = sx2;
+         sy = sy2;
+       }
 
-         if (!button_press_event)
-           DrawLine(last_sx, last_sy, sx, sy, new_element, TRUE);
+       if (!button_press_event)
+         DrawLine(last_sx, last_sy, sx, sy, new_element, TRUE);
 
-         last_sx = sx;
-         last_sy = sy;
-       }
+       last_sx = sx;
+       last_sy = sy;
       }
       break;
 
@@ -13344,11 +13404,11 @@ static void HandleCounterButtons(struct GadgetInfo *gi)
       break;
 
     case ED_COUNTER_ID_ANDROID_CONTENT:
-      DrawAndroidElementArea(properties_element);
+      DrawAndroidElementArea();
       break;
 
     case ED_COUNTER_ID_GROUP_CONTENT:
-      DrawGroupElementArea(properties_element);
+      DrawGroupElementArea();
       CopyGroupElementPropertiesToGame(properties_element);
       break;
 
@@ -13356,6 +13416,10 @@ static void HandleCounterButtons(struct GadgetInfo *gi)
       DrawPlayerInitialInventoryArea(properties_element);
       break;
 
+    case ED_COUNTER_ID_MM_BALL_CONTENT:
+      DrawMMBallContentArea();
+      break;
+
     case ED_COUNTER_ID_ENVELOPE_XSIZE:
     case ED_COUNTER_ID_ENVELOPE_YSIZE:
       DrawEnvelopeTextArea(-1);
@@ -14250,7 +14314,8 @@ static void HandleControlButtons(struct GadgetInfo *gi)
          id <= GADGET_ID_ELEMENTLIST_LAST)
       {
        int element_position = id - GADGET_ID_ELEMENTLIST_FIRST;
-       int new_element = editor_elements[element_position + element_shift];
+
+       new_element = editor_elements[element_position + element_shift];
 
        if (IS_EDITOR_CASCADE(new_element))
        {
@@ -14544,7 +14609,6 @@ static void ClearEditorGadgetInfoText(void)
 void PrintEditorGadgetInfoText(struct GadgetInfo *gi)
 {
   char infotext[MAX_OUTPUT_LINESIZE + 1];
-  char shortcut[MAX_OUTPUT_LINESIZE + 1];
   int max_infotext_len = getMaxInfoTextLength();
 
   if (gi == NULL || strlen(gi->info_text) == 0)
@@ -14559,6 +14623,8 @@ void PrintEditorGadgetInfoText(struct GadgetInfo *gi)
 
     if (key)
     {
+      char shortcut[MAX_OUTPUT_LINESIZE + 1];
+
       if (gi->custom_id == GADGET_ID_SINGLE_ITEMS)
        sprintf(shortcut, " ('.' or '%c')", key);
       else if (gi->custom_id == GADGET_ID_PICK_ELEMENT)
@@ -14602,7 +14668,6 @@ void HandleEditorGadgetInfoText(void *ptr)
 
 static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
 {
-  static int start_lx, start_ly;
   int id = gi->custom_id;
   int type_id = gi->custom_type_id;
   int sx = gi->event.x;
@@ -14615,7 +14680,6 @@ static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
   int actual_drawing_function = drawing_function;
   int max_infotext_len = getMaxInfoTextLength();
   char infotext[MAX_OUTPUT_LINESIZE + 1];
-  char *text;
 
   infotext[0] = '\0';          // start with empty info text
 
@@ -14656,6 +14720,10 @@ static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
     {
       if (button_status)       // if (gi->state == GD_BUTTON_PRESSED)
       {
+       static int start_lx = 0;
+       static int start_ly = 0;
+       char *text;
+
        if (gi->event.type == GD_EVENT_PRESSED)
        {
          start_lx = lx;