diff --git a/data/images/tiles.strf b/data/images/tiles.strf index 29a7ca07c2..ae213cbf82 100644 --- a/data/images/tiles.strf +++ b/data/images/tiles.strf @@ -25,7 +25,8 @@ ;; No group ids are currently skipped! Delete this line if any are and replace it with said ids... (tilegroup - (name (_ "Snow")) + (parent_group (_"Snow")) + (name (_ "Basic Snow")) (tiles 7 8 9 202 13 14 15 203 @@ -114,7 +115,12 @@ 3153 3154 3148 11 3157 3158 5368 5369 1834 5368 5369 11 - + ) + ) + (tilegroup + (parent_group (_"Snow")) + (name (_ "Snow Special")) + (tiles ;; Snow Special 3044 3045 3046 3047 @@ -129,7 +135,13 @@ 4029 4030 4031 4032 4033 4034 4035 0 5528 5529 0 0 - + ) + ) + + (tilegroup + (parent_group (_"Snow")) + (name (_ "Ice Floor special")) + (tiles ;; Ice Floor special 7422 7423 7424 7425 @@ -140,7 +152,13 @@ 7439 7440 7441 7442 7443 7444 7445 7446 7447 7448 7449 7450 - + ) + ) + + (tilegroup + (parent_group (_"Snow")) + (name (_ " Walljump + Unisolid + Ice Spike")) + (tiles ;; Walljump + Unisolid + Ice Spike 4104 4105 4106 0 @@ -172,7 +190,13 @@ 2155 2156 2157 2163 2158 2159 2154 0 2160 2161 2162 0 - + ) + ) + + (tilegroup + (parent_group (_"Snow")) + (name (_ "Underground Snow")) + (tiles ;; Underground Snow 2384 2385 2386 2949 @@ -260,10 +284,16 @@ 4069 4070 4071 4072 4073 4074 4075 4076 4077 7538 7539 7540 - 7526 7527 7528 7529 - 7530 7531 7532 7533 - 7534 7535 7536 7537 - + 7526 7527 7528 7529 + 7530 7531 7532 7533 + 7534 7535 7536 7537 + ) + ) + + (tilegroup + (parent_group (_"Snow")) + (name (_ "Snowfort + Ice Chunck")) + (tiles ;; Snowfort + Ice Chunck 3930 3931 3932 3939 @@ -321,7 +351,8 @@ ) (tilegroup - (name (_ "Snow Background")) + (parent_group (_ "Snow Background")) + (name (_ "Basic Snow Background")) (tiles 2185 2186 2180 2181 2193 2194 2188 2189 @@ -370,7 +401,8 @@ ) (tilegroup - (name (_ "Crystal")) + (parent_group (_ "Crystal")) + (name (_ "Basic Crystal")) (tiles 4723 4724 4725 4726 4736 4737 4738 4739 @@ -470,7 +502,8 @@ ) (tilegroup - (name (_ "Forest")) + (parent_group (_ "Forest")) + (name (_ "Basic Forest")) (tiles 1000 1001 1002 1003 1004 1005 1006 1007 @@ -570,6 +603,13 @@ 5596 5597 5598 5599 5600 5601 5602 5603 5590 5595 1042 1043 + ) + ) + + (tilegroup + (parent_group (_ "Forest")) + (name (_ "Branch + Spike Vine + Foreground")) + (tiles ;; Branch + Spike Vine + Foreground @@ -588,6 +628,13 @@ 5580 0 0 0 5584 0 0 0 5585 0 0 0 + ) + ) + + (tilegroup + (parent_group (_ "Forest")) + (name (_ "Underground Forest")) + (tiles ;; Underground Forest @@ -695,7 +742,8 @@ ) (tilegroup - (name (_ "Forest Background")) + (parent_group (_ "Forest Background")) + (name (_ "Basic Forest Background")) (tiles 5645 5646 5663 5664 5643 5644 5665 5674 @@ -872,7 +920,8 @@ ) (tilegroup - (name (_ "Corrupted Forest")) + (parent_group (_ "Corrupted Forest")) + (name (_ "Basic Corrupted Forest")) (tiles 1423 1424 1425 1426 1427 1428 1429 1430 @@ -967,6 +1016,13 @@ 6593 6594 6595 6596 6597 6598 6539 6540 6546 0 0 0 + ) + ) + + (tilegroup + (parent_group (_ "Corrupted Forest")) + (name (_ "Branch + Spike Vine + Foreground")) + (tiles ;; Branch + Spike Vine + Foreground @@ -982,6 +1038,13 @@ 6121 0 0 0 6130 0 0 0 6137 0 0 0 + ) + ) + + (tilegroup + (parent_group (_ "Corrupted Forest")) + (name (_ "Underground Corrupted Forest")) + (tiles ;; Underground Corrupted Forest @@ -1112,7 +1175,8 @@ ) (tilegroup - (name (_ "Corrupted Background")) + (parent_group (_ "Corrupted Background")) + (name (_ "Basic Corrupted Background")) (tiles 6142 6143 6160 6161 6140 6141 6162 6171 @@ -1259,7 +1323,8 @@ ) (tilegroup - (name (_ "Jagged Rocks")) + (parent_group (_ "Jagged Rocks")) + (name (_ "Basic Jagged Rocks")) (tiles 7312 7313 7314 7315 7316 7317 7318 7319 @@ -1303,7 +1368,8 @@ (tilegroup - (name (_ "Block + Bonus")) + (parent_group (_ "Block + Bonus")) + (name (_ "Basic Block + Bonus")) (tiles 27 28 29 47 48 50 49 211 @@ -1382,7 +1448,8 @@ ) (tilegroup - (name (_ "Pole + Signs")) + (parent_group (_ "Pole + Signs")) + (name (_ "Basic Pole + Signs")) (tiles 136 137 141 142 138 139 143 144 @@ -1435,7 +1502,8 @@ ) (tilegroup - (name (_ "Liquid")) + (parent_group (_ "Liquid")) + (name (_ "Water")) (tiles ;; Water @@ -1450,6 +1518,13 @@ 175 176 177 178 195 176 177 196 197 198 198 199 + ) + ) + + (tilegroup + (parent_group (_ "Liquid")) + (name (_ "Lava")) + (tiles ;; Lava @@ -1459,7 +1534,8 @@ ) (tilegroup - (name (_ "Castle")) + (parent_group (_ "Castle")) + (name (_ "Ice Castle")) (tiles ;; Ice Castle @@ -1488,6 +1564,13 @@ 4601 4591 0 0 4565 4612 4590 4591 4566 4565 4566 4602 + ) + ) + + (tilegroup + (parent_group (_ "Castle")) + (name (_ "Forest Castle")) + (tiles ;; Forest Castle @@ -1518,6 +1601,13 @@ 4512 4513 0 0 4480 4528 4527 4513 4479 4480 4479 4542 + ) + ) + + (tilegroup + (parent_group (_ "Castle")) + (name (_ "Ruin")) + (tiles ;; Ruin @@ -1554,6 +1644,13 @@ 1490 1491 1492 0 1497 1498 1499 0 1504 1505 1506 0 + ) + ) + + (tilegroup + (parent_group (_ "Castle")) + (name (_ "Chains")) + (tiles ;; Chains @@ -1566,6 +1663,14 @@ 4685 4686 4687 4688 7463 7465 7467 7469 7464 7466 7468 7470 + ) + ) + + + (tilegroup + (parent_group (_ "Castle")) + (name (_ "Misc")) + (tiles ;; Misc @@ -1585,7 +1690,8 @@ ) (tilegroup - (name (_ "Halloween")) + (parent_group (_ "Halloween")) + (name (_ "Basic Halloween")) (tiles 3068 3069 3070 3071 3072 3073 3074 3075 @@ -1626,7 +1732,8 @@ ) (tilegroup - (name (_ "Industrial")) + (parent_group (_ "Industrial")) + (name (_ "Basic Industrial")) (tiles 3167 3168 3169 3170 3173 3174 3175 3189 @@ -1641,7 +1748,8 @@ ) (tilegroup - (name (_ "Unisolid + Lightmap")) + (parent_group (_ "Unisolid + Lightmap")) + (name (_ "Basic Unisolid + Lightmap")) (tiles 2817 2818 2819 2820 2823 2821 2822 2824 @@ -1668,7 +1776,8 @@ ) (tilegroup - (name (_ "Miscellaneous")) + (parent_group (_ "Miscellaneous")) + (name (_ "Basic Miscellaneous")) (tiles 130 4970 2047 3927 129 4969 2048 3928 @@ -1699,7 +1808,8 @@ ) (tilegroup - (name (_ "Retro Tiles")) + (parent_group (_ "Retro Tiles")) + (name (_ "Basic Retro Tiles")) (tiles ;; Retro Snow @@ -1733,6 +1843,14 @@ 93 94 95 96 97 98 99 100 + ) + ) + + + (tilegroup + (parent_group (_ "Retro Tiles")) + (name (_ "Retro Cave")) + (tiles ;; Retro Cave @@ -1756,6 +1874,14 @@ 7255 7262 7256 7263 7257 7264 7258 7269 7270 7271 7272 0 + + ) + ) + + (tilegroup + (parent_group (_ "Retro Tiles")) + (name (_ "Retro Castle")) + (tiles ;; Retro Castle diff --git a/src/editor/editor.cpp b/src/editor/editor.cpp index 25a0cb69b3..0dcb04350f 100644 --- a/src/editor/editor.cpp +++ b/src/editor/editor.cpp @@ -27,6 +27,7 @@ #endif #include +#include #include "zip_manager.hpp" @@ -409,10 +410,14 @@ Editor::open_level_directory() void Editor::scroll(const Vector& velocity) { - if (!m_levelloaded) return; - - m_sector->get_camera().move(velocity / m_sector->get_camera().get_current_scale()); - keep_camera_in_bounds(); + const Uint16 mod_state = SDL_GetModState(); + const bool shiftPressed = (mod_state & KMOD_SHIFT) != 0; + if (!shiftPressed) + { + if (!m_levelloaded) return; + m_sector->get_camera().move(velocity / m_sector->get_camera().get_current_scale()); + keep_camera_in_bounds(); + } } void @@ -973,9 +978,9 @@ Editor::sort_layers() } void -Editor::select_tilegroup(int id) +Editor::select_tilegroup(int id, bool subgroup) { - m_toolbox_widget->select_tilegroup(id); + m_toolbox_widget->select_tilegroup(id, subgroup); } const std::vector& diff --git a/src/editor/editor.hpp b/src/editor/editor.hpp index 659ad80508..ff43dd5efc 100644 --- a/src/editor/editor.hpp +++ b/src/editor/editor.hpp @@ -137,7 +137,7 @@ class Editor final : public Screen, void delete_markers(); void sort_layers(); - void select_tilegroup(int id); + void select_tilegroup(int id, bool subgroup); const std::vector& get_tilegroups() const; void change_tileset(); diff --git a/src/editor/overlay_widget.cpp b/src/editor/overlay_widget.cpp index 68fb70af99..deb2409081 100644 --- a/src/editor/overlay_widget.cpp +++ b/src/editor/overlay_widget.cpp @@ -1500,14 +1500,29 @@ EditorOverlayWidget::draw(DrawingContext& context) m_object_tip->draw(context, m_mouse_pos); - // Draw zoom indicator. + // Draw zoom indicator and current mode (tiles/objects) // The placing on the top-right is temporary, will be moved with the implementation of an editor toolbar. const float scale = m_editor.get_sector()->get_camera().get_current_scale(); const int scale_percentage = static_cast(roundf(scale * 100.f)); - if (scale_percentage != 100) - context.color().draw_text(Resources::big_font, std::to_string(scale_percentage) + '%', - Vector(context.get_width() - 140.f, 15.f), - ALIGN_RIGHT, LAYER_OBJECTS + 1, Color::WHITE); + std::string mode_text; + switch (m_editor.get_tileselect_input_type()) + { + case EditorTilebox::InputType::TILE: + mode_text = _("TILE MODE (Click S to open tiles subgroups)"); + break; + case EditorTilebox::InputType::OBJECT: + mode_text = _("OBJECT MODE"); + break; + default: + mode_text = _("NONE"); + break; + } + std::string zoom_text = (scale_percentage != 100) + ? std::to_string(scale_percentage) + "% " + mode_text + : mode_text; + context.color().draw_text(Resources::normal_font, zoom_text, + Vector(144, 55), + ALIGN_LEFT, LAYER_OBJECTS + 1, EditorOverlayWidget::text_autotile_available_color); context.push_transform(); context.set_translation(m_editor.get_sector()->get_camera().get_translation()); diff --git a/src/editor/tilebox.cpp b/src/editor/tilebox.cpp index 1ee9d53e74..81b8f4695e 100644 --- a/src/editor/tilebox.cpp +++ b/src/editor/tilebox.cpp @@ -31,6 +31,13 @@ #include "util/log.hpp" #include "video/drawing_context.hpp" +int current_selected_tilegroup_index = 0; +int previous_tilegroup_index = 0; +int current_selected_objectgroup_index = 0; +int previous_objectgroup_index = 0; +bool tilegroup_selected = false; +bool subgroup_selected = false; + EditorTilebox::EditorTilebox(Editor& editor, const Rectf& rect) : m_editor(editor), m_rect(rect), @@ -53,6 +60,22 @@ EditorTilebox::EditorTilebox(Editor& editor, const Rectf& rect) : m_scrollbar.reset(new ControlScrollbar(1.f, 1.f, m_scroll_progress, 35.f)); } + +int +EditorTilebox::get_parentgroup_size() const +{ + int parent_group_size = 0; + std::string parent_group_name = m_active_tilegroup->parent_group; + for (const auto& tilegroup :m_editor.get_tileset()->get_tilegroups()) + { + if (tilegroup.parent_group == parent_group_name) { + parent_group_size += tilegroup.tiles.size(); + } + + } + return parent_group_size; +} + void EditorTilebox::draw(DrawingContext& context) { @@ -100,20 +123,57 @@ void EditorTilebox::draw_tilegroup(DrawingContext& context) { int pos = -1; - for (auto& tile_ID : m_active_tilegroup->tiles) + + if (!subgroup_selected) { - pos++; - if (pos / 4 < static_cast(m_scroll_progress / 32.f)) - continue; + int id = 0; + // Skip the previous index groups + while (m_editor.get_tileset()->get_tilegroups()[id].parent_group != m_active_tilegroup->parent_group + && m_active_tilegroup->parent_group != "") + { + id ++; + } + + // Treat all same group subgroups + while ((id < m_editor.get_tileset()->get_tilegroups().size() + && m_editor.get_tileset()->get_tilegroups()[id].parent_group == m_active_tilegroup->parent_group) + && m_active_tilegroup->parent_group != "") { + for (auto& tile_ID :m_editor.get_tileset()->get_tilegroups()[id].tiles) + { + pos++; + if (pos / 4 < static_cast(m_scroll_progress / 32.f)) + continue; + + auto position = get_tile_coords(pos, false); + m_editor.get_tileset()->get(tile_ID).draw(context.color(), position, LAYER_GUI - 9); + + if (g_config->developer_mode && (m_active_tilegroup->developers_group || g_debug.show_toolbox_tile_ids) && tile_ID != 0) + { + // Display tile ID on top of tile: + context.color().draw_text(Resources::console_font, std::to_string(tile_ID), + position + Vector(16, 16), ALIGN_CENTER, LAYER_GUI - 9, Color::WHITE); + } + } + id ++; + } + } + else + { + for (auto& tile_ID :m_active_tilegroup->tiles) + { + pos++; + if (pos / 4 < static_cast(m_scroll_progress / 32.f)) + continue; - auto position = get_tile_coords(pos, false); - m_editor.get_tileset()->get(tile_ID).draw(context.color(), position, LAYER_GUI - 9); + auto position = get_tile_coords(pos, false); + m_editor.get_tileset()->get(tile_ID).draw(context.color(), position, LAYER_GUI - 9); - if (g_config->developer_mode && (m_active_tilegroup->developers_group || g_debug.show_toolbox_tile_ids) && tile_ID != 0) - { - // Display tile ID on top of tile: - context.color().draw_text(Resources::console_font, std::to_string(tile_ID), - position + Vector(16, 16), ALIGN_CENTER, LAYER_GUI - 9, Color::WHITE); + if (g_config->developer_mode && (m_active_tilegroup->developers_group || g_debug.show_toolbox_tile_ids) && tile_ID != 0) + { + // Display tile ID on top of tile: + context.color().draw_text(Resources::console_font, std::to_string(tile_ID), + position + Vector(16, 16), ALIGN_CENTER, LAYER_GUI - 9, Color::WHITE); + } } } } @@ -370,16 +430,40 @@ EditorTilebox::on_select(const std::function& callback) } void -EditorTilebox::select_tilegroup(int id) +EditorTilebox::select_tilegroup(int id, bool subgroup) { - m_active_tilegroup.reset(new Tilegroup(m_editor.get_tileset()->get_tilegroups()[id])); + if (tilegroup_selected) { + previous_tilegroup_index = current_selected_tilegroup_index; + } + tilegroup_selected = true; + Tilegroup newTilegroup(m_editor.get_tileset()->get_tilegroups()[id]); + + if (!subgroup) + { + current_selected_tilegroup_index = id; + int i = 1; + while (m_editor.get_tileset()->get_tilegroups()[id + i].parent_group == newTilegroup.parent_group + && id + i < m_editor.get_tileset()->get_tilegroups().size()) + { + newTilegroup.add_tiles(m_editor.get_tileset()->get_tilegroups()[id + i].tiles); + i++; + } + } + + m_active_tilegroup.reset(new Tilegroup(newTilegroup)); m_input_type = InputType::TILE; + subgroup_selected = subgroup; reset_scrollbar(); } void EditorTilebox::select_objectgroup(int id) { + if (!tilegroup_selected) { + previous_objectgroup_index = current_selected_objectgroup_index; + } + current_selected_objectgroup_index = id; + tilegroup_selected = false; m_active_objectgroup = &m_object_info->m_groups[id]; m_input_type = InputType::OBJECT; reset_scrollbar(); @@ -412,7 +496,12 @@ EditorTilebox::get_tiles_height() const switch (m_input_type) { case InputType::TILE: - return ceilf(static_cast(m_active_tilegroup->tiles.size()) / 4.f) * 32.f; + if (subgroup_selected) { + return ceilf(static_cast(m_active_tilegroup->tiles.size()) / 4.f) * 32.f; + } + else { + return ceilf(static_cast(get_parentgroup_size()) / 4.f) * 32.f; + } case InputType::OBJECT: return ceilf(static_cast(m_active_objectgroup->get_icons().size()) / 4.f) * 32.f; @@ -422,6 +511,30 @@ EditorTilebox::get_tiles_height() const } } +int +EditorTilebox::get_current_tilegroup_index() const +{ + return current_selected_tilegroup_index; +} + +int +EditorTilebox::get_previous_tilegroup_index() const +{ + return previous_tilegroup_index; +} + +int +EditorTilebox::get_current_objectgroup_index() const +{ + return current_selected_objectgroup_index; +} + +int +EditorTilebox::get_previous_objectgroup_index() const +{ + return previous_objectgroup_index; +} + void EditorTilebox::reset_scrollbar() { diff --git a/src/editor/tilebox.hpp b/src/editor/tilebox.hpp index 3284605a72..72d8bd01f9 100644 --- a/src/editor/tilebox.hpp +++ b/src/editor/tilebox.hpp @@ -59,6 +59,8 @@ class EditorTilebox final : public Widget public: EditorTilebox(Editor& editor, const Rectf& rect); + int get_parentgroup_size() const; + virtual void draw(DrawingContext& context) override; virtual bool on_mouse_button_up(const SDL_MouseButtonEvent& button) override; @@ -74,7 +76,7 @@ class EditorTilebox final : public Widget void on_select(const std::function& callback); - void select_tilegroup(int id); + void select_tilegroup(int id, bool subgroup); inline void set_tilegroup(std::unique_ptr tilegroup) { m_active_tilegroup = std::move(tilegroup); } void select_objectgroup(int id); bool select_layers_objectgroup(); @@ -88,6 +90,10 @@ class EditorTilebox final : public Widget inline void set_object(const std::string& object) { m_object = object; } float get_tiles_height() const; + int get_current_tilegroup_index() const; + int get_previous_tilegroup_index() const; + int get_current_objectgroup_index() const; + int get_previous_objectgroup_index() const; inline bool has_active_object_tip() const { return m_object_tip->get_visible(); } diff --git a/src/editor/toolbox_widget.cpp b/src/editor/toolbox_widget.cpp index dcb959b0ec..d0db8bc99a 100644 --- a/src/editor/toolbox_widget.cpp +++ b/src/editor/toolbox_widget.cpp @@ -33,6 +33,14 @@ #include "video/video_system.hpp" #include "video/viewport.hpp" +#include +#include +#include + +int current_tilegroup_index = 0; +int current_objectgroup_index = 0; +int opened_tilesubgroup_menu = -1; + using InputType = EditorTilebox::InputType; EditorToolboxWidget::EditorToolboxWidget(Editor& editor) : @@ -127,7 +135,7 @@ EditorToolboxWidget::on_mouse_button_down(const SDL_MouseButtonEvent& button) } else { - select_tilegroup(0); + select_tilegroup(0, false); } return true; @@ -200,6 +208,94 @@ EditorToolboxWidget::on_mouse_button_down(const SDL_MouseButtonEvent& button) } } +bool +EditorToolboxWidget::on_key_down(const SDL_KeyboardEvent& key) +{ + if (key.keysym.sym == SDLK_q) + { + bool shiftPressed = (key.keysym.mod & KMOD_SHIFT) != 0; + if (shiftPressed) + { + if (m_tilebox->get_input_type() == InputType::TILE) + { + if (m_editor.get_level()->is_worldmap()) + { + select_objectgroup(m_tilebox->get_object_info().get_first_worldmap_group_index()); + } + else + { + current_tilegroup_index = m_tilebox->get_previous_tilegroup_index(); + select_tilegroup(current_tilegroup_index, false); + opened_tilesubgroup_menu = -1; + } + } + else if (m_tilebox->get_input_type() == InputType::OBJECT) + { + current_objectgroup_index = m_tilebox->get_previous_objectgroup_index(); + select_objectgroup(current_objectgroup_index); + } + } + else + { + if (m_tilebox->get_input_type() == InputType::TILE) + { + if (m_editor.get_level()->is_worldmap()) + { + select_objectgroup(m_tilebox->get_object_info().get_first_worldmap_group_index()); + } + else + { + current_tilegroup_index = m_tilebox->get_current_tilegroup_index(); + select_objectgroup(current_objectgroup_index); + opened_tilesubgroup_menu = -1; + } + } + else if (m_tilebox->get_input_type() == InputType::OBJECT) + { + current_objectgroup_index = m_tilebox->get_current_objectgroup_index(); + select_tilegroup(current_tilegroup_index, false); + opened_tilesubgroup_menu = -1; + } + } + + return true; + } + else if (key.keysym.sym == SDLK_g) + { + if (m_tilebox->get_input_type() == InputType::TILE) + { + const auto& tilegroup = m_editor.get_tileset()->get_tilegroups()[current_tilegroup_index]; + const std::string& parent_group = tilegroup.parent_group; + + m_editor.disable_keyboard(); + + std::string enum_name = "EDITOR_TILESUBGROUP_MENU_" + parent_group; + std::string transformed; + for (char c : enum_name) + { + if (c == ' ' && transformed.back() != '_') transformed += '_'; + else if (c != '+' && c != ' ') transformed += std::toupper(static_cast(c)); + } + + auto menu_id = MenuStorage::get_menu_id(transformed); + + if (opened_tilesubgroup_menu == menu_id && MenuManager::instance().is_active()) + { + MenuManager::instance().pop_menu(); + opened_tilesubgroup_menu = -1; + } + else + { + MenuManager::instance().push_menu(menu_id); + opened_tilesubgroup_menu = menu_id; + } + } + return true; + } + + return false; +} + bool EditorToolboxWidget::on_mouse_motion(const SDL_MouseMotionEvent& motion) { @@ -252,6 +348,45 @@ EditorToolboxWidget::on_mouse_motion(const SDL_MouseMotionEvent& motion) bool EditorToolboxWidget::on_mouse_wheel(const SDL_MouseWheelEvent& wheel) { + const Uint16 mod_state = SDL_GetModState(); + const bool shiftPressed = (mod_state & KMOD_SHIFT) != 0; + + if (shiftPressed) + { + if (m_tilebox->get_input_type() == InputType::TILE) + { + if (m_editor.get_tileset()->get_tilegroups().size() > 1) + { + m_editor.disable_keyboard(); + MenuManager::instance().push_menu(MenuStorage::EDITOR_TILEGROUP_MENU); + return true; + } + else + { + select_tilegroup(0, false); + return true; + } + } + else if (m_tilebox->get_input_type() == InputType::OBJECT) + { + if ((m_editor.get_level()->is_worldmap() && m_tilebox->get_object_info().get_num_worldmap_groups() > 1) || + (!m_editor.get_level()->is_worldmap() && m_tilebox->get_object_info().get_num_level_groups() > 1)) + { + m_editor.disable_keyboard(); + MenuManager::instance().push_menu(MenuStorage::EDITOR_OBJECTGROUP_MENU); + return true; + } + else + { + if (m_editor.get_level()->is_worldmap()) + select_objectgroup(m_tilebox->get_object_info().get_first_worldmap_group_index()); + else + select_objectgroup(0); + return true; + } + } + } + return m_tilebox->on_mouse_wheel(wheel); } @@ -281,9 +416,10 @@ EditorToolboxWidget::setup() } void -EditorToolboxWidget::select_tilegroup(int id) +EditorToolboxWidget::select_tilegroup(int id, bool subgroup) { - m_tilebox->select_tilegroup(id); + current_tilegroup_index = id; + m_tilebox->select_tilegroup(id, subgroup); update_mouse_icon(); } diff --git a/src/editor/toolbox_widget.hpp b/src/editor/toolbox_widget.hpp index e763e5efd8..af78511e0d 100644 --- a/src/editor/toolbox_widget.hpp +++ b/src/editor/toolbox_widget.hpp @@ -47,13 +47,14 @@ class EditorToolboxWidget final : public Widget virtual bool on_mouse_button_up(const SDL_MouseButtonEvent& button) override; virtual bool on_mouse_button_down(const SDL_MouseButtonEvent& button) override; + bool on_key_down(const SDL_KeyboardEvent& key) override; virtual bool on_mouse_motion(const SDL_MouseMotionEvent& motion) override; virtual bool on_mouse_wheel(const SDL_MouseWheelEvent& wheel) override; virtual void setup() override; virtual void on_window_resize() override; - void select_tilegroup(int id); + void select_tilegroup(int id, bool subgroup); void select_objectgroup(int id); int get_tileselect_select_mode() const; diff --git a/src/gui/menu.cpp b/src/gui/menu.cpp index 3f6c82cc05..274cbbb5a6 100644 --- a/src/gui/menu.cpp +++ b/src/gui/menu.cpp @@ -52,6 +52,8 @@ #include "video/renderer.hpp" #include "video/video_system.hpp" #include "video/viewport.hpp" +#include "supertux/menu/editor_tilegroup_menu.hpp" +#include "supertux/menu/editor_objectgroup_menu.hpp" #include "supertux/error_handler.hpp" @@ -416,7 +418,7 @@ Menu::process_action(const MenuAction& action) if (m_items[m_active_item]->changes_width()) calculate_width(); - if (action == MenuAction::HIT) + if (action == MenuAction::HIT) menu_action(*m_items[m_active_item]); } @@ -652,6 +654,47 @@ Menu::event(const SDL_Event& ev) } break; + case SDL_MOUSEWHEEL: + { + const Uint8* keystate = SDL_GetKeyboardState(nullptr); + bool shiftPressed = keystate[SDL_SCANCODE_LSHIFT] || keystate[SDL_SCANCODE_RSHIFT]; + + if (shiftPressed) + { + if (dynamic_cast(MenuManager::instance().current_menu()) + || dynamic_cast(MenuManager::instance().current_menu())) + { + if (ev.wheel.y > 0) + { + process_action(MenuAction::UP); + } + else if (ev.wheel.y < 0) + { + process_action(MenuAction::DOWN); + } + + return; + } + } + } + break; + + case SDL_KEYUP: + { + if (ev.key.keysym.sym == SDLK_LSHIFT || ev.key.keysym.sym == SDLK_RSHIFT) + { + Menu* current = MenuManager::instance().current_menu(); + + if (dynamic_cast(current) || + dynamic_cast(current)) + { + process_action(MenuAction::HIT); + return; + } + } + break; + } + default: break; } diff --git a/src/supertux/menu/editor_menu.cpp b/src/supertux/menu/editor_menu.cpp index f766d80899..a21a21b604 100644 --- a/src/supertux/menu/editor_menu.cpp +++ b/src/supertux/menu/editor_menu.cpp @@ -216,7 +216,10 @@ EditorMenu::menu_action(MenuItem& item) _("F8 = Show Grid") + "\n" + _("Ctrl++ or Ctrl+Scroll Up = Zoom In") + "\n" + _("Ctrl+- or Ctrl+Scroll Down = Zoom Out") + "\n" + - _("Ctrl+D = Reset Zoom") + "\n\n" + + _("Ctrl+D = Reset Zoom") + "\n" + + _("Q = Change between Tile and Object mode") + "\n" + + _("Shift+Q = Change to the previous group") + "\n" + + _("Shift+Scroll = Open groups flash menu") + "\n\n" + _("Scripting Shortcuts:") + "\n" + "-------------" + "\n" + _("Home = Go to beginning of line") + "\n" + diff --git a/src/supertux/menu/editor_tilegroup_menu.cpp b/src/supertux/menu/editor_tilegroup_menu.cpp index cbd73699ff..35fe9b60b4 100644 --- a/src/supertux/menu/editor_tilegroup_menu.cpp +++ b/src/supertux/menu/editor_tilegroup_menu.cpp @@ -26,9 +26,14 @@ EditorTilegroupMenu::EditorTilegroupMenu() add_label(_("Tiles")); add_hl(); + std::string previous_parent_group = ""; int id = 0; for (auto& tg : Editor::current()->get_tilegroups()) { - add_entry(id, _(tg.name)); + if (previous_parent_group == "" || previous_parent_group != tg.parent_group) + { + add_entry(id, _(tg.parent_group)); + previous_parent_group = tg.parent_group; + } id++; } @@ -50,7 +55,7 @@ EditorTilegroupMenu::menu_action(MenuItem& item) { if (item.get_id() >= 0) { - Editor::current()->select_tilegroup(item.get_id()); + Editor::current()->select_tilegroup(item.get_id(), false); } MenuManager::instance().clear_menu_stack(); } diff --git a/src/supertux/menu/editor_tilesubgroup_menu.cpp b/src/supertux/menu/editor_tilesubgroup_menu.cpp new file mode 100644 index 0000000000..8d048fadb1 --- /dev/null +++ b/src/supertux/menu/editor_tilesubgroup_menu.cpp @@ -0,0 +1,60 @@ +// SuperTux +// Copyright (C) 2025 Vasco Rodrigues +// 2025 Afonso Mateus +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "supertux/menu/editor_tilesubgroup_menu.hpp" +#include "editor/editor.hpp" +#include "gui/menu_item.hpp" +#include "gui/menu_manager.hpp" +#include "util/gettext.hpp" + +EditorTilesubgroupMenu::EditorTilesubgroupMenu(std::string parent_group) +{ + add_label(_(parent_group)); + add_hl(); + + int id = 0; + for (auto& tg : Editor::current()->get_tilegroups()) { + if (tg.parent_group == parent_group){ + add_entry(id, _(tg.name)); + } + id++; + } + + add_hl(); + add_entry(-1,_("Cancel")); +} + +EditorTilesubgroupMenu::~EditorTilesubgroupMenu() +{ + auto editor = Editor::current(); + if (editor == nullptr) { + return; + } + editor->m_reactivate_request = true; +} + +void +EditorTilesubgroupMenu::menu_action(MenuItem& item) +{ + if (item.get_id() >= 0) + { + Editor::current()->select_tilegroup(item.get_id(), true); + } + MenuManager::instance().clear_menu_stack(); +} + +/* EOF */ diff --git a/src/supertux/menu/editor_tilesubgroup_menu.hpp b/src/supertux/menu/editor_tilesubgroup_menu.hpp new file mode 100644 index 0000000000..c6946b3690 --- /dev/null +++ b/src/supertux/menu/editor_tilesubgroup_menu.hpp @@ -0,0 +1,39 @@ +// SuperTux +// Copyright (C) 2025 Vasco Rodrigues +// 2025 Afonso Mateus +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#ifndef HEADER_SUPERTUX_SUPERTUX_MENU_EDITOR_TILESUBGROUP_MENU_HPP +#define HEADER_SUPERTUX_SUPERTUX_MENU_EDITOR_TILESUBGROUP_MENU_HPP + +#include "gui/menu.hpp" + +class EditorTilesubgroupMenu final : public Menu +{ +public: + EditorTilesubgroupMenu(std::string parent_group); + ~EditorTilesubgroupMenu() override; + + void menu_action(MenuItem& item) override; + +private: + EditorTilesubgroupMenu(const EditorTilesubgroupMenu&) = delete; + EditorTilesubgroupMenu& operator=(const EditorTilesubgroupMenu&) = delete; + +}; + +#endif + +/* EOF */ diff --git a/src/supertux/menu/menu_storage.cpp b/src/supertux/menu/menu_storage.cpp index fccc028c50..73d37fd8f0 100644 --- a/src/supertux/menu/menu_storage.cpp +++ b/src/supertux/menu/menu_storage.cpp @@ -32,6 +32,7 @@ #include "supertux/menu/editor_new_levelset_menu.hpp" #include "supertux/menu/editor_objectgroup_menu.hpp" #include "supertux/menu/editor_tilegroup_menu.hpp" +#include "supertux/menu/editor_tilesubgroup_menu.hpp" #include "supertux/menu/editor_sector_menu.hpp" #include "supertux/menu/editor_sectors_menu.hpp" #include "supertux/menu/game_menu.hpp" @@ -153,6 +154,57 @@ MenuStorage::create(MenuId menu_id) case EDITOR_TILEGROUP_MENU: return std::make_unique(); + + case EDITOR_TILESUBGROUP_MENU_SNOW: + return std::make_unique("Snow"); + + case EDITOR_TILESUBGROUP_MENU_SNOW_BACKGROUND: + return std::make_unique("Snow Background"); + + case EDITOR_TILESUBGROUP_MENU_CRYSTAL: + return std::make_unique("Crystal"); + + case EDITOR_TILESUBGROUP_MENU_FOREST: + return std::make_unique("Forest"); + + case EDITOR_TILESUBGROUP_MENU_FOREST_BACKGROUND: + return std::make_unique("Forest Background"); + + case EDITOR_TILESUBGROUP_MENU_CORRUPTED_FOREST: + return std::make_unique("Corrupted Forest"); + + case EDITOR_TILESUBGROUP_MENU_CORRUPTED_BACKGROUND: + return std::make_unique("Corrupted Background"); + + case EDITOR_TILESUBGROUP_MENU_JAGGED_ROCKS: + return std::make_unique("Jagged Rocks"); + + case EDITOR_TILESUBGROUP_MENU_BLOCK_BONUS: + return std::make_unique("Block + Bonus"); + + case EDITOR_TILESUBGROUP_MENU_POLE_SIGNS: + return std::make_unique("Pole + Signs"); + + case EDITOR_TILESUBGROUP_MENU_LIQUID: + return std::make_unique("Liquid"); + + case EDITOR_TILESUBGROUP_MENU_CASTLE: + return std::make_unique("Castle"); + + case EDITOR_TILESUBGROUP_MENU_HALLOWEEN: + return std::make_unique("Halloween"); + + case EDITOR_TILESUBGROUP_MENU_INDUSTRIAL: + return std::make_unique("Industrial"); + + case EDITOR_TILESUBGROUP_MENU_UNISOLID_LIGHTMAP: + return std::make_unique("Unisolid + Lightmap"); + + case EDITOR_TILESUBGROUP_MENU_MISCELLANEOUS: + return std::make_unique("Miscellaneous"); + + case EDITOR_TILESUBGROUP_MENU_RETRO_TILES: + return std::make_unique("Retro Tiles"); case EDITOR_OBJECTGROUP_MENU: return std::make_unique(); @@ -207,4 +259,74 @@ MenuStorage::create(MenuId menu_id) } } +const char* MenuStorage::MenuIdNames[] = { + "NO_MENU", + "MAIN_MENU", + "OPTIONS_MENU", + "INGAME_OPTIONS_MENU", + "PROFILE_MENU", + "WORLDSET_MENU", + "CONTRIB_MENU", + "CONTRIB_WORLD_MENU", + "ADDON_MENU", + "LANGPACK_MENU", + "LANGPACK_AUTO_UPDATE_MENU", + "LANGUAGE_MENU", + "KEYBOARD_MENU", + "JOYSTICK_MENU", + "VIDEO_SYSTEM_MENU", + "WORLDMAP_MENU", + "WORLDMAP_CHEAT_MENU", + "WORLDMAP_LEVEL_SELECT_MENU", + "GAME_MENU", + "CHEAT_MENU", + "DEBUG_MENU", + "EDITOR_LEVELSET_SELECT_MENU", + "EDITOR_NEW_LEVELSET_MENU", + "EDITOR_LEVEL_SELECT_MENU", + "EDITOR_MENU", + "EDITOR_TILEGROUP_MENU", + "EDITOR_TILESUBGROUP_MENU_SNOW", + "EDITOR_TILESUBGROUP_MENU_SNOW_BACKGROUND", + "EDITOR_TILESUBGROUP_MENU_CRYSTAL", + "EDITOR_TILESUBGROUP_MENU_FOREST", + "EDITOR_TILESUBGROUP_MENU_FOREST_BACKGROUND", + "EDITOR_TILESUBGROUP_MENU_CORRUPTED_FOREST", + "EDITOR_TILESUBGROUP_MENU_CORRUPTED_BACKGROUND", + "EDITOR_TILESUBGROUP_MENU_JAGGED_ROCKS", + "EDITOR_TILESUBGROUP_MENU_BLOCK_BONUS", + "EDITOR_TILESUBGROUP_MENU_POLE_SIGNS", + "EDITOR_TILESUBGROUP_MENU_LIQUID", + "EDITOR_TILESUBGROUP_MENU_CASTLE", + "EDITOR_TILESUBGROUP_MENU_HALLOWEEN", + "EDITOR_TILESUBGROUP_MENU_INDUSTRIAL", + "EDITOR_TILESUBGROUP_MENU_UNISOLID_LIGHTMAP", + "EDITOR_TILESUBGROUP_MENU_MISCELLANEOUS", + "EDITOR_TILESUBGROUP_MENU_RETRO_TILES", + "EDITOR_OBJECTGROUP_MENU", + "EDITOR_SECTORS_MENU", + "EDITOR_SECTOR_MENU", + "EDITOR_LEVEL_MENU", + "EDITOR_CONVERTERS_MENU", + "PARTICLE_EDITOR_MENU", + "PARTICLE_EDITOR_SAVE_AS", + "PARTICLE_EDITOR_OPEN", + "INTEGRATIONS_MENU", + "ASSET_MENU", + "CUSTOM_MENU_MENU", + "MULTIPLAYER_MENU", + "MULTIPLAYER_PLAYERS_MENU" +}; + +int +MenuStorage::get_menu_id(std::string menu_name) +{ + for (size_t i = 0; i < sizeof(MenuIdNames)/sizeof(MenuIdNames[0]); ++i) { + if (MenuIdNames[i] == menu_name) { + return i; + } + } + return -1; +} + /* EOF */ diff --git a/src/supertux/menu/menu_storage.hpp b/src/supertux/menu/menu_storage.hpp index 096dac374b..d4cc8bf4c5 100644 --- a/src/supertux/menu/menu_storage.hpp +++ b/src/supertux/menu/menu_storage.hpp @@ -56,6 +56,23 @@ class MenuStorage final EDITOR_LEVEL_SELECT_MENU, EDITOR_MENU, EDITOR_TILEGROUP_MENU, + EDITOR_TILESUBGROUP_MENU_SNOW, + EDITOR_TILESUBGROUP_MENU_SNOW_BACKGROUND, + EDITOR_TILESUBGROUP_MENU_CRYSTAL, + EDITOR_TILESUBGROUP_MENU_FOREST, + EDITOR_TILESUBGROUP_MENU_FOREST_BACKGROUND, + EDITOR_TILESUBGROUP_MENU_CORRUPTED_FOREST, + EDITOR_TILESUBGROUP_MENU_CORRUPTED_BACKGROUND, + EDITOR_TILESUBGROUP_MENU_JAGGED_ROCKS, + EDITOR_TILESUBGROUP_MENU_BLOCK_BONUS, + EDITOR_TILESUBGROUP_MENU_POLE_SIGNS, + EDITOR_TILESUBGROUP_MENU_LIQUID, + EDITOR_TILESUBGROUP_MENU_CASTLE, + EDITOR_TILESUBGROUP_MENU_HALLOWEEN, + EDITOR_TILESUBGROUP_MENU_INDUSTRIAL, + EDITOR_TILESUBGROUP_MENU_UNISOLID_LIGHTMAP, + EDITOR_TILESUBGROUP_MENU_MISCELLANEOUS, + EDITOR_TILESUBGROUP_MENU_RETRO_TILES, EDITOR_OBJECTGROUP_MENU, EDITOR_SECTORS_MENU, EDITOR_SECTOR_MENU, @@ -71,11 +88,14 @@ class MenuStorage final MULTIPLAYER_PLAYERS_MENU }; + static const char* MenuIdNames[]; + public: MenuStorage(); ~MenuStorage(); std::unique_ptr create(MenuId menu_id); + static int get_menu_id(std::string menu_name); private: MenuStorage(const MenuStorage&) = delete; diff --git a/src/supertux/tile_set.hpp b/src/supertux/tile_set.hpp index 9a1bbc7845..be5764fcbb 100644 --- a/src/supertux/tile_set.hpp +++ b/src/supertux/tile_set.hpp @@ -37,8 +37,13 @@ class Tilegroup final Tilegroup(); bool developers_group = false; + std::string parent_group; std::string name; std::vector tiles; + + void add_tiles(const std::vector& new_tiles) { + tiles.insert(tiles.end(), new_tiles.begin(), new_tiles.end()); + } }; class TileSet final diff --git a/src/supertux/tile_set_parser.cpp b/src/supertux/tile_set_parser.cpp index 2272dc3975..8d8eececc6 100644 --- a/src/supertux/tile_set_parser.cpp +++ b/src/supertux/tile_set_parser.cpp @@ -82,7 +82,13 @@ TileSetParser::parse(bool imported) /* tilegroups are only interesting for the editor */ ReaderMapping reader = iter.as_mapping(); Tilegroup tilegroup; + reader.get("parent_group", tilegroup.parent_group); reader.get("name", tilegroup.name); + + if (tilegroup.parent_group.empty()) { + tilegroup.parent_group = tilegroup.name; + } + reader.get("tiles", tilegroup.tiles); // Allow offsetting every tile ID, specified in the tilegroup