tilemap-editor 4.3.7__tar.gz → 4.3.9__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.9/CHANGELOG.md +239 -0
  2. {tilemap_editor-4.3.7/src/tilemap_editor.egg-info → tilemap_editor-4.3.9}/PKG-INFO +3 -1
  3. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/pyproject.toml +36 -7
  4. tilemap_editor-4.3.9/src/plugins/sprite_editor/camera.py +97 -0
  5. tilemap_editor-4.3.9/src/plugins/sprite_editor/clipboard.py +74 -0
  6. tilemap_editor-4.3.9/src/plugins/sprite_editor/commands.py +248 -0
  7. tilemap_editor-4.3.9/src/plugins/sprite_editor/document.py +352 -0
  8. tilemap_editor-4.3.9/src/plugins/sprite_editor/editor.py +658 -0
  9. tilemap_editor-4.3.9/src/plugins/sprite_editor/overlays.py +155 -0
  10. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/plugins/sprite_editor/region_export.py +3 -3
  11. tilemap_editor-4.3.9/src/plugins/sprite_editor/selection.py +99 -0
  12. tilemap_editor-4.3.9/src/plugins/sprite_editor/tools.py +745 -0
  13. tilemap_editor-4.3.9/src/plugins/sprite_editor/viewport.py +179 -0
  14. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/plugins/tileset_collision/editor.py +12 -5
  15. tilemap_editor-4.3.9/src/run.py +3 -0
  16. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9/src/tilemap_editor.egg-info}/PKG-INFO +3 -1
  17. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor.egg-info/SOURCES.txt +15 -1
  18. tilemap_editor-4.3.9/src/tilemap_editor.egg-info/requires.txt +4 -0
  19. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/utils/font_manager.py +15 -1
  20. tilemap_editor-4.3.9/src/utils/natural_sort.py +29 -0
  21. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/filemanager.py +4 -3
  22. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/ui/region_selector.py +20 -6
  23. tilemap_editor-4.3.9/tests/test_natural_sort.py +80 -0
  24. tilemap_editor-4.3.9/tests/test_sprite_editor_commands.py +271 -0
  25. tilemap_editor-4.3.9/tests/test_sprite_editor_interaction.py +610 -0
  26. tilemap_editor-4.3.9/tests/test_sprite_editor_models.py +380 -0
  27. tilemap_editor-4.3.7/src/plugins/sprite_editor/editor.py +0 -631
  28. tilemap_editor-4.3.7/src/tilemap_editor.egg-info/requires.txt +0 -1
  29. tilemap_editor-4.3.7/src/widgets/spritesheet_grid.py +0 -707
  30. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/LICENSE +0 -0
  31. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/MANIFEST.in +0 -0
  32. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/README.md +0 -0
  33. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/assets/fonts/jetbrain-fonts/JetBrainsMono-Bold.ttf +0 -0
  34. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/assets/fonts/jetbrain-fonts/JetBrainsMono-BoldItalic.ttf +0 -0
  35. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/assets/fonts/jetbrain-fonts/JetBrainsMono-Italic.ttf +0 -0
  36. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/assets/fonts/jetbrain-fonts/JetBrainsMono-Regular.ttf +0 -0
  37. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/assets/fonts/noto/NotoSans-Bold.ttf +0 -0
  38. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/assets/fonts/noto/NotoSans-BoldItalic.ttf +0 -0
  39. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/assets/fonts/noto/NotoSans-Italic.ttf +0 -0
  40. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/assets/fonts/noto/NotoSans-Regular.ttf +0 -0
  41. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/assets/icons/arrow-down.svg +0 -0
  42. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/assets/icons/check.svg +0 -0
  43. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/assets/icons/checked.svg +0 -0
  44. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/assets/icons/close.svg +0 -0
  45. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/assets/icons/duplicate.svg +0 -0
  46. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/assets/icons/error.svg +0 -0
  47. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/assets/icons/file.svg +0 -0
  48. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/assets/icons/filedead.svg +0 -0
  49. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/assets/icons/fit.svg +0 -0
  50. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/assets/icons/folder.svg +0 -0
  51. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/assets/icons/grid.svg +0 -0
  52. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/assets/icons/image.svg +0 -0
  53. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/assets/icons/info.svg +0 -0
  54. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/assets/icons/load.svg +0 -0
  55. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/assets/icons/loop.svg +0 -0
  56. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/assets/icons/onion.svg +0 -0
  57. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/assets/icons/pan.svg +0 -0
  58. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/assets/icons/pause.svg +0 -0
  59. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/assets/icons/pencil.svg +0 -0
  60. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/assets/icons/play.svg +0 -0
  61. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/assets/icons/plus.svg +0 -0
  62. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/assets/icons/radio.svg +0 -0
  63. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/assets/icons/reset.svg +0 -0
  64. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/assets/icons/save.svg +0 -0
  65. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/assets/icons/skip-back.svg +0 -0
  66. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/assets/icons/skip-forward.svg +0 -0
  67. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/assets/icons/stop.svg +0 -0
  68. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/assets/icons/tilemap.svg +0 -0
  69. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/assets/icons/tileset.svg +0 -0
  70. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/assets/icons/unchecked.svg +0 -0
  71. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/assets/icons/warning.svg +0 -0
  72. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/assets/icons/zoomin.svg +0 -0
  73. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/assets/icons/zoomout.svg +0 -0
  74. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/setup.cfg +0 -0
  75. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/constants.py +0 -0
  76. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/editor.py +0 -0
  77. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/event_map.py +0 -0
  78. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/layers.py +0 -0
  79. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/main.py +0 -0
  80. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/node_manager.py +0 -0
  81. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/nodes.py +0 -0
  82. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/plugins/__init__.py +0 -0
  83. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/plugins/character_collision/__init__.py +0 -0
  84. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/plugins/character_collision/editor.py +0 -0
  85. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/plugins/character_collision/models.py +0 -0
  86. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/plugins/character_collision/protocols.py +0 -0
  87. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/plugins/character_collision/shape_editor.py +0 -0
  88. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/plugins/character_collision/standalone.py +0 -0
  89. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/plugins/object_tileset_collision/__init__.py +0 -0
  90. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/plugins/object_tileset_collision/editor.py +0 -0
  91. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/plugins/object_tileset_collision/models.py +0 -0
  92. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/plugins/object_tileset_collision/protocols.py +0 -0
  93. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/plugins/object_tileset_collision/standalone.py +0 -0
  94. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/plugins/sprite_animation/__init__.py +0 -0
  95. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/plugins/sprite_animation/__main__.py +0 -0
  96. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/plugins/sprite_animation/clipboard_util.py +0 -0
  97. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/plugins/sprite_animation/editor.py +0 -0
  98. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/plugins/sprite_animation/frame_picker.py +0 -0
  99. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/plugins/sprite_animation/models.py +0 -0
  100. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/plugins/sprite_animation/preview.py +0 -0
  101. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/plugins/sprite_animation/protocols.py +0 -0
  102. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/plugins/sprite_animation/runtime_load.py +0 -0
  103. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/plugins/sprite_animation/standalone.py +0 -0
  104. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/plugins/sprite_animation/timeline.py +0 -0
  105. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/plugins/sprite_animation/validation.py +0 -0
  106. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/plugins/sprite_editor/__init__.py +0 -0
  107. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/plugins/sprite_editor/dialogs.py +0 -0
  108. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/plugins/sprite_editor/standalone.py +0 -0
  109. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/plugins/tileset_collision/__init__.py +0 -0
  110. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/plugins/tileset_collision/collision_painter.py +0 -0
  111. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/plugins/tileset_collision/models.py +0 -0
  112. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/plugins/tileset_collision/protocols.py +0 -0
  113. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/plugins/tileset_collision/standalone.py +0 -0
  114. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/standalone_automap.py +0 -0
  115. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/standalone_error_console.py +0 -0
  116. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/standalone_filemanager.py +0 -0
  117. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/standalone_image_viewer.py +0 -0
  118. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap.py +0 -0
  119. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/__init__.py +0 -0
  120. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/__main__.py +0 -0
  121. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/__init__.py +0 -0
  122. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/fonts/jetbrain-fonts/JetBrainsMono-Bold.ttf +0 -0
  123. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/fonts/jetbrain-fonts/JetBrainsMono-BoldItalic.ttf +0 -0
  124. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/fonts/jetbrain-fonts/JetBrainsMono-Italic.ttf +0 -0
  125. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/fonts/jetbrain-fonts/JetBrainsMono-Regular.ttf +0 -0
  126. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/fonts/noto/NotoSans-Bold.ttf +0 -0
  127. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/fonts/noto/NotoSans-BoldItalic.ttf +0 -0
  128. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/fonts/noto/NotoSans-Italic.ttf +0 -0
  129. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/fonts/noto/NotoSans-Regular.ttf +0 -0
  130. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/icons/ToolMove.svg +0 -0
  131. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/icons/arrow-down.svg +0 -0
  132. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/icons/check.svg +0 -0
  133. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/icons/checked.svg +0 -0
  134. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/icons/close.svg +0 -0
  135. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/icons/duplicate.svg +0 -0
  136. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/icons/error.svg +0 -0
  137. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/icons/file.svg +0 -0
  138. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/icons/filedead.svg +0 -0
  139. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/icons/fit.svg +0 -0
  140. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/icons/fold_down_arrow.svg +0 -0
  141. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/icons/folder.svg +0 -0
  142. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/icons/gear.svg +0 -0
  143. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/icons/grid.svg +0 -0
  144. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/icons/image.svg +0 -0
  145. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/icons/info.svg +0 -0
  146. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/icons/load.svg +0 -0
  147. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/icons/loop.svg +0 -0
  148. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/icons/miniobj.svg +0 -0
  149. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/icons/onion.svg +0 -0
  150. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/icons/pan.svg +0 -0
  151. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/icons/pause.svg +0 -0
  152. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/icons/pencil.svg +0 -0
  153. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/icons/play.svg +0 -0
  154. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/icons/plus.svg +0 -0
  155. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/icons/radio.svg +0 -0
  156. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/icons/reset.svg +0 -0
  157. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/icons/save.svg +0 -0
  158. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/icons/skip-back.svg +0 -0
  159. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/icons/skip-forward.svg +0 -0
  160. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/icons/stop.svg +0 -0
  161. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/icons/tilemap.svg +0 -0
  162. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/icons/tileset.svg +0 -0
  163. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/icons/unchecked.svg +0 -0
  164. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/icons/unfold_right_arrow.svg +0 -0
  165. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/icons/warning.svg +0 -0
  166. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/icons/zoomin.svg +0 -0
  167. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/assets/icons/zoomout.svg +0 -0
  168. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/cli.py +0 -0
  169. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/main.py +0 -0
  170. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor/settings.py +0 -0
  171. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor.egg-info/dependency_links.txt +0 -0
  172. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor.egg-info/entry_points.txt +0 -0
  173. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/tilemap_editor.egg-info/top_level.txt +0 -0
  174. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/ttypes/__init__.py +0 -0
  175. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/ttypes/tilemap.py +0 -0
  176. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/utils/__init__.py +0 -0
  177. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/utils/editor_preference.py +0 -0
  178. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/utils/error_handler.py +0 -0
  179. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/utils/history.py +0 -0
  180. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/utils/icon_manager.py +0 -0
  181. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/utils/icons_cache.py +0 -0
  182. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/utils/log_capture.py +0 -0
  183. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/utils/project_paths.py +0 -0
  184. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/utils/property_suggestions.py +0 -0
  185. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/utils/serialization.py +0 -0
  186. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/utils/standalone.py +0 -0
  187. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/utils/validation.py +0 -0
  188. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/__init__.py +0 -0
  189. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/automap_models.py +0 -0
  190. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/autotile_template.py +0 -0
  191. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/autotiler.py +0 -0
  192. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/input.py +0 -0
  193. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/layer_selector.py +0 -0
  194. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/map_properties.py +0 -0
  195. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/mapsetup.py +0 -0
  196. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/particle_presets.py +0 -0
  197. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/particle_system.py +0 -0
  198. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/regex_automap_designer.py +0 -0
  199. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/tile_grid.py +0 -0
  200. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/tile_selector.py +0 -0
  201. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/ui/button.py +0 -0
  202. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/ui/checkbox.py +0 -0
  203. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/ui/collision_layer_mask.py +0 -0
  204. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/ui/collision_layer_sidebar.py +0 -0
  205. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/ui/confirm_dialog.py +0 -0
  206. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/ui/dialog_base.py +0 -0
  207. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/ui/drag_tracker.py +0 -0
  208. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/ui/draw_utils.py +0 -0
  209. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/ui/fileinput.py +0 -0
  210. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/ui/label.py +0 -0
  211. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/ui/layer_type_dialog.py +0 -0
  212. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/ui/menubar.py +0 -0
  213. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/ui/mode_indicator.py +0 -0
  214. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/ui/node_editor.py +0 -0
  215. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/ui/node_selector.py +0 -0
  216. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/ui/notification.py +0 -0
  217. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/ui/particle_config_dialog.py +0 -0
  218. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/ui/property_editor.py +0 -0
  219. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/ui/resize_map_dialog.py +0 -0
  220. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/ui/scrollbar.py +0 -0
  221. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/ui/sidebar_container.py +0 -0
  222. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/ui/splitter.py +0 -0
  223. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/ui/status_bar.py +0 -0
  224. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/ui/theme.py +0 -0
  225. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/ui/tileset_type_dialog.py +0 -0
  226. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/ui/toast.py +0 -0
  227. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/ui/tool_manager.py +0 -0
  228. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/ui/toolbar.py +0 -0
  229. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/ui/tooltip.py +0 -0
  230. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/ui/tree_widget.py +0 -0
  231. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/src/widgets/widget_base.py +0 -0
  232. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/tests/test_animation_library_grid_offset.py +0 -0
  233. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/tests/test_collision_layer_mask.py +0 -0
  234. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/tests/test_collision_layer_sidebar.py +0 -0
  235. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/tests/test_drag_tracker.py +0 -0
  236. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/tests/test_editor_pan_mode.py +0 -0
  237. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/tests/test_gid_collision.py +0 -0
  238. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/tests/test_layers_autotile.py +0 -0
  239. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/tests/test_map_resize_model.py +0 -0
  240. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/tests/test_project_paths.py +0 -0
  241. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/tests/test_render_scale.py +0 -0
  242. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/tests/test_serialization_regression.py +0 -0
  243. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/tests/test_sprite_animation_editor_grid.py +0 -0
  244. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/tests/test_tile_grid_selection.py +0 -0
  245. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/tests/test_tile_selector_pick.py +0 -0
  246. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/tests/test_tilemap_save.py +0 -0
  247. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/tests/test_timeline_invalidate_cache.py +0 -0
  248. {tilemap_editor-4.3.7 → tilemap_editor-4.3.9}/tests/test_toolbar_tools.py +0 -0
@@ -0,0 +1,239 @@
1
+ # Changelog
2
+
3
+ <!-- towncrier release notes start -->
4
+ # tilemap_editor 4.3.9 (2026-08-04)
5
+
6
+ ## Bug Fixes
7
+
8
+ - Fixed tileset collision editor tile picking when the tileset is centered in the selector: mouse clicks now map to the correct tile after the centering offset is applied.
9
+ - Fixed region selector coordinate conversion (screen↔image) to account for the centered image when it is smaller than the viewport, so drawing, selection, and drag operations stay aligned.
10
+
11
+ # tilemap_editor 4.3.8 (2026-08-04)
12
+
13
+ ## Features
14
+
15
+ - Sprite editor: two-row grouped toolbar, natural filename sorting on multi-sheet loads, and a Stack V/H toggle for vertical or horizontal sheet stacking.
16
+ - 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)
17
+
18
+ ## Bug Fixes
19
+
20
+ - Fixed sprite editor undo history corruption from shared region references, viewport cache staleness after region edits, coordinate errors after loading new sheets, index lookup failures with negative-origin canvases, and canvas expansion failures for negative cell coordinates
21
+ - 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)
22
+ - 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)
23
+
24
+
25
+ ## [4.3.7] - 2026-07-30
26
+
27
+ ### Bug Fixes
28
+
29
+ - Replaced buggy auto-resize system with explicit offset + size model for widget positioning
30
+
31
+ ## [4.3.6] - 2026-07-26
32
+
33
+ ### Features
34
+
35
+ - Added tileset properties completion
36
+ - Updated README with credits and Python version info
37
+
38
+ ### Bug Fixes
39
+
40
+ - Fixed UX bugs and node prescale problem
41
+
42
+ ## [4.3.4] - 2026-07-24
43
+
44
+ ### Features
45
+
46
+ - Added y-sort option for tile rendering order
47
+
48
+ ### Changed
49
+
50
+ - Restructured codebase with enhanced UI components and preference persistence
51
+ - Improved shape editor UX with theme integration and viewport centering
52
+
53
+ ## [4.3.1] - 2026-07-17
54
+
55
+ ### Bug Fixes
56
+
57
+ - Fixed create folder blocker in file manager
58
+ - Adjusted input field inner size
59
+
60
+ ## [4.3.0] - 2026-07-16
61
+
62
+ ### Changed
63
+
64
+ - Refactored toolbar and tool system with ToolManager/ToolKind central state
65
+ - Replaced editor boolean flags with centralized ToolManager mutual exclusion
66
+ - CLI `--theme` support
67
+
68
+ ### Added
69
+
70
+ - Icon-only compact toolbar (28px) with separator bars and tooltips
71
+
72
+ ### Bug Fixes
73
+
74
+ - Fixed node and object render_scale bugs (selection rect, move offset, hit-test)
75
+
76
+ ## [4.2.0] - 2026-07-15
77
+
78
+ ### Features
79
+
80
+ - Separated autotile group from layer tile data
81
+ - Added global ID system for tiles
82
+ - Re-added autotile early-out optimization
83
+ - Added auto-detect group from variant
84
+
85
+ ## [4.1.0] - 2026-07-13
86
+
87
+ ### Features
88
+
89
+ - Added .tmx file open/save support with TMX-to-dict converter
90
+
91
+ ### Bug Fixes
92
+
93
+ - Fixed alignment of tmx converter with parser fixes (mask, props, gid count)
94
+
95
+ ### Misc
96
+
97
+ - Formatted code and applied unsafe fixes with ruff
98
+
99
+ ## [4.0.0] - 2026-07-11
100
+
101
+ ### Changed
102
+
103
+ - Refactored widget theme system with dynamic COLORS proxy, SHAPE, FONTS, SPACING
104
+ - Applied theme from settings.json with custom theme loading support
105
+ - Added theme-aware WidgetBase with box model (padding, border, content_rect)
106
+
107
+ ### Added
108
+
109
+ - CLI `--theme` argument accepting name or path to .json file
110
+
111
+ ### Bug Fixes
112
+
113
+ - Fixed tile grid issues and serialization
114
+ - Improved node ui/ux with ctrl/cmd+shift+n toggle for node manager
115
+ - Improved particle rendering
116
+ - Temporarily disabled autotile propagation on collision paint
117
+
118
+ ## [3.3.8] - 2026-07-01
119
+
120
+ ### Bug Fixes
121
+
122
+ - Replaced smoothscale with scale for broader compatibility
123
+ - Fixed fallback to scale when smoothscale fails on non-32bit surfaces
124
+ - Replaced unicode characters with SVG icons for frame nav and onion skin
125
+
126
+ ## [3.3.4] - 2026-06-17
127
+
128
+ ### Features
129
+
130
+ - Enhanced sprite editor with cut/copy/paste functionality
131
+ - Added checkbox widget for UI controls
132
+
133
+ ### Documentation
134
+
135
+ - Added documentation for tilemap-editor (setup, project structure, architecture, usage)
136
+
137
+ ## [3.3.3] - 2026-06-10
138
+
139
+ ### Features
140
+
141
+ - Added particle system with 66 presets across 11 categories
142
+ - Added particle system editor integration with config dialog
143
+ - Added particle preview in TileGrid
144
+
145
+ ### Bug Fixes
146
+
147
+ - Fixed propagation of negative grid offsets
148
+ - Fixed zero animation frame_stride guard
149
+ - Fixed preset dropdown refresh on node switch
150
+ - Fixed particle preview reset on config save
151
+
152
+ ### Misc
153
+
154
+ - Added 'synchronize' type to PR agent workflow triggers
155
+
156
+ ## [3.2.10] - 2026-06-07
157
+
158
+ ### Bug Fixes
159
+
160
+ - Fixed tab click offset ignoring scroll_x
161
+
162
+ ### Added
163
+
164
+ - Hover-only arrow buttons for tab navigation
165
+
166
+ ## [3.2.9] - 2026-06-07
167
+
168
+ ### Bug Fixes
169
+
170
+ - Fixed stride normalization — removed % stride normalization, auto-compute stride
171
+ - Fixed dialog UI overlap
172
+
173
+ ## [3.2.8] - 2026-06-07
174
+
175
+ ### Features
176
+
177
+ - Added node system with NodeManager, NodeSelector, NodeEditor, and TileGrid overlay
178
+ - Added lenient tileset loading with warn dialog instead of reject on size mismatch
179
+
180
+ ### Bug Fixes
181
+
182
+ - Fixed layer rename text not visible during editing
183
+ - Fixed object layer position offset from render_scale
184
+ - Fixed capsule move icon and animation preview grid_offset
185
+ - Fixed layer rename Cmd+Backspace interaction
186
+
187
+ ## [3.2.4] - 2026-06-04
188
+
189
+ ### Features
190
+
191
+ - Added copy/paste collision shapes with toast feedback and painted tiles focus mode
192
+ - Added sprite editor integration with flip ghosting fix, tileset zoom, autotiler import fix
193
+ - Added auto-expand spritesheet canvas on paste overflow
194
+ - Added editable name field in character collision editor
195
+ - Added renaming support in character collision
196
+ - Added animation library loading and tool state management
197
+ - Added auto-propagation of collision shapes to auto-tile variant groups on save
198
+
199
+ ### Bug Fixes
200
+
201
+ - Fixed animation rename shortcuts, path resolution, file input overflow, and dual-focus metadata fields
202
+ - Fixed sprite editor multi-row paste flattening and missing tile-size arg
203
+ - Fixed dynamic grid span
204
+ - Fixed L shortcut conflict with name input
205
+
206
+ ### Misc
207
+
208
+ - Added unit tests
209
+
210
+ ## [3.1.6] - 2026-05-21
211
+
212
+ ### Bug Fixes
213
+
214
+ - Fixed NameError in save_map
215
+ - Fixed asymmetry in load path resolution
216
+ - Fixed path resolution in init
217
+
218
+ ### Added
219
+
220
+ - Added render_scale to map properties with dialog UI and TileGrid support
221
+ - Added auto-creation of data directory on init
222
+
223
+ ## [3.1.0] - 2026-05-18
224
+
225
+ ### Features
226
+
227
+ - Added Godot-inspired physics layer (radio) + mask (checkbox) bit selector (16 layers)
228
+ - Added collision layer sidebar overlay with toggle/close/dim
229
+ - Added object tileset collision editor with region support
230
+ - Added reusable text input system with cursor, selection, and shortcuts
231
+ - Added project initialization, asset management, and data structure improvements
232
+ - Added theme support
233
+ - Added collision mask support
234
+ - Implemented event priority system and modal overlays in autotiler
235
+
236
+ ### Changed
237
+
238
+ - Improved file manager path handling and directory initialization
239
+ - 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.9
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.9"
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)