tilemap-editor 3.2.10__tar.gz → 3.3.1__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.10/src/tilemap_editor.egg-info → tilemap_editor-3.3.1}/PKG-INFO +1 -1
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/pyproject.toml +3 -1
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/editor.py +67 -12
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/plugins/sprite_editor/editor.py +161 -8
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/plugins/sprite_editor/standalone.py +23 -17
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1/src/tilemap_editor.egg-info}/PKG-INFO +1 -1
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor.egg-info/top_level.txt +2 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/widgets/filemanager.py +13 -4
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/widgets/tile_grid.py +5 -4
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/widgets/ui/menubar.py +5 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/widgets/ui/tileset_type_dialog.py +2 -2
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/LICENSE +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/MANIFEST.in +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/README.md +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/assets/fonts/jetbrain-fonts/JetBrainsMono-Bold.ttf +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/assets/fonts/jetbrain-fonts/JetBrainsMono-BoldItalic.ttf +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/assets/fonts/jetbrain-fonts/JetBrainsMono-Italic.ttf +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/assets/fonts/jetbrain-fonts/JetBrainsMono-Regular.ttf +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/assets/fonts/noto/NotoSans-Bold.ttf +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/assets/fonts/noto/NotoSans-BoldItalic.ttf +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/assets/fonts/noto/NotoSans-Italic.ttf +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/assets/fonts/noto/NotoSans-Regular.ttf +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/assets/icons/arrow-down.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/assets/icons/check.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/assets/icons/checked.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/assets/icons/close.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/assets/icons/duplicate.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/assets/icons/error.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/assets/icons/file.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/assets/icons/filedead.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/assets/icons/fit.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/assets/icons/folder.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/assets/icons/grid.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/assets/icons/image.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/assets/icons/info.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/assets/icons/load.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/assets/icons/loop.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/assets/icons/pan.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/assets/icons/pause.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/assets/icons/pencil.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/assets/icons/play.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/assets/icons/plus.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/assets/icons/radio.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/assets/icons/reset.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/assets/icons/save.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/assets/icons/stop.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/assets/icons/tilemap.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/assets/icons/tileset.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/assets/icons/unchecked.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/assets/icons/warning.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/assets/icons/zoomin.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/assets/icons/zoomout.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/setup.cfg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/configs/themes.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/constants.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/event_map.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/layers.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/main.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/node_manager.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/nodes.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/plugins/__init__.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/plugins/character_collision/__init__.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/plugins/character_collision/editor.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/plugins/character_collision/models.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/plugins/character_collision/protocols.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/plugins/character_collision/shape_editor.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/plugins/character_collision/standalone.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/plugins/object_tileset_collision/__init__.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/plugins/object_tileset_collision/editor.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/plugins/object_tileset_collision/models.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/plugins/object_tileset_collision/protocols.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/plugins/object_tileset_collision/standalone.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/plugins/sprite_animation/__init__.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/plugins/sprite_animation/__main__.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/plugins/sprite_animation/clipboard_util.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/plugins/sprite_animation/editor.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/plugins/sprite_animation/frame_picker.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/plugins/sprite_animation/models.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/plugins/sprite_animation/preview.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/plugins/sprite_animation/protocols.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/plugins/sprite_animation/runtime_load.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/plugins/sprite_animation/standalone.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/plugins/sprite_animation/timeline.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/plugins/sprite_animation/validation.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/plugins/sprite_editor/__init__.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/plugins/tileset_collision/__init__.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/plugins/tileset_collision/collision_painter.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/plugins/tileset_collision/editor.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/plugins/tileset_collision/models.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/plugins/tileset_collision/protocols.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/plugins/tileset_collision/standalone.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/standalone_automap.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/standalone_error_console.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/standalone_filemanager.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/standalone_image_viewer.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/__init__.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/__main__.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/assets/__init__.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/assets/fonts/jetbrain-fonts/JetBrainsMono-Bold.ttf +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/assets/fonts/jetbrain-fonts/JetBrainsMono-BoldItalic.ttf +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/assets/fonts/jetbrain-fonts/JetBrainsMono-Italic.ttf +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/assets/fonts/jetbrain-fonts/JetBrainsMono-Regular.ttf +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/assets/fonts/noto/NotoSans-Bold.ttf +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/assets/fonts/noto/NotoSans-BoldItalic.ttf +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/assets/fonts/noto/NotoSans-Italic.ttf +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/assets/fonts/noto/NotoSans-Regular.ttf +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/assets/icons/ToolMove.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/assets/icons/arrow-down.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/assets/icons/check.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/assets/icons/checked.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/assets/icons/close.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/assets/icons/duplicate.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/assets/icons/error.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/assets/icons/file.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/assets/icons/filedead.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/assets/icons/fit.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/assets/icons/folder.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/assets/icons/grid.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/assets/icons/image.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/assets/icons/info.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/assets/icons/load.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/assets/icons/loop.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/assets/icons/pan.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/assets/icons/pause.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/assets/icons/pencil.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/assets/icons/play.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/assets/icons/plus.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/assets/icons/radio.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/assets/icons/reset.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/assets/icons/save.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/assets/icons/stop.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/assets/icons/tilemap.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/assets/icons/tileset.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/assets/icons/unchecked.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/assets/icons/warning.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/assets/icons/zoomin.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/assets/icons/zoomout.svg +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/cli.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/main.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor/settings.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor.egg-info/SOURCES.txt +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor.egg-info/dependency_links.txt +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor.egg-info/entry_points.txt +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/tilemap_editor.egg-info/requires.txt +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/ttypes/__init__.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/ttypes/tilemap.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/utils/__init__.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/utils/editor_preference.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/utils/error_handler.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/utils/font_manager.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/utils/history.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/utils/icon_manager.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/utils/icons_cache.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/utils/log_capture.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/utils/project_paths.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/utils/serialization.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/utils/standalone.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/utils/validation.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/widgets/__init__.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/widgets/automap_models.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/widgets/autotile_template.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/widgets/autotiler.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/widgets/input.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/widgets/layer_selector.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/widgets/map_properties.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/widgets/mapsetup.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/widgets/regex_automap_designer.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/widgets/spritesheet_grid.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/widgets/tile_selector.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/widgets/ui/collision_layer_mask.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/widgets/ui/collision_layer_sidebar.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/widgets/ui/confirm_dialog.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/widgets/ui/draw_utils.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/widgets/ui/fileinput.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/widgets/ui/layer_type_dialog.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/widgets/ui/mode_indicator.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/widgets/ui/node_editor.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/widgets/ui/node_selector.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/widgets/ui/notification.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/widgets/ui/property_editor.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/widgets/ui/region_selector.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/widgets/ui/status_bar.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/widgets/ui/theme.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/widgets/ui/toolbar.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/src/widgets/ui/tooltip.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/tests/test_animation_library_grid_offset.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/tests/test_collision_layer_mask.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/tests/test_collision_layer_sidebar.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/tests/test_editor_pan_mode.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/tests/test_project_paths.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/tests/test_render_scale.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/tests/test_sprite_animation_editor_grid.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/tests/test_tile_grid_selection.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/tests/test_tile_selector_pick.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/tests/test_tilemap_save.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/tests/test_timeline_invalidate_cache.py +0 -0
- {tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/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.1"
|
|
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",
|
|
@@ -242,7 +242,7 @@ class Editor:
|
|
|
242
242
|
center_x = (self.width - 400) // 2
|
|
243
243
|
center_y = (self.height - 400) // 2
|
|
244
244
|
self.map_setup_widget = MapSetup(self, Rect(center_x, center_y, 400, 400))
|
|
245
|
-
self.map_setup_widget.visible =
|
|
245
|
+
self.map_setup_widget.visible = True
|
|
246
246
|
self.map_properties_dialog = MapPropertiesDialog(self, Rect(center_x, center_y, 400, 260))
|
|
247
247
|
self.node_manager = NodeManager(self)
|
|
248
248
|
self.node_selector = NodeSelector(self, 0, 65, 260, 240)
|
|
@@ -442,6 +442,67 @@ class Editor:
|
|
|
442
442
|
except Exception as e:
|
|
443
443
|
error_handler.capture(e, context="save_map_selected")
|
|
444
444
|
|
|
445
|
+
def export_selection_as_png(self):
|
|
446
|
+
rect = self.tile_grid_widget.selection_rect
|
|
447
|
+
if rect is None:
|
|
448
|
+
self.notifications.notify("No region selected", duration=2.0)
|
|
449
|
+
return
|
|
450
|
+
self.open_file_manager(
|
|
451
|
+
on_save=self._on_export_selection_png,
|
|
452
|
+
allowed_exts=[".png"],
|
|
453
|
+
mode="save",
|
|
454
|
+
default_name="selection.png",
|
|
455
|
+
)
|
|
456
|
+
|
|
457
|
+
def _on_export_selection_png(self, path: Path):
|
|
458
|
+
rect = self.tile_grid_widget.selection_rect
|
|
459
|
+
if rect is None:
|
|
460
|
+
return
|
|
461
|
+
x1, y1, x2, y2 = rect
|
|
462
|
+
tw, th = self.tilemap.tile_size
|
|
463
|
+
pw = (x2 - x1 + 1) * tw
|
|
464
|
+
ph = (y2 - y1 + 1) * th
|
|
465
|
+
if pw <= 0 or ph <= 0:
|
|
466
|
+
return
|
|
467
|
+
|
|
468
|
+
export_surf = pygame.Surface((pw, ph), pygame.SRCALPHA)
|
|
469
|
+
layers = self.tilemap.layer_manager.get_rendered_layers()
|
|
470
|
+
tileset_map = self.tileset_widget.tileset_map
|
|
471
|
+
|
|
472
|
+
for layer in layers:
|
|
473
|
+
if layer.layer_type != "tile":
|
|
474
|
+
continue
|
|
475
|
+
if layer.opacity < 1.0:
|
|
476
|
+
layer_surf = pygame.Surface((pw, ph), pygame.SRCALPHA)
|
|
477
|
+
else:
|
|
478
|
+
layer_surf = export_surf
|
|
479
|
+
|
|
480
|
+
for (gx, gy), tile in layer.tiles.items():
|
|
481
|
+
if not (x1 <= gx <= x2 and y1 <= gy <= y2):
|
|
482
|
+
continue
|
|
483
|
+
dx = (gx - x1) * tw
|
|
484
|
+
dy = (gy - y1) * th
|
|
485
|
+
ttype = int(tile["ttype"])
|
|
486
|
+
if ttype not in tileset_map:
|
|
487
|
+
continue
|
|
488
|
+
ts = tileset_map[ttype]
|
|
489
|
+
variant_id = tile["variant"]
|
|
490
|
+
sheet_w = ts.surface.get_width()
|
|
491
|
+
sheet_cols = sheet_w // tw
|
|
492
|
+
src_x = (variant_id % sheet_cols) * tw
|
|
493
|
+
src_y = (variant_id // sheet_cols) * th
|
|
494
|
+
src_rect = Rect(src_x, src_y, tw, th)
|
|
495
|
+
if not ts.surface.get_rect().contains(src_rect):
|
|
496
|
+
continue
|
|
497
|
+
layer_surf.blit(ts.surface, (dx, dy), src_rect)
|
|
498
|
+
|
|
499
|
+
if layer.opacity < 1.0:
|
|
500
|
+
layer_surf.set_alpha(int(layer.opacity * 255))
|
|
501
|
+
export_surf.blit(layer_surf, (0, 0))
|
|
502
|
+
|
|
503
|
+
pygame.image.save(export_surf, str(path))
|
|
504
|
+
self.notifications.notify(f"Exported selection to {path.name}", duration=2.0)
|
|
505
|
+
|
|
445
506
|
def perform_load(self):
|
|
446
507
|
self.open_file_manager(
|
|
447
508
|
on_select=self.on_map_file_selected,
|
|
@@ -771,23 +832,14 @@ class Editor:
|
|
|
771
832
|
error_handler.capture(e, context="launch_animation_editor")
|
|
772
833
|
|
|
773
834
|
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."""
|
|
835
|
+
"""Launch the sprite editor (blank) in a new window. Use [Open] inside to load sheets."""
|
|
784
836
|
try:
|
|
785
837
|
tile_size = "32x32"
|
|
786
838
|
if hasattr(self.tilemap, "tile_size") and self.tilemap.tile_size:
|
|
787
839
|
tw, th = self.tilemap.tile_size
|
|
788
840
|
tile_size = f"{tw}x{th}"
|
|
789
841
|
|
|
790
|
-
args = [
|
|
842
|
+
args = ["--tile-size", tile_size, "--data-root", str(self.data_root)]
|
|
791
843
|
process = launch_standalone(
|
|
792
844
|
"plugins.sprite_editor.standalone",
|
|
793
845
|
args,
|
|
@@ -1161,6 +1213,9 @@ class Editor:
|
|
|
1161
1213
|
elif event.mod & pygame.KMOD_CTRL and event.key == pygame.K_g:
|
|
1162
1214
|
self.toggle_grid()
|
|
1163
1215
|
continue
|
|
1216
|
+
elif event.key == pygame.K_e and ctrl_held and shift_held:
|
|
1217
|
+
self.export_selection_as_png()
|
|
1218
|
+
continue
|
|
1164
1219
|
elif event.key == pygame.K_t and (ctrl_held or meta_held):
|
|
1165
1220
|
self.cycle_theme()
|
|
1166
1221
|
continue
|
|
@@ -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
|
|
@@ -1449,10 +1449,11 @@ class TileGrid:
|
|
|
1449
1449
|
|
|
1450
1450
|
sel_rect = Rect(int(sx), int(sy), int(sw), int(sh))
|
|
1451
1451
|
|
|
1452
|
-
# Semi-transparent fill
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1452
|
+
# Semi-transparent fill (skip during drag to avoid visual noise)
|
|
1453
|
+
if not self.is_selecting:
|
|
1454
|
+
fill_surf = pygame.Surface((int(sw), int(sh)), pygame.SRCALPHA)
|
|
1455
|
+
fill_surf.fill((100, 180, 255, 40))
|
|
1456
|
+
screen.blit(fill_surf, (int(sx), int(sy)))
|
|
1456
1457
|
|
|
1457
1458
|
# Dashed border (draw segments)
|
|
1458
1459
|
border_color = (100, 180, 255) if not self.is_moving else (255, 200, 50)
|
|
@@ -76,6 +76,11 @@ class MenuBar:
|
|
|
76
76
|
MenuAction(
|
|
77
77
|
"Toggle Auto-Autotile", self.editor.toggle_auto_autotile
|
|
78
78
|
),
|
|
79
|
+
MenuAction(
|
|
80
|
+
"Export Selection as PNG",
|
|
81
|
+
self.editor.export_selection_as_png,
|
|
82
|
+
"Ctrl+Shift+E",
|
|
83
|
+
),
|
|
79
84
|
MenuAction(
|
|
80
85
|
"Launch External Viewer", self.editor.launch_external_automap
|
|
81
86
|
),
|
|
@@ -71,7 +71,7 @@ class TilesetTypeDialog:
|
|
|
71
71
|
"""Position child controls from the current dialog rect."""
|
|
72
72
|
self.rect.center = self.editor_rect.center
|
|
73
73
|
|
|
74
|
-
h =
|
|
74
|
+
h = 260
|
|
75
75
|
if self.animated or self._editing_field is not None:
|
|
76
76
|
h = 420
|
|
77
77
|
self.rect.h = h
|
|
@@ -97,7 +97,7 @@ class TilesetTypeDialog:
|
|
|
97
97
|
)
|
|
98
98
|
|
|
99
99
|
# Animated checkbox
|
|
100
|
-
anim_y = first_y + (row_h + gap) * 2 +
|
|
100
|
+
anim_y = first_y + (row_h + gap) * 2 + 16
|
|
101
101
|
self.anim_check_rect = Rect(radio_x, anim_y, 16, 16)
|
|
102
102
|
|
|
103
103
|
# Animation fields (collapsible)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/assets/fonts/jetbrain-fonts/JetBrainsMono-Bold.ttf
RENAMED
|
File without changes
|
|
File without changes
|
{tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/assets/fonts/jetbrain-fonts/JetBrainsMono-Italic.ttf
RENAMED
|
File without changes
|
{tilemap_editor-3.2.10 → tilemap_editor-3.3.1}/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
|