tilemap-editor 4.3.7__tar.gz → 4.3.8__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 (248) hide show
  1. tilemap_editor-4.3.8/CHANGELOG.md +231 -0
  2. {tilemap_editor-4.3.7/src/tilemap_editor.egg-info → tilemap_editor-4.3.8}/PKG-INFO +3 -1
  3. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/pyproject.toml +36 -7
  4. tilemap_editor-4.3.8/src/plugins/sprite_editor/camera.py +97 -0
  5. tilemap_editor-4.3.8/src/plugins/sprite_editor/clipboard.py +74 -0
  6. tilemap_editor-4.3.8/src/plugins/sprite_editor/commands.py +248 -0
  7. tilemap_editor-4.3.8/src/plugins/sprite_editor/document.py +352 -0
  8. tilemap_editor-4.3.8/src/plugins/sprite_editor/editor.py +658 -0
  9. tilemap_editor-4.3.8/src/plugins/sprite_editor/overlays.py +155 -0
  10. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/plugins/sprite_editor/region_export.py +3 -3
  11. tilemap_editor-4.3.8/src/plugins/sprite_editor/selection.py +99 -0
  12. tilemap_editor-4.3.8/src/plugins/sprite_editor/tools.py +745 -0
  13. tilemap_editor-4.3.8/src/plugins/sprite_editor/viewport.py +179 -0
  14. tilemap_editor-4.3.8/src/run.py +3 -0
  15. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8/src/tilemap_editor.egg-info}/PKG-INFO +3 -1
  16. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor.egg-info/SOURCES.txt +15 -1
  17. tilemap_editor-4.3.8/src/tilemap_editor.egg-info/requires.txt +4 -0
  18. tilemap_editor-4.3.8/src/utils/natural_sort.py +29 -0
  19. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/filemanager.py +4 -3
  20. tilemap_editor-4.3.8/tests/test_natural_sort.py +80 -0
  21. tilemap_editor-4.3.8/tests/test_sprite_editor_commands.py +271 -0
  22. tilemap_editor-4.3.8/tests/test_sprite_editor_interaction.py +610 -0
  23. tilemap_editor-4.3.8/tests/test_sprite_editor_models.py +380 -0
  24. tilemap_editor-4.3.7/src/plugins/sprite_editor/editor.py +0 -631
  25. tilemap_editor-4.3.7/src/tilemap_editor.egg-info/requires.txt +0 -1
  26. tilemap_editor-4.3.7/src/widgets/spritesheet_grid.py +0 -707
  27. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/LICENSE +0 -0
  28. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/MANIFEST.in +0 -0
  29. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/README.md +0 -0
  30. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/assets/fonts/jetbrain-fonts/JetBrainsMono-Bold.ttf +0 -0
  31. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/assets/fonts/jetbrain-fonts/JetBrainsMono-BoldItalic.ttf +0 -0
  32. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/assets/fonts/jetbrain-fonts/JetBrainsMono-Italic.ttf +0 -0
  33. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/assets/fonts/jetbrain-fonts/JetBrainsMono-Regular.ttf +0 -0
  34. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/assets/fonts/noto/NotoSans-Bold.ttf +0 -0
  35. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/assets/fonts/noto/NotoSans-BoldItalic.ttf +0 -0
  36. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/assets/fonts/noto/NotoSans-Italic.ttf +0 -0
  37. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/assets/fonts/noto/NotoSans-Regular.ttf +0 -0
  38. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/assets/icons/arrow-down.svg +0 -0
  39. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/assets/icons/check.svg +0 -0
  40. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/assets/icons/checked.svg +0 -0
  41. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/assets/icons/close.svg +0 -0
  42. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/assets/icons/duplicate.svg +0 -0
  43. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/assets/icons/error.svg +0 -0
  44. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/assets/icons/file.svg +0 -0
  45. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/assets/icons/filedead.svg +0 -0
  46. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/assets/icons/fit.svg +0 -0
  47. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/assets/icons/folder.svg +0 -0
  48. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/assets/icons/grid.svg +0 -0
  49. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/assets/icons/image.svg +0 -0
  50. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/assets/icons/info.svg +0 -0
  51. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/assets/icons/load.svg +0 -0
  52. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/assets/icons/loop.svg +0 -0
  53. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/assets/icons/onion.svg +0 -0
  54. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/assets/icons/pan.svg +0 -0
  55. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/assets/icons/pause.svg +0 -0
  56. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/assets/icons/pencil.svg +0 -0
  57. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/assets/icons/play.svg +0 -0
  58. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/assets/icons/plus.svg +0 -0
  59. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/assets/icons/radio.svg +0 -0
  60. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/assets/icons/reset.svg +0 -0
  61. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/assets/icons/save.svg +0 -0
  62. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/assets/icons/skip-back.svg +0 -0
  63. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/assets/icons/skip-forward.svg +0 -0
  64. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/assets/icons/stop.svg +0 -0
  65. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/assets/icons/tilemap.svg +0 -0
  66. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/assets/icons/tileset.svg +0 -0
  67. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/assets/icons/unchecked.svg +0 -0
  68. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/assets/icons/warning.svg +0 -0
  69. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/assets/icons/zoomin.svg +0 -0
  70. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/assets/icons/zoomout.svg +0 -0
  71. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/setup.cfg +0 -0
  72. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/constants.py +0 -0
  73. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/editor.py +0 -0
  74. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/event_map.py +0 -0
  75. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/layers.py +0 -0
  76. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/main.py +0 -0
  77. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/node_manager.py +0 -0
  78. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/nodes.py +0 -0
  79. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/plugins/__init__.py +0 -0
  80. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/plugins/character_collision/__init__.py +0 -0
  81. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/plugins/character_collision/editor.py +0 -0
  82. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/plugins/character_collision/models.py +0 -0
  83. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/plugins/character_collision/protocols.py +0 -0
  84. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/plugins/character_collision/shape_editor.py +0 -0
  85. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/plugins/character_collision/standalone.py +0 -0
  86. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/plugins/object_tileset_collision/__init__.py +0 -0
  87. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/plugins/object_tileset_collision/editor.py +0 -0
  88. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/plugins/object_tileset_collision/models.py +0 -0
  89. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/plugins/object_tileset_collision/protocols.py +0 -0
  90. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/plugins/object_tileset_collision/standalone.py +0 -0
  91. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/plugins/sprite_animation/__init__.py +0 -0
  92. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/plugins/sprite_animation/__main__.py +0 -0
  93. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/plugins/sprite_animation/clipboard_util.py +0 -0
  94. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/plugins/sprite_animation/editor.py +0 -0
  95. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/plugins/sprite_animation/frame_picker.py +0 -0
  96. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/plugins/sprite_animation/models.py +0 -0
  97. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/plugins/sprite_animation/preview.py +0 -0
  98. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/plugins/sprite_animation/protocols.py +0 -0
  99. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/plugins/sprite_animation/runtime_load.py +0 -0
  100. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/plugins/sprite_animation/standalone.py +0 -0
  101. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/plugins/sprite_animation/timeline.py +0 -0
  102. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/plugins/sprite_animation/validation.py +0 -0
  103. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/plugins/sprite_editor/__init__.py +0 -0
  104. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/plugins/sprite_editor/dialogs.py +0 -0
  105. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/plugins/sprite_editor/standalone.py +0 -0
  106. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/plugins/tileset_collision/__init__.py +0 -0
  107. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/plugins/tileset_collision/collision_painter.py +0 -0
  108. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/plugins/tileset_collision/editor.py +0 -0
  109. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/plugins/tileset_collision/models.py +0 -0
  110. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/plugins/tileset_collision/protocols.py +0 -0
  111. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/plugins/tileset_collision/standalone.py +0 -0
  112. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/standalone_automap.py +0 -0
  113. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/standalone_error_console.py +0 -0
  114. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/standalone_filemanager.py +0 -0
  115. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/standalone_image_viewer.py +0 -0
  116. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap.py +0 -0
  117. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/__init__.py +0 -0
  118. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/__main__.py +0 -0
  119. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/__init__.py +0 -0
  120. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/fonts/jetbrain-fonts/JetBrainsMono-Bold.ttf +0 -0
  121. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/fonts/jetbrain-fonts/JetBrainsMono-BoldItalic.ttf +0 -0
  122. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/fonts/jetbrain-fonts/JetBrainsMono-Italic.ttf +0 -0
  123. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/fonts/jetbrain-fonts/JetBrainsMono-Regular.ttf +0 -0
  124. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/fonts/noto/NotoSans-Bold.ttf +0 -0
  125. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/fonts/noto/NotoSans-BoldItalic.ttf +0 -0
  126. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/fonts/noto/NotoSans-Italic.ttf +0 -0
  127. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/fonts/noto/NotoSans-Regular.ttf +0 -0
  128. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/icons/ToolMove.svg +0 -0
  129. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/icons/arrow-down.svg +0 -0
  130. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/icons/check.svg +0 -0
  131. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/icons/checked.svg +0 -0
  132. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/icons/close.svg +0 -0
  133. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/icons/duplicate.svg +0 -0
  134. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/icons/error.svg +0 -0
  135. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/icons/file.svg +0 -0
  136. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/icons/filedead.svg +0 -0
  137. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/icons/fit.svg +0 -0
  138. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/icons/fold_down_arrow.svg +0 -0
  139. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/icons/folder.svg +0 -0
  140. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/icons/gear.svg +0 -0
  141. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/icons/grid.svg +0 -0
  142. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/icons/image.svg +0 -0
  143. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/icons/info.svg +0 -0
  144. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/icons/load.svg +0 -0
  145. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/icons/loop.svg +0 -0
  146. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/icons/miniobj.svg +0 -0
  147. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/icons/onion.svg +0 -0
  148. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/icons/pan.svg +0 -0
  149. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/icons/pause.svg +0 -0
  150. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/icons/pencil.svg +0 -0
  151. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/icons/play.svg +0 -0
  152. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/icons/plus.svg +0 -0
  153. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/icons/radio.svg +0 -0
  154. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/icons/reset.svg +0 -0
  155. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/icons/save.svg +0 -0
  156. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/icons/skip-back.svg +0 -0
  157. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/icons/skip-forward.svg +0 -0
  158. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/icons/stop.svg +0 -0
  159. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/icons/tilemap.svg +0 -0
  160. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/icons/tileset.svg +0 -0
  161. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/icons/unchecked.svg +0 -0
  162. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/icons/unfold_right_arrow.svg +0 -0
  163. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/icons/warning.svg +0 -0
  164. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/icons/zoomin.svg +0 -0
  165. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/assets/icons/zoomout.svg +0 -0
  166. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/cli.py +0 -0
  167. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/main.py +0 -0
  168. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor/settings.py +0 -0
  169. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor.egg-info/dependency_links.txt +0 -0
  170. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor.egg-info/entry_points.txt +0 -0
  171. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/tilemap_editor.egg-info/top_level.txt +0 -0
  172. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/ttypes/__init__.py +0 -0
  173. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/ttypes/tilemap.py +0 -0
  174. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/utils/__init__.py +0 -0
  175. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/utils/editor_preference.py +0 -0
  176. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/utils/error_handler.py +0 -0
  177. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/utils/font_manager.py +0 -0
  178. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/utils/history.py +0 -0
  179. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/utils/icon_manager.py +0 -0
  180. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/utils/icons_cache.py +0 -0
  181. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/utils/log_capture.py +0 -0
  182. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/utils/project_paths.py +0 -0
  183. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/utils/property_suggestions.py +0 -0
  184. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/utils/serialization.py +0 -0
  185. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/utils/standalone.py +0 -0
  186. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/utils/validation.py +0 -0
  187. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/__init__.py +0 -0
  188. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/automap_models.py +0 -0
  189. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/autotile_template.py +0 -0
  190. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/autotiler.py +0 -0
  191. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/input.py +0 -0
  192. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/layer_selector.py +0 -0
  193. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/map_properties.py +0 -0
  194. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/mapsetup.py +0 -0
  195. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/particle_presets.py +0 -0
  196. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/particle_system.py +0 -0
  197. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/regex_automap_designer.py +0 -0
  198. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/tile_grid.py +0 -0
  199. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/tile_selector.py +0 -0
  200. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/ui/button.py +0 -0
  201. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/ui/checkbox.py +0 -0
  202. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/ui/collision_layer_mask.py +0 -0
  203. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/ui/collision_layer_sidebar.py +0 -0
  204. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/ui/confirm_dialog.py +0 -0
  205. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/ui/dialog_base.py +0 -0
  206. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/ui/drag_tracker.py +0 -0
  207. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/ui/draw_utils.py +0 -0
  208. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/ui/fileinput.py +0 -0
  209. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/ui/label.py +0 -0
  210. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/ui/layer_type_dialog.py +0 -0
  211. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/ui/menubar.py +0 -0
  212. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/ui/mode_indicator.py +0 -0
  213. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/ui/node_editor.py +0 -0
  214. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/ui/node_selector.py +0 -0
  215. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/ui/notification.py +0 -0
  216. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/ui/particle_config_dialog.py +0 -0
  217. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/ui/property_editor.py +0 -0
  218. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/ui/region_selector.py +0 -0
  219. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/ui/resize_map_dialog.py +0 -0
  220. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/ui/scrollbar.py +0 -0
  221. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/ui/sidebar_container.py +0 -0
  222. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/ui/splitter.py +0 -0
  223. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/ui/status_bar.py +0 -0
  224. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/ui/theme.py +0 -0
  225. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/ui/tileset_type_dialog.py +0 -0
  226. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/ui/toast.py +0 -0
  227. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/ui/tool_manager.py +0 -0
  228. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/ui/toolbar.py +0 -0
  229. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/ui/tooltip.py +0 -0
  230. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/ui/tree_widget.py +0 -0
  231. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/src/widgets/widget_base.py +0 -0
  232. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/tests/test_animation_library_grid_offset.py +0 -0
  233. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/tests/test_collision_layer_mask.py +0 -0
  234. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/tests/test_collision_layer_sidebar.py +0 -0
  235. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/tests/test_drag_tracker.py +0 -0
  236. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/tests/test_editor_pan_mode.py +0 -0
  237. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/tests/test_gid_collision.py +0 -0
  238. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/tests/test_layers_autotile.py +0 -0
  239. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/tests/test_map_resize_model.py +0 -0
  240. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/tests/test_project_paths.py +0 -0
  241. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/tests/test_render_scale.py +0 -0
  242. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/tests/test_serialization_regression.py +0 -0
  243. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/tests/test_sprite_animation_editor_grid.py +0 -0
  244. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/tests/test_tile_grid_selection.py +0 -0
  245. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/tests/test_tile_selector_pick.py +0 -0
  246. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/tests/test_tilemap_save.py +0 -0
  247. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/tests/test_timeline_invalidate_cache.py +0 -0
  248. {tilemap_editor-4.3.7 → tilemap_editor-4.3.8}/tests/test_toolbar_tools.py +0 -0
@@ -0,0 +1,231 @@
1
+ # Changelog
2
+
3
+ <!-- towncrier release notes start -->
4
+ # tilemap_editor 4.3.8 (2026-08-04)
5
+
6
+ ## Features
7
+
8
+ - Sprite editor: two-row grouped toolbar (no more clipped buttons at the default window size), natural filename sorting on multi-sheet loads, and a Stack V/H toggle for vertical or horizontal sheet stacking. (sprite-editor-toolbar-sort)
9
+ - Rewrote the sprite editor around a command stack with single-canvas undo memory: shared clipboard with relative-tile pasting that survives scale/grid changes, drag-move and rubber-band selection that can expand the canvas, object-selection undo restore, and a pure camera with cursor-anchored zoom. (sprite-editor-v2)
10
+
11
+ ## Bug Fixes
12
+
13
+ - Fixed sprite editor paste landing in wrong cells after a scale or grid-size change (clipboard now stores relative tile offsets), paste/cut double-clipboard split-brain, paste preview lacking pixel ghost, and moves/pastes past the canvas edge now expanding the canvas. (sprite-editor-paste-fixes)
14
+ - Fixed sprite editor theming and camera gestures: the canvas, header bar, grid lines, and overlays now use theme colors/fonts instead of hardcoded dark values (canvas no longer stays black on light themes), the canvas header no longer covers the sheet's top rows, and mouse wheel zoom/pan work again with the same 30px/1.12x behavior as the old editor. (sprite-editor-theme-wheel)
15
+
16
+
17
+ ## [4.3.7] - 2026-07-30
18
+
19
+ ### Bug Fixes
20
+
21
+ - Replaced buggy auto-resize system with explicit offset + size model for widget positioning
22
+
23
+ ## [4.3.6] - 2026-07-26
24
+
25
+ ### Features
26
+
27
+ - Added tileset properties completion
28
+ - Updated README with credits and Python version info
29
+
30
+ ### Bug Fixes
31
+
32
+ - Fixed UX bugs and node prescale problem
33
+
34
+ ## [4.3.4] - 2026-07-24
35
+
36
+ ### Features
37
+
38
+ - Added y-sort option for tile rendering order
39
+
40
+ ### Changed
41
+
42
+ - Restructured codebase with enhanced UI components and preference persistence
43
+ - Improved shape editor UX with theme integration and viewport centering
44
+
45
+ ## [4.3.1] - 2026-07-17
46
+
47
+ ### Bug Fixes
48
+
49
+ - Fixed create folder blocker in file manager
50
+ - Adjusted input field inner size
51
+
52
+ ## [4.3.0] - 2026-07-16
53
+
54
+ ### Changed
55
+
56
+ - Refactored toolbar and tool system with ToolManager/ToolKind central state
57
+ - Replaced editor boolean flags with centralized ToolManager mutual exclusion
58
+ - CLI `--theme` support
59
+
60
+ ### Added
61
+
62
+ - Icon-only compact toolbar (28px) with separator bars and tooltips
63
+
64
+ ### Bug Fixes
65
+
66
+ - Fixed node and object render_scale bugs (selection rect, move offset, hit-test)
67
+
68
+ ## [4.2.0] - 2026-07-15
69
+
70
+ ### Features
71
+
72
+ - Separated autotile group from layer tile data
73
+ - Added global ID system for tiles
74
+ - Re-added autotile early-out optimization
75
+ - Added auto-detect group from variant
76
+
77
+ ## [4.1.0] - 2026-07-13
78
+
79
+ ### Features
80
+
81
+ - Added .tmx file open/save support with TMX-to-dict converter
82
+
83
+ ### Bug Fixes
84
+
85
+ - Fixed alignment of tmx converter with parser fixes (mask, props, gid count)
86
+
87
+ ### Misc
88
+
89
+ - Formatted code and applied unsafe fixes with ruff
90
+
91
+ ## [4.0.0] - 2026-07-11
92
+
93
+ ### Changed
94
+
95
+ - Refactored widget theme system with dynamic COLORS proxy, SHAPE, FONTS, SPACING
96
+ - Applied theme from settings.json with custom theme loading support
97
+ - Added theme-aware WidgetBase with box model (padding, border, content_rect)
98
+
99
+ ### Added
100
+
101
+ - CLI `--theme` argument accepting name or path to .json file
102
+
103
+ ### Bug Fixes
104
+
105
+ - Fixed tile grid issues and serialization
106
+ - Improved node ui/ux with ctrl/cmd+shift+n toggle for node manager
107
+ - Improved particle rendering
108
+ - Temporarily disabled autotile propagation on collision paint
109
+
110
+ ## [3.3.8] - 2026-07-01
111
+
112
+ ### Bug Fixes
113
+
114
+ - Replaced smoothscale with scale for broader compatibility
115
+ - Fixed fallback to scale when smoothscale fails on non-32bit surfaces
116
+ - Replaced unicode characters with SVG icons for frame nav and onion skin
117
+
118
+ ## [3.3.4] - 2026-06-17
119
+
120
+ ### Features
121
+
122
+ - Enhanced sprite editor with cut/copy/paste functionality
123
+ - Added checkbox widget for UI controls
124
+
125
+ ### Documentation
126
+
127
+ - Added documentation for tilemap-editor (setup, project structure, architecture, usage)
128
+
129
+ ## [3.3.3] - 2026-06-10
130
+
131
+ ### Features
132
+
133
+ - Added particle system with 66 presets across 11 categories
134
+ - Added particle system editor integration with config dialog
135
+ - Added particle preview in TileGrid
136
+
137
+ ### Bug Fixes
138
+
139
+ - Fixed propagation of negative grid offsets
140
+ - Fixed zero animation frame_stride guard
141
+ - Fixed preset dropdown refresh on node switch
142
+ - Fixed particle preview reset on config save
143
+
144
+ ### Misc
145
+
146
+ - Added 'synchronize' type to PR agent workflow triggers
147
+
148
+ ## [3.2.10] - 2026-06-07
149
+
150
+ ### Bug Fixes
151
+
152
+ - Fixed tab click offset ignoring scroll_x
153
+
154
+ ### Added
155
+
156
+ - Hover-only arrow buttons for tab navigation
157
+
158
+ ## [3.2.9] - 2026-06-07
159
+
160
+ ### Bug Fixes
161
+
162
+ - Fixed stride normalization — removed % stride normalization, auto-compute stride
163
+ - Fixed dialog UI overlap
164
+
165
+ ## [3.2.8] - 2026-06-07
166
+
167
+ ### Features
168
+
169
+ - Added node system with NodeManager, NodeSelector, NodeEditor, and TileGrid overlay
170
+ - Added lenient tileset loading with warn dialog instead of reject on size mismatch
171
+
172
+ ### Bug Fixes
173
+
174
+ - Fixed layer rename text not visible during editing
175
+ - Fixed object layer position offset from render_scale
176
+ - Fixed capsule move icon and animation preview grid_offset
177
+ - Fixed layer rename Cmd+Backspace interaction
178
+
179
+ ## [3.2.4] - 2026-06-04
180
+
181
+ ### Features
182
+
183
+ - Added copy/paste collision shapes with toast feedback and painted tiles focus mode
184
+ - Added sprite editor integration with flip ghosting fix, tileset zoom, autotiler import fix
185
+ - Added auto-expand spritesheet canvas on paste overflow
186
+ - Added editable name field in character collision editor
187
+ - Added renaming support in character collision
188
+ - Added animation library loading and tool state management
189
+ - Added auto-propagation of collision shapes to auto-tile variant groups on save
190
+
191
+ ### Bug Fixes
192
+
193
+ - Fixed animation rename shortcuts, path resolution, file input overflow, and dual-focus metadata fields
194
+ - Fixed sprite editor multi-row paste flattening and missing tile-size arg
195
+ - Fixed dynamic grid span
196
+ - Fixed L shortcut conflict with name input
197
+
198
+ ### Misc
199
+
200
+ - Added unit tests
201
+
202
+ ## [3.1.6] - 2026-05-21
203
+
204
+ ### Bug Fixes
205
+
206
+ - Fixed NameError in save_map
207
+ - Fixed asymmetry in load path resolution
208
+ - Fixed path resolution in init
209
+
210
+ ### Added
211
+
212
+ - Added render_scale to map properties with dialog UI and TileGrid support
213
+ - Added auto-creation of data directory on init
214
+
215
+ ## [3.1.0] - 2026-05-18
216
+
217
+ ### Features
218
+
219
+ - Added Godot-inspired physics layer (radio) + mask (checkbox) bit selector (16 layers)
220
+ - Added collision layer sidebar overlay with toggle/close/dim
221
+ - Added object tileset collision editor with region support
222
+ - Added reusable text input system with cursor, selection, and shortcuts
223
+ - Added project initialization, asset management, and data structure improvements
224
+ - Added theme support
225
+ - Added collision mask support
226
+ - Implemented event priority system and modal overlays in autotiler
227
+
228
+ ### Changed
229
+
230
+ - Improved file manager path handling and directory initialization
231
+ - Improved tileset collision help panel and macOS HiDPI support
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tilemap-editor
3
- Version: 4.3.7
3
+ Version: 4.3.8
4
4
  Summary: Pygame tilemap editor with collision, animation, sprite & particle tools
5
5
  Author: tilemap editor contributors
6
6
  License: Proprietary
@@ -12,6 +12,8 @@ Requires-Python: >=3.11
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE
14
14
  Requires-Dist: pygame-ce>=2.5
15
+ Provides-Extra: dev
16
+ Requires-Dist: towncrier; extra == "dev"
15
17
  Dynamic: license-file
16
18
 
17
19
  # tilemap-editor
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "tilemap-editor"
7
- version = "4.3.7"
7
+ version = "4.3.8"
8
8
  description = "Pygame tilemap editor with collision, animation, sprite & particle tools"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -24,6 +24,41 @@ classifiers = [
24
24
  tilemap-editor = "tilemap_editor.cli:main"
25
25
  tilemap-anim-editor = "plugins.sprite_animation.standalone:main"
26
26
 
27
+ [project.optional-dependencies]
28
+ dev = ["towncrier"]
29
+
30
+ [tool.towncrier]
31
+ package = "tilemap_editor"
32
+ directory = "changes"
33
+ filename = "CHANGELOG.md"
34
+ start_string = "<!-- towncrier release notes start -->"
35
+ underlines = ["-", "~", "^"]
36
+
37
+ [[tool.towncrier.type]]
38
+ directory = "feature"
39
+ name = "Features"
40
+ showcontent = true
41
+
42
+ [[tool.towncrier.type]]
43
+ directory = "bugfix"
44
+ name = "Bug Fixes"
45
+ showcontent = true
46
+
47
+ [[tool.towncrier.type]]
48
+ directory = "doc"
49
+ name = "Documentation"
50
+ showcontent = true
51
+
52
+ [[tool.towncrier.type]]
53
+ directory = "removal"
54
+ name = "Deprecations and Removals"
55
+ showcontent = true
56
+
57
+ [[tool.towncrier.type]]
58
+ directory = "misc"
59
+ name = "Misc"
60
+ showcontent = true
61
+
27
62
  [tool.setuptools]
28
63
  package-dir = {"" = "src"}
29
64
  include-package-data = true
@@ -62,9 +97,3 @@ namespaces = true
62
97
 
63
98
  [tool.setuptools.exclude-package-data]
64
99
  "*" = ["*.spec", "*.sh"]
65
-
66
- # Keep data-files for backward compatibility (one release cycle)
67
- [tool.setuptools.data-files]
68
- "share/tilemap_editor/assets/icons" = ["assets/icons/*.svg"]
69
- "share/tilemap_editor/assets/fonts/noto" = ["assets/fonts/noto/*.ttf"]
70
- "share/tilemap_editor/assets/fonts/jetbrain-fonts" = ["assets/fonts/jetbrain-fonts/*.ttf"]
@@ -0,0 +1,97 @@
1
+ """Pure camera math — world (document) <-> screen transforms.
2
+
3
+ No pygame imports: this module is fully usable and testable headlessly.
4
+ Holds viewport origin and scroll as plain floats; the viewport provides
5
+ the pygame-side rect/bilt machinery.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ MIN_ZOOM = 0.1
11
+ MAX_ZOOM = 16.0
12
+
13
+
14
+ def _clamp_zoom(value: float) -> float:
15
+ return max(MIN_ZOOM, min(MAX_ZOOM, value))
16
+
17
+
18
+ class Camera:
19
+ """One monotonic linear transform between document and screen space.
20
+
21
+ screen = (local - origin) * zoom + viewport_topleft + scroll
22
+ local = (screen - viewport_topleft - scroll) / zoom + origin
23
+ """
24
+
25
+ def __init__(
26
+ self,
27
+ viewport_x: float = 0.0,
28
+ viewport_y: float = 0.0,
29
+ zoom: float = 1.0,
30
+ scroll_x: float = 0.0,
31
+ scroll_y: float = 0.0,
32
+ ):
33
+ self.viewport_x = float(viewport_x)
34
+ self.viewport_y = float(viewport_y)
35
+ self._zoom = _clamp_zoom(float(zoom))
36
+ self.scroll_x = float(scroll_x)
37
+ self.scroll_y = float(scroll_y)
38
+
39
+ @property
40
+ def zoom(self) -> float:
41
+ return self._zoom
42
+
43
+ @zoom.setter
44
+ def zoom(self, value: float) -> None:
45
+ self._zoom = _clamp_zoom(float(value))
46
+
47
+ def world_to_screen(self, x: float, y: float) -> tuple[float, float]:
48
+ return (
49
+ self.viewport_x + self.scroll_x + x * self._zoom,
50
+ self.viewport_y + self.scroll_y + y * self._zoom,
51
+ )
52
+
53
+ def screen_to_world(self, sx: float, sy: float) -> tuple[float, float]:
54
+ if self._zoom <= 0:
55
+ return (0.0, 0.0)
56
+ return (
57
+ (sx - self.viewport_x - self.scroll_x) / self._zoom,
58
+ (sy - self.viewport_y - self.scroll_y) / self._zoom,
59
+ )
60
+
61
+ def fit(self, world_size: tuple[float, float], viewport_size: tuple[float, float]) -> None:
62
+ """Zoom so the whole document fits the viewport, centered."""
63
+ ww, wh = world_size
64
+ vw, vh = viewport_size
65
+ if ww <= 0 or wh <= 0 or vw <= 0 or vh <= 0:
66
+ self.reset()
67
+ return
68
+ self._zoom = _clamp_zoom(min(vw / ww, vh / wh))
69
+ self.scroll_x = (vw - ww * self._zoom) / 2.0
70
+ self.scroll_y = (vh - wh * self._zoom) / 2.0
71
+
72
+ def reset(self) -> None:
73
+ """100% zoom, document origin at the viewport top-left."""
74
+ self._zoom = 1.0
75
+ self.scroll_x = 0.0
76
+ self.scroll_y = 0.0
77
+
78
+ def zoom_at(self, screen_point: tuple[float, float], factor: float) -> None:
79
+ """Zoom by factor while keeping the world point under the cursor fixed."""
80
+ sx, sy = screen_point
81
+ wx, wy = self.screen_to_world(sx, sy)
82
+ new_zoom = _clamp_zoom(self._zoom * factor)
83
+ if abs(new_zoom - self._zoom) < 1e-9:
84
+ return
85
+ self._zoom = new_zoom
86
+ self.scroll_x = sx - self.viewport_x - wx * self._zoom
87
+ self.scroll_y = sy - self.viewport_y - wy * self._zoom
88
+
89
+ def pan(self, dx: float, dy: float) -> None:
90
+ """Scroll by a screen-space delta (content follows the cursor)."""
91
+ self.scroll_x += float(dx)
92
+ self.scroll_y += float(dy)
93
+
94
+ def world_to_screen_rect(self, x: float, y: float, w: float, h: float) -> tuple[float, float, float, float]:
95
+ """Screen-space rect for a world-space rect (floats)."""
96
+ sx, sy = self.world_to_screen(x, y)
97
+ return (sx, sy, w * self._zoom, h * self._zoom)
@@ -0,0 +1,74 @@
1
+ """Clipboard — layout-relative tile data, independent of the UI.
2
+
3
+ Fixes the old absolute-index clipboard (P5/P6): tiles are stored as
4
+ (dx, dy) offsets relative to the clipboard origin, plus a source
5
+ tile-size snapshot, so pasting recomputes destination cells in the
6
+ *current* grid and never lands in surprising places after Scale/Grid.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from pygame import Surface
12
+
13
+ from .document import Document
14
+ from .selection import Selection
15
+
16
+
17
+ class Clipboard:
18
+ __slots__ = ("tiles", "tile_size", "origin_local")
19
+
20
+ def __init__(self) -> None:
21
+ self.tiles: list[tuple[int, int, Surface]] = []
22
+ self.tile_size: tuple[int, int] = (0, 0)
23
+ self.origin_local: tuple[int, int] = (0, 0)
24
+
25
+ def __len__(self) -> int:
26
+ return len(self.tiles)
27
+
28
+ @property
29
+ def is_empty(self) -> bool:
30
+ return not self.tiles
31
+
32
+ def clear(self) -> None:
33
+ self.tiles = []
34
+ self.tile_size = (0, 0)
35
+ self.origin_local = (0, 0)
36
+
37
+ def copy_from_selection(self, doc: Document, selection: Selection) -> bool:
38
+ """Snapshot the selected cells as (dx, dy, surface) tiles.
39
+
40
+ Returns True if anything was copied.
41
+ """
42
+ cells = selection.sorted_cells()
43
+ if not cells or not doc.surface:
44
+ self.clear()
45
+ return False
46
+ min_col = min(c for c, _ in cells)
47
+ min_row = min(r for _, r in cells)
48
+ self.tiles = [
49
+ (col - min_col, row - min_row, doc.extract_tile(col, row))
50
+ for col, row in cells
51
+ ]
52
+ self.tile_size = doc.tile_size
53
+ self.origin_local = (min_col * doc.tw, min_row * doc.th)
54
+ return True
55
+
56
+ def covered_cells(self, target_col: int, target_row: int) -> list[tuple[int, int]]:
57
+ """Cell list the clipboard would occupy anchored at a target cell."""
58
+ return [
59
+ (target_col + dx, target_row + dy)
60
+ for dx, dy, _ in self.tiles
61
+ ]
62
+
63
+ def paste_surfaces(self, target_col: int, target_row: int) -> list[tuple[int, int, Surface]]:
64
+ """(col, row, surface) placements anchored at a target cell."""
65
+ return [
66
+ (target_col + dx, target_row + dy, surf)
67
+ for dx, dy, surf in self.tiles
68
+ ]
69
+
70
+ def bounds_cells(self) -> tuple[int, int]:
71
+ """Bounding box (ncols, nrows) of the clipboard tiles."""
72
+ if not self.tiles:
73
+ return (0, 0)
74
+ return (max(dx for dx, _, _ in self.tiles) + 1, max(dy for _, dy, _ in self.tiles) + 1)