tilemap-editor 3.2.9__tar.gz → 3.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {tilemap_editor-3.2.9/src/tilemap_editor.egg-info → tilemap_editor-3.3.0}/PKG-INFO +1 -1
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/pyproject.toml +3 -1
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/editor.py +2 -11
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/plugins/sprite_editor/editor.py +161 -8
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/plugins/sprite_editor/standalone.py +23 -17
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0/src/tilemap_editor.egg-info}/PKG-INFO +1 -1
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor.egg-info/top_level.txt +2 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/widgets/filemanager.py +13 -4
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/widgets/tile_selector.py +54 -8
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/LICENSE +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/MANIFEST.in +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/README.md +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/assets/fonts/jetbrain-fonts/JetBrainsMono-Bold.ttf +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/assets/fonts/jetbrain-fonts/JetBrainsMono-BoldItalic.ttf +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/assets/fonts/jetbrain-fonts/JetBrainsMono-Italic.ttf +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/assets/fonts/jetbrain-fonts/JetBrainsMono-Regular.ttf +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/assets/fonts/noto/NotoSans-Bold.ttf +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/assets/fonts/noto/NotoSans-BoldItalic.ttf +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/assets/fonts/noto/NotoSans-Italic.ttf +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/assets/fonts/noto/NotoSans-Regular.ttf +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/assets/icons/arrow-down.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/assets/icons/check.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/assets/icons/checked.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/assets/icons/close.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/assets/icons/duplicate.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/assets/icons/error.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/assets/icons/file.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/assets/icons/filedead.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/assets/icons/fit.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/assets/icons/folder.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/assets/icons/grid.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/assets/icons/image.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/assets/icons/info.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/assets/icons/load.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/assets/icons/loop.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/assets/icons/pan.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/assets/icons/pause.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/assets/icons/pencil.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/assets/icons/play.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/assets/icons/plus.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/assets/icons/radio.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/assets/icons/reset.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/assets/icons/save.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/assets/icons/stop.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/assets/icons/tilemap.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/assets/icons/tileset.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/assets/icons/unchecked.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/assets/icons/warning.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/assets/icons/zoomin.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/assets/icons/zoomout.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/setup.cfg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/configs/themes.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/constants.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/event_map.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/layers.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/main.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/node_manager.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/nodes.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/plugins/__init__.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/plugins/character_collision/__init__.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/plugins/character_collision/editor.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/plugins/character_collision/models.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/plugins/character_collision/protocols.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/plugins/character_collision/shape_editor.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/plugins/character_collision/standalone.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/plugins/object_tileset_collision/__init__.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/plugins/object_tileset_collision/editor.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/plugins/object_tileset_collision/models.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/plugins/object_tileset_collision/protocols.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/plugins/object_tileset_collision/standalone.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/plugins/sprite_animation/__init__.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/plugins/sprite_animation/__main__.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/plugins/sprite_animation/clipboard_util.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/plugins/sprite_animation/editor.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/plugins/sprite_animation/frame_picker.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/plugins/sprite_animation/models.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/plugins/sprite_animation/preview.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/plugins/sprite_animation/protocols.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/plugins/sprite_animation/runtime_load.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/plugins/sprite_animation/standalone.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/plugins/sprite_animation/timeline.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/plugins/sprite_animation/validation.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/plugins/sprite_editor/__init__.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/plugins/tileset_collision/__init__.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/plugins/tileset_collision/collision_painter.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/plugins/tileset_collision/editor.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/plugins/tileset_collision/models.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/plugins/tileset_collision/protocols.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/plugins/tileset_collision/standalone.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/standalone_automap.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/standalone_error_console.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/standalone_filemanager.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/standalone_image_viewer.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/__init__.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/__main__.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/assets/__init__.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/assets/fonts/jetbrain-fonts/JetBrainsMono-Bold.ttf +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/assets/fonts/jetbrain-fonts/JetBrainsMono-BoldItalic.ttf +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/assets/fonts/jetbrain-fonts/JetBrainsMono-Italic.ttf +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/assets/fonts/jetbrain-fonts/JetBrainsMono-Regular.ttf +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/assets/fonts/noto/NotoSans-Bold.ttf +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/assets/fonts/noto/NotoSans-BoldItalic.ttf +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/assets/fonts/noto/NotoSans-Italic.ttf +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/assets/fonts/noto/NotoSans-Regular.ttf +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/assets/icons/ToolMove.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/assets/icons/arrow-down.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/assets/icons/check.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/assets/icons/checked.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/assets/icons/close.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/assets/icons/duplicate.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/assets/icons/error.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/assets/icons/file.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/assets/icons/filedead.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/assets/icons/fit.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/assets/icons/folder.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/assets/icons/grid.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/assets/icons/image.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/assets/icons/info.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/assets/icons/load.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/assets/icons/loop.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/assets/icons/pan.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/assets/icons/pause.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/assets/icons/pencil.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/assets/icons/play.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/assets/icons/plus.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/assets/icons/radio.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/assets/icons/reset.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/assets/icons/save.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/assets/icons/stop.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/assets/icons/tilemap.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/assets/icons/tileset.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/assets/icons/unchecked.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/assets/icons/warning.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/assets/icons/zoomin.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/assets/icons/zoomout.svg +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/cli.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/main.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor/settings.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor.egg-info/SOURCES.txt +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor.egg-info/dependency_links.txt +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor.egg-info/entry_points.txt +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/tilemap_editor.egg-info/requires.txt +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/ttypes/__init__.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/ttypes/tilemap.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/utils/__init__.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/utils/editor_preference.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/utils/error_handler.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/utils/font_manager.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/utils/history.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/utils/icon_manager.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/utils/icons_cache.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/utils/log_capture.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/utils/project_paths.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/utils/serialization.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/utils/standalone.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/utils/validation.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/widgets/__init__.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/widgets/automap_models.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/widgets/autotile_template.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/widgets/autotiler.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/widgets/input.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/widgets/layer_selector.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/widgets/map_properties.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/widgets/mapsetup.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/widgets/regex_automap_designer.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/widgets/spritesheet_grid.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/widgets/tile_grid.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/widgets/ui/collision_layer_mask.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/widgets/ui/collision_layer_sidebar.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/widgets/ui/confirm_dialog.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/widgets/ui/draw_utils.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/widgets/ui/fileinput.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/widgets/ui/layer_type_dialog.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/widgets/ui/menubar.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/widgets/ui/mode_indicator.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/widgets/ui/node_editor.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/widgets/ui/node_selector.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/widgets/ui/notification.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/widgets/ui/property_editor.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/widgets/ui/region_selector.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/widgets/ui/status_bar.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/widgets/ui/theme.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/widgets/ui/tileset_type_dialog.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/widgets/ui/toolbar.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/src/widgets/ui/tooltip.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/tests/test_animation_library_grid_offset.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/tests/test_collision_layer_mask.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/tests/test_collision_layer_sidebar.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/tests/test_editor_pan_mode.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/tests/test_project_paths.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/tests/test_render_scale.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/tests/test_sprite_animation_editor_grid.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/tests/test_tile_grid_selection.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/tests/test_tile_selector_pick.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/tests/test_tilemap_save.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/tests/test_timeline_invalidate_cache.py +0 -0
- {tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/tests/test_toolbar_tools.py +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "tilemap-editor"
|
|
7
|
-
version = "3.
|
|
7
|
+
version = "3.3.0"
|
|
8
8
|
description = "Pygame tilemap editor with SVG icons, professional UI, and sprite animation tools"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -32,6 +32,8 @@ py-modules = [
|
|
|
32
32
|
"editor",
|
|
33
33
|
"event_map",
|
|
34
34
|
"layers",
|
|
35
|
+
"node_manager",
|
|
36
|
+
"nodes",
|
|
35
37
|
"tilemap",
|
|
36
38
|
"standalone_filemanager",
|
|
37
39
|
"standalone_image_viewer",
|
|
@@ -771,23 +771,14 @@ class Editor:
|
|
|
771
771
|
error_handler.capture(e, context="launch_animation_editor")
|
|
772
772
|
|
|
773
773
|
def launch_sprite_editor(self):
|
|
774
|
-
"""Launch the sprite editor in a new window."""
|
|
775
|
-
self.open_file_manager(
|
|
776
|
-
on_select=self._launch_sprite_editor_with_image,
|
|
777
|
-
initial_dir=self.data_root,
|
|
778
|
-
allowed_exts=[".png", ".jpg", ".jpeg"],
|
|
779
|
-
mode="open",
|
|
780
|
-
)
|
|
781
|
-
|
|
782
|
-
def _launch_sprite_editor_with_image(self, path: Path):
|
|
783
|
-
"""Launch sprite editor subprocess with selected image."""
|
|
774
|
+
"""Launch the sprite editor (blank) in a new window. Use [Open] inside to load sheets."""
|
|
784
775
|
try:
|
|
785
776
|
tile_size = "32x32"
|
|
786
777
|
if hasattr(self.tilemap, "tile_size") and self.tilemap.tile_size:
|
|
787
778
|
tw, th = self.tilemap.tile_size
|
|
788
779
|
tile_size = f"{tw}x{th}"
|
|
789
780
|
|
|
790
|
-
args = [
|
|
781
|
+
args = ["--tile-size", tile_size, "--data-root", str(self.data_root)]
|
|
791
782
|
process = launch_standalone(
|
|
792
783
|
"plugins.sprite_editor.standalone",
|
|
793
784
|
args,
|
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
SpriteEditor — standalone widget wrapping SpritesheetGrid with editing toolbar.
|
|
3
3
|
|
|
4
4
|
Toolbar:
|
|
5
|
-
[Flip X] [Flip Y] [Copy] [Paste] [Undo] [Redo] [Scale...] [Save PNG]
|
|
5
|
+
[Flip X] [Flip Y] [Copy] [Paste] [Undo] [Redo] [Scale...] [Grid WxH] [Open] [Save PNG]
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
from __future__ import annotations
|
|
9
9
|
|
|
10
10
|
from pathlib import Path
|
|
11
|
-
from typing import Dict, Optional
|
|
11
|
+
from typing import Dict, List, Optional, Union
|
|
12
12
|
|
|
13
13
|
import pygame
|
|
14
|
-
from pygame import Rect, Surface
|
|
14
|
+
from pygame import Rect, Surface, SRCALPHA
|
|
15
15
|
|
|
16
16
|
from widgets.spritesheet_grid import SpritesheetGrid
|
|
17
17
|
from widgets.ui.theme import COLORS
|
|
@@ -34,6 +34,8 @@ _BUTTON_ICONS: dict[str, str | None] = {
|
|
|
34
34
|
"Undo": None,
|
|
35
35
|
"Redo": None,
|
|
36
36
|
"Scale": None,
|
|
37
|
+
"Grid": None,
|
|
38
|
+
"Open": None,
|
|
37
39
|
"Save": "save",
|
|
38
40
|
}
|
|
39
41
|
|
|
@@ -42,8 +44,8 @@ class SpriteEditor:
|
|
|
42
44
|
def __init__(
|
|
43
45
|
self,
|
|
44
46
|
rect: Rect,
|
|
45
|
-
surface: Surface,
|
|
46
|
-
tile_size: tuple[int, int],
|
|
47
|
+
surface: Optional[Surface] = None,
|
|
48
|
+
tile_size: tuple[int, int] = (32, 32),
|
|
47
49
|
image_path: Optional[Path] = None,
|
|
48
50
|
data_root: Optional[Path] = None,
|
|
49
51
|
):
|
|
@@ -51,9 +53,17 @@ class SpriteEditor:
|
|
|
51
53
|
self.image_path = image_path
|
|
52
54
|
self._data_root = data_root or (image_path.parent if image_path else Path.cwd())
|
|
53
55
|
|
|
56
|
+
# Start blank if no surface provided; track real sheets separately
|
|
57
|
+
if surface is None:
|
|
58
|
+
placeholder = Surface((1, 1), SRCALPHA)
|
|
59
|
+
self._sheet_surfaces: List[Surface] = []
|
|
60
|
+
else:
|
|
61
|
+
placeholder = surface
|
|
62
|
+
self._sheet_surfaces = [surface]
|
|
63
|
+
|
|
54
64
|
# Grid
|
|
55
65
|
grid_rect = Rect(rect.x, rect.y + TOOLBAR_H, rect.w, rect.h - TOOLBAR_H - STATUS_H)
|
|
56
|
-
self.grid = SpritesheetGrid(grid_rect,
|
|
66
|
+
self.grid = SpritesheetGrid(grid_rect, placeholder, tile_size)
|
|
57
67
|
|
|
58
68
|
# Clipboard for copy/paste
|
|
59
69
|
self._clipboard: Dict[int, Surface] = {}
|
|
@@ -64,6 +74,11 @@ class SpriteEditor:
|
|
|
64
74
|
self._scale_text: str = "2.0"
|
|
65
75
|
self._scale_error: Optional[str] = None
|
|
66
76
|
|
|
77
|
+
# Grid dialog state
|
|
78
|
+
self._grid_active: bool = False
|
|
79
|
+
self._grid_text: str = f"{tile_size[0]}x{tile_size[1]}"
|
|
80
|
+
self._grid_error: Optional[str] = None
|
|
81
|
+
|
|
67
82
|
# Save path — never auto-overwrite original
|
|
68
83
|
self._save_path: Optional[Path] = None
|
|
69
84
|
|
|
@@ -81,13 +96,19 @@ class SpriteEditor:
|
|
|
81
96
|
ty = self.rect.y + (TOOLBAR_H - BTN_H) // 2
|
|
82
97
|
gap = 6
|
|
83
98
|
x = self.rect.x + gap
|
|
84
|
-
labels = ["Flip X", "Flip Y", "Copy", "Paste", "Undo", "Redo", "Scale", "Save"]
|
|
99
|
+
labels = ["Flip X", "Flip Y", "Copy", "Paste", "Undo", "Redo", "Scale", "Grid", "Open", "Save"]
|
|
85
100
|
for lbl in labels:
|
|
86
101
|
self._btn_rects[lbl] = Rect(x, ty, BTN_W, BTN_H)
|
|
87
102
|
x += BTN_W + gap
|
|
88
103
|
|
|
89
104
|
def _get_status_text(self) -> str:
|
|
90
|
-
|
|
105
|
+
n = len(self._sheet_surfaces)
|
|
106
|
+
if n == 0:
|
|
107
|
+
return " No spritesheets loaded — Click [Open] to load one or more sheets"
|
|
108
|
+
tw, th = self.grid.tile_size
|
|
109
|
+
parts = [f"Tile: {tw}×{th} Zoom: {self.grid.zoom:.1f}x"]
|
|
110
|
+
if n > 1:
|
|
111
|
+
parts.append(f"Sheets: {n}")
|
|
91
112
|
sel = len(self.grid.selected_indices)
|
|
92
113
|
if sel:
|
|
93
114
|
parts.append(f"Selected: {sel}")
|
|
@@ -109,6 +130,9 @@ class SpriteEditor:
|
|
|
109
130
|
if self._scale_active:
|
|
110
131
|
return self._handle_scale_dialog(event)
|
|
111
132
|
|
|
133
|
+
if self._grid_active:
|
|
134
|
+
return self._handle_grid_dialog(event)
|
|
135
|
+
|
|
112
136
|
mouse = pygame.mouse.get_pos()
|
|
113
137
|
|
|
114
138
|
# Keyboard shortcuts
|
|
@@ -182,6 +206,15 @@ class SpriteEditor:
|
|
|
182
206
|
self._scale_text = "2.0"
|
|
183
207
|
self._scale_error = None
|
|
184
208
|
return True
|
|
209
|
+
elif lbl == "Grid":
|
|
210
|
+
self._grid_active = True
|
|
211
|
+
tw, th = self.grid.tile_size
|
|
212
|
+
self._grid_text = f"{tw}x{th}"
|
|
213
|
+
self._grid_error = None
|
|
214
|
+
return True
|
|
215
|
+
elif lbl == "Open":
|
|
216
|
+
self._open_add_sheets_dialog()
|
|
217
|
+
return True
|
|
185
218
|
elif lbl == "Save":
|
|
186
219
|
self._open_save_dialog()
|
|
187
220
|
return True
|
|
@@ -213,6 +246,44 @@ class SpriteEditor:
|
|
|
213
246
|
return True
|
|
214
247
|
return False
|
|
215
248
|
|
|
249
|
+
def _handle_grid_dialog(self, event: pygame.event.Event) -> bool:
|
|
250
|
+
if event.type == pygame.KEYDOWN:
|
|
251
|
+
if event.key in (pygame.K_RETURN, pygame.K_KP_ENTER):
|
|
252
|
+
parts = self._grid_text.lower().split("x")
|
|
253
|
+
try:
|
|
254
|
+
tw = int(parts[0])
|
|
255
|
+
th = int(parts[1]) if len(parts) > 1 else tw
|
|
256
|
+
if tw < 1 or th < 1:
|
|
257
|
+
self._grid_error = "Must be >= 1"
|
|
258
|
+
else:
|
|
259
|
+
self.grid.set_tile_size(tw, th)
|
|
260
|
+
self._grid_active = False
|
|
261
|
+
self._grid_error = None
|
|
262
|
+
except ValueError:
|
|
263
|
+
self._grid_error = "Use format: WxH or N"
|
|
264
|
+
return True
|
|
265
|
+
elif event.key == pygame.K_ESCAPE:
|
|
266
|
+
self._grid_active = False
|
|
267
|
+
self._grid_error = None
|
|
268
|
+
return True
|
|
269
|
+
elif event.key == pygame.K_BACKSPACE:
|
|
270
|
+
self._grid_text = self._grid_text[:-1]
|
|
271
|
+
return True
|
|
272
|
+
elif event.unicode and event.unicode in "0123456789xX" and len(self._grid_text) < 10:
|
|
273
|
+
self._grid_text += event.unicode
|
|
274
|
+
return True
|
|
275
|
+
return False
|
|
276
|
+
|
|
277
|
+
@staticmethod
|
|
278
|
+
def _detect_tile_size(surface: Surface) -> tuple[int, int]:
|
|
279
|
+
w, h = surface.get_size()
|
|
280
|
+
candidates = [8, 12, 16, 24, 32, 48, 64, 128]
|
|
281
|
+
best = 8
|
|
282
|
+
for s in candidates:
|
|
283
|
+
if w % s == 0 and h % s == 0:
|
|
284
|
+
best = s
|
|
285
|
+
return (best, best)
|
|
286
|
+
|
|
216
287
|
def _open_save_dialog(self) -> None:
|
|
217
288
|
"""Open FileManager in save mode to pick a PNG path."""
|
|
218
289
|
from widgets.filemanager import FileManager
|
|
@@ -253,6 +324,64 @@ class SpriteEditor:
|
|
|
253
324
|
def set_save_path(self, path: Path) -> None:
|
|
254
325
|
self._save_path = path
|
|
255
326
|
|
|
327
|
+
# ------------------------------------------------------------------
|
|
328
|
+
# Multi-sheet: stack sheets vertically into one combined surface
|
|
329
|
+
# ------------------------------------------------------------------
|
|
330
|
+
|
|
331
|
+
def _build_combined_surface(self) -> None:
|
|
332
|
+
"""Rebuild the combined surface from all loaded sheets (stacked vertically)."""
|
|
333
|
+
n = len(self._sheet_surfaces)
|
|
334
|
+
if n == 0:
|
|
335
|
+
return
|
|
336
|
+
if n == 1:
|
|
337
|
+
self.grid.set_surface(self._sheet_surfaces[0])
|
|
338
|
+
return
|
|
339
|
+
|
|
340
|
+
max_w = max(s.get_width() for s in self._sheet_surfaces)
|
|
341
|
+
total_h = sum(s.get_height() for s in self._sheet_surfaces)
|
|
342
|
+
combined = Surface((max_w, total_h), SRCALPHA)
|
|
343
|
+
combined.fill((0, 0, 0, 0))
|
|
344
|
+
y = 0
|
|
345
|
+
for surf in self._sheet_surfaces:
|
|
346
|
+
combined.blit(surf, (0, y))
|
|
347
|
+
y += surf.get_height()
|
|
348
|
+
self.grid.set_surface(combined)
|
|
349
|
+
|
|
350
|
+
def _open_add_sheets_dialog(self) -> None:
|
|
351
|
+
"""Open FileManager in multi-select mode to pick one or more sheets."""
|
|
352
|
+
from widgets.filemanager import FileManager
|
|
353
|
+
|
|
354
|
+
fm_rect = self._file_manager_rect()
|
|
355
|
+
self._file_manager = FileManager(
|
|
356
|
+
rect=fm_rect,
|
|
357
|
+
initial_dir=self._data_root,
|
|
358
|
+
allowed_exts=[".png", ".jpg", ".jpeg", ".bmp", ".gif"],
|
|
359
|
+
on_select=self._on_add_sheets,
|
|
360
|
+
mode="open",
|
|
361
|
+
on_cancel=self._close_file_manager,
|
|
362
|
+
multi_select=True,
|
|
363
|
+
data_root=self._data_root,
|
|
364
|
+
)
|
|
365
|
+
|
|
366
|
+
def _on_add_sheets(self, selection: Union[Path, List[Path]]) -> None:
|
|
367
|
+
if isinstance(selection, Path):
|
|
368
|
+
selection = [selection]
|
|
369
|
+
was_empty = len(self._sheet_surfaces) == 0
|
|
370
|
+
loaded = 0
|
|
371
|
+
for path in selection:
|
|
372
|
+
try:
|
|
373
|
+
surf = pygame.image.load(str(path)).convert_alpha()
|
|
374
|
+
self._sheet_surfaces.append(surf)
|
|
375
|
+
loaded += 1
|
|
376
|
+
except Exception as e:
|
|
377
|
+
print(f"Failed to load {path.name}: {e}")
|
|
378
|
+
if loaded:
|
|
379
|
+
if was_empty:
|
|
380
|
+
detected = self._detect_tile_size(self._sheet_surfaces[0])
|
|
381
|
+
self.grid.set_tile_size(*detected)
|
|
382
|
+
self._build_combined_surface()
|
|
383
|
+
self._close_file_manager()
|
|
384
|
+
|
|
256
385
|
# ------------------------------------------------------------------
|
|
257
386
|
# Drawing
|
|
258
387
|
# ------------------------------------------------------------------
|
|
@@ -295,6 +424,8 @@ class SpriteEditor:
|
|
|
295
424
|
|
|
296
425
|
if self._scale_active:
|
|
297
426
|
self._draw_scale_dialog(screen)
|
|
427
|
+
if self._grid_active:
|
|
428
|
+
self._draw_grid_dialog(screen)
|
|
298
429
|
|
|
299
430
|
# File manager overlay
|
|
300
431
|
if self._file_manager is not None:
|
|
@@ -321,3 +452,25 @@ class SpriteEditor:
|
|
|
321
452
|
|
|
322
453
|
hint = self._font_sm.render("Enter / Esc", True, COLORS.text_dim)
|
|
323
454
|
screen.blit(hint, (dlg.right - 90, dlg.bottom - 22))
|
|
455
|
+
|
|
456
|
+
def _draw_grid_dialog(self, screen: Surface) -> None:
|
|
457
|
+
dw, dh = 260, 100
|
|
458
|
+
cx, cy = self.rect.center
|
|
459
|
+
dlg = Rect(cx - dw // 2, cy - dh // 2, dw, dh)
|
|
460
|
+
draw_panel(screen, dlg, COLORS.panel, COLORS.border)
|
|
461
|
+
|
|
462
|
+
title = self._font.render("Tile Size (WxH)", True, COLORS.text)
|
|
463
|
+
screen.blit(title, title.get_rect(centerx=dlg.centerx, top=dlg.top + 10))
|
|
464
|
+
|
|
465
|
+
inp = Rect(dlg.x + 20, dlg.top + 36, dw - 40, 28)
|
|
466
|
+
pygame.draw.rect(screen, COLORS.selected, inp, border_radius=4)
|
|
467
|
+
pygame.draw.rect(screen, COLORS.accent, inp, 2, border_radius=4)
|
|
468
|
+
txt = self._grid_text + ("|" if (pygame.time.get_ticks() // 400) % 2 else "")
|
|
469
|
+
screen.blit(self._font_sm.render(txt, True, COLORS.text), (inp.x + 6, inp.y + 5))
|
|
470
|
+
|
|
471
|
+
if self._grid_error:
|
|
472
|
+
err = self._font_sm.render(self._grid_error, True, COLORS.danger)
|
|
473
|
+
screen.blit(err, (dlg.x + 20, dlg.bottom - 22))
|
|
474
|
+
|
|
475
|
+
hint = self._font_sm.render("Enter / Esc", True, COLORS.text_dim)
|
|
476
|
+
screen.blit(hint, (dlg.right - 90, dlg.bottom - 22))
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
Standalone launcher for the Sprite Editor.
|
|
3
3
|
|
|
4
4
|
Usage:
|
|
5
|
+
python standalone.py # start blank, then click [Open]
|
|
5
6
|
python standalone.py path/to/spritesheet.png
|
|
6
7
|
python standalone.py path/to/spritesheet.png --tile-size 32
|
|
7
|
-
python standalone.py path/to/spritesheet.png --save output.png
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
from __future__ import annotations
|
|
@@ -47,7 +47,8 @@ def main(argv: list[str] | None = None) -> None:
|
|
|
47
47
|
sys.excepthook = handle_exception
|
|
48
48
|
|
|
49
49
|
parser = argparse.ArgumentParser(description="Grid Sprite Editor")
|
|
50
|
-
parser.add_argument("image", type=str,
|
|
50
|
+
parser.add_argument("image", type=str, nargs="?", default=None,
|
|
51
|
+
help="Path to spritesheet image (optional — start blank)")
|
|
51
52
|
parser.add_argument("--tile-size", type=str, default="32",
|
|
52
53
|
help="Tile size (e.g. 32 or 32x32)")
|
|
53
54
|
parser.add_argument("--save", type=str, default=None,
|
|
@@ -59,30 +60,35 @@ def main(argv: list[str] | None = None) -> None:
|
|
|
59
60
|
|
|
60
61
|
args = parser.parse_args(argv)
|
|
61
62
|
|
|
62
|
-
image_path = Path(args.image)
|
|
63
|
-
if not image_path.is_file():
|
|
64
|
-
print(f"Error: file not found: {image_path}")
|
|
65
|
-
sys.exit(1)
|
|
66
|
-
|
|
67
63
|
ts_parts = args.tile_size.lower().split("x")
|
|
68
64
|
tw = int(ts_parts[0])
|
|
69
65
|
th = int(ts_parts[1]) if len(ts_parts) > 1 else tw
|
|
70
66
|
|
|
71
67
|
window_size = parse_window_size(args.window_size)
|
|
72
|
-
data_root = Path(args.data_root) if args.data_root else image_path.parent
|
|
73
68
|
|
|
74
69
|
pygame.init()
|
|
75
70
|
screen = pygame.display.set_mode(window_size, pygame.RESIZABLE)
|
|
76
|
-
pygame.display.set_caption(f"Sprite Editor - {image_path.name}")
|
|
77
|
-
|
|
78
|
-
surface = pygame.image.load(str(image_path)).convert_alpha()
|
|
79
71
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
image_path
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
72
|
+
if args.image:
|
|
73
|
+
image_path = Path(args.image)
|
|
74
|
+
if not image_path.is_file():
|
|
75
|
+
print(f"Error: file not found: {image_path}")
|
|
76
|
+
sys.exit(1)
|
|
77
|
+
data_root = Path(args.data_root) if args.data_root else image_path.parent
|
|
78
|
+
surface = pygame.image.load(str(image_path)).convert_alpha()
|
|
79
|
+
pygame.display.set_caption(f"Sprite Editor - {image_path.name}")
|
|
80
|
+
editor = SpriteEditor(
|
|
81
|
+
screen.get_rect(), surface, (tw, th),
|
|
82
|
+
image_path=image_path, data_root=data_root,
|
|
83
|
+
)
|
|
84
|
+
if args.save:
|
|
85
|
+
editor.set_save_path(Path(args.save))
|
|
86
|
+
else:
|
|
87
|
+
data_root = Path(args.data_root) if args.data_root else Path.cwd()
|
|
88
|
+
pygame.display.set_caption("Sprite Editor — blank")
|
|
89
|
+
editor = SpriteEditor(
|
|
90
|
+
screen.get_rect(), tile_size=(tw, th), data_root=data_root,
|
|
91
|
+
)
|
|
86
92
|
|
|
87
93
|
clock = pygame.time.Clock()
|
|
88
94
|
running = True
|
|
@@ -503,6 +503,7 @@ class FileManager:
|
|
|
503
503
|
|
|
504
504
|
self.font_main = pygame.font.SysFont("Arial", 14)
|
|
505
505
|
self.font_bold = pygame.font.SysFont("Arial", 14, bold=True)
|
|
506
|
+
self.font_small = pygame.font.SysFont("Arial", 11)
|
|
506
507
|
self.font_icon = pygame.font.SysFont("Consolas", 20)
|
|
507
508
|
|
|
508
509
|
self.search_input = InlineTextInput("search", "")
|
|
@@ -1606,13 +1607,21 @@ class FileManager:
|
|
|
1606
1607
|
pygame.draw.rect(screen, COLORS["border"], bar_rect, border_radius=2)
|
|
1607
1608
|
|
|
1608
1609
|
def _draw_footer(self, screen, rect):
|
|
1609
|
-
sel_txt
|
|
1610
|
-
if self.
|
|
1610
|
+
sel_txt: str
|
|
1611
|
+
if self.multi_select and len(self.selected_indices) > 1:
|
|
1612
|
+
sel_txt = f"{len(self.selected_indices)} files selected"
|
|
1613
|
+
elif self.selected_index != -1:
|
|
1611
1614
|
sel_txt = self.items[self.selected_index].name
|
|
1615
|
+
else:
|
|
1616
|
+
sel_txt = "No file selected"
|
|
1612
1617
|
|
|
1613
|
-
txt_surf = self.font_main.render(sel_txt, True, COLORS["text_dim"])
|
|
1614
1618
|
if self.mode == "open":
|
|
1615
|
-
|
|
1619
|
+
txt_surf = self.font_main.render(sel_txt, True, COLORS["text_dim"])
|
|
1620
|
+
screen.blit(txt_surf, (rect.x + 10, rect.y + 12))
|
|
1621
|
+
if self.multi_select:
|
|
1622
|
+
hint = "[Ctrl+Click] toggle [Shift+Click] range [Open] confirm"
|
|
1623
|
+
hint_surf = self.font_small.render(hint, True, COLORS["text_dim"])
|
|
1624
|
+
screen.blit(hint_surf, (rect.x + 10, rect.y + 28))
|
|
1616
1625
|
|
|
1617
1626
|
btn_w, btn_h = 80, 30
|
|
1618
1627
|
margin = 10
|
|
@@ -46,6 +46,10 @@ class TileSelector:
|
|
|
46
46
|
x, y + self.top_bar_h, w, h - self.top_bar_h - self.btm_bar_h
|
|
47
47
|
)
|
|
48
48
|
self.tab_scroll_x = 0
|
|
49
|
+
arrow_h = self.top_bar_h - 4
|
|
50
|
+
arrow_y = y + (self.top_bar_h - arrow_h) // 2
|
|
51
|
+
self._tab_arrow_left = Rect(x + 2, arrow_y, 18, arrow_h)
|
|
52
|
+
self._tab_arrow_right = Rect(x + w - 20, arrow_y, 18, arrow_h)
|
|
49
53
|
self.is_panning = False
|
|
50
54
|
self.pan_start = (0, 0)
|
|
51
55
|
self.pan_start_offset = (0, 0)
|
|
@@ -86,6 +90,10 @@ class TileSelector:
|
|
|
86
90
|
self.btn_collision = Rect(x + w - 105, btn_y, 30, 30)
|
|
87
91
|
self.btn_add = Rect(x + w - 70, btn_y, 30, 30)
|
|
88
92
|
self.btn_rem = Rect(x + w - 35, btn_y, 30, 30)
|
|
93
|
+
arrow_h = self.top_bar_h - 4
|
|
94
|
+
arrow_y = y + (self.top_bar_h - arrow_h) // 2
|
|
95
|
+
self._tab_arrow_left = Rect(x + 2, arrow_y, 18, arrow_h)
|
|
96
|
+
self._tab_arrow_right = Rect(x + w - 20, arrow_y, 18, arrow_h)
|
|
89
97
|
|
|
90
98
|
def set_rule_hints(self, hints: Set[int]):
|
|
91
99
|
self.rule_hints = hints
|
|
@@ -179,6 +187,13 @@ class TileSelector:
|
|
|
179
187
|
return True
|
|
180
188
|
|
|
181
189
|
if self.rect.collidepoint(mouse_pos) and mouse_pos[1] < self.view_rect.top:
|
|
190
|
+
# Check arrow buttons first
|
|
191
|
+
if self._tab_arrow_left.collidepoint(mouse_pos):
|
|
192
|
+
self._scroll_tabs(100)
|
|
193
|
+
return True
|
|
194
|
+
if self._tab_arrow_right.collidepoint(mouse_pos):
|
|
195
|
+
self._scroll_tabs(-100)
|
|
196
|
+
return True
|
|
182
197
|
self.check_tab_click(mouse_pos)
|
|
183
198
|
return True
|
|
184
199
|
|
|
@@ -561,8 +576,8 @@ class TileSelector:
|
|
|
561
576
|
def _get_tab_at_pos(self, pos) -> Optional[int]:
|
|
562
577
|
if not self.tilesets:
|
|
563
578
|
return None
|
|
564
|
-
tab_w =
|
|
565
|
-
idx = (pos[0] - self.rect.x) // tab_w
|
|
579
|
+
tab_w = 100
|
|
580
|
+
idx = (pos[0] - self.rect.x + self.tab_scroll_x) // tab_w
|
|
566
581
|
if 0 <= idx < len(self.tilesets):
|
|
567
582
|
return int(idx)
|
|
568
583
|
return None
|
|
@@ -875,14 +890,19 @@ class TileSelector:
|
|
|
875
890
|
clip = screen.get_clip()
|
|
876
891
|
tab_area = Rect(self.rect.x, self.rect.y, self.rect.width, self.top_bar_h)
|
|
877
892
|
screen.set_clip(tab_area)
|
|
893
|
+
|
|
894
|
+
pygame.draw.rect(screen, COLORS.header, tab_area)
|
|
895
|
+
|
|
878
896
|
tab_w = 100
|
|
879
897
|
total_w = tab_w * len(self.tilesets)
|
|
880
|
-
|
|
898
|
+
has_overflow = total_w > self.rect.width
|
|
899
|
+
if has_overflow:
|
|
881
900
|
self.tab_scroll_x = max(
|
|
882
901
|
0, min(self.tab_scroll_x, total_w - self.rect.width)
|
|
883
902
|
)
|
|
884
903
|
else:
|
|
885
904
|
self.tab_scroll_x = 0
|
|
905
|
+
|
|
886
906
|
for i, ts in enumerate(self.tilesets):
|
|
887
907
|
r = Rect(
|
|
888
908
|
self.rect.x + i * tab_w - self.tab_scroll_x,
|
|
@@ -895,13 +915,25 @@ class TileSelector:
|
|
|
895
915
|
is_active = i == self.active_idx
|
|
896
916
|
col = COLORS.selected if is_active else COLORS.header
|
|
897
917
|
pygame.draw.rect(screen, col, r)
|
|
898
|
-
|
|
918
|
+
if not is_active:
|
|
919
|
+
pygame.draw.line(screen, COLORS.border, r.bottomleft, r.bottomright, 1)
|
|
899
920
|
t = ts.name[:8] + ".." if len(ts.name) > 10 else ts.name
|
|
900
921
|
screen.blit(self.font.render(t, True, COLORS.text), (r.x + 5, r.y + 5))
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
922
|
+
|
|
923
|
+
mx, my = pygame.mouse.get_pos()
|
|
924
|
+
show_arrows = has_overflow and tab_area.collidepoint(mx, my)
|
|
925
|
+
|
|
926
|
+
if show_arrows:
|
|
927
|
+
for arrow_rect, label in [
|
|
928
|
+
(self._tab_arrow_left, "<"),
|
|
929
|
+
(self._tab_arrow_right, ">"),
|
|
930
|
+
]:
|
|
931
|
+
pygame.draw.rect(screen, COLORS.selected, arrow_rect)
|
|
932
|
+
pygame.draw.rect(screen, COLORS.border, arrow_rect, 1)
|
|
933
|
+
arrow_surf = self.font.render(label, True, COLORS.text)
|
|
934
|
+
arrow_rect_text = arrow_surf.get_rect(center=arrow_rect.center)
|
|
935
|
+
screen.blit(arrow_surf, arrow_rect_text)
|
|
936
|
+
|
|
905
937
|
bar_w = max(30, int(self.rect.width * (self.rect.width / total_w)))
|
|
906
938
|
bar_x = self.rect.x + int(
|
|
907
939
|
(self.tab_scroll_x / (total_w - self.rect.width))
|
|
@@ -909,6 +941,20 @@ class TileSelector:
|
|
|
909
941
|
)
|
|
910
942
|
bar_rect = Rect(bar_x, self.rect.y + self.top_bar_h - 4, bar_w, 3)
|
|
911
943
|
pygame.draw.rect(screen, COLORS.border_soft, bar_rect, border_radius=2)
|
|
944
|
+
|
|
945
|
+
# Tooltip for tab name
|
|
946
|
+
if tab_area.collidepoint(mx, my) and not (
|
|
947
|
+
show_arrows and (
|
|
948
|
+
self._tab_arrow_left.collidepoint(mx, my) or
|
|
949
|
+
self._tab_arrow_right.collidepoint(mx, my)
|
|
950
|
+
)
|
|
951
|
+
):
|
|
952
|
+
idx = self._get_tab_at_pos((mx, my))
|
|
953
|
+
if idx is not None and 0 <= idx < len(self.tilesets):
|
|
954
|
+
self.editor.tooltip.show(
|
|
955
|
+
self.tilesets[idx].name, (mx + 10, my + 10)
|
|
956
|
+
)
|
|
957
|
+
|
|
912
958
|
screen.set_clip(clip)
|
|
913
959
|
|
|
914
960
|
def _scroll_tabs(self, delta: float):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/assets/fonts/jetbrain-fonts/JetBrainsMono-Bold.ttf
RENAMED
|
File without changes
|
|
File without changes
|
{tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/assets/fonts/jetbrain-fonts/JetBrainsMono-Italic.ttf
RENAMED
|
File without changes
|
{tilemap_editor-3.2.9 → tilemap_editor-3.3.0}/assets/fonts/jetbrain-fonts/JetBrainsMono-Regular.ttf
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|