tilemap-editor 3.1.7__tar.gz → 3.2.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.1.7/src/tilemap_editor.egg-info → tilemap_editor-3.2.0}/PKG-INFO +1 -1
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/pyproject.toml +1 -1
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/editor.py +24 -0
- tilemap_editor-3.2.0/src/plugins/sprite_editor/__init__.py +3 -0
- tilemap_editor-3.2.0/src/plugins/sprite_editor/editor.py +323 -0
- tilemap_editor-3.2.0/src/plugins/sprite_editor/standalone.py +118 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0/src/tilemap_editor.egg-info}/PKG-INFO +1 -1
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor.egg-info/SOURCES.txt +4 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/widgets/autotiler.py +2 -0
- tilemap_editor-3.2.0/src/widgets/spritesheet_grid.py +580 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/widgets/tile_selector.py +50 -14
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/widgets/ui/menubar.py +1 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/LICENSE +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/MANIFEST.in +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/README.md +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/assets/fonts/jetbrain-fonts/JetBrainsMono-Bold.ttf +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/assets/fonts/jetbrain-fonts/JetBrainsMono-BoldItalic.ttf +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/assets/fonts/jetbrain-fonts/JetBrainsMono-Italic.ttf +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/assets/fonts/jetbrain-fonts/JetBrainsMono-Regular.ttf +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/assets/fonts/noto/NotoSans-Bold.ttf +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/assets/fonts/noto/NotoSans-BoldItalic.ttf +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/assets/fonts/noto/NotoSans-Italic.ttf +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/assets/fonts/noto/NotoSans-Regular.ttf +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/assets/icons/arrow-down.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/assets/icons/check.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/assets/icons/checked.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/assets/icons/close.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/assets/icons/duplicate.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/assets/icons/error.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/assets/icons/file.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/assets/icons/filedead.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/assets/icons/fit.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/assets/icons/folder.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/assets/icons/grid.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/assets/icons/image.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/assets/icons/info.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/assets/icons/load.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/assets/icons/loop.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/assets/icons/pan.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/assets/icons/pause.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/assets/icons/pencil.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/assets/icons/play.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/assets/icons/plus.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/assets/icons/radio.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/assets/icons/reset.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/assets/icons/save.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/assets/icons/stop.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/assets/icons/tilemap.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/assets/icons/tileset.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/assets/icons/unchecked.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/assets/icons/warning.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/assets/icons/zoomin.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/assets/icons/zoomout.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/setup.cfg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/configs/themes.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/constants.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/event_map.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/layers.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/main.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/plugins/__init__.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/plugins/character_collision/__init__.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/plugins/character_collision/editor.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/plugins/character_collision/models.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/plugins/character_collision/protocols.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/plugins/character_collision/shape_editor.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/plugins/character_collision/standalone.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/plugins/object_tileset_collision/__init__.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/plugins/object_tileset_collision/editor.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/plugins/object_tileset_collision/models.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/plugins/object_tileset_collision/protocols.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/plugins/object_tileset_collision/standalone.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/plugins/sprite_animation/__init__.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/plugins/sprite_animation/__main__.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/plugins/sprite_animation/clipboard_util.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/plugins/sprite_animation/editor.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/plugins/sprite_animation/frame_picker.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/plugins/sprite_animation/models.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/plugins/sprite_animation/preview.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/plugins/sprite_animation/protocols.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/plugins/sprite_animation/runtime_load.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/plugins/sprite_animation/standalone.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/plugins/sprite_animation/timeline.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/plugins/sprite_animation/validation.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/plugins/tileset_collision/__init__.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/plugins/tileset_collision/collision_painter.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/plugins/tileset_collision/editor.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/plugins/tileset_collision/models.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/plugins/tileset_collision/protocols.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/plugins/tileset_collision/standalone.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/standalone_automap.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/standalone_error_console.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/standalone_filemanager.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/standalone_image_viewer.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/__init__.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/__main__.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/assets/__init__.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/assets/fonts/jetbrain-fonts/JetBrainsMono-Bold.ttf +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/assets/fonts/jetbrain-fonts/JetBrainsMono-BoldItalic.ttf +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/assets/fonts/jetbrain-fonts/JetBrainsMono-Italic.ttf +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/assets/fonts/jetbrain-fonts/JetBrainsMono-Regular.ttf +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/assets/fonts/noto/NotoSans-Bold.ttf +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/assets/fonts/noto/NotoSans-BoldItalic.ttf +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/assets/fonts/noto/NotoSans-Italic.ttf +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/assets/fonts/noto/NotoSans-Regular.ttf +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/assets/icons/ToolMove.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/assets/icons/arrow-down.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/assets/icons/check.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/assets/icons/checked.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/assets/icons/close.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/assets/icons/duplicate.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/assets/icons/error.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/assets/icons/file.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/assets/icons/filedead.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/assets/icons/fit.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/assets/icons/folder.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/assets/icons/grid.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/assets/icons/image.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/assets/icons/info.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/assets/icons/load.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/assets/icons/loop.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/assets/icons/pan.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/assets/icons/pause.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/assets/icons/pencil.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/assets/icons/play.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/assets/icons/plus.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/assets/icons/radio.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/assets/icons/reset.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/assets/icons/save.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/assets/icons/stop.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/assets/icons/tilemap.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/assets/icons/tileset.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/assets/icons/unchecked.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/assets/icons/warning.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/assets/icons/zoomin.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/assets/icons/zoomout.svg +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/cli.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/main.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor/settings.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor.egg-info/dependency_links.txt +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor.egg-info/entry_points.txt +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor.egg-info/requires.txt +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/tilemap_editor.egg-info/top_level.txt +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/ttypes/__init__.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/ttypes/tilemap.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/utils/__init__.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/utils/editor_preference.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/utils/error_handler.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/utils/font_manager.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/utils/history.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/utils/icon_manager.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/utils/icons_cache.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/utils/log_capture.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/utils/project_paths.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/utils/serialization.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/utils/standalone.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/utils/validation.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/widgets/__init__.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/widgets/automap_models.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/widgets/autotile_template.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/widgets/filemanager.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/widgets/input.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/widgets/layer_selector.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/widgets/map_properties.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/widgets/mapsetup.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/widgets/regex_automap_designer.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/widgets/tile_grid.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/widgets/ui/collision_layer_mask.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/widgets/ui/collision_layer_sidebar.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/widgets/ui/draw_utils.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/widgets/ui/fileinput.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/widgets/ui/layer_type_dialog.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/widgets/ui/mode_indicator.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/widgets/ui/notification.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/widgets/ui/property_editor.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/widgets/ui/region_selector.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/widgets/ui/status_bar.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/widgets/ui/theme.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/widgets/ui/tileset_type_dialog.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/widgets/ui/toolbar.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/src/widgets/ui/tooltip.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/tests/test_collision_layer_mask.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/tests/test_collision_layer_sidebar.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/tests/test_project_paths.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/tests/test_render_scale.py +0 -0
- {tilemap_editor-3.1.7 → tilemap_editor-3.2.0}/tests/test_tilemap_save.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.2.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"
|
|
@@ -40,6 +40,7 @@ from utils import error_handler, error_context
|
|
|
40
40
|
|
|
41
41
|
if TYPE_CHECKING:
|
|
42
42
|
from plugins.sprite_animation import SpriteAnimationEditor
|
|
43
|
+
from plugins.sprite_editor import SpriteEditor
|
|
43
44
|
|
|
44
45
|
|
|
45
46
|
def setup_error_logging():
|
|
@@ -710,6 +711,29 @@ class Editor:
|
|
|
710
711
|
except Exception as e:
|
|
711
712
|
error_handler.capture(e, context="launch_animation_editor")
|
|
712
713
|
|
|
714
|
+
def launch_sprite_editor(self):
|
|
715
|
+
"""Launch the sprite editor in a new window."""
|
|
716
|
+
self.open_file_manager(
|
|
717
|
+
on_select=self._launch_sprite_editor_with_image,
|
|
718
|
+
initial_dir=self.data_root,
|
|
719
|
+
allowed_exts=[".png", ".jpg", ".jpeg"],
|
|
720
|
+
mode="open",
|
|
721
|
+
)
|
|
722
|
+
|
|
723
|
+
def _launch_sprite_editor_with_image(self, path: Path):
|
|
724
|
+
"""Launch sprite editor subprocess with selected image."""
|
|
725
|
+
try:
|
|
726
|
+
args = [str(path), "--data-root", str(self.data_root)]
|
|
727
|
+
process = launch_standalone(
|
|
728
|
+
"plugins.sprite_editor.standalone",
|
|
729
|
+
args,
|
|
730
|
+
cwd=self.base_path,
|
|
731
|
+
text=True,
|
|
732
|
+
)
|
|
733
|
+
self.child_processes.append(process)
|
|
734
|
+
except Exception as e:
|
|
735
|
+
error_handler.capture(e, context="launch_sprite_editor")
|
|
736
|
+
|
|
713
737
|
def launch_collision_editor(self, tileset_type: str = "tile"):
|
|
714
738
|
"""Launch the collision editor in a new window.
|
|
715
739
|
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
"""
|
|
2
|
+
SpriteEditor — standalone widget wrapping SpritesheetGrid with editing toolbar.
|
|
3
|
+
|
|
4
|
+
Toolbar:
|
|
5
|
+
[Flip X] [Flip Y] [Copy] [Paste] [Undo] [Redo] [Scale...] [Save PNG]
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Dict, Optional
|
|
12
|
+
|
|
13
|
+
import pygame
|
|
14
|
+
from pygame import Rect, Surface
|
|
15
|
+
|
|
16
|
+
from widgets.spritesheet_grid import SpritesheetGrid
|
|
17
|
+
from widgets.ui.theme import COLORS
|
|
18
|
+
from widgets.ui.draw_utils import draw_panel, draw_button
|
|
19
|
+
from utils.font_manager import font_manager, FontWeight
|
|
20
|
+
from utils.icon_manager import icon_manager
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
TOOLBAR_H = 42
|
|
24
|
+
STATUS_H = 22
|
|
25
|
+
BTN_W = 64
|
|
26
|
+
BTN_H = 28
|
|
27
|
+
|
|
28
|
+
# Map toolbar labels to icon_manager keys (None = text only)
|
|
29
|
+
_BUTTON_ICONS: dict[str, str | None] = {
|
|
30
|
+
"Flip X": None,
|
|
31
|
+
"Flip Y": None,
|
|
32
|
+
"Copy": "duplicate",
|
|
33
|
+
"Paste": None,
|
|
34
|
+
"Undo": None,
|
|
35
|
+
"Redo": None,
|
|
36
|
+
"Scale": None,
|
|
37
|
+
"Save": "save",
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class SpriteEditor:
|
|
42
|
+
def __init__(
|
|
43
|
+
self,
|
|
44
|
+
rect: Rect,
|
|
45
|
+
surface: Surface,
|
|
46
|
+
tile_size: tuple[int, int],
|
|
47
|
+
image_path: Optional[Path] = None,
|
|
48
|
+
data_root: Optional[Path] = None,
|
|
49
|
+
):
|
|
50
|
+
self.rect = rect
|
|
51
|
+
self.image_path = image_path
|
|
52
|
+
self._data_root = data_root or (image_path.parent if image_path else Path.cwd())
|
|
53
|
+
|
|
54
|
+
# Grid
|
|
55
|
+
grid_rect = Rect(rect.x, rect.y + TOOLBAR_H, rect.w, rect.h - TOOLBAR_H - STATUS_H)
|
|
56
|
+
self.grid = SpritesheetGrid(grid_rect, surface, tile_size)
|
|
57
|
+
|
|
58
|
+
# Clipboard for copy/paste
|
|
59
|
+
self._clipboard: Dict[int, Surface] = {}
|
|
60
|
+
self._paste_mode: bool = False
|
|
61
|
+
|
|
62
|
+
# Scale dialog state
|
|
63
|
+
self._scale_active: bool = False
|
|
64
|
+
self._scale_text: str = "2.0"
|
|
65
|
+
self._scale_error: Optional[str] = None
|
|
66
|
+
|
|
67
|
+
# Save path — never auto-overwrite original
|
|
68
|
+
self._save_path: Optional[Path] = None
|
|
69
|
+
|
|
70
|
+
# File manager modal
|
|
71
|
+
self._file_manager: Optional[object] = None
|
|
72
|
+
|
|
73
|
+
# Toolbar button rects
|
|
74
|
+
self._btn_rects: dict[str, Rect] = {}
|
|
75
|
+
self._layout_toolbar()
|
|
76
|
+
|
|
77
|
+
self._font = font_manager.get_font("monospace", 13, FontWeight.BOLD)
|
|
78
|
+
self._font_sm = font_manager.get_font("monospace", 11, FontWeight.BOLD)
|
|
79
|
+
|
|
80
|
+
def _layout_toolbar(self) -> None:
|
|
81
|
+
ty = self.rect.y + (TOOLBAR_H - BTN_H) // 2
|
|
82
|
+
gap = 6
|
|
83
|
+
x = self.rect.x + gap
|
|
84
|
+
labels = ["Flip X", "Flip Y", "Copy", "Paste", "Undo", "Redo", "Scale", "Save"]
|
|
85
|
+
for lbl in labels:
|
|
86
|
+
self._btn_rects[lbl] = Rect(x, ty, BTN_W, BTN_H)
|
|
87
|
+
x += BTN_W + gap
|
|
88
|
+
|
|
89
|
+
def _get_status_text(self) -> str:
|
|
90
|
+
parts = [f"Zoom: {self.grid.zoom:.1f}x"]
|
|
91
|
+
sel = len(self.grid.selected_indices)
|
|
92
|
+
if sel:
|
|
93
|
+
parts.append(f"Selected: {sel}")
|
|
94
|
+
if self._paste_mode:
|
|
95
|
+
parts.append("Click grid to paste")
|
|
96
|
+
if self.grid.can_undo:
|
|
97
|
+
parts.append(f"Undo ({len(self.grid._undo_stack)})")
|
|
98
|
+
return " | ".join(parts)
|
|
99
|
+
|
|
100
|
+
# ------------------------------------------------------------------
|
|
101
|
+
# Events
|
|
102
|
+
# ------------------------------------------------------------------
|
|
103
|
+
|
|
104
|
+
def handle_event(self, event: pygame.event.Event) -> bool:
|
|
105
|
+
# File manager modal blocks everything
|
|
106
|
+
if self._file_manager is not None:
|
|
107
|
+
return self._file_manager.handle_event(event)
|
|
108
|
+
|
|
109
|
+
if self._scale_active:
|
|
110
|
+
return self._handle_scale_dialog(event)
|
|
111
|
+
|
|
112
|
+
mouse = pygame.mouse.get_pos()
|
|
113
|
+
|
|
114
|
+
# Keyboard shortcuts
|
|
115
|
+
if event.type == pygame.KEYDOWN:
|
|
116
|
+
mods = pygame.key.get_mods()
|
|
117
|
+
ctrl = mods & (pygame.KMOD_LCTRL | pygame.KMOD_LMETA)
|
|
118
|
+
|
|
119
|
+
if ctrl:
|
|
120
|
+
if event.key == pygame.K_z:
|
|
121
|
+
if self.grid.undo():
|
|
122
|
+
self.grid.selected_indices.clear()
|
|
123
|
+
return True
|
|
124
|
+
elif event.key == pygame.K_y:
|
|
125
|
+
if self.grid.redo():
|
|
126
|
+
self.grid.selected_indices.clear()
|
|
127
|
+
return True
|
|
128
|
+
|
|
129
|
+
# Toolbar clicks
|
|
130
|
+
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
|
|
131
|
+
for lbl, r in self._btn_rects.items():
|
|
132
|
+
if r.collidepoint(mouse):
|
|
133
|
+
return self._handle_tool(lbl)
|
|
134
|
+
|
|
135
|
+
# Paste mode: next grid click pastes
|
|
136
|
+
if self._paste_mode and event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
|
|
137
|
+
idx = self.grid.index_at_pos(mouse)
|
|
138
|
+
if idx >= 0 and self.grid.rect.collidepoint(mouse):
|
|
139
|
+
self.grid.paste_at(idx, self._clipboard)
|
|
140
|
+
self._paste_mode = False
|
|
141
|
+
self.grid.paste_preview_idx = -1
|
|
142
|
+
return True
|
|
143
|
+
|
|
144
|
+
# Paste preview on hover
|
|
145
|
+
if self._paste_mode and event.type == pygame.MOUSEMOTION:
|
|
146
|
+
idx = self.grid.index_at_pos(mouse)
|
|
147
|
+
self.grid.paste_preview_idx = idx if idx >= 0 else -1
|
|
148
|
+
|
|
149
|
+
return self.grid.handle_event(event)
|
|
150
|
+
|
|
151
|
+
def _handle_tool(self, lbl: str) -> bool:
|
|
152
|
+
if lbl == "Flip X":
|
|
153
|
+
if self.grid.has_selection():
|
|
154
|
+
self.grid.flip_selected(True, False)
|
|
155
|
+
return True
|
|
156
|
+
elif lbl == "Flip Y":
|
|
157
|
+
if self.grid.has_selection():
|
|
158
|
+
self.grid.flip_selected(False, True)
|
|
159
|
+
return True
|
|
160
|
+
elif lbl == "Copy":
|
|
161
|
+
if self.grid.has_selection():
|
|
162
|
+
self._clipboard = self.grid.copy_selected()
|
|
163
|
+
self._paste_mode = False
|
|
164
|
+
self.grid.paste_preview_idx = -1
|
|
165
|
+
return True
|
|
166
|
+
elif lbl == "Paste":
|
|
167
|
+
if self._clipboard:
|
|
168
|
+
self._paste_mode = not self._paste_mode
|
|
169
|
+
if not self._paste_mode:
|
|
170
|
+
self.grid.paste_preview_idx = -1
|
|
171
|
+
return True
|
|
172
|
+
elif lbl == "Undo":
|
|
173
|
+
self.grid.undo()
|
|
174
|
+
self.grid.selected_indices.clear()
|
|
175
|
+
return True
|
|
176
|
+
elif lbl == "Redo":
|
|
177
|
+
self.grid.redo()
|
|
178
|
+
self.grid.selected_indices.clear()
|
|
179
|
+
return True
|
|
180
|
+
elif lbl == "Scale":
|
|
181
|
+
self._scale_active = True
|
|
182
|
+
self._scale_text = "2.0"
|
|
183
|
+
self._scale_error = None
|
|
184
|
+
return True
|
|
185
|
+
elif lbl == "Save":
|
|
186
|
+
self._open_save_dialog()
|
|
187
|
+
return True
|
|
188
|
+
return False
|
|
189
|
+
|
|
190
|
+
def _handle_scale_dialog(self, event: pygame.event.Event) -> bool:
|
|
191
|
+
if event.type == pygame.KEYDOWN:
|
|
192
|
+
if event.key in (pygame.K_RETURN, pygame.K_KP_ENTER):
|
|
193
|
+
try:
|
|
194
|
+
factor = float(self._scale_text)
|
|
195
|
+
if factor <= 0:
|
|
196
|
+
self._scale_error = "Must be > 0"
|
|
197
|
+
else:
|
|
198
|
+
self.grid.scale(factor)
|
|
199
|
+
self._scale_active = False
|
|
200
|
+
self._scale_error = None
|
|
201
|
+
except ValueError:
|
|
202
|
+
self._scale_error = "Invalid number"
|
|
203
|
+
return True
|
|
204
|
+
elif event.key == pygame.K_ESCAPE:
|
|
205
|
+
self._scale_active = False
|
|
206
|
+
self._scale_error = None
|
|
207
|
+
return True
|
|
208
|
+
elif event.key == pygame.K_BACKSPACE:
|
|
209
|
+
self._scale_text = self._scale_text[:-1]
|
|
210
|
+
return True
|
|
211
|
+
elif event.unicode and event.unicode in "0123456789." and len(self._scale_text) < 8:
|
|
212
|
+
self._scale_text += event.unicode
|
|
213
|
+
return True
|
|
214
|
+
return False
|
|
215
|
+
|
|
216
|
+
def _open_save_dialog(self) -> None:
|
|
217
|
+
"""Open FileManager in save mode to pick a PNG path."""
|
|
218
|
+
from widgets.filemanager import FileManager
|
|
219
|
+
|
|
220
|
+
initial_dir = self._save_path.parent if self._save_path else self._data_root
|
|
221
|
+
default_name = self._save_path.name if self._save_path else (
|
|
222
|
+
f"{self.image_path.stem}_edited.png" if self.image_path else "spritesheet.png"
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
fm_rect = self._file_manager_rect()
|
|
226
|
+
self._file_manager = FileManager(
|
|
227
|
+
rect=fm_rect,
|
|
228
|
+
initial_dir=initial_dir,
|
|
229
|
+
allowed_exts=[".png"],
|
|
230
|
+
on_save=self._on_save_path_selected,
|
|
231
|
+
mode="save",
|
|
232
|
+
default_name=default_name,
|
|
233
|
+
on_cancel=self._close_file_manager,
|
|
234
|
+
data_root=self._data_root,
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
def _on_save_path_selected(self, path: Path) -> None:
|
|
238
|
+
try:
|
|
239
|
+
self.grid.save_png(path)
|
|
240
|
+
self._save_path = path
|
|
241
|
+
except Exception as e:
|
|
242
|
+
print(f"Save failed: {e}")
|
|
243
|
+
self._close_file_manager()
|
|
244
|
+
|
|
245
|
+
def _close_file_manager(self) -> None:
|
|
246
|
+
self._file_manager = None
|
|
247
|
+
|
|
248
|
+
def _file_manager_rect(self) -> Rect:
|
|
249
|
+
w, h = 600, 400
|
|
250
|
+
cx, cy = self.rect.center
|
|
251
|
+
return Rect(cx - w // 2, cy - h // 2, w, h)
|
|
252
|
+
|
|
253
|
+
def set_save_path(self, path: Path) -> None:
|
|
254
|
+
self._save_path = path
|
|
255
|
+
|
|
256
|
+
# ------------------------------------------------------------------
|
|
257
|
+
# Drawing
|
|
258
|
+
# ------------------------------------------------------------------
|
|
259
|
+
|
|
260
|
+
def draw(self, screen: Surface) -> None:
|
|
261
|
+
draw_panel(screen, self.rect, COLORS.bg, COLORS.border)
|
|
262
|
+
|
|
263
|
+
# Toolbar
|
|
264
|
+
toolbar_rect = Rect(self.rect.x, self.rect.y, self.rect.w, TOOLBAR_H)
|
|
265
|
+
draw_panel(screen, toolbar_rect, COLORS.header, COLORS.border)
|
|
266
|
+
|
|
267
|
+
mouse = pygame.mouse.get_pos()
|
|
268
|
+
for lbl, r in self._btn_rects.items():
|
|
269
|
+
hover = r.collidepoint(mouse)
|
|
270
|
+
active = (lbl == "Paste" and self._paste_mode)
|
|
271
|
+
disable = (lbl in ("Undo",) and not self.grid.can_undo) or \
|
|
272
|
+
(lbl in ("Redo",) and not self.grid.can_redo)
|
|
273
|
+
|
|
274
|
+
icon_key = _BUTTON_ICONS.get(lbl)
|
|
275
|
+
if icon_key and icon_manager.has_icon(icon_key):
|
|
276
|
+
color = COLORS.text_dim if disable else COLORS.text
|
|
277
|
+
icon = icon_manager.get_icon(icon_key, 18, color)
|
|
278
|
+
draw_button(screen, r, icon, hover=hover and not disable, active=active and not disable)
|
|
279
|
+
else:
|
|
280
|
+
label_surf = self._font_sm.render(lbl, True, COLORS.text_dim if disable else COLORS.text)
|
|
281
|
+
draw_button(screen, r, label_surf, hover=hover and not disable, active=active and not disable)
|
|
282
|
+
|
|
283
|
+
# Grid
|
|
284
|
+
if self._file_manager is None:
|
|
285
|
+
self.grid.draw(screen)
|
|
286
|
+
|
|
287
|
+
# Status bar
|
|
288
|
+
status_rect = Rect(self.rect.x, self.rect.bottom - STATUS_H, self.rect.w, STATUS_H)
|
|
289
|
+
draw_panel(screen, status_rect, COLORS.header, COLORS.border)
|
|
290
|
+
st = self._get_status_text()
|
|
291
|
+
screen.blit(
|
|
292
|
+
self._font_sm.render(st, True, COLORS.text_dim),
|
|
293
|
+
(status_rect.x + 6, status_rect.y + 4),
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
if self._scale_active:
|
|
297
|
+
self._draw_scale_dialog(screen)
|
|
298
|
+
|
|
299
|
+
# File manager overlay
|
|
300
|
+
if self._file_manager is not None:
|
|
301
|
+
self._file_manager.draw(screen)
|
|
302
|
+
|
|
303
|
+
def _draw_scale_dialog(self, screen: Surface) -> None:
|
|
304
|
+
dw, dh = 260, 100
|
|
305
|
+
cx, cy = self.rect.center
|
|
306
|
+
dlg = Rect(cx - dw // 2, cy - dh // 2, dw, dh)
|
|
307
|
+
draw_panel(screen, dlg, COLORS.panel, COLORS.border)
|
|
308
|
+
|
|
309
|
+
title = self._font.render("Scale Factor", True, COLORS.text)
|
|
310
|
+
screen.blit(title, title.get_rect(centerx=dlg.centerx, top=dlg.top + 10))
|
|
311
|
+
|
|
312
|
+
inp = Rect(dlg.x + 20, dlg.top + 36, dw - 40, 28)
|
|
313
|
+
pygame.draw.rect(screen, COLORS.selected, inp, border_radius=4)
|
|
314
|
+
pygame.draw.rect(screen, COLORS.accent, inp, 2, border_radius=4)
|
|
315
|
+
txt = self._scale_text + ("|" if (pygame.time.get_ticks() // 400) % 2 else "")
|
|
316
|
+
screen.blit(self._font_sm.render(txt, True, COLORS.text), (inp.x + 6, inp.y + 5))
|
|
317
|
+
|
|
318
|
+
if self._scale_error:
|
|
319
|
+
err = self._font_sm.render(self._scale_error, True, COLORS.danger)
|
|
320
|
+
screen.blit(err, (dlg.x + 20, dlg.bottom - 22))
|
|
321
|
+
|
|
322
|
+
hint = self._font_sm.render("Enter / Esc", True, COLORS.text_dim)
|
|
323
|
+
screen.blit(hint, (dlg.right - 90, dlg.bottom - 22))
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Standalone launcher for the Sprite Editor.
|
|
3
|
+
|
|
4
|
+
Usage:
|
|
5
|
+
python standalone.py path/to/spritesheet.png
|
|
6
|
+
python standalone.py path/to/spritesheet.png --tile-size 32
|
|
7
|
+
python standalone.py path/to/spritesheet.png --save output.png
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import argparse
|
|
13
|
+
import sys
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
|
|
16
|
+
_current_file = Path(__file__).resolve()
|
|
17
|
+
_src_dir = _current_file.parent.parent.parent
|
|
18
|
+
if str(_src_dir) not in sys.path:
|
|
19
|
+
sys.path.insert(0, str(_src_dir))
|
|
20
|
+
|
|
21
|
+
import pygame
|
|
22
|
+
from pygame import Rect
|
|
23
|
+
|
|
24
|
+
try:
|
|
25
|
+
from .editor import SpriteEditor, TOOLBAR_H, STATUS_H
|
|
26
|
+
except ImportError:
|
|
27
|
+
from plugins.sprite_editor.editor import SpriteEditor, TOOLBAR_H, STATUS_H
|
|
28
|
+
from utils import error_handler, error_context
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def parse_window_size(s: str) -> tuple[int, int]:
|
|
32
|
+
parts = s.lower().split("x")
|
|
33
|
+
if len(parts) == 2:
|
|
34
|
+
return int(parts[0]), int(parts[1])
|
|
35
|
+
v = int(parts[0])
|
|
36
|
+
return v, v
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def main(argv: list[str] | None = None) -> None:
|
|
40
|
+
def handle_exception(exc_type, exc_value, exc_traceback):
|
|
41
|
+
if issubclass(exc_type, KeyboardInterrupt):
|
|
42
|
+
sys.__excepthook__(exc_type, exc_value, exc_traceback)
|
|
43
|
+
return
|
|
44
|
+
error_handler.capture(exc_value, context="sprite_editor_exception")
|
|
45
|
+
sys.__excepthook__(exc_type, exc_value, exc_traceback)
|
|
46
|
+
|
|
47
|
+
sys.excepthook = handle_exception
|
|
48
|
+
|
|
49
|
+
parser = argparse.ArgumentParser(description="Grid Sprite Editor")
|
|
50
|
+
parser.add_argument("image", type=str, help="Path to spritesheet image")
|
|
51
|
+
parser.add_argument("--tile-size", type=str, default="32",
|
|
52
|
+
help="Tile size (e.g. 32 or 32x32)")
|
|
53
|
+
parser.add_argument("--save", type=str, default=None,
|
|
54
|
+
help="Output path for modified spritesheet")
|
|
55
|
+
parser.add_argument("--window-size", type=str, default="1000x700",
|
|
56
|
+
help="Window size WxH (default 1000x700)")
|
|
57
|
+
parser.add_argument("--data-root", type=str, default=None,
|
|
58
|
+
help="Project data root (for file dialogs)")
|
|
59
|
+
|
|
60
|
+
args = parser.parse_args(argv)
|
|
61
|
+
|
|
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
|
+
ts_parts = args.tile_size.lower().split("x")
|
|
68
|
+
tw = int(ts_parts[0])
|
|
69
|
+
th = int(ts_parts[1]) if len(ts_parts) > 1 else tw
|
|
70
|
+
|
|
71
|
+
window_size = parse_window_size(args.window_size)
|
|
72
|
+
data_root = Path(args.data_root) if args.data_root else image_path.parent
|
|
73
|
+
|
|
74
|
+
pygame.init()
|
|
75
|
+
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
|
+
|
|
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
|
+
|
|
87
|
+
clock = pygame.time.Clock()
|
|
88
|
+
running = True
|
|
89
|
+
|
|
90
|
+
with error_context("sprite_editor"):
|
|
91
|
+
while running:
|
|
92
|
+
clock.tick(60)
|
|
93
|
+
for event in pygame.event.get():
|
|
94
|
+
if event.type == pygame.QUIT:
|
|
95
|
+
running = False
|
|
96
|
+
elif event.type == pygame.VIDEORESIZE:
|
|
97
|
+
screen = pygame.display.set_mode(
|
|
98
|
+
(event.w, event.h), pygame.RESIZABLE
|
|
99
|
+
)
|
|
100
|
+
editor.rect = screen.get_rect()
|
|
101
|
+
editor.grid.rect = Rect(
|
|
102
|
+
editor.rect.x,
|
|
103
|
+
editor.rect.y + TOOLBAR_H,
|
|
104
|
+
editor.rect.w,
|
|
105
|
+
editor.rect.h - TOOLBAR_H - STATUS_H,
|
|
106
|
+
)
|
|
107
|
+
else:
|
|
108
|
+
editor.handle_event(event)
|
|
109
|
+
|
|
110
|
+
screen.fill((0, 0, 0))
|
|
111
|
+
editor.draw(screen)
|
|
112
|
+
pygame.display.flip()
|
|
113
|
+
|
|
114
|
+
pygame.quit()
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
if __name__ == "__main__":
|
|
118
|
+
main()
|
|
@@ -75,6 +75,9 @@ src/plugins/sprite_animation/runtime_load.py
|
|
|
75
75
|
src/plugins/sprite_animation/standalone.py
|
|
76
76
|
src/plugins/sprite_animation/timeline.py
|
|
77
77
|
src/plugins/sprite_animation/validation.py
|
|
78
|
+
src/plugins/sprite_editor/__init__.py
|
|
79
|
+
src/plugins/sprite_editor/editor.py
|
|
80
|
+
src/plugins/sprite_editor/standalone.py
|
|
78
81
|
src/plugins/tileset_collision/__init__.py
|
|
79
82
|
src/plugins/tileset_collision/collision_painter.py
|
|
80
83
|
src/plugins/tileset_collision/editor.py
|
|
@@ -156,6 +159,7 @@ src/widgets/layer_selector.py
|
|
|
156
159
|
src/widgets/map_properties.py
|
|
157
160
|
src/widgets/mapsetup.py
|
|
158
161
|
src/widgets/regex_automap_designer.py
|
|
162
|
+
src/widgets/spritesheet_grid.py
|
|
159
163
|
src/widgets/tile_grid.py
|
|
160
164
|
src/widgets/tile_selector.py
|
|
161
165
|
src/widgets/ui/collision_layer_mask.py
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import pygame
|
|
2
2
|
from pygame import Surface, Rect, Color
|
|
3
3
|
from typing import TYPE_CHECKING, List, Tuple, Set, Optional
|
|
4
|
+
from pathlib import Path
|
|
4
5
|
import time
|
|
5
6
|
|
|
7
|
+
from constants import BASE_PATH
|
|
6
8
|
from utils.error_handler import error_handler
|
|
7
9
|
from utils.icon_manager import icon_manager
|
|
8
10
|
from .autotile_template import AutotileTemplateApplier
|