tilemap-editor 3.2.5__tar.gz → 3.2.7__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.5/src/tilemap_editor.egg-info → tilemap_editor-3.2.7}/PKG-INFO +1 -1
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/pyproject.toml +1 -1
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/editor.py +13 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/plugins/character_collision/shape_editor.py +3 -3
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/plugins/sprite_animation/editor.py +7 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/plugins/sprite_animation/preview.py +9 -2
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7/src/tilemap_editor.egg-info}/PKG-INFO +1 -1
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor.egg-info/SOURCES.txt +1 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/widgets/tile_grid.py +14 -11
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/widgets/tile_selector.py +72 -46
- tilemap_editor-3.2.7/src/widgets/ui/confirm_dialog.py +149 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/LICENSE +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/MANIFEST.in +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/README.md +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/assets/fonts/jetbrain-fonts/JetBrainsMono-Bold.ttf +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/assets/fonts/jetbrain-fonts/JetBrainsMono-BoldItalic.ttf +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/assets/fonts/jetbrain-fonts/JetBrainsMono-Italic.ttf +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/assets/fonts/jetbrain-fonts/JetBrainsMono-Regular.ttf +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/assets/fonts/noto/NotoSans-Bold.ttf +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/assets/fonts/noto/NotoSans-BoldItalic.ttf +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/assets/fonts/noto/NotoSans-Italic.ttf +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/assets/fonts/noto/NotoSans-Regular.ttf +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/assets/icons/arrow-down.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/assets/icons/check.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/assets/icons/checked.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/assets/icons/close.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/assets/icons/duplicate.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/assets/icons/error.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/assets/icons/file.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/assets/icons/filedead.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/assets/icons/fit.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/assets/icons/folder.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/assets/icons/grid.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/assets/icons/image.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/assets/icons/info.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/assets/icons/load.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/assets/icons/loop.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/assets/icons/pan.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/assets/icons/pause.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/assets/icons/pencil.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/assets/icons/play.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/assets/icons/plus.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/assets/icons/radio.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/assets/icons/reset.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/assets/icons/save.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/assets/icons/stop.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/assets/icons/tilemap.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/assets/icons/tileset.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/assets/icons/unchecked.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/assets/icons/warning.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/assets/icons/zoomin.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/assets/icons/zoomout.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/setup.cfg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/configs/themes.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/constants.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/event_map.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/layers.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/main.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/plugins/__init__.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/plugins/character_collision/__init__.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/plugins/character_collision/editor.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/plugins/character_collision/models.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/plugins/character_collision/protocols.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/plugins/character_collision/standalone.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/plugins/object_tileset_collision/__init__.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/plugins/object_tileset_collision/editor.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/plugins/object_tileset_collision/models.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/plugins/object_tileset_collision/protocols.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/plugins/object_tileset_collision/standalone.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/plugins/sprite_animation/__init__.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/plugins/sprite_animation/__main__.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/plugins/sprite_animation/clipboard_util.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/plugins/sprite_animation/frame_picker.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/plugins/sprite_animation/models.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/plugins/sprite_animation/protocols.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/plugins/sprite_animation/runtime_load.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/plugins/sprite_animation/standalone.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/plugins/sprite_animation/timeline.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/plugins/sprite_animation/validation.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/plugins/sprite_editor/__init__.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/plugins/sprite_editor/editor.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/plugins/sprite_editor/standalone.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/plugins/tileset_collision/__init__.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/plugins/tileset_collision/collision_painter.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/plugins/tileset_collision/editor.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/plugins/tileset_collision/models.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/plugins/tileset_collision/protocols.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/plugins/tileset_collision/standalone.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/standalone_automap.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/standalone_error_console.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/standalone_filemanager.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/standalone_image_viewer.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/__init__.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/__main__.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/assets/__init__.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/assets/fonts/jetbrain-fonts/JetBrainsMono-Bold.ttf +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/assets/fonts/jetbrain-fonts/JetBrainsMono-BoldItalic.ttf +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/assets/fonts/jetbrain-fonts/JetBrainsMono-Italic.ttf +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/assets/fonts/jetbrain-fonts/JetBrainsMono-Regular.ttf +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/assets/fonts/noto/NotoSans-Bold.ttf +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/assets/fonts/noto/NotoSans-BoldItalic.ttf +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/assets/fonts/noto/NotoSans-Italic.ttf +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/assets/fonts/noto/NotoSans-Regular.ttf +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/assets/icons/ToolMove.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/assets/icons/arrow-down.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/assets/icons/check.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/assets/icons/checked.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/assets/icons/close.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/assets/icons/duplicate.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/assets/icons/error.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/assets/icons/file.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/assets/icons/filedead.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/assets/icons/fit.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/assets/icons/folder.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/assets/icons/grid.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/assets/icons/image.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/assets/icons/info.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/assets/icons/load.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/assets/icons/loop.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/assets/icons/pan.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/assets/icons/pause.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/assets/icons/pencil.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/assets/icons/play.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/assets/icons/plus.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/assets/icons/radio.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/assets/icons/reset.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/assets/icons/save.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/assets/icons/stop.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/assets/icons/tilemap.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/assets/icons/tileset.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/assets/icons/unchecked.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/assets/icons/warning.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/assets/icons/zoomin.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/assets/icons/zoomout.svg +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/cli.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/main.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor/settings.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor.egg-info/dependency_links.txt +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor.egg-info/entry_points.txt +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor.egg-info/requires.txt +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/tilemap_editor.egg-info/top_level.txt +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/ttypes/__init__.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/ttypes/tilemap.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/utils/__init__.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/utils/editor_preference.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/utils/error_handler.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/utils/font_manager.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/utils/history.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/utils/icon_manager.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/utils/icons_cache.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/utils/log_capture.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/utils/project_paths.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/utils/serialization.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/utils/standalone.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/utils/validation.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/widgets/__init__.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/widgets/automap_models.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/widgets/autotile_template.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/widgets/autotiler.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/widgets/filemanager.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/widgets/input.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/widgets/layer_selector.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/widgets/map_properties.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/widgets/mapsetup.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/widgets/regex_automap_designer.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/widgets/spritesheet_grid.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/widgets/ui/collision_layer_mask.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/widgets/ui/collision_layer_sidebar.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/widgets/ui/draw_utils.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/widgets/ui/fileinput.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/widgets/ui/layer_type_dialog.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/widgets/ui/menubar.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/widgets/ui/mode_indicator.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/widgets/ui/notification.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/widgets/ui/property_editor.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/widgets/ui/region_selector.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/widgets/ui/status_bar.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/widgets/ui/theme.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/widgets/ui/tileset_type_dialog.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/widgets/ui/toolbar.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/widgets/ui/tooltip.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/tests/test_animation_library_grid_offset.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/tests/test_collision_layer_mask.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/tests/test_collision_layer_sidebar.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/tests/test_editor_pan_mode.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/tests/test_project_paths.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/tests/test_render_scale.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/tests/test_sprite_animation_editor_grid.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/tests/test_tile_grid_selection.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/tests/test_tile_selector_pick.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/tests/test_tilemap_save.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/tests/test_timeline_invalidate_cache.py +0 -0
- {tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/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.2.
|
|
7
|
+
version = "3.2.7"
|
|
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"
|
|
@@ -27,6 +27,7 @@ from widgets.tile_grid import TileGrid
|
|
|
27
27
|
from widgets.layer_selector import LayerSelector
|
|
28
28
|
from widgets.ui.fileinput import FilenameInput
|
|
29
29
|
from widgets.ui.tileset_type_dialog import TilesetTypeDialog
|
|
30
|
+
from widgets.ui.confirm_dialog import ConfirmDialog
|
|
30
31
|
from widgets.ui.layer_type_dialog import LayerTypeDialog
|
|
31
32
|
from widgets.ui.menubar import MenuBar
|
|
32
33
|
from widgets.ui.toolbar import Toolbar
|
|
@@ -208,6 +209,7 @@ class Editor:
|
|
|
208
209
|
on_cancel=lambda: None,
|
|
209
210
|
)
|
|
210
211
|
self.tileset_type_dialog = TilesetTypeDialog(editor_rect)
|
|
212
|
+
self.confirm_dialog = ConfirmDialog(editor_rect)
|
|
211
213
|
self.layer_type_dialog = LayerTypeDialog(editor_rect)
|
|
212
214
|
|
|
213
215
|
self.menubar = MenuBar(self, self.width, 30)
|
|
@@ -542,6 +544,8 @@ class Editor:
|
|
|
542
544
|
|
|
543
545
|
if hasattr(self, "tileset_type_dialog") and self.tileset_type_dialog:
|
|
544
546
|
self.tileset_type_dialog.editor_rect = rect_full
|
|
547
|
+
if hasattr(self, "confirm_dialog") and self.confirm_dialog:
|
|
548
|
+
self.confirm_dialog.editor_rect = rect_full
|
|
545
549
|
if hasattr(self, "layer_type_dialog") and self.layer_type_dialog:
|
|
546
550
|
self.layer_type_dialog.editor_rect = rect_full
|
|
547
551
|
|
|
@@ -1052,6 +1056,10 @@ class Editor:
|
|
|
1052
1056
|
self.tileset_type_dialog.handle_event(event)
|
|
1053
1057
|
continue
|
|
1054
1058
|
|
|
1059
|
+
if self.confirm_dialog.active:
|
|
1060
|
+
self.confirm_dialog.handle_event(event)
|
|
1061
|
+
continue
|
|
1062
|
+
|
|
1055
1063
|
if self.layer_type_dialog.active:
|
|
1056
1064
|
self.layer_type_dialog.handle_event(event)
|
|
1057
1065
|
continue
|
|
@@ -1261,6 +1269,11 @@ class Editor:
|
|
|
1261
1269
|
overlay.fill((0, 0, 0, 150))
|
|
1262
1270
|
self.screen.blit(overlay, (0, 0))
|
|
1263
1271
|
self.tileset_type_dialog.draw(self.screen)
|
|
1272
|
+
if self.confirm_dialog.active:
|
|
1273
|
+
overlay = pygame.Surface((self.width, self.height), pygame.SRCALPHA)
|
|
1274
|
+
overlay.fill((0, 0, 0, 150))
|
|
1275
|
+
self.screen.blit(overlay, (0, 0))
|
|
1276
|
+
self.confirm_dialog.draw(self.screen)
|
|
1264
1277
|
if self.layer_type_dialog.active:
|
|
1265
1278
|
overlay = pygame.Surface((self.width, self.height), pygame.SRCALPHA)
|
|
1266
1279
|
overlay.fill((0, 0, 0, 150))
|
{tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/src/plugins/character_collision/shape_editor.py
RENAMED
|
@@ -294,8 +294,8 @@ class ShapeEditor:
|
|
|
294
294
|
self._dragging_shape = False
|
|
295
295
|
return True
|
|
296
296
|
|
|
297
|
-
# Check if clicking on
|
|
298
|
-
if self.
|
|
297
|
+
# Check if clicking inside the shape body (but not on a handle)
|
|
298
|
+
if self._is_inside_shape(mouse) and not self._pan_mode:
|
|
299
299
|
self._dragging_shape = True
|
|
300
300
|
self._drag_start = mouse
|
|
301
301
|
self._save_shape_positions()
|
|
@@ -462,7 +462,7 @@ class ShapeEditor:
|
|
|
462
462
|
elif self.shape_type == "circle":
|
|
463
463
|
return self._sprite_to_screen((self.circle_x, self.circle_y - self.circle_radius))
|
|
464
464
|
elif self.shape_type == "capsule":
|
|
465
|
-
return self._sprite_to_screen((self.capsule_x, self.capsule_y))
|
|
465
|
+
return self._sprite_to_screen((self.capsule_x, self.capsule_y + self.capsule_height / 2))
|
|
466
466
|
elif self.shape_type == "polygon" and len(self.polygon_vertices) >= 3:
|
|
467
467
|
# Top-center of polygon bounding box
|
|
468
468
|
min_y = min(v[1] for v in self.polygon_vertices)
|
|
@@ -168,6 +168,7 @@ class SpriteAnimationEditor:
|
|
|
168
168
|
self.timeline.on_frames_changed = self._on_frames_changed
|
|
169
169
|
self.timeline.on_markers_changed = self._on_markers_changed
|
|
170
170
|
self.preview.on_playback_fps_changed = self._on_preview_fps_changed
|
|
171
|
+
self.preview.on_loop_changed = self._on_preview_loop_changed
|
|
171
172
|
|
|
172
173
|
# Create a default animation (now safe — widgets exist)
|
|
173
174
|
self._create_new_animation("idle")
|
|
@@ -1566,6 +1567,12 @@ class SpriteAnimationEditor:
|
|
|
1566
1567
|
self.preview.authoring_fps = float(fps)
|
|
1567
1568
|
self._notify_animation_modified()
|
|
1568
1569
|
|
|
1570
|
+
def _on_preview_loop_changed(self, loop: bool) -> None:
|
|
1571
|
+
anim = self._get_active()
|
|
1572
|
+
if anim:
|
|
1573
|
+
anim.loop = loop
|
|
1574
|
+
self._notify_animation_modified()
|
|
1575
|
+
|
|
1569
1576
|
def _metadata_apply_add(self, anim: Animation) -> None:
|
|
1570
1577
|
key = self._meta_key_input.strip()
|
|
1571
1578
|
if not key:
|
|
@@ -58,10 +58,13 @@ class AnimationPreview:
|
|
|
58
58
|
self.frames: List[AnimationFrame] = []
|
|
59
59
|
self.playing = False
|
|
60
60
|
self.loop = True
|
|
61
|
+
self.grid_offset_x: int = 0
|
|
62
|
+
self.grid_offset_y: int = 0
|
|
61
63
|
self.playback_fps: float = 60.0
|
|
62
64
|
self.show_onion = False
|
|
63
65
|
|
|
64
66
|
self.on_playback_fps_changed: Optional[Callable[[float], None]] = None
|
|
67
|
+
self.on_loop_changed: Optional[Callable[[bool], None]] = None
|
|
65
68
|
self.authoring_fps: float = 60.0
|
|
66
69
|
|
|
67
70
|
self.current_frame: int = 0
|
|
@@ -221,6 +224,8 @@ class AnimationPreview:
|
|
|
221
224
|
return True
|
|
222
225
|
if self._btn_loop.collidepoint(mouse):
|
|
223
226
|
self.loop = not self.loop
|
|
227
|
+
if self.on_loop_changed:
|
|
228
|
+
self.on_loop_changed(self.loop)
|
|
224
229
|
return True
|
|
225
230
|
if self._btn_onion.collidepoint(mouse):
|
|
226
231
|
self.show_onion = not self.show_onion
|
|
@@ -411,10 +416,12 @@ class AnimationPreview:
|
|
|
411
416
|
|
|
412
417
|
def _extract_tile(self, variant_id: int) -> Optional[pygame.Surface]:
|
|
413
418
|
tw, th = self.tile_size
|
|
414
|
-
|
|
419
|
+
ox, oy = self.grid_offset_x, self.grid_offset_y
|
|
420
|
+
available_w = self.surface.get_width() - ox
|
|
421
|
+
cols = max(1, available_w // tw)
|
|
415
422
|
col = variant_id % cols
|
|
416
423
|
row = variant_id // cols
|
|
417
|
-
src = Rect(col * tw, row * th, tw, th)
|
|
424
|
+
src = Rect(ox + col * tw, oy + row * th, tw, th)
|
|
418
425
|
if self.surface.get_rect().contains(src):
|
|
419
426
|
return self.surface.subsurface(src).copy()
|
|
420
427
|
return None
|
|
@@ -164,6 +164,7 @@ src/widgets/tile_grid.py
|
|
|
164
164
|
src/widgets/tile_selector.py
|
|
165
165
|
src/widgets/ui/collision_layer_mask.py
|
|
166
166
|
src/widgets/ui/collision_layer_sidebar.py
|
|
167
|
+
src/widgets/ui/confirm_dialog.py
|
|
167
168
|
src/widgets/ui/draw_utils.py
|
|
168
169
|
src/widgets/ui/fileinput.py
|
|
169
170
|
src/widgets/ui/layer_type_dialog.py
|
|
@@ -499,8 +499,10 @@ class TileGrid:
|
|
|
499
499
|
start_sy = src_rect[1] // tile_h
|
|
500
500
|
|
|
501
501
|
if active_layer.layer_type == "object":
|
|
502
|
-
|
|
503
|
-
|
|
502
|
+
mouse_pos = pygame.mouse.get_pos()
|
|
503
|
+
world_x, world_y = self.screen_to_world(mouse_pos)
|
|
504
|
+
pixel_x = world_x
|
|
505
|
+
pixel_y = world_y
|
|
504
506
|
pixel_w = sel_w_tiles * tile_w
|
|
505
507
|
pixel_h = sel_h_tiles * tile_h
|
|
506
508
|
|
|
@@ -1040,13 +1042,14 @@ class TileGrid:
|
|
|
1040
1042
|
|
|
1041
1043
|
if active_layer.layer_type == "object":
|
|
1042
1044
|
mouse_pos = pygame.mouse.get_pos()
|
|
1043
|
-
self.screen_to_world(mouse_pos)
|
|
1045
|
+
world_x, world_y = self.screen_to_world(mouse_pos)
|
|
1046
|
+
rs = self.editor.tilemap.render_scale
|
|
1044
1047
|
|
|
1045
|
-
sel_width = int(src_rect[2] * self.zoom_level)
|
|
1046
|
-
sel_height = int(src_rect[3] * self.zoom_level)
|
|
1048
|
+
sel_width = int(src_rect[2] * rs * self.zoom_level)
|
|
1049
|
+
sel_height = int(src_rect[3] * rs * self.zoom_level)
|
|
1047
1050
|
|
|
1048
|
-
screen_x =
|
|
1049
|
-
screen_y =
|
|
1051
|
+
screen_x = (world_x - self.scroll_x) * self.zoom_level + self.rect.x
|
|
1052
|
+
screen_y = (world_y - self.scroll_y) * self.zoom_level + self.rect.y
|
|
1050
1053
|
|
|
1051
1054
|
dest_rect = Rect(screen_x, screen_y, sel_width, sel_height)
|
|
1052
1055
|
pygame.draw.rect(screen, (255, 255, 0), dest_rect, 2)
|
|
@@ -1336,12 +1339,12 @@ class TileGrid:
|
|
|
1336
1339
|
src_rect = Rect(src_x, src_y, obj_w, obj_h)
|
|
1337
1340
|
|
|
1338
1341
|
dest_x = (
|
|
1339
|
-
(obj_x
|
|
1342
|
+
(obj_x - self.scroll_x) * self.zoom_level
|
|
1340
1343
|
+ self.rect.x
|
|
1341
1344
|
+ draw_offset_x
|
|
1342
1345
|
)
|
|
1343
1346
|
dest_y = (
|
|
1344
|
-
(obj_y
|
|
1347
|
+
(obj_y - self.scroll_y) * self.zoom_level
|
|
1345
1348
|
+ self.rect.y
|
|
1346
1349
|
+ draw_offset_y
|
|
1347
1350
|
)
|
|
@@ -1565,11 +1568,11 @@ class TileGrid:
|
|
|
1565
1568
|
new_x = area["x"] + dx
|
|
1566
1569
|
new_y = area["y"] + dy
|
|
1567
1570
|
dest_x = (
|
|
1568
|
-
(new_x
|
|
1571
|
+
(new_x - self.scroll_x) * self.zoom_level
|
|
1569
1572
|
+ self.rect.x
|
|
1570
1573
|
)
|
|
1571
1574
|
dest_y = (
|
|
1572
|
-
(new_y
|
|
1575
|
+
(new_y - self.scroll_y) * self.zoom_level
|
|
1573
1576
|
+ self.rect.y
|
|
1574
1577
|
)
|
|
1575
1578
|
|
|
@@ -61,6 +61,7 @@ class TileSelector:
|
|
|
61
61
|
self.zoom: float = 1.0
|
|
62
62
|
|
|
63
63
|
btn_y = y + h - 35
|
|
64
|
+
self.btn_export = Rect(x + w - 140, btn_y, 30, 30)
|
|
64
65
|
self.btn_collision = Rect(x + w - 105, btn_y, 30, 30)
|
|
65
66
|
self.btn_add = Rect(x + w - 70, btn_y, 30, 30)
|
|
66
67
|
self.btn_rem = Rect(x + w - 35, btn_y, 30, 30)
|
|
@@ -80,6 +81,7 @@ class TileSelector:
|
|
|
80
81
|
x, y + self.top_bar_h, w, h - self.top_bar_h - self.btm_bar_h
|
|
81
82
|
)
|
|
82
83
|
btn_y = y + h - 35
|
|
84
|
+
self.btn_export = Rect(x + w - 140, btn_y, 30, 30)
|
|
83
85
|
self.btn_collision = Rect(x + w - 105, btn_y, 30, 30)
|
|
84
86
|
self.btn_add = Rect(x + w - 70, btn_y, 30, 30)
|
|
85
87
|
self.btn_rem = Rect(x + w - 35, btn_y, 30, 30)
|
|
@@ -162,6 +164,9 @@ class TileSelector:
|
|
|
162
164
|
return True
|
|
163
165
|
|
|
164
166
|
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
|
|
167
|
+
if self.btn_export.collidepoint(mouse_pos):
|
|
168
|
+
self._export_selected_as_png_dialog()
|
|
169
|
+
return True
|
|
165
170
|
if self.btn_collision.collidepoint(mouse_pos):
|
|
166
171
|
self.open_collision_editor()
|
|
167
172
|
return True
|
|
@@ -246,6 +251,11 @@ class TileSelector:
|
|
|
246
251
|
ts.offset[1] += event.y * 20
|
|
247
252
|
return True
|
|
248
253
|
|
|
254
|
+
elif event.type == pygame.KEYDOWN and event.key == pygame.K_e:
|
|
255
|
+
if self.selected_tile and self.active_idx != -1:
|
|
256
|
+
self._export_selected_as_png_dialog()
|
|
257
|
+
return True
|
|
258
|
+
|
|
249
259
|
return False
|
|
250
260
|
|
|
251
261
|
def update_selection_rect(self, current_grid: Tuple[int, int]):
|
|
@@ -348,66 +358,56 @@ class TileSelector:
|
|
|
348
358
|
if path.exists():
|
|
349
359
|
try:
|
|
350
360
|
surf = pygame.image.load(path).convert_alpha()
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
)
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
)
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
self.
|
|
365
|
-
self.active_idx = len(self.tilesets) - 1
|
|
366
|
-
self.tileset_map[self.active_idx] = tileset_data
|
|
367
|
-
if tileset_type == "object":
|
|
368
|
-
self.selected_tile = (0, 0, surf.get_width(), surf.get_height())
|
|
369
|
-
else:
|
|
370
|
-
print("Tileset isnt multiple of tile size")
|
|
361
|
+
tileset_data = TilesetData(
|
|
362
|
+
path.name, path, surf, tileset_type=tileset_type
|
|
363
|
+
)
|
|
364
|
+
tileset_data.properties = properties
|
|
365
|
+
tileset_data.tile_properties = {
|
|
366
|
+
int(k): v for k, v in tile_properties.items()
|
|
367
|
+
}
|
|
368
|
+
self._load_collision_data_for_tileset(tileset_data)
|
|
369
|
+
|
|
370
|
+
self.tilesets.append(tileset_data)
|
|
371
|
+
self.active_idx = len(self.tilesets) - 1
|
|
372
|
+
self.tileset_map[self.active_idx] = tileset_data
|
|
373
|
+
if tileset_type == "object":
|
|
374
|
+
self.selected_tile = (0, 0, surf.get_width(), surf.get_height())
|
|
371
375
|
except Exception as e:
|
|
372
376
|
error_handler.capture(e, context="load_tileset_surface")
|
|
373
377
|
|
|
374
378
|
def _on_tileset_type_selected(self, tileset_type: str):
|
|
375
379
|
"""Callback when user selects tileset type from dialog."""
|
|
376
|
-
print(f"DEBUG: Tileset type selected: {tileset_type}")
|
|
377
380
|
if not hasattr(self, "_pending_tileset_path"):
|
|
378
|
-
print("DEBUG: No pending tileset path!")
|
|
379
381
|
return
|
|
380
382
|
|
|
381
|
-
path = self._pending_tileset_path
|
|
382
383
|
surf = self._pending_tileset_surf
|
|
383
384
|
|
|
384
385
|
if tileset_type == "tile" and not is_image_multipleof(
|
|
385
386
|
surf.get_size(), self.editor.tilemap.tile_size
|
|
386
387
|
):
|
|
387
|
-
|
|
388
|
-
|
|
388
|
+
w, h = surf.get_size()
|
|
389
|
+
tw, th = self.editor.tilemap.tile_size
|
|
390
|
+
self.editor.confirm_dialog.show(
|
|
391
|
+
title="Tileset Size Warning",
|
|
392
|
+
message=f"Image size ({w}x{h}) is not an exact multiple of tile size ({tw}x{th}). "
|
|
393
|
+
f"Some pixels at the edges will be ignored. Proceed?",
|
|
394
|
+
on_confirm=lambda: self._commit_tileset_load(tileset_type),
|
|
395
|
+
on_cancel=self._on_tileset_type_cancel,
|
|
389
396
|
)
|
|
390
|
-
delattr(self, "_pending_tileset_path")
|
|
391
|
-
delattr(self, "_pending_tileset_surf")
|
|
392
|
-
if self._pending_tileset_queue:
|
|
393
|
-
error_handler.capture(
|
|
394
|
-
Exception(
|
|
395
|
-
f"Queue error continuation: {len(self._pending_tileset_queue)} items"
|
|
396
|
-
),
|
|
397
|
-
context="tileset_queue_error",
|
|
398
|
-
severity="info",
|
|
399
|
-
)
|
|
400
|
-
# Delay slightly to allow dialog to fully close
|
|
401
|
-
pygame.time.set_timer(pygame.USEREVENT + 1, 100, 1)
|
|
402
|
-
self._queue_timer_active = True
|
|
403
397
|
return
|
|
404
398
|
|
|
399
|
+
self._commit_tileset_load(tileset_type)
|
|
400
|
+
|
|
401
|
+
def _commit_tileset_load(self, tileset_type: str):
|
|
402
|
+
path = self._pending_tileset_path
|
|
403
|
+
surf = self._pending_tileset_surf
|
|
404
|
+
|
|
405
405
|
tileset_data = TilesetData(path.name, path, surf, tileset_type=tileset_type)
|
|
406
406
|
self._load_collision_data_for_tileset(tileset_data)
|
|
407
407
|
self.tilesets.append(tileset_data)
|
|
408
408
|
self.active_idx = len(self.tilesets) - 1
|
|
409
409
|
self.tileset_map[self.active_idx] = tileset_data
|
|
410
|
-
|
|
410
|
+
|
|
411
411
|
if tileset_type == "object":
|
|
412
412
|
self.selected_tile = (0, 0, surf.get_width(), surf.get_height())
|
|
413
413
|
else:
|
|
@@ -416,14 +416,8 @@ class TileSelector:
|
|
|
416
416
|
delattr(self, "_pending_tileset_path")
|
|
417
417
|
delattr(self, "_pending_tileset_surf")
|
|
418
418
|
if self._pending_tileset_queue:
|
|
419
|
-
print(
|
|
420
|
-
f"DEBUG: Continuing queue, {len(self._pending_tileset_queue)} items remaining"
|
|
421
|
-
)
|
|
422
|
-
# Delay slightly to allow dialog to fully close
|
|
423
419
|
pygame.time.set_timer(pygame.USEREVENT + 1, 100, 1)
|
|
424
420
|
self._queue_timer_active = True
|
|
425
|
-
else:
|
|
426
|
-
print("DEBUG: Queue processing complete")
|
|
427
421
|
|
|
428
422
|
def _load_collision_data_for_tileset(self, tileset_data: TilesetData) -> None:
|
|
429
423
|
"""Attach existing collision data for tilesets that have sidecar files."""
|
|
@@ -631,6 +625,27 @@ class TileSelector:
|
|
|
631
625
|
self.selected_tile = (col * tw, row * th, tw, th)
|
|
632
626
|
return True
|
|
633
627
|
|
|
628
|
+
def _export_selected_as_png_dialog(self):
|
|
629
|
+
if not self.selected_tile or self.active_idx == -1:
|
|
630
|
+
return
|
|
631
|
+
ts = self.tilesets[self.active_idx]
|
|
632
|
+
default = Path(ts.name).stem + "_extracted.png"
|
|
633
|
+
self.editor.open_file_manager(
|
|
634
|
+
on_save=self._on_export_selected_path,
|
|
635
|
+
allowed_exts=[".png"],
|
|
636
|
+
mode="save",
|
|
637
|
+
default_name=default,
|
|
638
|
+
)
|
|
639
|
+
|
|
640
|
+
def _on_export_selected_path(self, path: Path):
|
|
641
|
+
try:
|
|
642
|
+
sx, sy, sw, sh = self.selected_tile
|
|
643
|
+
ts = self.tilesets[self.active_idx]
|
|
644
|
+
extracted = ts.surface.subsurface(Rect(sx, sy, sw, sh)).copy()
|
|
645
|
+
pygame.image.save(extracted, str(path))
|
|
646
|
+
except Exception as e:
|
|
647
|
+
error_handler.capture(e, context="export_selected_png")
|
|
648
|
+
|
|
634
649
|
def draw(self, screen: pygame.Surface):
|
|
635
650
|
self.draw_background(screen)
|
|
636
651
|
self.draw_view_area(screen)
|
|
@@ -791,6 +806,15 @@ class TileSelector:
|
|
|
791
806
|
screen.blit(name_surf, (self.rect.x + 5, self.rect.bottom - 30))
|
|
792
807
|
|
|
793
808
|
def draw_buttons(self, screen):
|
|
809
|
+
# Export selection as PNG button
|
|
810
|
+
pygame.draw.rect(
|
|
811
|
+
screen, COLORS.header, self.btn_export, border_radius=SHAPE.radius_sm
|
|
812
|
+
)
|
|
813
|
+
screen.blit(
|
|
814
|
+
self.font.render("E", True, COLORS.text),
|
|
815
|
+
(self.btn_export.x + 9, self.btn_export.y + 5),
|
|
816
|
+
)
|
|
817
|
+
|
|
794
818
|
# Collision editor button
|
|
795
819
|
pygame.draw.rect(
|
|
796
820
|
screen, COLORS.header, self.btn_collision, border_radius=SHAPE.radius_sm
|
|
@@ -815,7 +839,9 @@ class TileSelector:
|
|
|
815
839
|
(self.btn_rem.x + 10, self.btn_rem.y + 5),
|
|
816
840
|
)
|
|
817
841
|
mx, my = pygame.mouse.get_pos()
|
|
818
|
-
if self.
|
|
842
|
+
if self.btn_export.collidepoint(mx, my):
|
|
843
|
+
self.editor.tooltip.show("E: Export selection as PNG", (mx + 10, my + 10))
|
|
844
|
+
elif self.btn_collision.collidepoint(mx, my):
|
|
819
845
|
self.editor.tooltip.show("Edit Collision Shapes", (mx + 10, my + 10))
|
|
820
846
|
elif self.btn_add.collidepoint(mx, my):
|
|
821
847
|
self.editor.tooltip.show("Add Tileset", (mx + 10, my + 10))
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import pygame
|
|
2
|
+
from pygame import Rect, Surface
|
|
3
|
+
from typing import Callable, Optional
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ConfirmDialog:
|
|
7
|
+
def __init__(self, editor_rect: Rect):
|
|
8
|
+
self.editor_rect = editor_rect
|
|
9
|
+
self.rect = Rect(0, 0, 420, 180)
|
|
10
|
+
self.rect.center = editor_rect.center
|
|
11
|
+
|
|
12
|
+
self.active = False
|
|
13
|
+
self.title = ""
|
|
14
|
+
self.message = ""
|
|
15
|
+
self.on_confirm: Optional[Callable[[], None]] = None
|
|
16
|
+
self.on_cancel: Optional[Callable[[], None]] = None
|
|
17
|
+
|
|
18
|
+
self.bg_color = (40, 40, 40)
|
|
19
|
+
self.border_color = (100, 100, 100)
|
|
20
|
+
self.text_color = (255, 255, 255)
|
|
21
|
+
self.warn_color = (255, 200, 60)
|
|
22
|
+
self.button_color = (60, 100, 180)
|
|
23
|
+
self.button_hover_color = (80, 120, 200)
|
|
24
|
+
|
|
25
|
+
self.btn_proceed = Rect(0, 0, 110, 30)
|
|
26
|
+
self.btn_cancel = Rect(0, 0, 110, 30)
|
|
27
|
+
|
|
28
|
+
self.font_title = pygame.font.SysFont("Arial", 18, bold=True)
|
|
29
|
+
self.font_text = pygame.font.SysFont("Arial", 14)
|
|
30
|
+
self.font_btn = pygame.font.SysFont("Arial", 14, bold=True)
|
|
31
|
+
|
|
32
|
+
self.btn_proceed_hover = False
|
|
33
|
+
self.btn_cancel_hover = False
|
|
34
|
+
self._layout()
|
|
35
|
+
|
|
36
|
+
def _layout(self):
|
|
37
|
+
self.rect.center = self.editor_rect.center
|
|
38
|
+
btn_y = self.rect.bottom - 50
|
|
39
|
+
cx = self.rect.centerx
|
|
40
|
+
self.btn_cancel = Rect(cx - 120, btn_y, 110, 30)
|
|
41
|
+
self.btn_proceed = Rect(cx + 10, btn_y, 110, 30)
|
|
42
|
+
|
|
43
|
+
def show(
|
|
44
|
+
self,
|
|
45
|
+
title: str,
|
|
46
|
+
message: str,
|
|
47
|
+
on_confirm: Callable[[], None],
|
|
48
|
+
on_cancel: Callable[[], None],
|
|
49
|
+
):
|
|
50
|
+
if self.active:
|
|
51
|
+
self.hide()
|
|
52
|
+
self.active = True
|
|
53
|
+
self.title = title
|
|
54
|
+
self.message = message
|
|
55
|
+
self.on_confirm = on_confirm
|
|
56
|
+
self.on_cancel = on_cancel
|
|
57
|
+
self.btn_proceed_hover = False
|
|
58
|
+
self.btn_cancel_hover = False
|
|
59
|
+
self._layout()
|
|
60
|
+
|
|
61
|
+
def hide(self):
|
|
62
|
+
self.active = False
|
|
63
|
+
|
|
64
|
+
def handle_event(self, event: pygame.event.Event) -> bool:
|
|
65
|
+
if not self.active:
|
|
66
|
+
return False
|
|
67
|
+
|
|
68
|
+
self._layout()
|
|
69
|
+
mouse_pos = pygame.mouse.get_pos()
|
|
70
|
+
|
|
71
|
+
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
|
|
72
|
+
if self.btn_proceed.collidepoint(mouse_pos):
|
|
73
|
+
if self.on_confirm:
|
|
74
|
+
self.on_confirm()
|
|
75
|
+
self.hide()
|
|
76
|
+
return True
|
|
77
|
+
if self.btn_cancel.collidepoint(mouse_pos):
|
|
78
|
+
if self.on_cancel:
|
|
79
|
+
self.on_cancel()
|
|
80
|
+
self.hide()
|
|
81
|
+
return True
|
|
82
|
+
|
|
83
|
+
elif event.type == pygame.KEYDOWN:
|
|
84
|
+
if event.key == pygame.K_ESCAPE:
|
|
85
|
+
if self.on_cancel:
|
|
86
|
+
self.on_cancel()
|
|
87
|
+
self.hide()
|
|
88
|
+
return True
|
|
89
|
+
elif event.key == pygame.K_RETURN:
|
|
90
|
+
if self.on_confirm:
|
|
91
|
+
self.on_confirm()
|
|
92
|
+
self.hide()
|
|
93
|
+
return True
|
|
94
|
+
|
|
95
|
+
elif event.type == pygame.MOUSEMOTION:
|
|
96
|
+
self.btn_proceed_hover = self.btn_proceed.collidepoint(mouse_pos)
|
|
97
|
+
self.btn_cancel_hover = self.btn_cancel.collidepoint(mouse_pos)
|
|
98
|
+
|
|
99
|
+
return False
|
|
100
|
+
|
|
101
|
+
def draw(self, surface: Surface):
|
|
102
|
+
if not self.active:
|
|
103
|
+
return
|
|
104
|
+
|
|
105
|
+
self._layout()
|
|
106
|
+
pygame.draw.rect(surface, self.bg_color, self.rect)
|
|
107
|
+
pygame.draw.rect(surface, self.border_color, self.rect, 2)
|
|
108
|
+
|
|
109
|
+
title_surf = self.font_title.render(self.title, True, self.warn_color)
|
|
110
|
+
title_rect = title_surf.get_rect(topleft=(self.rect.x + 20, self.rect.y + 15))
|
|
111
|
+
surface.blit(title_surf, title_rect)
|
|
112
|
+
|
|
113
|
+
lines = self._wrap_text(self.message, self.rect.width - 40)
|
|
114
|
+
y = self.rect.y + 50
|
|
115
|
+
for line in lines:
|
|
116
|
+
line_surf = self.font_text.render(line, True, self.text_color)
|
|
117
|
+
surface.blit(line_surf, (self.rect.x + 20, y))
|
|
118
|
+
y += 22
|
|
119
|
+
|
|
120
|
+
proceed_color = self.button_hover_color if self.btn_proceed_hover else self.button_color
|
|
121
|
+
cancel_color = self.button_hover_color if self.btn_cancel_hover else (60, 60, 60)
|
|
122
|
+
|
|
123
|
+
pygame.draw.rect(surface, cancel_color, self.btn_cancel)
|
|
124
|
+
pygame.draw.rect(surface, proceed_color, self.btn_proceed)
|
|
125
|
+
|
|
126
|
+
cancel_text = self.font_btn.render("Cancel", True, self.text_color)
|
|
127
|
+
proceed_text = self.font_btn.render("Proceed", True, self.text_color)
|
|
128
|
+
|
|
129
|
+
cancel_text_rect = cancel_text.get_rect(center=self.btn_cancel.center)
|
|
130
|
+
proceed_text_rect = proceed_text.get_rect(center=self.btn_proceed.center)
|
|
131
|
+
|
|
132
|
+
surface.blit(cancel_text, cancel_text_rect)
|
|
133
|
+
surface.blit(proceed_text, proceed_text_rect)
|
|
134
|
+
|
|
135
|
+
def _wrap_text(self, text: str, max_width: int):
|
|
136
|
+
words = text.split()
|
|
137
|
+
lines = []
|
|
138
|
+
current = ""
|
|
139
|
+
for word in words:
|
|
140
|
+
test = f"{current} {word}".strip()
|
|
141
|
+
if self.font_text.size(test)[0] <= max_width:
|
|
142
|
+
current = test
|
|
143
|
+
else:
|
|
144
|
+
if current:
|
|
145
|
+
lines.append(current)
|
|
146
|
+
current = word
|
|
147
|
+
if current:
|
|
148
|
+
lines.append(current)
|
|
149
|
+
return lines
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/assets/fonts/jetbrain-fonts/JetBrainsMono-Bold.ttf
RENAMED
|
File without changes
|
|
File without changes
|
{tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/assets/fonts/jetbrain-fonts/JetBrainsMono-Italic.ttf
RENAMED
|
File without changes
|
{tilemap_editor-3.2.5 → tilemap_editor-3.2.7}/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
|