tilemap-editor 4.3.5__tar.gz → 4.3.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.
Files changed (231) hide show
  1. {tilemap_editor-4.3.5/src/tilemap_editor.egg-info → tilemap_editor-4.3.7}/PKG-INFO +1 -1
  2. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/pyproject.toml +1 -1
  3. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/editor.py +29 -78
  4. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/layers.py +8 -1
  5. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap.py +23 -49
  6. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7/src/tilemap_editor.egg-info}/PKG-INFO +1 -1
  7. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor.egg-info/SOURCES.txt +3 -0
  8. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/utils/font_manager.py +4 -0
  9. tilemap_editor-4.3.7/src/utils/property_suggestions.py +70 -0
  10. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/input.py +31 -6
  11. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/layer_selector.py +1 -0
  12. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/tile_grid.py +91 -76
  13. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/tile_selector.py +5 -0
  14. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/ui/menubar.py +36 -3
  15. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/ui/node_editor.py +2 -0
  16. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/ui/property_editor.py +118 -18
  17. tilemap_editor-4.3.7/src/widgets/ui/resize_map_dialog.py +223 -0
  18. tilemap_editor-4.3.7/tests/test_map_resize_model.py +50 -0
  19. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/tests/test_serialization_regression.py +19 -5
  20. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/tests/test_tile_grid_selection.py +1 -1
  21. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/LICENSE +0 -0
  22. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/MANIFEST.in +0 -0
  23. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/README.md +0 -0
  24. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/assets/fonts/jetbrain-fonts/JetBrainsMono-Bold.ttf +0 -0
  25. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/assets/fonts/jetbrain-fonts/JetBrainsMono-BoldItalic.ttf +0 -0
  26. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/assets/fonts/jetbrain-fonts/JetBrainsMono-Italic.ttf +0 -0
  27. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/assets/fonts/jetbrain-fonts/JetBrainsMono-Regular.ttf +0 -0
  28. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/assets/fonts/noto/NotoSans-Bold.ttf +0 -0
  29. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/assets/fonts/noto/NotoSans-BoldItalic.ttf +0 -0
  30. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/assets/fonts/noto/NotoSans-Italic.ttf +0 -0
  31. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/assets/fonts/noto/NotoSans-Regular.ttf +0 -0
  32. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/assets/icons/arrow-down.svg +0 -0
  33. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/assets/icons/check.svg +0 -0
  34. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/assets/icons/checked.svg +0 -0
  35. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/assets/icons/close.svg +0 -0
  36. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/assets/icons/duplicate.svg +0 -0
  37. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/assets/icons/error.svg +0 -0
  38. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/assets/icons/file.svg +0 -0
  39. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/assets/icons/filedead.svg +0 -0
  40. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/assets/icons/fit.svg +0 -0
  41. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/assets/icons/folder.svg +0 -0
  42. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/assets/icons/grid.svg +0 -0
  43. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/assets/icons/image.svg +0 -0
  44. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/assets/icons/info.svg +0 -0
  45. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/assets/icons/load.svg +0 -0
  46. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/assets/icons/loop.svg +0 -0
  47. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/assets/icons/onion.svg +0 -0
  48. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/assets/icons/pan.svg +0 -0
  49. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/assets/icons/pause.svg +0 -0
  50. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/assets/icons/pencil.svg +0 -0
  51. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/assets/icons/play.svg +0 -0
  52. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/assets/icons/plus.svg +0 -0
  53. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/assets/icons/radio.svg +0 -0
  54. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/assets/icons/reset.svg +0 -0
  55. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/assets/icons/save.svg +0 -0
  56. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/assets/icons/skip-back.svg +0 -0
  57. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/assets/icons/skip-forward.svg +0 -0
  58. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/assets/icons/stop.svg +0 -0
  59. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/assets/icons/tilemap.svg +0 -0
  60. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/assets/icons/tileset.svg +0 -0
  61. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/assets/icons/unchecked.svg +0 -0
  62. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/assets/icons/warning.svg +0 -0
  63. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/assets/icons/zoomin.svg +0 -0
  64. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/assets/icons/zoomout.svg +0 -0
  65. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/setup.cfg +0 -0
  66. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/constants.py +0 -0
  67. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/event_map.py +0 -0
  68. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/main.py +0 -0
  69. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/node_manager.py +0 -0
  70. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/nodes.py +0 -0
  71. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/plugins/__init__.py +0 -0
  72. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/plugins/character_collision/__init__.py +0 -0
  73. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/plugins/character_collision/editor.py +0 -0
  74. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/plugins/character_collision/models.py +0 -0
  75. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/plugins/character_collision/protocols.py +0 -0
  76. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/plugins/character_collision/shape_editor.py +0 -0
  77. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/plugins/character_collision/standalone.py +0 -0
  78. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/plugins/object_tileset_collision/__init__.py +0 -0
  79. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/plugins/object_tileset_collision/editor.py +0 -0
  80. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/plugins/object_tileset_collision/models.py +0 -0
  81. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/plugins/object_tileset_collision/protocols.py +0 -0
  82. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/plugins/object_tileset_collision/standalone.py +0 -0
  83. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/plugins/sprite_animation/__init__.py +0 -0
  84. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/plugins/sprite_animation/__main__.py +0 -0
  85. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/plugins/sprite_animation/clipboard_util.py +0 -0
  86. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/plugins/sprite_animation/editor.py +0 -0
  87. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/plugins/sprite_animation/frame_picker.py +0 -0
  88. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/plugins/sprite_animation/models.py +0 -0
  89. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/plugins/sprite_animation/preview.py +0 -0
  90. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/plugins/sprite_animation/protocols.py +0 -0
  91. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/plugins/sprite_animation/runtime_load.py +0 -0
  92. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/plugins/sprite_animation/standalone.py +0 -0
  93. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/plugins/sprite_animation/timeline.py +0 -0
  94. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/plugins/sprite_animation/validation.py +0 -0
  95. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/plugins/sprite_editor/__init__.py +0 -0
  96. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/plugins/sprite_editor/dialogs.py +0 -0
  97. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/plugins/sprite_editor/editor.py +0 -0
  98. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/plugins/sprite_editor/region_export.py +0 -0
  99. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/plugins/sprite_editor/standalone.py +0 -0
  100. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/plugins/tileset_collision/__init__.py +0 -0
  101. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/plugins/tileset_collision/collision_painter.py +0 -0
  102. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/plugins/tileset_collision/editor.py +0 -0
  103. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/plugins/tileset_collision/models.py +0 -0
  104. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/plugins/tileset_collision/protocols.py +0 -0
  105. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/plugins/tileset_collision/standalone.py +0 -0
  106. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/standalone_automap.py +0 -0
  107. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/standalone_error_console.py +0 -0
  108. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/standalone_filemanager.py +0 -0
  109. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/standalone_image_viewer.py +0 -0
  110. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/__init__.py +0 -0
  111. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/__main__.py +0 -0
  112. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/__init__.py +0 -0
  113. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/fonts/jetbrain-fonts/JetBrainsMono-Bold.ttf +0 -0
  114. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/fonts/jetbrain-fonts/JetBrainsMono-BoldItalic.ttf +0 -0
  115. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/fonts/jetbrain-fonts/JetBrainsMono-Italic.ttf +0 -0
  116. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/fonts/jetbrain-fonts/JetBrainsMono-Regular.ttf +0 -0
  117. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/fonts/noto/NotoSans-Bold.ttf +0 -0
  118. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/fonts/noto/NotoSans-BoldItalic.ttf +0 -0
  119. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/fonts/noto/NotoSans-Italic.ttf +0 -0
  120. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/fonts/noto/NotoSans-Regular.ttf +0 -0
  121. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/icons/ToolMove.svg +0 -0
  122. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/icons/arrow-down.svg +0 -0
  123. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/icons/check.svg +0 -0
  124. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/icons/checked.svg +0 -0
  125. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/icons/close.svg +0 -0
  126. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/icons/duplicate.svg +0 -0
  127. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/icons/error.svg +0 -0
  128. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/icons/file.svg +0 -0
  129. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/icons/filedead.svg +0 -0
  130. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/icons/fit.svg +0 -0
  131. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/icons/fold_down_arrow.svg +0 -0
  132. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/icons/folder.svg +0 -0
  133. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/icons/gear.svg +0 -0
  134. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/icons/grid.svg +0 -0
  135. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/icons/image.svg +0 -0
  136. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/icons/info.svg +0 -0
  137. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/icons/load.svg +0 -0
  138. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/icons/loop.svg +0 -0
  139. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/icons/miniobj.svg +0 -0
  140. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/icons/onion.svg +0 -0
  141. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/icons/pan.svg +0 -0
  142. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/icons/pause.svg +0 -0
  143. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/icons/pencil.svg +0 -0
  144. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/icons/play.svg +0 -0
  145. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/icons/plus.svg +0 -0
  146. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/icons/radio.svg +0 -0
  147. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/icons/reset.svg +0 -0
  148. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/icons/save.svg +0 -0
  149. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/icons/skip-back.svg +0 -0
  150. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/icons/skip-forward.svg +0 -0
  151. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/icons/stop.svg +0 -0
  152. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/icons/tilemap.svg +0 -0
  153. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/icons/tileset.svg +0 -0
  154. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/icons/unchecked.svg +0 -0
  155. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/icons/unfold_right_arrow.svg +0 -0
  156. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/icons/warning.svg +0 -0
  157. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/icons/zoomin.svg +0 -0
  158. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/assets/icons/zoomout.svg +0 -0
  159. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/cli.py +0 -0
  160. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/main.py +0 -0
  161. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor/settings.py +0 -0
  162. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor.egg-info/dependency_links.txt +0 -0
  163. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor.egg-info/entry_points.txt +0 -0
  164. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor.egg-info/requires.txt +0 -0
  165. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/tilemap_editor.egg-info/top_level.txt +0 -0
  166. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/ttypes/__init__.py +0 -0
  167. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/ttypes/tilemap.py +0 -0
  168. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/utils/__init__.py +0 -0
  169. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/utils/editor_preference.py +0 -0
  170. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/utils/error_handler.py +0 -0
  171. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/utils/history.py +0 -0
  172. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/utils/icon_manager.py +0 -0
  173. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/utils/icons_cache.py +0 -0
  174. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/utils/log_capture.py +0 -0
  175. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/utils/project_paths.py +0 -0
  176. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/utils/serialization.py +0 -0
  177. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/utils/standalone.py +0 -0
  178. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/utils/validation.py +0 -0
  179. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/__init__.py +0 -0
  180. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/automap_models.py +0 -0
  181. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/autotile_template.py +0 -0
  182. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/autotiler.py +0 -0
  183. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/filemanager.py +0 -0
  184. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/map_properties.py +0 -0
  185. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/mapsetup.py +0 -0
  186. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/particle_presets.py +0 -0
  187. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/particle_system.py +0 -0
  188. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/regex_automap_designer.py +0 -0
  189. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/spritesheet_grid.py +0 -0
  190. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/ui/button.py +0 -0
  191. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/ui/checkbox.py +0 -0
  192. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/ui/collision_layer_mask.py +0 -0
  193. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/ui/collision_layer_sidebar.py +0 -0
  194. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/ui/confirm_dialog.py +0 -0
  195. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/ui/dialog_base.py +0 -0
  196. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/ui/drag_tracker.py +0 -0
  197. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/ui/draw_utils.py +0 -0
  198. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/ui/fileinput.py +0 -0
  199. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/ui/label.py +0 -0
  200. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/ui/layer_type_dialog.py +0 -0
  201. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/ui/mode_indicator.py +0 -0
  202. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/ui/node_selector.py +0 -0
  203. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/ui/notification.py +0 -0
  204. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/ui/particle_config_dialog.py +0 -0
  205. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/ui/region_selector.py +0 -0
  206. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/ui/scrollbar.py +0 -0
  207. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/ui/sidebar_container.py +0 -0
  208. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/ui/splitter.py +0 -0
  209. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/ui/status_bar.py +0 -0
  210. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/ui/theme.py +0 -0
  211. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/ui/tileset_type_dialog.py +0 -0
  212. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/ui/toast.py +0 -0
  213. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/ui/tool_manager.py +0 -0
  214. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/ui/toolbar.py +0 -0
  215. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/ui/tooltip.py +0 -0
  216. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/ui/tree_widget.py +0 -0
  217. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/src/widgets/widget_base.py +0 -0
  218. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/tests/test_animation_library_grid_offset.py +0 -0
  219. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/tests/test_collision_layer_mask.py +0 -0
  220. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/tests/test_collision_layer_sidebar.py +0 -0
  221. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/tests/test_drag_tracker.py +0 -0
  222. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/tests/test_editor_pan_mode.py +0 -0
  223. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/tests/test_gid_collision.py +0 -0
  224. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/tests/test_layers_autotile.py +0 -0
  225. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/tests/test_project_paths.py +0 -0
  226. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/tests/test_render_scale.py +0 -0
  227. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/tests/test_sprite_animation_editor_grid.py +0 -0
  228. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/tests/test_tile_selector_pick.py +0 -0
  229. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/tests/test_tilemap_save.py +0 -0
  230. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/tests/test_timeline_invalidate_cache.py +0 -0
  231. {tilemap_editor-4.3.5 → tilemap_editor-4.3.7}/tests/test_toolbar_tools.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tilemap-editor
3
- Version: 4.3.5
3
+ Version: 4.3.7
4
4
  Summary: Pygame tilemap editor with collision, animation, sprite & particle tools
5
5
  Author: tilemap editor contributors
6
6
  License: Proprietary
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "tilemap-editor"
7
- version = "4.3.5"
7
+ version = "4.3.7"
8
8
  description = "Pygame tilemap editor with collision, animation, sprite & particle tools"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -21,6 +21,7 @@ from constants import BASE_PATH
21
21
  from node_manager import NodeManager
22
22
  from tilemap import Tilemap
23
23
  from utils import error_context, error_handler
24
+ from utils.property_suggestions import PropertySuggestionRegistry
24
25
  from utils.standalone import launch_standalone
25
26
  from widgets.autotiler import AutotileRuleDesigner
26
27
  from widgets.layer_selector import LayerSelector
@@ -38,6 +39,7 @@ from widgets.ui.node_selector import NodeSelector
38
39
  from widgets.ui.notification import NotificationManager
39
40
  from widgets.ui.particle_config_dialog import ParticleConfigDialog
40
41
  from widgets.ui.property_editor import PropertyEditor
42
+ from widgets.ui.resize_map_dialog import ResizeMapDialog
41
43
  from widgets.ui.sidebar_container import SidebarContainer, ToolbarAction
42
44
  from widgets.ui.theme import COLORS, THEMES, get_theme_manager, set_theme
43
45
  from widgets.ui.tileset_type_dialog import TilesetTypeDialog
@@ -205,13 +207,13 @@ class Editor:
205
207
  self.tile_grid_widget: TileGrid | None = None
206
208
 
207
209
  self.left_panel_visible = False
208
- self.animation_panel: SpriteAnimationEditor | None = None
209
- self._animation_panel_surface: pygame.Surface | None = None
210
+ self.left_panel_w = 300
210
211
 
211
212
  self.autotiler = AutotileRuleDesigner(self, 100, 100)
212
213
  self.regex_automap_designer = RegexAutomapDesigner(self, 150, 100)
213
214
  self.notifications = NotificationManager(self)
214
215
  self.tooltip = TooltipManager()
216
+ self.suggestion_registry = PropertySuggestionRegistry()
215
217
  self.error_console_process: subprocess.Popen | None = None
216
218
  self.property_editor: PropertyEditor | None = None
217
219
  self.particle_config_dialog: ParticleConfigDialog | None = None
@@ -238,6 +240,8 @@ class Editor:
238
240
  self.tileset_type_dialog = TilesetTypeDialog(editor_rect)
239
241
  self.confirm_dialog = ConfirmDialog(editor_rect)
240
242
  self.layer_type_dialog = LayerTypeDialog(editor_rect)
243
+ self.resize_map_dialog = ResizeMapDialog(editor_rect)
244
+ self.resize_map_dialog.editor = self
241
245
 
242
246
  self.menubar = MenuBar(self, self.width, 30)
243
247
  self.toolbar = Toolbar(self, 0, 30, self.width, 35)
@@ -620,13 +624,6 @@ class Editor:
620
624
 
621
625
  self._update_side_panel_layout()
622
626
 
623
- if self.left_panel_visible and self.animation_panel:
624
- panel_rect = Rect(0, menu_h + toolbar_h, self.left_panel_w, height - (menu_h + toolbar_h))
625
- if hasattr(self.animation_panel, "rect"):
626
- self.animation_panel.rect = panel_rect
627
- if hasattr(self.animation_panel, "_relayout"):
628
- self.animation_panel._relayout()
629
-
630
627
  rect_full = Rect(0, 0, width, height)
631
628
 
632
629
  if hasattr(self, "tileset_type_dialog") and self.tileset_type_dialog:
@@ -661,6 +658,12 @@ class Editor:
661
658
  return
662
659
  self.map_properties_dialog.open()
663
660
 
661
+ def open_resize_map_dialog(self):
662
+ if self.resize_map_dialog is None:
663
+ logger.warning({"msg": "resize_map_dialog is not initialized"})
664
+ return
665
+ self.resize_map_dialog.open()
666
+
664
667
  def toggle_autotiler(self):
665
668
  if self.autotiler.visible:
666
669
  self.autotiler.hide()
@@ -673,47 +676,6 @@ class Editor:
673
676
  else:
674
677
  self.regex_automap_designer.show()
675
678
 
676
- def toggle_animation_panel(self):
677
- """Toggle the dockable animation panel visibility (Cmd/Ctrl+B)."""
678
- if not self.left_panel_visible:
679
- if self.animation_panel is None:
680
- self._init_animation_panel()
681
- if self.animation_panel is not None:
682
- self.left_panel_visible = True
683
- else:
684
- self.left_panel_visible = False
685
- self.handle_resize(self.width, self.height)
686
-
687
- def _init_animation_panel(self):
688
- """Initialize the animation panel without loading any tileset."""
689
- from plugins.sprite_animation.editor import SpriteAnimationEditor
690
-
691
- try:
692
-
693
- class _PanelConsumer:
694
- editor_instance = self
695
-
696
- def on_animation_saved(self, name: str, data: dict) -> None:
697
- self.editor_instance.notifications.notify(f"Animation saved: {name}")
698
-
699
- def on_animation_deleted(self, name: str) -> None:
700
- self.editor_instance.notifications.notify(f"Animation deleted: {name}")
701
-
702
- consumer = _PanelConsumer()
703
-
704
- panel_rect = Rect(0, 65, self.left_panel_w, self.height - 65)
705
-
706
- self.animation_panel = SpriteAnimationEditor(
707
- panel_rect,
708
- surface=None,
709
- tile_size=(32, 32),
710
- consumer=consumer,
711
- )
712
- self.animation_panel._data_root = self.data_root
713
- except Exception as e:
714
- error_handler.capture(e, context="init_animation_panel")
715
- self.notifications.notify(f"Failed to init animation panel: {e}")
716
-
717
679
  def undo(self):
718
680
  self.tilemap.undo()
719
681
  if self.tile_grid_widget:
@@ -728,6 +690,12 @@ class Editor:
728
690
  if self.tile_grid_widget:
729
691
  self.tile_grid_widget.show_grid = not self.tile_grid_widget.show_grid
730
692
 
693
+ def toggle_map_boundary(self):
694
+ if self.tile_grid_widget:
695
+ self.tile_grid_widget.show_map_boundary = (
696
+ not self.tile_grid_widget.show_map_boundary
697
+ )
698
+
731
699
  def cycle_theme(self):
732
700
  """Cycle through available themes."""
733
701
  theme_names = list(THEMES.keys())
@@ -1143,6 +1111,10 @@ class Editor:
1143
1111
  self.layer_type_dialog.handle_event(event)
1144
1112
  continue
1145
1113
 
1114
+ if self.resize_map_dialog and self.resize_map_dialog.active:
1115
+ self.resize_map_dialog.handle_event(event)
1116
+ continue
1117
+
1146
1118
  if self.map_setup_widget and self.map_setup_widget.visible:
1147
1119
  if self.map_setup_widget.handle_event(event):
1148
1120
  continue
@@ -1240,7 +1212,7 @@ class Editor:
1240
1212
  self.cycle_theme()
1241
1213
  continue
1242
1214
  if event.key == pygame.K_b and (ctrl_held or meta_held):
1243
- self.toggle_animation_panel()
1215
+ self.toggle_map_boundary()
1244
1216
  continue
1245
1217
  if pygame.K_1 <= event.key <= pygame.K_9:
1246
1218
  if not (self.node_editor and self.node_editor.visible and self.node_editor.editing_field):
@@ -1257,11 +1229,6 @@ class Editor:
1257
1229
  if self.toolbar and self.toolbar.handle_event(event):
1258
1230
  continue
1259
1231
 
1260
- if self.left_panel_visible and self.animation_panel:
1261
- if hasattr(self.animation_panel, "handle_event"):
1262
- if self.animation_panel.handle_event(event):
1263
- continue
1264
-
1265
1232
  if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
1266
1233
  mx, my = event.pos
1267
1234
  edge_x = self.width - self._effective_selector_w
@@ -1308,10 +1275,6 @@ class Editor:
1308
1275
  if self.tile_grid_widget:
1309
1276
  self.tile_grid_widget.update()
1310
1277
 
1311
- if self.left_panel_visible and self.animation_panel:
1312
- if hasattr(self.animation_panel, "update"):
1313
- self.animation_panel.update()
1314
-
1315
1278
  self.screen.fill(COLORS.bg)
1316
1279
  self.tooltip.hide()
1317
1280
 
@@ -1339,20 +1302,6 @@ class Editor:
1339
1302
  self.screen.blit(overlay, (0, 0))
1340
1303
  self.regex_automap_designer.draw(self.screen)
1341
1304
 
1342
- if self.left_panel_visible and self.animation_panel:
1343
- panel_surf = pygame.Surface((self.left_panel_w, self.height), pygame.SRCALPHA)
1344
- panel_surf.fill((*COLORS.panel_alt, 255))
1345
- self.screen.blit(panel_surf, (0, 65))
1346
-
1347
- pygame.draw.rect(
1348
- self.screen,
1349
- COLORS.border,
1350
- Rect(0, 65, self.left_panel_w, self.height - 65),
1351
- 1,
1352
- )
1353
- if hasattr(self.animation_panel, "draw"):
1354
- self.animation_panel.draw(self.screen)
1355
-
1356
1305
  self.notifications.draw(self.screen)
1357
1306
 
1358
1307
  if self.map_setup_widget and self.map_setup_widget.visible:
@@ -1371,16 +1320,18 @@ class Editor:
1371
1320
  overlay.fill((0, 0, 0, 150))
1372
1321
  self.screen.blit(overlay, (0, 0))
1373
1322
  self.tileset_type_dialog.draw(self.screen)
1374
- if self.confirm_dialog.active:
1323
+ if self.resize_map_dialog and self.resize_map_dialog.active:
1324
+ self.resize_map_dialog.draw(self.screen)
1325
+ if self.layer_type_dialog.active:
1375
1326
  overlay = pygame.Surface((self.width, self.height), pygame.SRCALPHA)
1376
1327
  overlay.fill((0, 0, 0, 150))
1377
1328
  self.screen.blit(overlay, (0, 0))
1378
- self.confirm_dialog.draw(self.screen)
1379
- if self.layer_type_dialog.active:
1329
+ self.layer_type_dialog.draw(self.screen)
1330
+ if self.confirm_dialog.active:
1380
1331
  overlay = pygame.Surface((self.width, self.height), pygame.SRCALPHA)
1381
1332
  overlay.fill((0, 0, 0, 150))
1382
1333
  self.screen.blit(overlay, (0, 0))
1383
- self.layer_type_dialog.draw(self.screen)
1334
+ self.confirm_dialog.draw(self.screen)
1384
1335
 
1385
1336
  if self.loading_state["active"]:
1386
1337
  overlay = pygame.Surface((self.width, self.height), pygame.SRCALPHA)
@@ -217,6 +217,7 @@ class Layer:
217
217
  start_pos: tuple[int, int],
218
218
  new_tile_data: TypeTile,
219
219
  map_size: tuple[int, int],
220
+ offset: tuple[int, int] = (0, 0),
220
221
  ) -> None:
221
222
  """Replace contiguous tiles of the same type starting from start_pos."""
222
223
  if self.locked or self.layer_type != "tile":
@@ -238,7 +239,13 @@ class Layer:
238
239
  while queue:
239
240
  curr = queue.pop(0)
240
241
 
241
- if curr[0] < 0 or curr[0] >= map_size[0] or curr[1] < 0 or curr[1] >= map_size[1]:
242
+ ox, oy = offset
243
+ if (
244
+ curr[0] < ox
245
+ or curr[0] >= ox + map_size[0]
246
+ or curr[1] < oy
247
+ or curr[1] >= oy + map_size[1]
248
+ ):
242
249
  continue
243
250
 
244
251
  curr_tile = self.tiles.get(curr)
@@ -40,7 +40,7 @@ class Tilemap:
40
40
 
41
41
  self.tile_size = (32, 32)
42
42
  self.map_size = (50, 50)
43
- self.initial_map_size = (50, 50)
43
+ self.offset = (0, 0)
44
44
  self.initialized = False
45
45
  self.render_scale = 1.0
46
46
 
@@ -62,10 +62,10 @@ class Tilemap:
62
62
  if active_layer:
63
63
  active_layer.tiles = value
64
64
 
65
- def init_size(self, tile_size: "TCoor", map_size: "TCoor", render_scale: float = 1.0):
65
+ def init_size(self, tile_size: "TCoor", map_size: "TCoor", offset: "TCoor" = (0, 0), render_scale: float = 1.0):
66
66
  self.tile_size = tile_size
67
67
  self.map_size = map_size
68
- self.initial_map_size = map_size
68
+ self.offset = offset
69
69
  self.initialized = True
70
70
  self.render_scale = render_scale
71
71
  self.active_project_path = None
@@ -88,6 +88,7 @@ class Tilemap:
88
88
  "active_layer_idx": self.layer_manager.active_layer_idx,
89
89
  "tile_size": self.tile_size,
90
90
  "map_size": self.map_size,
91
+ "offset": self.offset,
91
92
  "render_scale": self.render_scale,
92
93
  }
93
94
  self.history.save_state(state, description)
@@ -105,6 +106,7 @@ class Tilemap:
105
106
  "active_layer_idx": self.layer_manager.active_layer_idx,
106
107
  "tile_size": self.tile_size,
107
108
  "map_size": self.map_size,
109
+ "offset": self.offset,
108
110
  "render_scale": self.render_scale,
109
111
  }
110
112
  prev_state = self.history.undo(current_state)
@@ -124,6 +126,7 @@ class Tilemap:
124
126
  "active_layer_idx": self.layer_manager.active_layer_idx,
125
127
  "tile_size": self.tile_size,
126
128
  "map_size": self.map_size,
129
+ "offset": self.offset,
127
130
  "render_scale": self.render_scale,
128
131
  }
129
132
  next_state = self.history.redo(current_state)
@@ -131,28 +134,7 @@ class Tilemap:
131
134
  self._apply_history_state(next_state)
132
135
 
133
136
  def update_map_size(self):
134
- """Full scan to recalculate map size based on all layers."""
135
- if not self.initialized:
136
- return
137
-
138
- max_w = self.initial_map_size[0]
139
- max_h = self.initial_map_size[1]
140
-
141
- for layer in self.layer_manager.layers:
142
- if layer.tiles:
143
- for pos in layer.tiles:
144
- max_w = max(max_w, pos[0] + 1)
145
- max_h = max(max_h, pos[1] + 1)
146
-
147
- if layer.objects:
148
- for obj in layer.objects.values():
149
- area = obj["area"]
150
- grid_r = (area["x"] + area["w"]) / self.tile_size[0]
151
- grid_b = (area["y"] + area["h"]) / self.tile_size[1]
152
- max_w = max(max_w, int(grid_r) + 1)
153
- max_h = max(max_h, int(grid_b) + 1)
154
-
155
- self.map_size = (max_w, max_h)
137
+ """Deprecated compatibility hook retained as no-op."""
156
138
 
157
139
  def incremental_update_map_size(
158
140
  self,
@@ -160,22 +142,15 @@ class Tilemap:
160
142
  is_pixel: bool = False,
161
143
  size: tuple[int, int] | None = None,
162
144
  ):
163
- """Update map size based on a single point or area without full scan."""
164
- if not self.initialized:
165
- return
166
-
167
- if is_pixel:
168
- w, h = size if size else self.tile_size
169
- grid_r = int((pos[0] + w) / self.tile_size[0]) + 1
170
- grid_b = int((pos[1] + h) / self.tile_size[1]) + 1
171
- new_w = max(self.map_size[0], grid_r)
172
- new_h = max(self.map_size[1], grid_b)
173
- else:
174
- new_w = max(self.map_size[0], pos[0] + 1)
175
- new_h = max(self.map_size[1], pos[1] + 1)
145
+ """Deprecated compatibility hook retained as no-op."""
176
146
 
177
- if (new_w, new_h) != self.map_size:
178
- self.map_size = (new_w, new_h)
147
+ def resize(self, offset: "TCoor", size: "TCoor"):
148
+ """Manually set the map offset and size."""
149
+ self.offset = offset
150
+ self.map_size = (max(1, size[0]), max(1, size[1]))
151
+ tile_grid_widget = getattr(self.editor, "tile_grid_widget", None)
152
+ if tile_grid_widget is not None and hasattr(tile_grid_widget, "invalidate_bounds_cache"):
153
+ tile_grid_widget.invalidate_bounds_cache()
179
154
 
180
155
  def _apply_history_state(self, state):
181
156
  from layers import Layer
@@ -185,6 +160,7 @@ class Tilemap:
185
160
  self.layer_manager.active_layer_idx = state["active_layer_idx"]
186
161
  self.tile_size = state["tile_size"]
187
162
  self.map_size = state["map_size"]
163
+ self.offset = state.get("offset", (0, 0))
188
164
  self.render_scale = state.get("render_scale", 1.0)
189
165
 
190
166
  if hasattr(self.editor, "autotiler"):
@@ -259,7 +235,7 @@ class Tilemap:
259
235
  (getattr(self.editor.tile_grid_widget, "scroll_y", 0) if self.editor.tile_grid_widget else 0),
260
236
  )
261
237
  ),
262
- "initial_map_size": serialize_point(self.initial_map_size),
238
+ "offset": serialize_point(self.offset),
263
239
  "render_scale": self.render_scale,
264
240
  "version": "1.1",
265
241
  },
@@ -470,11 +446,7 @@ class Tilemap:
470
446
  self.tile_size = deserialize_point(payload["meta"]["tile_size"])
471
447
  self.map_size = deserialize_point(payload["meta"].get("map_size", "50;50"))
472
448
 
473
- self.initial_map_size = payload["meta"].get("initial_map_size")
474
- if self.initial_map_size:
475
- self.initial_map_size = deserialize_point(self.initial_map_size)
476
- else:
477
- self.initial_map_size = self.map_size
449
+ self.offset = deserialize_point(payload["meta"].get("offset", "0;0"))
478
450
  self.render_scale = float(payload["meta"].get("render_scale", 1.0))
479
451
  except (KeyError, ValueError) as e:
480
452
  raise ValueError(f"Error loading map metadata: {e}") from e
@@ -576,8 +548,8 @@ class Tilemap:
576
548
  designer.groups.append(AutotileGroup("Default"))
577
549
  designer.selected_group_idx = 0
578
550
 
579
- if hasattr(self.editor, "regex_automap_designer") and self.editor.regex_automap_designer:
580
- if "project_state" in payload and "automap_rules" in payload["project_state"]:
551
+ if (hasattr(self.editor, "regex_automap_designer") and self.editor.regex_automap_designer
552
+ and "project_state" in payload and "automap_rules" in payload["project_state"]):
581
553
  try:
582
554
  automap_rules_data = payload["project_state"]["automap_rules"]
583
555
  if isinstance(automap_rules_data, list):
@@ -623,6 +595,8 @@ class Tilemap:
623
595
  if hasattr(self.editor, "node_selector"):
624
596
  self.editor.node_selector._rebuild_filter()
625
597
 
598
+ if hasattr(self.editor, "suggestion_registry"):
599
+ self.editor.suggestion_registry.refresh(self.editor)
626
600
  self.initialized = True
627
601
 
628
602
  if self.editor.tile_grid_widget:
@@ -754,7 +728,7 @@ class Tilemap:
754
728
  meta = {
755
729
  "tile_size": f"{tile_w},{tile_h}",
756
730
  "map_size": f"{map_w},{map_h}",
757
- "initial_map_size": f"{map_w},{map_h}",
731
+ "offset": "0,0",
758
732
  "render_scale": 1.0,
759
733
  "version": "1.1",
760
734
  "zoom_level": 1.0,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tilemap-editor
3
- Version: 4.3.5
3
+ Version: 4.3.7
4
4
  Summary: Pygame tilemap editor with collision, animation, sprite & particle tools
5
5
  Author: tilemap editor contributors
6
6
  License: Proprietary
@@ -159,6 +159,7 @@ src/utils/icon_manager.py
159
159
  src/utils/icons_cache.py
160
160
  src/utils/log_capture.py
161
161
  src/utils/project_paths.py
162
+ src/utils/property_suggestions.py
162
163
  src/utils/serialization.py
163
164
  src/utils/standalone.py
164
165
  src/utils/validation.py
@@ -197,6 +198,7 @@ src/widgets/ui/notification.py
197
198
  src/widgets/ui/particle_config_dialog.py
198
199
  src/widgets/ui/property_editor.py
199
200
  src/widgets/ui/region_selector.py
201
+ src/widgets/ui/resize_map_dialog.py
200
202
  src/widgets/ui/scrollbar.py
201
203
  src/widgets/ui/sidebar_container.py
202
204
  src/widgets/ui/splitter.py
@@ -215,6 +217,7 @@ tests/test_drag_tracker.py
215
217
  tests/test_editor_pan_mode.py
216
218
  tests/test_gid_collision.py
217
219
  tests/test_layers_autotile.py
220
+ tests/test_map_resize_model.py
218
221
  tests/test_project_paths.py
219
222
  tests/test_render_scale.py
220
223
  tests/test_serialization_regression.py
@@ -109,6 +109,10 @@ class FontManager:
109
109
  bold: bool | None = None,
110
110
  italic: bool | None = None,
111
111
  ) -> pygame.font.Font:
112
+ if not pygame.get_init():
113
+ pygame.init()
114
+ if not pygame.font.get_init():
115
+ pygame.font.init()
112
116
  """
113
117
  Get a font with specified properties.
114
118
 
@@ -0,0 +1,70 @@
1
+ from typing import TYPE_CHECKING
2
+
3
+ if TYPE_CHECKING:
4
+ from editor import Editor
5
+
6
+
7
+ class PropertySuggestionRegistry:
8
+ def __init__(self):
9
+ self._data: dict[str, list[str]] = {}
10
+
11
+ def refresh(self, editor: "Editor"):
12
+ values: dict[str, set[str]] = {}
13
+
14
+ if editor.tileset_widget:
15
+ for ts in editor.tileset_widget.tilesets:
16
+ for k, v in ts.properties.items():
17
+ values.setdefault(k, set()).add(str(v))
18
+ for tile_props in ts.tile_properties.values():
19
+ for k, v in tile_props.items():
20
+ values.setdefault(k, set()).add(str(v))
21
+
22
+ if editor.tilemap:
23
+ for layer in editor.tilemap.layer_manager.layers:
24
+ for k, v in layer.properties.items():
25
+ values.setdefault(k, set()).add(str(v))
26
+ for tile in layer.tiles.values():
27
+ if "properties" in tile:
28
+ for k, v in tile["properties"].items():
29
+ values.setdefault(k, set()).add(str(v))
30
+ if layer.layer_type == "object":
31
+ for obj in layer.objects.values():
32
+ if "properties" in obj:
33
+ for k, v in obj["properties"].items():
34
+ values.setdefault(k, set()).add(str(v))
35
+
36
+ if editor.node_manager:
37
+ for node in editor.node_manager.nodes.values():
38
+ for k, v in node.properties.items():
39
+ values.setdefault(k, set()).add(str(v))
40
+
41
+ self._data = {k: sorted(v) for k, v in values.items()}
42
+
43
+ @property
44
+ def known_keys(self) -> list[str]:
45
+ return sorted(self._data.keys())
46
+
47
+ def ghost_text(self, key: str, input_text: str) -> str:
48
+ if key not in self._data:
49
+ return ""
50
+ prefix = input_text.lower()
51
+ matches = [
52
+ v
53
+ for v in self._data[key]
54
+ if v.lower().startswith(prefix) and v != input_text
55
+ ]
56
+ if matches:
57
+ return matches[0][len(input_text):]
58
+ return ""
59
+
60
+ def key_ghost(self, input_text: str) -> str:
61
+ if not input_text:
62
+ return ""
63
+ prefix = input_text.lower()
64
+ matches = [
65
+ k for k in self._data
66
+ if k.lower().startswith(prefix) and k != input_text
67
+ ]
68
+ if matches:
69
+ return sorted(matches)[0][len(input_text):]
70
+ return ""
@@ -148,9 +148,8 @@ class InputBox(WidgetBase):
148
148
  self.insert_text(event.unicode)
149
149
  return True
150
150
 
151
- if self.is_focused and event.type == pygame.KEYUP:
152
- if event.key in (pygame.K_LSHIFT, pygame.K_RSHIFT):
153
- self.selection_start = None
151
+ if self.is_focused and event.type == pygame.KEYUP and event.key in (pygame.K_LSHIFT, pygame.K_RSHIFT):
152
+ self.selection_start = None
154
153
 
155
154
  return False
156
155
 
@@ -442,9 +441,8 @@ class InlineTextInput:
442
441
  self.insert_text(event.unicode)
443
442
  return True
444
443
 
445
- if event.type == pygame.KEYUP:
446
- if event.key in (pygame.K_LSHIFT, pygame.K_RSHIFT):
447
- self.selection_start = None
444
+ if event.type == pygame.KEYUP and event.key in (pygame.K_LSHIFT, pygame.K_RSHIFT):
445
+ self.selection_start = None
448
446
 
449
447
  return False
450
448
 
@@ -470,3 +468,30 @@ class DigitInput(BaseTextInput):
470
468
 
471
469
  def get_value(self) -> int:
472
470
  return self.get_int_value()
471
+
472
+
473
+ class SignedIntInput(BaseTextInput):
474
+ def __init__(
475
+ self,
476
+ rect: Rect,
477
+ label: str,
478
+ key: str,
479
+ default_val: str = "",
480
+ tab_index: int | None = None,
481
+ ):
482
+ super().__init__(
483
+ rect,
484
+ label,
485
+ key,
486
+ default_val,
487
+ tab_index,
488
+ allowed_chars="-0123456789",
489
+ )
490
+
491
+ def is_char_allowed(self, char: str) -> bool:
492
+ if char in "-":
493
+ return self.text == ""
494
+ return char.isdigit()
495
+
496
+ def get_value(self) -> int:
497
+ return self.get_int_value()
@@ -408,6 +408,7 @@ class LayerSelector:
408
408
 
409
409
  def _save_layer_properties(self, layer: Layer, props: dict):
410
410
  layer.properties = props
411
+ self.editor.suggestion_registry.refresh(self.editor)
411
412
  print(f"Saved properties for layer: {layer.name}")
412
413
 
413
414
  def draw(self, screen: Surface) -> None: