tilemap-editor 2.0.1__tar.gz → 2.0.3__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-2.0.1 → tilemap_editor-2.0.3}/CHANGELOG.md +19 -0
- {tilemap_editor-2.0.1/src/tilemap_editor.egg-info → tilemap_editor-2.0.3}/PKG-INFO +1 -1
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/pyproject.toml +1 -1
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/editor.py +30 -9
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3/src/tilemap_editor.egg-info}/PKG-INFO +1 -1
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/widgets/autotile_template.py +24 -23
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/widgets/autotiler.py +85 -48
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/LICENSE +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/MANIFEST.in +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/README.md +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/assets/fonts/jetbrain-fonts/JetBrainsMono-Bold.ttf +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/assets/fonts/jetbrain-fonts/JetBrainsMono-BoldItalic.ttf +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/assets/fonts/jetbrain-fonts/JetBrainsMono-Italic.ttf +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/assets/fonts/jetbrain-fonts/JetBrainsMono-Regular.ttf +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/assets/fonts/noto/NotoSans-Bold.ttf +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/assets/fonts/noto/NotoSans-BoldItalic.ttf +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/assets/fonts/noto/NotoSans-Italic.ttf +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/assets/fonts/noto/NotoSans-Regular.ttf +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/assets/icons/arrow-down.svg +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/assets/icons/check.svg +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/assets/icons/checked.svg +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/assets/icons/close.svg +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/assets/icons/duplicate.svg +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/assets/icons/error.svg +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/assets/icons/file.svg +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/assets/icons/filedead.svg +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/assets/icons/fit.svg +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/assets/icons/folder.svg +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/assets/icons/grid.svg +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/assets/icons/image.svg +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/assets/icons/info.svg +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/assets/icons/load.svg +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/assets/icons/loop.svg +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/assets/icons/pan.svg +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/assets/icons/pause.svg +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/assets/icons/pencil.svg +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/assets/icons/play.svg +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/assets/icons/plus.svg +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/assets/icons/radio.svg +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/assets/icons/reset.svg +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/assets/icons/save.svg +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/assets/icons/stop.svg +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/assets/icons/tilemap.svg +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/assets/icons/tileset.svg +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/assets/icons/unchecked.svg +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/assets/icons/warning.svg +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/assets/icons/zoomin.svg +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/assets/icons/zoomout.svg +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/setup.cfg +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/configs/themes.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/constants.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/event_map.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/layers.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/main.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/plugins/__init__.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/plugins/character_collision/__init__.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/plugins/character_collision/editor.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/plugins/character_collision/models.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/plugins/character_collision/protocols.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/plugins/character_collision/shape_editor.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/plugins/character_collision/standalone.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/plugins/sprite_animation/__init__.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/plugins/sprite_animation/__main__.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/plugins/sprite_animation/clipboard_util.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/plugins/sprite_animation/editor.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/plugins/sprite_animation/frame_picker.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/plugins/sprite_animation/models.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/plugins/sprite_animation/preview.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/plugins/sprite_animation/protocols.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/plugins/sprite_animation/runtime_load.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/plugins/sprite_animation/standalone.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/plugins/sprite_animation/timeline.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/plugins/sprite_animation/validation.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/plugins/tileset_collision/__init__.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/plugins/tileset_collision/collision_painter.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/plugins/tileset_collision/editor.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/plugins/tileset_collision/models.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/plugins/tileset_collision/protocols.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/plugins/tileset_collision/standalone.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/standalone_automap.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/standalone_error_console.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/standalone_filemanager.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/standalone_image_viewer.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/tilemap.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/tilemap_editor/__init__.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/tilemap_editor/__main__.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/tilemap_editor/cli.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/tilemap_editor.egg-info/SOURCES.txt +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/tilemap_editor.egg-info/dependency_links.txt +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/tilemap_editor.egg-info/entry_points.txt +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/tilemap_editor.egg-info/requires.txt +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/tilemap_editor.egg-info/top_level.txt +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/ttypes/__init__.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/ttypes/tilemap.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/utils/__init__.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/utils/error_handler.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/utils/font_manager.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/utils/history.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/utils/icon_manager.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/utils/icons_cache.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/utils/log_capture.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/utils/serialization.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/utils/settings.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/utils/standalone.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/utils/validation.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/widgets/__init__.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/widgets/automap_models.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/widgets/filemanager.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/widgets/layer_selector.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/widgets/mapsetup.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/widgets/regex_automap_designer.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/widgets/tile_grid.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/widgets/tile_selector.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/widgets/ui/draw_utils.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/widgets/ui/fileinput.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/widgets/ui/layer_type_dialog.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/widgets/ui/menubar.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/widgets/ui/notification.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/widgets/ui/property_editor.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/widgets/ui/theme.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/widgets/ui/tileset_type_dialog.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/widgets/ui/toolbar.py +0 -0
- {tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/widgets/ui/tooltip.py +0 -0
|
@@ -5,6 +5,25 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [2.0.1] - 2025-04-23
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **Tileset Collision Plugin**: Godot-like polygon collision editor
|
|
12
|
+
- `CollisionPainter`: Interactive polygon drawing with edge-constrain mode
|
|
13
|
+
- `TilesetCollisionEditor`: Full editor with tile selector and painted tiles list
|
|
14
|
+
- `TilesetCollisionLibrary`: Persistent collision data management
|
|
15
|
+
- Edge-draw mode (`E` key + `Shift`) for precise slope/stair creation
|
|
16
|
+
- Help panel (`H` key) with all controls documented
|
|
17
|
+
- One-way collision support for platforms
|
|
18
|
+
- Zoom, pan, and grid controls
|
|
19
|
+
- **Character Collision Plugin**: Shape-based character collision editor
|
|
20
|
+
- Rectangle, Circle, and Capsule shape support
|
|
21
|
+
- Protocol-based design for easy integration
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
- Updated pyproject.toml version to 2.0.1
|
|
25
|
+
- Improved editor.py and tile_selector.py integration
|
|
26
|
+
|
|
8
27
|
## [2.0.0] - 2025-04-22
|
|
9
28
|
|
|
10
29
|
### Major Changes
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "tilemap-editor"
|
|
7
|
-
version = "2.0.
|
|
7
|
+
version = "2.0.3"
|
|
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"
|
|
@@ -762,6 +762,7 @@ class Editor:
|
|
|
762
762
|
if event.type == pygame.VIDEORESIZE:
|
|
763
763
|
self.handle_resize(event.w, event.h)
|
|
764
764
|
|
|
765
|
+
# Priority 1: Modal dialogs and inputs (highest priority)
|
|
765
766
|
if self.save_input.active:
|
|
766
767
|
self.save_input.handle_event(event)
|
|
767
768
|
continue
|
|
@@ -782,9 +783,20 @@ class Editor:
|
|
|
782
783
|
if self.property_editor.handle_event(event):
|
|
783
784
|
continue
|
|
784
785
|
|
|
786
|
+
# Priority 2: Autotiler and Regex Designer (block all events when visible)
|
|
787
|
+
if self.autotiler.visible:
|
|
788
|
+
if self.autotiler.handle_event(event):
|
|
789
|
+
continue
|
|
790
|
+
|
|
791
|
+
if self.regex_automap_designer.visible:
|
|
792
|
+
if self.regex_automap_designer.handle_event(event):
|
|
793
|
+
continue
|
|
794
|
+
|
|
795
|
+
# Priority 3: Menu bar
|
|
785
796
|
if self.menubar.handle_event(event):
|
|
786
797
|
continue
|
|
787
798
|
|
|
799
|
+
# Priority 4: Keyboard shortcuts
|
|
788
800
|
if event.type == pygame.KEYDOWN:
|
|
789
801
|
mods = pygame.key.get_mods()
|
|
790
802
|
ctrl_held = mods & (pygame.KMOD_LCTRL | pygame.KMOD_RCTRL)
|
|
@@ -836,23 +848,17 @@ class Editor:
|
|
|
836
848
|
self.tilemap.layer_manager.set_active_layer(idx)
|
|
837
849
|
continue
|
|
838
850
|
|
|
851
|
+
# Priority 5: Toolbar
|
|
839
852
|
if self.toolbar and self.toolbar.handle_event(event):
|
|
840
853
|
continue
|
|
841
854
|
|
|
842
|
-
|
|
843
|
-
if self.autotiler.handle_event(event):
|
|
844
|
-
continue
|
|
845
|
-
|
|
846
|
-
if self.regex_automap_designer.visible:
|
|
847
|
-
if self.regex_automap_designer.handle_event(event):
|
|
848
|
-
continue
|
|
849
|
-
|
|
850
|
-
# Route events to the dockable animation panel
|
|
855
|
+
# Priority 6: Dockable animation panel
|
|
851
856
|
if self.left_panel_visible and self.animation_panel:
|
|
852
857
|
if hasattr(self.animation_panel, "handle_event"):
|
|
853
858
|
if self.animation_panel.handle_event(event):
|
|
854
859
|
continue
|
|
855
860
|
|
|
861
|
+
# Priority 7: Side panels (tileset and layer widgets)
|
|
856
862
|
consumed = False
|
|
857
863
|
if self.tileset_widget and self.tileset_widget.handle_event(event):
|
|
858
864
|
consumed = True
|
|
@@ -862,6 +868,8 @@ class Editor:
|
|
|
862
868
|
and self.layer_widget.handle_event(event)
|
|
863
869
|
):
|
|
864
870
|
consumed = True
|
|
871
|
+
|
|
872
|
+
# Priority 8: Main tile grid (lowest priority)
|
|
865
873
|
if not consumed and self.tile_grid_widget:
|
|
866
874
|
self.tile_grid_widget.handle_event(event)
|
|
867
875
|
|
|
@@ -894,9 +902,22 @@ class Editor:
|
|
|
894
902
|
self.tileset_widget.draw(self.screen)
|
|
895
903
|
if self.layer_widget:
|
|
896
904
|
self.layer_widget.draw(self.screen)
|
|
905
|
+
|
|
906
|
+
# Draw autotiler and regex designer with modal overlay
|
|
897
907
|
if self.autotiler:
|
|
908
|
+
if self.autotiler.visible:
|
|
909
|
+
# Dim background when autotiler is open
|
|
910
|
+
overlay = pygame.Surface((self.width, self.height), pygame.SRCALPHA)
|
|
911
|
+
overlay.fill((0, 0, 0, 100))
|
|
912
|
+
self.screen.blit(overlay, (0, 0))
|
|
898
913
|
self.autotiler.draw(self.screen)
|
|
914
|
+
|
|
899
915
|
if self.regex_automap_designer:
|
|
916
|
+
if self.regex_automap_designer.visible:
|
|
917
|
+
# Dim background when regex designer is open
|
|
918
|
+
overlay = pygame.Surface((self.width, self.height), pygame.SRCALPHA)
|
|
919
|
+
overlay.fill((0, 0, 0, 100))
|
|
920
|
+
self.screen.blit(overlay, (0, 0))
|
|
900
921
|
self.regex_automap_designer.draw(self.screen)
|
|
901
922
|
|
|
902
923
|
# Draw the dockable animation panel
|
|
@@ -166,6 +166,14 @@ class AutotileTemplateApplier:
|
|
|
166
166
|
if not ts:
|
|
167
167
|
return
|
|
168
168
|
|
|
169
|
+
# Check if a group is selected
|
|
170
|
+
if self.designer.selected_group_idx == -1:
|
|
171
|
+
print("Template Error: No group selected. Please select a group first.")
|
|
172
|
+
return
|
|
173
|
+
|
|
174
|
+
# Use the currently selected group
|
|
175
|
+
target_group = self.designer.groups[self.designer.selected_group_idx]
|
|
176
|
+
|
|
169
177
|
rx, ry, rw, rh = tile_selector.selected_tile
|
|
170
178
|
tile_w, tile_h = self.designer.editor.tilemap.tile_size
|
|
171
179
|
sheet_cols = ts.surface.get_width() // tile_w
|
|
@@ -173,24 +181,6 @@ class AutotileTemplateApplier:
|
|
|
173
181
|
start_col = rx // tile_w
|
|
174
182
|
start_row = ry // tile_h
|
|
175
183
|
|
|
176
|
-
# Define a unique group ID for THIS specific 3x3 selection area
|
|
177
|
-
# (e.g. "GrassSet_12_4")
|
|
178
|
-
set_id = f"{ts.name}_{start_col}_{start_row}"
|
|
179
|
-
|
|
180
|
-
from .autotiler import AutotileGroup
|
|
181
|
-
|
|
182
|
-
# Create a real group object in the designer
|
|
183
|
-
target_group = None
|
|
184
|
-
for g in self.designer.groups:
|
|
185
|
-
if g.name == set_id:
|
|
186
|
-
target_group = g
|
|
187
|
-
break
|
|
188
|
-
|
|
189
|
-
if not target_group:
|
|
190
|
-
target_group = AutotileGroup(set_id)
|
|
191
|
-
self.designer.groups.append(target_group)
|
|
192
|
-
self.designer.selected_group_idx = len(self.designer.groups) - 1
|
|
193
|
-
|
|
194
184
|
added_count = 0
|
|
195
185
|
updated_count = 0
|
|
196
186
|
|
|
@@ -204,32 +194,43 @@ class AutotileTemplateApplier:
|
|
|
204
194
|
|
|
205
195
|
ts_index = tile_selector.active_idx
|
|
206
196
|
|
|
207
|
-
# Check for existing rule in THIS group
|
|
197
|
+
# Check for existing rule in THIS group with EXACT same neighbors and tileset
|
|
208
198
|
matched_rule = None
|
|
209
199
|
for r in target_group.rules:
|
|
200
|
+
# Must match both neighbors AND tileset to be considered the same rule
|
|
210
201
|
if r.neighbors == neighbors and r.tileset_index == ts_index:
|
|
211
202
|
matched_rule = r
|
|
212
203
|
break
|
|
213
204
|
|
|
214
205
|
if matched_rule:
|
|
206
|
+
# Only add variant if it's not already there
|
|
215
207
|
if vid not in matched_rule.variant_ids:
|
|
216
208
|
matched_rule.variant_ids.append(vid)
|
|
217
209
|
updated_count += 1
|
|
218
210
|
else:
|
|
219
|
-
|
|
211
|
+
# Create a new rule with a unique name
|
|
212
|
+
rule_num = len(target_group.rules) + 1
|
|
213
|
+
rule_name = f"Rule {rule_num}"
|
|
214
|
+
|
|
215
|
+
# Ensure unique name
|
|
216
|
+
existing_names = {r.name for r in target_group.rules}
|
|
217
|
+
while rule_name in existing_names:
|
|
218
|
+
rule_num += 1
|
|
219
|
+
rule_name = f"Rule {rule_num}"
|
|
220
|
+
|
|
220
221
|
new_rule = AutotileRule(
|
|
221
222
|
name=rule_name,
|
|
222
|
-
neighbors=neighbors,
|
|
223
|
+
neighbors=set(neighbors), # Create a new set to avoid reference issues
|
|
223
224
|
tileset_path=str(ts.path),
|
|
224
225
|
variant_ids=[vid],
|
|
225
226
|
tileset_index=ts_index,
|
|
226
|
-
group_id=
|
|
227
|
+
group_id=target_group.name,
|
|
227
228
|
)
|
|
228
229
|
target_group.rules.append(new_rule)
|
|
229
230
|
added_count += 1
|
|
230
231
|
|
|
231
232
|
print(
|
|
232
|
-
f"Template Applied: {template.name}
|
|
233
|
+
f"Template Applied: {template.name} to Group '{target_group.name}'. {added_count} rules added, {updated_count} rules updated."
|
|
233
234
|
)
|
|
234
235
|
|
|
235
236
|
def draw(self, screen: Surface):
|
|
@@ -87,7 +87,7 @@ class AutotileGroup:
|
|
|
87
87
|
class AutotileRuleDesigner:
|
|
88
88
|
def __init__(self, editor: "Editor", x: int, y: int):
|
|
89
89
|
self.editor = editor
|
|
90
|
-
self.rect = Rect(x, y, 600,
|
|
90
|
+
self.rect = Rect(x, y, 600, 500) # Increased height to accommodate buttons outside list areas
|
|
91
91
|
self.header_height = 30
|
|
92
92
|
|
|
93
93
|
self.visible = False
|
|
@@ -102,7 +102,7 @@ class AutotileRuleDesigner:
|
|
|
102
102
|
self.rename_text: str = ""
|
|
103
103
|
|
|
104
104
|
self.scroll_offset: int = 0
|
|
105
|
-
self.max_visible_rules: int =
|
|
105
|
+
self.max_visible_rules: int = 6 # Reduced to make scrolling more visible
|
|
106
106
|
self.scroll_bar_rect: Optional[Rect] = None
|
|
107
107
|
self.is_scrollbar_dragging: bool = False
|
|
108
108
|
|
|
@@ -139,9 +139,16 @@ class AutotileRuleDesigner:
|
|
|
139
139
|
body_h = self.rect.height - self.header_height
|
|
140
140
|
sidebar_w = 200
|
|
141
141
|
self.list_area = Rect(self.rect.x, body_y, sidebar_w, body_h)
|
|
142
|
-
|
|
142
|
+
|
|
143
|
+
# Reserve space for buttons at the bottom of each list area
|
|
144
|
+
button_h = 30
|
|
145
|
+
group_content_h = (body_h // 2) - button_h
|
|
146
|
+
rule_content_h = (body_h // 2) - button_h
|
|
147
|
+
|
|
148
|
+
# Group list area excludes the button
|
|
149
|
+
self.group_list_area = Rect(self.rect.x, body_y, sidebar_w, group_content_h)
|
|
143
150
|
self.rule_list_area = Rect(
|
|
144
|
-
self.rect.x, body_y + body_h // 2, sidebar_w,
|
|
151
|
+
self.rect.x, body_y + body_h // 2, sidebar_w, rule_content_h
|
|
145
152
|
)
|
|
146
153
|
|
|
147
154
|
self.edit_area = Rect(
|
|
@@ -154,15 +161,16 @@ class AutotileRuleDesigner:
|
|
|
154
161
|
self.save_btn_rect = Rect(cx - btn_w - 5, btn_y, btn_w, 30)
|
|
155
162
|
self.delete_btn_rect = Rect(cx + 5, btn_y, btn_w, 30)
|
|
156
163
|
|
|
164
|
+
# Position buttons OUTSIDE their respective list areas to prevent click conflicts
|
|
157
165
|
self.new_group_btn_rect = Rect(
|
|
158
166
|
self.group_list_area.x + 10,
|
|
159
|
-
self.group_list_area.bottom
|
|
167
|
+
self.group_list_area.bottom + 5, # Below the group list area
|
|
160
168
|
self.group_list_area.width - 20,
|
|
161
169
|
25,
|
|
162
170
|
)
|
|
163
171
|
self.new_rule_btn_rect = Rect(
|
|
164
172
|
self.rule_list_area.x + 10,
|
|
165
|
-
self.rule_list_area.bottom
|
|
173
|
+
self.rule_list_area.bottom + 5, # Below the rule list area
|
|
166
174
|
self.rule_list_area.width - 20,
|
|
167
175
|
25,
|
|
168
176
|
)
|
|
@@ -250,7 +258,12 @@ class AutotileRuleDesigner:
|
|
|
250
258
|
if self._handle_group_rename(event):
|
|
251
259
|
return True
|
|
252
260
|
|
|
253
|
-
|
|
261
|
+
# Get mouse position from event if available, otherwise from pygame
|
|
262
|
+
if hasattr(event, 'pos'):
|
|
263
|
+
mouse_pos = event.pos
|
|
264
|
+
else:
|
|
265
|
+
mouse_pos = pygame.mouse.get_pos()
|
|
266
|
+
|
|
254
267
|
self._update_preview_from_selector()
|
|
255
268
|
|
|
256
269
|
if event.type == pygame.KEYDOWN:
|
|
@@ -272,40 +285,36 @@ class AutotileRuleDesigner:
|
|
|
272
285
|
)
|
|
273
286
|
return True
|
|
274
287
|
|
|
275
|
-
|
|
276
|
-
self._handle_group_list_click(mouse_pos)
|
|
277
|
-
return True
|
|
278
|
-
|
|
279
|
-
if self.rule_list_area.collidepoint(mouse_pos):
|
|
280
|
-
self._handle_rule_list_click(mouse_pos)
|
|
281
|
-
return True
|
|
282
|
-
|
|
283
|
-
if self.save_btn_rect.collidepoint(mouse_pos):
|
|
284
|
-
self._save_current_rule()
|
|
285
|
-
return True
|
|
286
|
-
if self.save_btn_rect.inflate(0, 40).collidepoint(mouse_pos):
|
|
287
|
-
pass
|
|
288
|
-
|
|
288
|
+
# Check buttons FIRST before checking list areas (since buttons are outside)
|
|
289
289
|
if self.new_group_btn_rect.collidepoint(mouse_pos):
|
|
290
290
|
self._create_new_group_with_focus()
|
|
291
291
|
return True
|
|
292
|
-
|
|
292
|
+
|
|
293
293
|
if self.new_rule_btn_rect.collidepoint(mouse_pos):
|
|
294
294
|
self._reset_selection()
|
|
295
295
|
return True
|
|
296
296
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
if self.delete_btn_rect.collidepoint(mouse_pos):
|
|
302
|
-
self._delete_current_rule()
|
|
297
|
+
# Then check list areas
|
|
298
|
+
if self.group_list_area.collidepoint(mouse_pos):
|
|
299
|
+
self._handle_group_list_click(mouse_pos)
|
|
303
300
|
return True
|
|
304
|
-
|
|
305
|
-
|
|
301
|
+
|
|
302
|
+
if self.rule_list_area.collidepoint(mouse_pos):
|
|
303
|
+
self._handle_rule_list_click(mouse_pos)
|
|
306
304
|
return True
|
|
307
|
-
|
|
308
|
-
|
|
305
|
+
|
|
306
|
+
# Edit area interactions
|
|
307
|
+
if self.edit_area.collidepoint(mouse_pos):
|
|
308
|
+
if self.save_btn_rect.collidepoint(mouse_pos):
|
|
309
|
+
self._save_current_rule()
|
|
310
|
+
elif self.delete_btn_rect.collidepoint(mouse_pos):
|
|
311
|
+
self._delete_current_rule()
|
|
312
|
+
elif self.external_btn_rect.collidepoint(mouse_pos):
|
|
313
|
+
self._launch_external_viewer()
|
|
314
|
+
elif self.template_btn_rect.collidepoint(mouse_pos):
|
|
315
|
+
self.template_manager.show_at(mouse_pos)
|
|
316
|
+
else:
|
|
317
|
+
self._handle_grid_click(mouse_pos)
|
|
309
318
|
return True
|
|
310
319
|
|
|
311
320
|
elif event.type == pygame.MOUSEBUTTONUP:
|
|
@@ -318,10 +327,8 @@ class AutotileRuleDesigner:
|
|
|
318
327
|
self._update_layout()
|
|
319
328
|
return True
|
|
320
329
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
return True
|
|
330
|
+
# Always consume events when visible to prevent clicks bleeding through
|
|
331
|
+
return self.rect.collidepoint(mouse_pos) or self.is_dragging
|
|
325
332
|
|
|
326
333
|
def _sync_last_editor_state(self):
|
|
327
334
|
tile_selector = getattr(self.editor, "tileset_widget", None)
|
|
@@ -409,7 +416,7 @@ class AutotileRuleDesigner:
|
|
|
409
416
|
return False
|
|
410
417
|
|
|
411
418
|
def _handle_group_list_click(self, mouse_pos):
|
|
412
|
-
start_y = self.group_list_area.y +
|
|
419
|
+
start_y = self.group_list_area.y + 25
|
|
413
420
|
item_h = 25
|
|
414
421
|
for i, group in enumerate(self.groups):
|
|
415
422
|
item_rect = Rect(
|
|
@@ -421,23 +428,37 @@ class AutotileRuleDesigner:
|
|
|
421
428
|
if item_rect.collidepoint(mouse_pos):
|
|
422
429
|
self.selected_group_idx = i
|
|
423
430
|
self.selected_rule_index = -1
|
|
431
|
+
self.scroll_offset = 0
|
|
424
432
|
return
|
|
425
433
|
|
|
426
434
|
def _handle_rule_list_click(self, mouse_pos):
|
|
427
|
-
if self.new_rule_btn_rect.collidepoint(mouse_pos):
|
|
428
|
-
self._reset_selection()
|
|
429
|
-
return
|
|
430
|
-
|
|
431
435
|
if self.selected_group_idx == -1:
|
|
432
436
|
return
|
|
433
437
|
|
|
434
438
|
group = self.groups[self.selected_group_idx]
|
|
435
|
-
start_y = self.rule_list_area.y +
|
|
439
|
+
start_y = self.rule_list_area.y + 25
|
|
436
440
|
item_h = 25
|
|
437
|
-
|
|
441
|
+
|
|
442
|
+
# Only process clicks within the visible list area
|
|
443
|
+
list_content_area = Rect(
|
|
444
|
+
self.rule_list_area.x,
|
|
445
|
+
self.rule_list_area.y + 25,
|
|
446
|
+
self.rule_list_area.width,
|
|
447
|
+
self.rule_list_area.height - 25 # Adjusted since button is outside
|
|
448
|
+
)
|
|
449
|
+
|
|
450
|
+
if not list_content_area.collidepoint(mouse_pos):
|
|
451
|
+
return
|
|
452
|
+
|
|
453
|
+
visible_start = self.scroll_offset
|
|
454
|
+
visible_end = min(visible_start + self.max_visible_rules, len(group.rules))
|
|
455
|
+
|
|
456
|
+
for i in range(visible_start, visible_end):
|
|
457
|
+
rule = group.rules[i]
|
|
458
|
+
display_index = i - visible_start
|
|
438
459
|
item_rect = Rect(
|
|
439
460
|
self.rule_list_area.x + 5,
|
|
440
|
-
start_y +
|
|
461
|
+
start_y + display_index * item_h,
|
|
441
462
|
self.rule_list_area.width - 10,
|
|
442
463
|
item_h,
|
|
443
464
|
)
|
|
@@ -672,6 +693,7 @@ class AutotileRuleDesigner:
|
|
|
672
693
|
d_name = name if len(name) < 22 else name[:19] + ".."
|
|
673
694
|
screen.blit(self.font.render(d_name, True, TEXT_COLOR), (r.x + 5, r.y + 5))
|
|
674
695
|
|
|
696
|
+
# Draw button OUTSIDE the group list area
|
|
675
697
|
pygame.draw.rect(
|
|
676
698
|
screen, (80, 120, 80), self.new_group_btn_rect, border_radius=4
|
|
677
699
|
)
|
|
@@ -688,6 +710,7 @@ class AutotileRuleDesigner:
|
|
|
688
710
|
|
|
689
711
|
self._draw_scrollable_rule_list(screen)
|
|
690
712
|
|
|
713
|
+
# Draw button OUTSIDE the rule list area
|
|
691
714
|
pygame.draw.rect(
|
|
692
715
|
screen, (70, 130, 180), self.new_rule_btn_rect, border_radius=4
|
|
693
716
|
)
|
|
@@ -697,7 +720,7 @@ class AutotileRuleDesigner:
|
|
|
697
720
|
)
|
|
698
721
|
|
|
699
722
|
def _draw_scrollable_rule_list(self, screen: Surface) -> None:
|
|
700
|
-
"""Draw rules with scroll indicators and scrollbar"""
|
|
723
|
+
"""Draw rules with scroll indicators and scrollbar - with clipping to prevent overflow"""
|
|
701
724
|
if self.selected_group_idx == -1:
|
|
702
725
|
return
|
|
703
726
|
|
|
@@ -708,6 +731,17 @@ class AutotileRuleDesigner:
|
|
|
708
731
|
|
|
709
732
|
self.scroll_offset = max(0, min(self.scroll_offset, max_scroll))
|
|
710
733
|
|
|
734
|
+
# Set clip rect to prevent rules from rendering outside the list area
|
|
735
|
+
# Since button is now outside, we can use more of the area
|
|
736
|
+
list_clip = Rect(
|
|
737
|
+
self.rule_list_area.x,
|
|
738
|
+
self.rule_list_area.y + 25,
|
|
739
|
+
self.rule_list_area.width,
|
|
740
|
+
self.rule_list_area.height - 25 # Just leave space for header
|
|
741
|
+
)
|
|
742
|
+
old_clip = screen.get_clip()
|
|
743
|
+
screen.set_clip(list_clip)
|
|
744
|
+
|
|
711
745
|
visible_start = self.scroll_offset
|
|
712
746
|
visible_end = min(visible_start + self.max_visible_rules, total_rules)
|
|
713
747
|
|
|
@@ -729,6 +763,9 @@ class AutotileRuleDesigner:
|
|
|
729
763
|
d_name = rule.name if len(rule.name) < 20 else rule.name[:17] + ".."
|
|
730
764
|
screen.blit(self.font.render(d_name, True, TEXT_COLOR), (r.x + 5, r.y + 5))
|
|
731
765
|
|
|
766
|
+
# Restore clip
|
|
767
|
+
screen.set_clip(old_clip)
|
|
768
|
+
|
|
732
769
|
if total_rules > self.max_visible_rules:
|
|
733
770
|
if self.scroll_offset > 0:
|
|
734
771
|
arrow_up = "▲"
|
|
@@ -743,11 +780,11 @@ class AutotileRuleDesigner:
|
|
|
743
780
|
arrow_surf = self.font.render(arrow_down, True, (150, 200, 255))
|
|
744
781
|
screen.blit(
|
|
745
782
|
arrow_surf,
|
|
746
|
-
(self.rule_list_area.right - 20, self.rule_list_area.bottom -
|
|
783
|
+
(self.rule_list_area.right - 20, self.rule_list_area.bottom - 20),
|
|
747
784
|
)
|
|
748
785
|
|
|
749
786
|
scrollbar_height = 60
|
|
750
|
-
track_height = self.rule_list_area.height -
|
|
787
|
+
track_height = self.rule_list_area.height - 50
|
|
751
788
|
scroll_ratio = self.scroll_offset / max_scroll if max_scroll > 0 else 0
|
|
752
789
|
|
|
753
790
|
scrollbar_y = (
|
|
@@ -800,7 +837,7 @@ class AutotileRuleDesigner:
|
|
|
800
837
|
elif event.type == pygame.MOUSEMOTION:
|
|
801
838
|
if self.is_scrollbar_dragging:
|
|
802
839
|
relative_y = event.pos[1] - self.rule_list_area.y - 25
|
|
803
|
-
track_height = self.rule_list_area.height -
|
|
840
|
+
track_height = self.rule_list_area.height - 50 # Updated to match drawing
|
|
804
841
|
|
|
805
842
|
if track_height > 0:
|
|
806
843
|
scroll_ratio = max(0, min(1, relative_y / track_height))
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/assets/fonts/jetbrain-fonts/JetBrainsMono-Bold.ttf
RENAMED
|
File without changes
|
|
File without changes
|
{tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/assets/fonts/jetbrain-fonts/JetBrainsMono-Italic.ttf
RENAMED
|
File without changes
|
{tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/assets/fonts/jetbrain-fonts/JetBrainsMono-Regular.ttf
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
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
|
{tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/plugins/character_collision/shape_editor.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/plugins/sprite_animation/clipboard_util.py
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
|
{tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/plugins/tileset_collision/collision_painter.py
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
|
{tilemap_editor-2.0.1 → tilemap_editor-2.0.3}/src/tilemap_editor.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|