tilemap-editor 3.1.2__tar.gz → 3.1.4__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.2/src/tilemap_editor.egg-info → tilemap_editor-3.1.4}/PKG-INFO +1 -1
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/pyproject.toml +1 -1
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/editor.py +19 -1
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap.py +9 -1
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/settings.py +4 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4/src/tilemap_editor.egg-info}/PKG-INFO +1 -1
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor.egg-info/SOURCES.txt +3 -1
- tilemap_editor-3.1.4/src/widgets/map_properties.py +133 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/widgets/tile_grid.py +55 -45
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/widgets/ui/menubar.py +1 -0
- tilemap_editor-3.1.4/tests/test_project_paths.py +145 -0
- tilemap_editor-3.1.4/tests/test_render_scale.py +174 -0
- tilemap_editor-3.1.2/tests/test_project_paths.py +0 -73
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/LICENSE +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/MANIFEST.in +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/README.md +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/assets/fonts/jetbrain-fonts/JetBrainsMono-Bold.ttf +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/assets/fonts/jetbrain-fonts/JetBrainsMono-BoldItalic.ttf +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/assets/fonts/jetbrain-fonts/JetBrainsMono-Italic.ttf +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/assets/fonts/jetbrain-fonts/JetBrainsMono-Regular.ttf +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/assets/fonts/noto/NotoSans-Bold.ttf +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/assets/fonts/noto/NotoSans-BoldItalic.ttf +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/assets/fonts/noto/NotoSans-Italic.ttf +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/assets/fonts/noto/NotoSans-Regular.ttf +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/assets/icons/arrow-down.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/assets/icons/check.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/assets/icons/checked.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/assets/icons/close.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/assets/icons/duplicate.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/assets/icons/error.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/assets/icons/file.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/assets/icons/filedead.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/assets/icons/fit.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/assets/icons/folder.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/assets/icons/grid.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/assets/icons/image.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/assets/icons/info.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/assets/icons/load.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/assets/icons/loop.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/assets/icons/pan.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/assets/icons/pause.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/assets/icons/pencil.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/assets/icons/play.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/assets/icons/plus.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/assets/icons/radio.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/assets/icons/reset.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/assets/icons/save.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/assets/icons/stop.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/assets/icons/tilemap.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/assets/icons/tileset.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/assets/icons/unchecked.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/assets/icons/warning.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/assets/icons/zoomin.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/assets/icons/zoomout.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/setup.cfg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/configs/themes.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/constants.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/event_map.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/layers.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/main.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/plugins/__init__.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/plugins/character_collision/__init__.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/plugins/character_collision/editor.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/plugins/character_collision/models.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/plugins/character_collision/protocols.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/plugins/character_collision/shape_editor.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/plugins/character_collision/standalone.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/plugins/object_tileset_collision/__init__.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/plugins/object_tileset_collision/editor.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/plugins/object_tileset_collision/models.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/plugins/object_tileset_collision/protocols.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/plugins/object_tileset_collision/standalone.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/plugins/sprite_animation/__init__.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/plugins/sprite_animation/__main__.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/plugins/sprite_animation/clipboard_util.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/plugins/sprite_animation/editor.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/plugins/sprite_animation/frame_picker.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/plugins/sprite_animation/models.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/plugins/sprite_animation/preview.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/plugins/sprite_animation/protocols.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/plugins/sprite_animation/runtime_load.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/plugins/sprite_animation/standalone.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/plugins/sprite_animation/timeline.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/plugins/sprite_animation/validation.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/plugins/tileset_collision/__init__.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/plugins/tileset_collision/collision_painter.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/plugins/tileset_collision/editor.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/plugins/tileset_collision/models.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/plugins/tileset_collision/protocols.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/plugins/tileset_collision/standalone.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/standalone_automap.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/standalone_error_console.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/standalone_filemanager.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/standalone_image_viewer.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/__init__.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/__main__.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/assets/__init__.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/assets/fonts/jetbrain-fonts/JetBrainsMono-Bold.ttf +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/assets/fonts/jetbrain-fonts/JetBrainsMono-BoldItalic.ttf +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/assets/fonts/jetbrain-fonts/JetBrainsMono-Italic.ttf +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/assets/fonts/jetbrain-fonts/JetBrainsMono-Regular.ttf +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/assets/fonts/noto/NotoSans-Bold.ttf +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/assets/fonts/noto/NotoSans-BoldItalic.ttf +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/assets/fonts/noto/NotoSans-Italic.ttf +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/assets/fonts/noto/NotoSans-Regular.ttf +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/assets/icons/ToolMove.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/assets/icons/arrow-down.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/assets/icons/check.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/assets/icons/checked.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/assets/icons/close.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/assets/icons/duplicate.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/assets/icons/error.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/assets/icons/file.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/assets/icons/filedead.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/assets/icons/fit.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/assets/icons/folder.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/assets/icons/grid.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/assets/icons/image.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/assets/icons/info.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/assets/icons/load.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/assets/icons/loop.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/assets/icons/pan.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/assets/icons/pause.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/assets/icons/pencil.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/assets/icons/play.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/assets/icons/plus.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/assets/icons/radio.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/assets/icons/reset.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/assets/icons/save.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/assets/icons/stop.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/assets/icons/tilemap.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/assets/icons/tileset.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/assets/icons/unchecked.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/assets/icons/warning.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/assets/icons/zoomin.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/assets/icons/zoomout.svg +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/cli.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor/main.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor.egg-info/dependency_links.txt +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor.egg-info/entry_points.txt +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor.egg-info/requires.txt +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/tilemap_editor.egg-info/top_level.txt +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/ttypes/__init__.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/ttypes/tilemap.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/utils/__init__.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/utils/editor_preference.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/utils/error_handler.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/utils/font_manager.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/utils/history.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/utils/icon_manager.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/utils/icons_cache.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/utils/log_capture.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/utils/project_paths.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/utils/serialization.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/utils/standalone.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/utils/validation.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/widgets/__init__.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/widgets/automap_models.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/widgets/autotile_template.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/widgets/autotiler.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/widgets/filemanager.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/widgets/input.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/widgets/layer_selector.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/widgets/mapsetup.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/widgets/regex_automap_designer.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/widgets/tile_selector.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/widgets/ui/collision_layer_mask.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/widgets/ui/collision_layer_sidebar.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/widgets/ui/draw_utils.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/widgets/ui/fileinput.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/widgets/ui/layer_type_dialog.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/widgets/ui/mode_indicator.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/widgets/ui/notification.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/widgets/ui/property_editor.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/widgets/ui/region_selector.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/widgets/ui/status_bar.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/widgets/ui/theme.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/widgets/ui/tileset_type_dialog.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/widgets/ui/toolbar.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/src/widgets/ui/tooltip.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/tests/test_collision_layer_mask.py +0 -0
- {tilemap_editor-3.1.2 → tilemap_editor-3.1.4}/tests/test_collision_layer_sidebar.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.1.
|
|
7
|
+
version = "3.1.4"
|
|
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"
|
|
@@ -21,6 +21,7 @@ from tilemap import Tilemap
|
|
|
21
21
|
from widgets.autotiler import AutotileRuleDesigner
|
|
22
22
|
from widgets.regex_automap_designer import RegexAutomapDesigner
|
|
23
23
|
from widgets.mapsetup import MapSetup
|
|
24
|
+
from widgets.map_properties import MapPropertiesDialog
|
|
24
25
|
from widgets.tile_selector import TileSelector
|
|
25
26
|
from widgets.tile_grid import TileGrid
|
|
26
27
|
from widgets.layer_selector import LayerSelector
|
|
@@ -117,7 +118,7 @@ def _load_project_config() -> tuple[Path, Path, dict]:
|
|
|
117
118
|
data_root = base_path / data_path
|
|
118
119
|
|
|
119
120
|
if not data_root.exists():
|
|
120
|
-
raise RuntimeError(f"Data directory not found: {data_root}. Run 'tilemap-editor init' to create project structure.")
|
|
121
|
+
raise RuntimeError(f"Data directory not found: {data_root}. Run 'tilemap-editor init' to create the project structure.")
|
|
121
122
|
|
|
122
123
|
# Initialize error_handler with proper paths
|
|
123
124
|
log_root = data_root / "logs"
|
|
@@ -166,6 +167,7 @@ class Editor:
|
|
|
166
167
|
self.tileset_h = 300
|
|
167
168
|
self.layer_h = 150
|
|
168
169
|
self.map_setup_widget: Optional[MapSetup] = None
|
|
170
|
+
self.map_properties_dialog: Optional[MapPropertiesDialog] = None
|
|
169
171
|
self.tileset_widget: Optional[TileSelector] = None
|
|
170
172
|
self.layer_widget: Optional[LayerSelector] = None
|
|
171
173
|
self.tile_grid_widget: Optional[TileGrid] = None
|
|
@@ -231,6 +233,7 @@ class Editor:
|
|
|
231
233
|
center_y = (self.height - 400) // 2
|
|
232
234
|
self.map_setup_widget = MapSetup(self, Rect(center_x, center_y, 400, 400))
|
|
233
235
|
self.map_setup_widget.visible = False
|
|
236
|
+
self.map_properties_dialog = MapPropertiesDialog(self, Rect(center_x, center_y, 400, 260))
|
|
234
237
|
|
|
235
238
|
def open_file_manager(
|
|
236
239
|
self,
|
|
@@ -542,6 +545,8 @@ class Editor:
|
|
|
542
545
|
center_x = (width - 400) // 2
|
|
543
546
|
center_y = (height - 400) // 2
|
|
544
547
|
self.map_setup_widget.resize(Rect(center_x, center_y, 400, 400))
|
|
548
|
+
if self.map_properties_dialog:
|
|
549
|
+
self.map_properties_dialog.resize(Rect(center_x, center_y, 400, 260))
|
|
545
550
|
|
|
546
551
|
def toggle_auto_autotile(self):
|
|
547
552
|
self.autotile_mode = not self.autotile_mode
|
|
@@ -555,6 +560,12 @@ class Editor:
|
|
|
555
560
|
return
|
|
556
561
|
self.map_setup_widget.visible = True
|
|
557
562
|
|
|
563
|
+
def open_map_properties(self):
|
|
564
|
+
if self.map_properties_dialog is None:
|
|
565
|
+
logger.warning({"msg": "map_properties_dialog is not initialized"})
|
|
566
|
+
return
|
|
567
|
+
self.map_properties_dialog.open()
|
|
568
|
+
|
|
558
569
|
def toggle_autotiler(self):
|
|
559
570
|
if self.autotiler.visible:
|
|
560
571
|
self.autotiler.hide()
|
|
@@ -919,6 +930,10 @@ class Editor:
|
|
|
919
930
|
if self.map_setup_widget.handle_event(event):
|
|
920
931
|
continue
|
|
921
932
|
|
|
933
|
+
if self.map_properties_dialog and self.map_properties_dialog.visible:
|
|
934
|
+
if self.map_properties_dialog.handle_event(event):
|
|
935
|
+
continue
|
|
936
|
+
|
|
922
937
|
if self.property_editor and self.property_editor.active:
|
|
923
938
|
if self.property_editor.handle_event(event):
|
|
924
939
|
continue
|
|
@@ -1089,6 +1104,9 @@ class Editor:
|
|
|
1089
1104
|
self.screen.blit(overlay, (0, 0))
|
|
1090
1105
|
self.map_setup_widget.draw(self.screen)
|
|
1091
1106
|
|
|
1107
|
+
if self.map_properties_dialog and self.map_properties_dialog.visible:
|
|
1108
|
+
self.map_properties_dialog.draw(self.screen)
|
|
1109
|
+
|
|
1092
1110
|
if self.save_input.active:
|
|
1093
1111
|
self.save_input.draw(self.screen)
|
|
1094
1112
|
if self.tileset_type_dialog.active:
|
|
@@ -40,6 +40,7 @@ class Tilemap:
|
|
|
40
40
|
self.map_size = (50, 50)
|
|
41
41
|
self.initial_map_size = (50, 50)
|
|
42
42
|
self.initialized = False
|
|
43
|
+
self.render_scale = 1.0
|
|
43
44
|
|
|
44
45
|
self.active_project_path: Optional[Path] = None
|
|
45
46
|
self.history = HistoryManager()
|
|
@@ -59,11 +60,12 @@ class Tilemap:
|
|
|
59
60
|
if active_layer:
|
|
60
61
|
active_layer.tiles = value
|
|
61
62
|
|
|
62
|
-
def init_size(self, tile_size: "TCoor", map_size: "TCoor"):
|
|
63
|
+
def init_size(self, tile_size: "TCoor", map_size: "TCoor", render_scale: float = 1.0):
|
|
63
64
|
self.tile_size = tile_size
|
|
64
65
|
self.map_size = map_size
|
|
65
66
|
self.initial_map_size = map_size # Store what user initially setup
|
|
66
67
|
self.initialized = True
|
|
68
|
+
self.render_scale = render_scale
|
|
67
69
|
self.active_project_path = None
|
|
68
70
|
|
|
69
71
|
# Clear and create default layer
|
|
@@ -85,6 +87,7 @@ class Tilemap:
|
|
|
85
87
|
"active_layer_idx": self.layer_manager.active_layer_idx,
|
|
86
88
|
"tile_size": self.tile_size,
|
|
87
89
|
"map_size": self.map_size,
|
|
90
|
+
"render_scale": self.render_scale,
|
|
88
91
|
}
|
|
89
92
|
self.history.save_state(state, description)
|
|
90
93
|
|
|
@@ -101,6 +104,7 @@ class Tilemap:
|
|
|
101
104
|
"active_layer_idx": self.layer_manager.active_layer_idx,
|
|
102
105
|
"tile_size": self.tile_size,
|
|
103
106
|
"map_size": self.map_size,
|
|
107
|
+
"render_scale": self.render_scale,
|
|
104
108
|
}
|
|
105
109
|
prev_state = self.history.undo(current_state)
|
|
106
110
|
if prev_state:
|
|
@@ -119,6 +123,7 @@ class Tilemap:
|
|
|
119
123
|
"active_layer_idx": self.layer_manager.active_layer_idx,
|
|
120
124
|
"tile_size": self.tile_size,
|
|
121
125
|
"map_size": self.map_size,
|
|
126
|
+
"render_scale": self.render_scale,
|
|
122
127
|
}
|
|
123
128
|
next_state = self.history.redo(current_state)
|
|
124
129
|
if next_state:
|
|
@@ -181,6 +186,7 @@ class Tilemap:
|
|
|
181
186
|
self.layer_manager.active_layer_idx = state["active_layer_idx"]
|
|
182
187
|
self.tile_size = state["tile_size"]
|
|
183
188
|
self.map_size = state["map_size"]
|
|
189
|
+
self.render_scale = state.get("render_scale", 1.0)
|
|
184
190
|
|
|
185
191
|
if hasattr(self.editor, "autotiler"):
|
|
186
192
|
designer = self.editor.autotiler
|
|
@@ -269,6 +275,7 @@ class Tilemap:
|
|
|
269
275
|
)
|
|
270
276
|
),
|
|
271
277
|
"initial_map_size": serialize_point(self.initial_map_size),
|
|
278
|
+
"render_scale": self.render_scale,
|
|
272
279
|
"version": "1.1",
|
|
273
280
|
},
|
|
274
281
|
"resources": {"tilesets": []},
|
|
@@ -470,6 +477,7 @@ class Tilemap:
|
|
|
470
477
|
self.initial_map_size = deserialize_point(self.initial_map_size)
|
|
471
478
|
else:
|
|
472
479
|
self.initial_map_size = self.map_size
|
|
480
|
+
self.render_scale = float(payload["meta"].get("render_scale", 1.0))
|
|
473
481
|
except (KeyError, ValueError) as e:
|
|
474
482
|
raise ValueError(f"Error loading map metadata: {e}") from e
|
|
475
483
|
|
|
@@ -42,6 +42,10 @@ def init_settings(generate_main: bool = False) -> None:
|
|
|
42
42
|
|
|
43
43
|
print(f"Created settings.json at {settings_file}")
|
|
44
44
|
|
|
45
|
+
data_dir = base_path / settings["data_path"]
|
|
46
|
+
data_dir.mkdir(parents=True, exist_ok=True)
|
|
47
|
+
print(f"Created data directory: {data_dir}")
|
|
48
|
+
|
|
45
49
|
if generate_main:
|
|
46
50
|
generate_main_file()
|
|
47
51
|
|
|
@@ -153,6 +153,7 @@ src/widgets/autotiler.py
|
|
|
153
153
|
src/widgets/filemanager.py
|
|
154
154
|
src/widgets/input.py
|
|
155
155
|
src/widgets/layer_selector.py
|
|
156
|
+
src/widgets/map_properties.py
|
|
156
157
|
src/widgets/mapsetup.py
|
|
157
158
|
src/widgets/regex_automap_designer.py
|
|
158
159
|
src/widgets/tile_grid.py
|
|
@@ -174,4 +175,5 @@ src/widgets/ui/toolbar.py
|
|
|
174
175
|
src/widgets/ui/tooltip.py
|
|
175
176
|
tests/test_collision_layer_mask.py
|
|
176
177
|
tests/test_collision_layer_sidebar.py
|
|
177
|
-
tests/test_project_paths.py
|
|
178
|
+
tests/test_project_paths.py
|
|
179
|
+
tests/test_render_scale.py
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import pygame
|
|
2
|
+
from typing import TYPE_CHECKING
|
|
3
|
+
from pygame import Rect
|
|
4
|
+
|
|
5
|
+
from .input import BaseTextInput
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from editor import Editor
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
COLOR_BG = (45, 45, 50)
|
|
12
|
+
COLOR_BORDER = (80, 80, 80)
|
|
13
|
+
COLOR_ACCENT = (60, 100, 160)
|
|
14
|
+
COLOR_TEXT = (220, 220, 220)
|
|
15
|
+
COLOR_ERROR = (200, 60, 60)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class MapPropertiesDialog:
|
|
19
|
+
def __init__(self, editor: "Editor", center_rect: Rect):
|
|
20
|
+
self.editor = editor
|
|
21
|
+
self.rect = center_rect
|
|
22
|
+
self.visible = False
|
|
23
|
+
self.error_message = ""
|
|
24
|
+
|
|
25
|
+
self.render_scale_input = BaseTextInput(
|
|
26
|
+
Rect(self.rect.x + 20, self.rect.y + 60, self.rect.width - 40, 60),
|
|
27
|
+
"Render Scale",
|
|
28
|
+
"render_scale",
|
|
29
|
+
str(editor.tilemap.render_scale),
|
|
30
|
+
allowed_chars="0123456789.",
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
self.btn_save = Rect(self.rect.centerx - 130, self.rect.bottom - 50, 120, 35)
|
|
34
|
+
self.btn_cancel = Rect(self.rect.centerx + 10, self.rect.bottom - 50, 120, 35)
|
|
35
|
+
self.font = pygame.font.SysFont("Arial", 20, bold=True)
|
|
36
|
+
self.font_info = pygame.font.SysFont("Arial", 14)
|
|
37
|
+
|
|
38
|
+
def open(self):
|
|
39
|
+
self.render_scale_input.text = str(self.editor.tilemap.render_scale)
|
|
40
|
+
self.render_scale_input.cursor_pos = len(self.render_scale_input.text)
|
|
41
|
+
self.render_scale_input.is_focused = False
|
|
42
|
+
self.error_message = ""
|
|
43
|
+
self.visible = True
|
|
44
|
+
|
|
45
|
+
def resize(self, center_rect: Rect):
|
|
46
|
+
self.rect = center_rect
|
|
47
|
+
self.render_scale_input.rect_area = Rect(
|
|
48
|
+
self.rect.x + 20, self.rect.y + 60, self.rect.width - 40, 60
|
|
49
|
+
)
|
|
50
|
+
self.render_scale_input.rect_input = Rect(
|
|
51
|
+
self.render_scale_input.rect_area.x,
|
|
52
|
+
self.render_scale_input.rect_area.y + 20,
|
|
53
|
+
self.render_scale_input.rect_area.width,
|
|
54
|
+
30,
|
|
55
|
+
)
|
|
56
|
+
self.btn_save = Rect(self.rect.centerx - 130, self.rect.bottom - 50, 120, 35)
|
|
57
|
+
self.btn_cancel = Rect(self.rect.centerx + 10, self.rect.bottom - 50, 120, 35)
|
|
58
|
+
|
|
59
|
+
def handle_event(self, event: pygame.event.Event) -> bool:
|
|
60
|
+
if not self.visible:
|
|
61
|
+
return False
|
|
62
|
+
|
|
63
|
+
if event.type == pygame.MOUSEBUTTONDOWN:
|
|
64
|
+
if event.button == 1:
|
|
65
|
+
if self.btn_save.collidepoint(event.pos):
|
|
66
|
+
self.submit()
|
|
67
|
+
return True
|
|
68
|
+
if self.btn_cancel.collidepoint(event.pos):
|
|
69
|
+
self.visible = False
|
|
70
|
+
return True
|
|
71
|
+
|
|
72
|
+
if event.type == pygame.KEYDOWN:
|
|
73
|
+
if event.key == pygame.K_ESCAPE:
|
|
74
|
+
self.visible = False
|
|
75
|
+
return True
|
|
76
|
+
if event.key == pygame.K_RETURN:
|
|
77
|
+
self.submit()
|
|
78
|
+
return True
|
|
79
|
+
|
|
80
|
+
self.render_scale_input.handle_event(event)
|
|
81
|
+
return True
|
|
82
|
+
|
|
83
|
+
def submit(self):
|
|
84
|
+
try:
|
|
85
|
+
raw = self.render_scale_input.text.strip()
|
|
86
|
+
if not raw:
|
|
87
|
+
raise ValueError("Render Scale is required")
|
|
88
|
+
value = float(raw)
|
|
89
|
+
if value <= 0:
|
|
90
|
+
raise ValueError("Render Scale must be greater than 0")
|
|
91
|
+
self.editor.tilemap.render_scale = value
|
|
92
|
+
self.editor.notifications.notify(f"Render Scale set to {value}")
|
|
93
|
+
self.visible = False
|
|
94
|
+
except ValueError as e:
|
|
95
|
+
self.error_message = str(e)
|
|
96
|
+
|
|
97
|
+
def draw(self, screen: pygame.Surface):
|
|
98
|
+
if not self.visible:
|
|
99
|
+
return
|
|
100
|
+
|
|
101
|
+
overlay = pygame.Surface(
|
|
102
|
+
(self.editor.width, self.editor.height), pygame.SRCALPHA
|
|
103
|
+
)
|
|
104
|
+
overlay.fill((0, 0, 0, 180))
|
|
105
|
+
screen.blit(overlay, (0, 0))
|
|
106
|
+
|
|
107
|
+
pygame.draw.rect(screen, COLOR_BG, self.rect, border_radius=8)
|
|
108
|
+
pygame.draw.rect(screen, COLOR_BORDER, self.rect, 2, border_radius=8)
|
|
109
|
+
|
|
110
|
+
title = self.font.render("Map Properties", True, COLOR_TEXT)
|
|
111
|
+
screen.blit(title, (self.rect.x + 20, self.rect.y + 15))
|
|
112
|
+
|
|
113
|
+
# Show read-only info about tile and map size
|
|
114
|
+
tm = self.editor.tilemap
|
|
115
|
+
info = f"Tile Size: {tm.tile_size[0]}x{tm.tile_size[1]} | Map Size: {tm.map_size[0]}x{tm.map_size[1]}"
|
|
116
|
+
info_surf = self.font_info.render(info, True, (150, 150, 150))
|
|
117
|
+
screen.blit(info_surf, (self.rect.x + 20, self.rect.y + 42))
|
|
118
|
+
|
|
119
|
+
self.render_scale_input.draw(screen)
|
|
120
|
+
|
|
121
|
+
for btn, text, col in [
|
|
122
|
+
(self.btn_save, "Apply", (40, 150, 80)),
|
|
123
|
+
(self.btn_cancel, "Cancel", (150, 60, 60)),
|
|
124
|
+
]:
|
|
125
|
+
pygame.draw.rect(screen, col, btn, border_radius=4)
|
|
126
|
+
txt_surf = self.font.render(text, True, COLOR_TEXT)
|
|
127
|
+
screen.blit(txt_surf, txt_surf.get_rect(center=btn.center))
|
|
128
|
+
|
|
129
|
+
if self.error_message:
|
|
130
|
+
err = pygame.font.SysFont("Arial", 12).render(
|
|
131
|
+
self.error_message, True, COLOR_ERROR
|
|
132
|
+
)
|
|
133
|
+
screen.blit(err, (self.rect.x + 20, self.btn_save.y - 20))
|
|
@@ -44,6 +44,12 @@ class TileGrid:
|
|
|
44
44
|
def tile_size(self):
|
|
45
45
|
return self.editor.tilemap.tile_size
|
|
46
46
|
|
|
47
|
+
@property
|
|
48
|
+
def effective_tile_size(self):
|
|
49
|
+
tw, th = self.editor.tilemap.tile_size
|
|
50
|
+
rs = self.editor.tilemap.render_scale
|
|
51
|
+
return (tw * rs, th * rs)
|
|
52
|
+
|
|
47
53
|
def screen_to_world(self, pos: Tuple[int, int]) -> Tuple[int, int]:
|
|
48
54
|
wx = (pos[0] - self.rect.x) / self.zoom_level + self.scroll_x
|
|
49
55
|
wy = (pos[1] - self.rect.y) / self.zoom_level + self.scroll_y
|
|
@@ -51,8 +57,8 @@ class TileGrid:
|
|
|
51
57
|
|
|
52
58
|
def get_grid_pos(self, pos: Tuple[int, int]) -> Tuple[int, int]:
|
|
53
59
|
wx, wy = self.screen_to_world(pos)
|
|
54
|
-
|
|
55
|
-
return int(wx //
|
|
60
|
+
eff_w, eff_h = self.effective_tile_size
|
|
61
|
+
return int(wx // eff_w), int(wy // eff_h)
|
|
56
62
|
|
|
57
63
|
def update(self):
|
|
58
64
|
event_blocked = not self.editor.save_input.active
|
|
@@ -117,8 +123,9 @@ class TileGrid:
|
|
|
117
123
|
self.scroll_y = 0
|
|
118
124
|
|
|
119
125
|
def fit_to_map(self):
|
|
120
|
-
|
|
121
|
-
|
|
126
|
+
eff_w, eff_h = self.effective_tile_size
|
|
127
|
+
world_w = self.editor.tilemap.map_size[0] * eff_w
|
|
128
|
+
world_h = self.editor.tilemap.map_size[1] * eff_h
|
|
122
129
|
if world_w <= 0 or world_h <= 0:
|
|
123
130
|
return
|
|
124
131
|
zoom_x = self.rect.width / world_w
|
|
@@ -129,8 +136,9 @@ class TileGrid:
|
|
|
129
136
|
|
|
130
137
|
def clamp_view(self):
|
|
131
138
|
self.zoom_level = max(self.min_zoom, min(self.max_zoom, self.zoom_level))
|
|
132
|
-
|
|
133
|
-
|
|
139
|
+
eff_w, eff_h = self.effective_tile_size
|
|
140
|
+
world_w = self.editor.tilemap.map_size[0] * eff_w
|
|
141
|
+
world_h = self.editor.tilemap.map_size[1] * eff_h
|
|
134
142
|
view_w = self.rect.width / self.zoom_level
|
|
135
143
|
view_h = self.rect.height / self.zoom_level
|
|
136
144
|
|
|
@@ -631,16 +639,18 @@ class TileGrid:
|
|
|
631
639
|
if not self.hover_cell:
|
|
632
640
|
return
|
|
633
641
|
|
|
642
|
+
eff_w, eff_h = self.effective_tile_size
|
|
643
|
+
|
|
634
644
|
if is_erasing:
|
|
635
645
|
# Eraser preview for tiles: show a red box based on eraser_size
|
|
636
646
|
screen_x = (
|
|
637
|
-
self.hover_cell[0] *
|
|
647
|
+
self.hover_cell[0] * eff_w - self.scroll_x
|
|
638
648
|
) * self.zoom_level + self.rect.x
|
|
639
649
|
screen_y = (
|
|
640
|
-
self.hover_cell[1] *
|
|
650
|
+
self.hover_cell[1] * eff_h - self.scroll_y
|
|
641
651
|
) * self.zoom_level + self.rect.y
|
|
642
|
-
size_w = int(
|
|
643
|
-
size_h = int(
|
|
652
|
+
size_w = int(eff_w * self.eraser_size * self.zoom_level)
|
|
653
|
+
size_h = int(eff_h * self.eraser_size * self.zoom_level)
|
|
644
654
|
dest_rect = Rect(screen_x, screen_y, size_w, size_h)
|
|
645
655
|
pygame.draw.rect(screen, (255, 50, 50), dest_rect, 2)
|
|
646
656
|
return
|
|
@@ -654,14 +664,14 @@ class TileGrid:
|
|
|
654
664
|
row = self.hover_cell[1] + y_off
|
|
655
665
|
|
|
656
666
|
screen_x = (
|
|
657
|
-
col *
|
|
667
|
+
col * eff_w - self.scroll_x
|
|
658
668
|
) * self.zoom_level + self.rect.x
|
|
659
669
|
screen_y = (
|
|
660
|
-
row *
|
|
670
|
+
row * eff_h - self.scroll_y
|
|
661
671
|
) * self.zoom_level + self.rect.y
|
|
662
672
|
|
|
663
|
-
dest_w = int(
|
|
664
|
-
dest_h = int(
|
|
673
|
+
dest_w = int(eff_w * self.zoom_level)
|
|
674
|
+
dest_h = int(eff_h * self.zoom_level)
|
|
665
675
|
dest_rect = Rect(screen_x, screen_y, dest_w, dest_h)
|
|
666
676
|
|
|
667
677
|
pygame.draw.rect(screen, (255, 255, 255), dest_rect, 1)
|
|
@@ -683,12 +693,12 @@ class TileGrid:
|
|
|
683
693
|
pass
|
|
684
694
|
|
|
685
695
|
def _draw_grid(self, screen):
|
|
686
|
-
|
|
696
|
+
eff_w, eff_h = self.effective_tile_size
|
|
687
697
|
map_w, map_h = self.editor.tilemap.map_size
|
|
688
698
|
|
|
689
699
|
# World coordinates of map boundaries
|
|
690
|
-
map_world_w = map_w *
|
|
691
|
-
map_world_h = map_h *
|
|
700
|
+
map_world_w = map_w * eff_w
|
|
701
|
+
map_world_h = map_h * eff_h
|
|
692
702
|
|
|
693
703
|
# Screen coordinates of map top-left
|
|
694
704
|
map_screen_x = (0 - self.scroll_x) * self.zoom_level + self.rect.x
|
|
@@ -703,15 +713,15 @@ class TileGrid:
|
|
|
703
713
|
visible_world_w = self.rect.width / self.zoom_level
|
|
704
714
|
visible_world_h = self.rect.height / self.zoom_level
|
|
705
715
|
|
|
706
|
-
start_col = max(0, int(self.scroll_x //
|
|
707
|
-
end_col = min(map_w, int((self.scroll_x + visible_world_w) //
|
|
716
|
+
start_col = max(0, int(self.scroll_x // eff_w))
|
|
717
|
+
end_col = min(map_w, int((self.scroll_x + visible_world_w) // eff_w) + 1)
|
|
708
718
|
|
|
709
|
-
start_row = max(0, int(self.scroll_y //
|
|
710
|
-
end_row = min(map_h, int((self.scroll_y + visible_world_h) //
|
|
719
|
+
start_row = max(0, int(self.scroll_y // eff_h))
|
|
720
|
+
end_row = min(map_h, int((self.scroll_y + visible_world_h) // eff_h) + 1)
|
|
711
721
|
|
|
712
722
|
# Draw vertical lines (at column positions)
|
|
713
723
|
for col in range(start_col, end_col + 1):
|
|
714
|
-
x = (col *
|
|
724
|
+
x = (col * eff_w - self.scroll_x) * self.zoom_level + self.rect.x
|
|
715
725
|
# Line goes from top of map to bottom of map (clipping handled by surface clip)
|
|
716
726
|
pygame.draw.line(
|
|
717
727
|
screen,
|
|
@@ -722,7 +732,7 @@ class TileGrid:
|
|
|
722
732
|
|
|
723
733
|
# Draw horizontal lines (at row positions)
|
|
724
734
|
for row in range(start_row, end_row + 1):
|
|
725
|
-
y = (row *
|
|
735
|
+
y = (row * eff_h - self.scroll_y) * self.zoom_level + self.rect.y
|
|
726
736
|
# Line goes from left of map to right of map
|
|
727
737
|
pygame.draw.line(
|
|
728
738
|
screen,
|
|
@@ -782,20 +792,21 @@ class TileGrid:
|
|
|
782
792
|
return
|
|
783
793
|
|
|
784
794
|
tile_w, tile_h = self.tile_size
|
|
795
|
+
rs = tilemap.render_scale
|
|
796
|
+
eff_w = tile_w * rs
|
|
797
|
+
eff_h = tile_h * rs
|
|
798
|
+
|
|
785
799
|
map_w, map_h = tilemap.map_size
|
|
786
800
|
|
|
787
|
-
# visible world bounds
|
|
801
|
+
# visible world bounds (in effective world space)
|
|
788
802
|
visible_world_w = self.rect.width / self.zoom_level
|
|
789
803
|
visible_world_h = self.rect.height / self.zoom_level
|
|
790
804
|
|
|
791
|
-
start_col = max(0, int(self.scroll_x //
|
|
792
|
-
end_col = min(map_w, int((self.scroll_x + visible_world_w) //
|
|
793
|
-
|
|
794
|
-
start_row = max(0, int(self.scroll_y // tile_h))
|
|
795
|
-
end_row = min(map_h, int((self.scroll_y + visible_world_h) // tile_h) + 1)
|
|
805
|
+
start_col = max(0, int(self.scroll_x // eff_w))
|
|
806
|
+
end_col = min(map_w, int((self.scroll_x + visible_world_w) // eff_w) + 1)
|
|
796
807
|
|
|
797
|
-
|
|
798
|
-
|
|
808
|
+
start_row = max(0, int(self.scroll_y // eff_h))
|
|
809
|
+
end_row = min(map_h, int((self.scroll_y + visible_world_h) // eff_h) + 1)
|
|
799
810
|
|
|
800
811
|
assert self.editor.tileset_widget is not None
|
|
801
812
|
tileset_map = self.editor.tileset_widget.tileset_map
|
|
@@ -836,29 +847,28 @@ class TileGrid:
|
|
|
836
847
|
variant_id = tile["variant"]
|
|
837
848
|
sheet_w = base_surf.get_width()
|
|
838
849
|
|
|
850
|
+
# Source rect always uses logical tile size
|
|
839
851
|
sheet_cols = sheet_w // tile_w
|
|
840
|
-
|
|
841
852
|
src_x = (variant_id % sheet_cols) * tile_w
|
|
842
853
|
src_y = (variant_id // sheet_cols) * tile_h
|
|
843
854
|
src_rect = Rect(src_x, src_y, tile_w, tile_h)
|
|
844
855
|
|
|
856
|
+
# Dest position uses effective (scaled) tile size
|
|
845
857
|
dest_x = (
|
|
846
|
-
(x *
|
|
858
|
+
(x * eff_w - self.scroll_x) * self.zoom_level
|
|
847
859
|
+ self.rect.x
|
|
848
860
|
+ draw_offset_x
|
|
849
861
|
)
|
|
850
862
|
dest_y = (
|
|
851
|
-
(y *
|
|
863
|
+
(y * eff_h - self.scroll_y) * self.zoom_level
|
|
852
864
|
+ self.rect.y
|
|
853
865
|
+ draw_offset_y
|
|
854
866
|
)
|
|
855
867
|
|
|
856
|
-
# Scale if
|
|
857
|
-
if self.zoom_level != 1.0:
|
|
858
|
-
scaled_w = int(
|
|
859
|
-
scaled_h = int(
|
|
860
|
-
|
|
861
|
-
# Bounds check
|
|
868
|
+
# Scale if zoomed or render_scaled
|
|
869
|
+
if self.zoom_level != 1.0 or rs != 1.0:
|
|
870
|
+
scaled_w = int(eff_w * self.zoom_level)
|
|
871
|
+
scaled_h = int(eff_h * self.zoom_level)
|
|
862
872
|
if base_surf.get_rect().contains(src_rect):
|
|
863
873
|
sub = base_surf.subsurface(src_rect)
|
|
864
874
|
scaled_sub = pygame.transform.scale(
|
|
@@ -895,19 +905,19 @@ class TileGrid:
|
|
|
895
905
|
src_rect = Rect(src_x, src_y, obj_w, obj_h)
|
|
896
906
|
|
|
897
907
|
dest_x = (
|
|
898
|
-
(obj_x - self.scroll_x) * self.zoom_level
|
|
908
|
+
(obj_x * rs - self.scroll_x) * self.zoom_level
|
|
899
909
|
+ self.rect.x
|
|
900
910
|
+ draw_offset_x
|
|
901
911
|
)
|
|
902
912
|
dest_y = (
|
|
903
|
-
(obj_y - self.scroll_y) * self.zoom_level
|
|
913
|
+
(obj_y * rs - self.scroll_y) * self.zoom_level
|
|
904
914
|
+ self.rect.y
|
|
905
915
|
+ draw_offset_y
|
|
906
916
|
)
|
|
907
917
|
|
|
908
|
-
if self.zoom_level != 1.0:
|
|
909
|
-
scaled_w = int(obj_w * self.zoom_level)
|
|
910
|
-
scaled_h = int(obj_h * self.zoom_level)
|
|
918
|
+
if self.zoom_level != 1.0 or rs != 1.0:
|
|
919
|
+
scaled_w = int(obj_w * rs * self.zoom_level)
|
|
920
|
+
scaled_h = int(obj_h * rs * self.zoom_level)
|
|
911
921
|
if base_surf.get_rect().contains(src_rect):
|
|
912
922
|
sub = base_surf.subsurface(src_rect)
|
|
913
923
|
scaled_sub = pygame.transform.scale(
|