tilemap-editor 3.2.1__tar.gz → 3.2.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (186) hide show
  1. {tilemap_editor-3.2.1/src/tilemap_editor.egg-info → tilemap_editor-3.2.3}/PKG-INFO +1 -1
  2. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/pyproject.toml +1 -1
  3. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/editor.py +68 -3
  4. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/plugins/character_collision/editor.py +91 -15
  5. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/plugins/sprite_animation/editor.py +46 -2
  6. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/plugins/sprite_animation/models.py +3 -0
  7. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/plugins/sprite_animation/timeline.py +4 -0
  8. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3/src/tilemap_editor.egg-info}/PKG-INFO +1 -1
  9. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/widgets/tile_grid.py +699 -65
  10. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/widgets/tile_selector.py +38 -0
  11. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/widgets/ui/toolbar.py +23 -0
  12. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/LICENSE +0 -0
  13. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/MANIFEST.in +0 -0
  14. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/README.md +0 -0
  15. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/assets/fonts/jetbrain-fonts/JetBrainsMono-Bold.ttf +0 -0
  16. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/assets/fonts/jetbrain-fonts/JetBrainsMono-BoldItalic.ttf +0 -0
  17. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/assets/fonts/jetbrain-fonts/JetBrainsMono-Italic.ttf +0 -0
  18. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/assets/fonts/jetbrain-fonts/JetBrainsMono-Regular.ttf +0 -0
  19. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/assets/fonts/noto/NotoSans-Bold.ttf +0 -0
  20. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/assets/fonts/noto/NotoSans-BoldItalic.ttf +0 -0
  21. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/assets/fonts/noto/NotoSans-Italic.ttf +0 -0
  22. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/assets/fonts/noto/NotoSans-Regular.ttf +0 -0
  23. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/assets/icons/arrow-down.svg +0 -0
  24. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/assets/icons/check.svg +0 -0
  25. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/assets/icons/checked.svg +0 -0
  26. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/assets/icons/close.svg +0 -0
  27. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/assets/icons/duplicate.svg +0 -0
  28. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/assets/icons/error.svg +0 -0
  29. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/assets/icons/file.svg +0 -0
  30. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/assets/icons/filedead.svg +0 -0
  31. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/assets/icons/fit.svg +0 -0
  32. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/assets/icons/folder.svg +0 -0
  33. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/assets/icons/grid.svg +0 -0
  34. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/assets/icons/image.svg +0 -0
  35. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/assets/icons/info.svg +0 -0
  36. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/assets/icons/load.svg +0 -0
  37. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/assets/icons/loop.svg +0 -0
  38. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/assets/icons/pan.svg +0 -0
  39. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/assets/icons/pause.svg +0 -0
  40. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/assets/icons/pencil.svg +0 -0
  41. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/assets/icons/play.svg +0 -0
  42. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/assets/icons/plus.svg +0 -0
  43. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/assets/icons/radio.svg +0 -0
  44. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/assets/icons/reset.svg +0 -0
  45. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/assets/icons/save.svg +0 -0
  46. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/assets/icons/stop.svg +0 -0
  47. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/assets/icons/tilemap.svg +0 -0
  48. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/assets/icons/tileset.svg +0 -0
  49. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/assets/icons/unchecked.svg +0 -0
  50. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/assets/icons/warning.svg +0 -0
  51. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/assets/icons/zoomin.svg +0 -0
  52. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/assets/icons/zoomout.svg +0 -0
  53. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/setup.cfg +0 -0
  54. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/configs/themes.py +0 -0
  55. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/constants.py +0 -0
  56. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/event_map.py +0 -0
  57. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/layers.py +0 -0
  58. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/main.py +0 -0
  59. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/plugins/__init__.py +0 -0
  60. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/plugins/character_collision/__init__.py +0 -0
  61. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/plugins/character_collision/models.py +0 -0
  62. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/plugins/character_collision/protocols.py +0 -0
  63. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/plugins/character_collision/shape_editor.py +0 -0
  64. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/plugins/character_collision/standalone.py +0 -0
  65. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/plugins/object_tileset_collision/__init__.py +0 -0
  66. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/plugins/object_tileset_collision/editor.py +0 -0
  67. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/plugins/object_tileset_collision/models.py +0 -0
  68. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/plugins/object_tileset_collision/protocols.py +0 -0
  69. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/plugins/object_tileset_collision/standalone.py +0 -0
  70. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/plugins/sprite_animation/__init__.py +0 -0
  71. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/plugins/sprite_animation/__main__.py +0 -0
  72. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/plugins/sprite_animation/clipboard_util.py +0 -0
  73. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/plugins/sprite_animation/frame_picker.py +0 -0
  74. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/plugins/sprite_animation/preview.py +0 -0
  75. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/plugins/sprite_animation/protocols.py +0 -0
  76. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/plugins/sprite_animation/runtime_load.py +0 -0
  77. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/plugins/sprite_animation/standalone.py +0 -0
  78. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/plugins/sprite_animation/validation.py +0 -0
  79. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/plugins/sprite_editor/__init__.py +0 -0
  80. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/plugins/sprite_editor/editor.py +0 -0
  81. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/plugins/sprite_editor/standalone.py +0 -0
  82. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/plugins/tileset_collision/__init__.py +0 -0
  83. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/plugins/tileset_collision/collision_painter.py +0 -0
  84. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/plugins/tileset_collision/editor.py +0 -0
  85. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/plugins/tileset_collision/models.py +0 -0
  86. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/plugins/tileset_collision/protocols.py +0 -0
  87. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/plugins/tileset_collision/standalone.py +0 -0
  88. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/standalone_automap.py +0 -0
  89. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/standalone_error_console.py +0 -0
  90. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/standalone_filemanager.py +0 -0
  91. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/standalone_image_viewer.py +0 -0
  92. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap.py +0 -0
  93. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/__init__.py +0 -0
  94. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/__main__.py +0 -0
  95. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/assets/__init__.py +0 -0
  96. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/assets/fonts/jetbrain-fonts/JetBrainsMono-Bold.ttf +0 -0
  97. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/assets/fonts/jetbrain-fonts/JetBrainsMono-BoldItalic.ttf +0 -0
  98. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/assets/fonts/jetbrain-fonts/JetBrainsMono-Italic.ttf +0 -0
  99. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/assets/fonts/jetbrain-fonts/JetBrainsMono-Regular.ttf +0 -0
  100. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/assets/fonts/noto/NotoSans-Bold.ttf +0 -0
  101. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/assets/fonts/noto/NotoSans-BoldItalic.ttf +0 -0
  102. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/assets/fonts/noto/NotoSans-Italic.ttf +0 -0
  103. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/assets/fonts/noto/NotoSans-Regular.ttf +0 -0
  104. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/assets/icons/ToolMove.svg +0 -0
  105. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/assets/icons/arrow-down.svg +0 -0
  106. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/assets/icons/check.svg +0 -0
  107. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/assets/icons/checked.svg +0 -0
  108. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/assets/icons/close.svg +0 -0
  109. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/assets/icons/duplicate.svg +0 -0
  110. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/assets/icons/error.svg +0 -0
  111. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/assets/icons/file.svg +0 -0
  112. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/assets/icons/filedead.svg +0 -0
  113. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/assets/icons/fit.svg +0 -0
  114. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/assets/icons/folder.svg +0 -0
  115. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/assets/icons/grid.svg +0 -0
  116. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/assets/icons/image.svg +0 -0
  117. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/assets/icons/info.svg +0 -0
  118. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/assets/icons/load.svg +0 -0
  119. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/assets/icons/loop.svg +0 -0
  120. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/assets/icons/pan.svg +0 -0
  121. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/assets/icons/pause.svg +0 -0
  122. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/assets/icons/pencil.svg +0 -0
  123. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/assets/icons/play.svg +0 -0
  124. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/assets/icons/plus.svg +0 -0
  125. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/assets/icons/radio.svg +0 -0
  126. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/assets/icons/reset.svg +0 -0
  127. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/assets/icons/save.svg +0 -0
  128. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/assets/icons/stop.svg +0 -0
  129. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/assets/icons/tilemap.svg +0 -0
  130. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/assets/icons/tileset.svg +0 -0
  131. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/assets/icons/unchecked.svg +0 -0
  132. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/assets/icons/warning.svg +0 -0
  133. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/assets/icons/zoomin.svg +0 -0
  134. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/assets/icons/zoomout.svg +0 -0
  135. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/cli.py +0 -0
  136. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/main.py +0 -0
  137. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor/settings.py +0 -0
  138. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor.egg-info/SOURCES.txt +0 -0
  139. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor.egg-info/dependency_links.txt +0 -0
  140. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor.egg-info/entry_points.txt +0 -0
  141. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor.egg-info/requires.txt +0 -0
  142. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/tilemap_editor.egg-info/top_level.txt +0 -0
  143. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/ttypes/__init__.py +0 -0
  144. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/ttypes/tilemap.py +0 -0
  145. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/utils/__init__.py +0 -0
  146. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/utils/editor_preference.py +0 -0
  147. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/utils/error_handler.py +0 -0
  148. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/utils/font_manager.py +0 -0
  149. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/utils/history.py +0 -0
  150. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/utils/icon_manager.py +0 -0
  151. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/utils/icons_cache.py +0 -0
  152. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/utils/log_capture.py +0 -0
  153. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/utils/project_paths.py +0 -0
  154. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/utils/serialization.py +0 -0
  155. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/utils/standalone.py +0 -0
  156. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/utils/validation.py +0 -0
  157. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/widgets/__init__.py +0 -0
  158. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/widgets/automap_models.py +0 -0
  159. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/widgets/autotile_template.py +0 -0
  160. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/widgets/autotiler.py +0 -0
  161. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/widgets/filemanager.py +0 -0
  162. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/widgets/input.py +0 -0
  163. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/widgets/layer_selector.py +0 -0
  164. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/widgets/map_properties.py +0 -0
  165. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/widgets/mapsetup.py +0 -0
  166. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/widgets/regex_automap_designer.py +0 -0
  167. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/widgets/spritesheet_grid.py +0 -0
  168. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/widgets/ui/collision_layer_mask.py +0 -0
  169. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/widgets/ui/collision_layer_sidebar.py +0 -0
  170. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/widgets/ui/draw_utils.py +0 -0
  171. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/widgets/ui/fileinput.py +0 -0
  172. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/widgets/ui/layer_type_dialog.py +0 -0
  173. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/widgets/ui/menubar.py +0 -0
  174. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/widgets/ui/mode_indicator.py +0 -0
  175. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/widgets/ui/notification.py +0 -0
  176. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/widgets/ui/property_editor.py +0 -0
  177. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/widgets/ui/region_selector.py +0 -0
  178. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/widgets/ui/status_bar.py +0 -0
  179. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/widgets/ui/theme.py +0 -0
  180. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/widgets/ui/tileset_type_dialog.py +0 -0
  181. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/src/widgets/ui/tooltip.py +0 -0
  182. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/tests/test_collision_layer_mask.py +0 -0
  183. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/tests/test_collision_layer_sidebar.py +0 -0
  184. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/tests/test_project_paths.py +0 -0
  185. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/tests/test_render_scale.py +0 -0
  186. {tilemap_editor-3.2.1 → tilemap_editor-3.2.3}/tests/test_tilemap_save.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tilemap-editor
3
- Version: 3.2.1
3
+ Version: 3.2.3
4
4
  Summary: Pygame tilemap editor with SVG icons, professional UI, and sprite animation 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 = "3.2.1"
7
+ version = "3.2.3"
8
8
  description = "Pygame tilemap editor with SVG icons, professional UI, and sprite animation tools"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -150,6 +150,9 @@ class Editor:
150
150
  self.running = False
151
151
  self.pan_mode = False
152
152
  self.autotile_mode = False
153
+ self.eraser_mode = False
154
+ self.select_mode = False
155
+ self._prev_tool = None
153
156
 
154
157
  if isinstance(size, tuple) and len(size) == 2:
155
158
  self.screen = pygame.display.set_mode(size, pygame.RESIZABLE)
@@ -684,13 +687,17 @@ class Editor:
684
687
  self.open_file_manager(
685
688
  on_select=self._launch_animation_editor_with_image,
686
689
  initial_dir=self.data_root,
687
- allowed_exts=[".png", ".jpg", ".jpeg"],
690
+ allowed_exts=[".png", ".jpg", ".jpeg", ".json"],
688
691
  mode="open",
689
692
  )
690
693
 
691
694
  def _launch_animation_editor_with_image(self, path: Path):
692
- """Launch animation editor subprocess with selected image."""
695
+ """Launch animation editor subprocess with selected image or JSON."""
693
696
  try:
697
+ if path.suffix.lower() == ".json":
698
+ self._launch_animation_editor_with_json(path)
699
+ return
700
+
694
701
  tile_size = "32x32"
695
702
  if hasattr(self.tilemap, "tile_size") and self.tilemap.tile_size:
696
703
  tw, th = self.tilemap.tile_size
@@ -711,6 +718,47 @@ class Editor:
711
718
  except Exception as e:
712
719
  error_handler.capture(e, context="launch_animation_editor")
713
720
 
721
+ def _launch_animation_editor_with_json(self, path: Path) -> None:
722
+ """Launch animation editor from a saved .anim.json file."""
723
+ try:
724
+ from plugins.sprite_animation.models import AnimationLibrary
725
+ from utils.project_paths import resolve_project_path
726
+
727
+ lib = AnimationLibrary.load(path)
728
+ spritesheet_path = lib.spritesheet_path
729
+ tile_size = lib.tile_size
730
+
731
+ if spritesheet_path:
732
+ resolved = resolve_project_path(
733
+ spritesheet_path,
734
+ path.parent,
735
+ fallback_roots=[self.base_path] if self.base_path else None,
736
+ must_exist=True,
737
+ )
738
+ else:
739
+ resolved = None
740
+
741
+ if not resolved or not resolved.exists():
742
+ print(f"Could not locate spritesheet for animation file: {path.name}")
743
+ return
744
+
745
+ args = [
746
+ str(resolved),
747
+ "--tile-size", f"{tile_size[0]}x{tile_size[1]}",
748
+ "--load", str(path),
749
+ "--data-root", str(self.data_root),
750
+ ]
751
+ process = launch_standalone(
752
+ "plugins.sprite_animation.standalone",
753
+ args,
754
+ cwd=self.base_path,
755
+ text=True,
756
+ )
757
+ self.child_processes.append(process)
758
+ print(f"Launched animation editor with: {path.name} (spritesheet: {resolved.name})")
759
+ except Exception as e:
760
+ error_handler.capture(e, context="launch_animation_editor")
761
+
714
762
  def launch_sprite_editor(self):
715
763
  """Launch the sprite editor in a new window."""
716
764
  self.open_file_manager(
@@ -1018,7 +1066,24 @@ class Editor:
1018
1066
  self.perform_load()
1019
1067
  continue
1020
1068
  elif event.key == pygame.K_SPACE:
1021
- self.pan_mode = not self.pan_mode
1069
+ if self.pan_mode:
1070
+ # Restoring: turn off pan, re-enable previous tool
1071
+ self.pan_mode = False
1072
+ if getattr(self, "_prev_tool", None) == "select":
1073
+ self.select_mode = True
1074
+ elif getattr(self, "_prev_tool", None) == "eraser":
1075
+ self.eraser_mode = True
1076
+ else:
1077
+ # Entering pan: save current tool, turn off others
1078
+ if self.select_mode:
1079
+ self._prev_tool = "select"
1080
+ elif self.eraser_mode:
1081
+ self._prev_tool = "eraser"
1082
+ else:
1083
+ self._prev_tool = None
1084
+ self.pan_mode = True
1085
+ self.select_mode = False
1086
+ self.eraser_mode = False
1022
1087
  continue
1023
1088
  elif event.mod & pygame.KMOD_CTRL and event.key == pygame.K_g:
1024
1089
  self.toggle_grid()
@@ -3,7 +3,7 @@ Character Collision Editor — Define collision shapes for character sprites.
3
3
 
4
4
  Layout:
5
5
  +----------------------------------------------------+
6
- | Toolbar: [Character Name] [Shape Type Buttons] |
6
+ | Toolbar: [Name: _______] [Shape Type Buttons] |
7
7
  +----------------------------------------------------+
8
8
  | |
9
9
  | Shape Editor |
@@ -16,6 +16,7 @@ Layout:
16
16
 
17
17
  from __future__ import annotations
18
18
 
19
+ import re
19
20
  from typing import Optional, Tuple, Dict, Any
20
21
  from pathlib import Path
21
22
 
@@ -30,6 +31,7 @@ from utils.error_handler import error_handler, error_context
30
31
  from widgets.ui.theme import COLORS, FONTS
31
32
  from widgets.ui.draw_utils import draw_panel, draw_button
32
33
  from widgets.ui.collision_layer_sidebar import CollisionLayerSidebar
34
+ from widgets.input import InlineTextInput
33
35
 
34
36
 
35
37
  class CharacterCollisionEditor:
@@ -73,6 +75,9 @@ class CharacterCollisionEditor:
73
75
  self._font = font_manager.get_font(FONTS.name, FONTS.size_md, FontWeight.REGULAR)
74
76
  self._font_sm = font_manager.get_font(FONTS.name, FONTS.size_sm, FontWeight.REGULAR)
75
77
 
78
+ # Editable name input
79
+ self._name_input = InlineTextInput("char_name", default_val=self.character_name)
80
+
76
81
  # Shape type buttons
77
82
  self.shape_buttons: Dict[ShapeType, Rect] = {}
78
83
  self._init_shape_buttons()
@@ -106,6 +111,18 @@ class CharacterCollisionEditor:
106
111
 
107
112
  self._init_shape_buttons()
108
113
 
114
+ def _get_save_name(self) -> str:
115
+ """Build filename from the name input.
116
+
117
+ Returns "<safe-name>-character.collision.json" if non-empty,
118
+ "character.collision.json" otherwise.
119
+ """
120
+ name = self._name_input.text.strip()
121
+ if name:
122
+ safe = re.sub(r'[^\w\-]+', '-', name).strip('-').lower()
123
+ return f"{safe}-character.collision.json"
124
+ return "character.collision.json"
125
+
109
126
  def get_collision_data(self) -> CharacterCollisionData:
110
127
  """Get the current collision data"""
111
128
  shape_data = self.shape_editor.get_shape_data()
@@ -145,7 +162,7 @@ class CharacterCollisionEditor:
145
162
  raise ValueError(f"Unknown shape type: {shape_type}")
146
163
 
147
164
  return CharacterCollisionData(
148
- name=self.character_name,
165
+ name=self._name_input.text.strip() or self.character_name,
149
166
  shape=shape,
150
167
  properties={
151
168
  "collision_layer": self.layer_sidebar.get_layer(),
@@ -156,12 +173,28 @@ class CharacterCollisionEditor:
156
173
  def load_collision_data(self, data: CharacterCollisionData) -> None:
157
174
  """Load collision data"""
158
175
  self.character_name = data.name
176
+ self._name_input.text = data.name
177
+ self._name_input.cursor_pos = len(data.name)
159
178
  self.shape_editor.load_shape_data(data.shape.to_dict())
160
179
  layer = data.properties.get("collision_layer", 1)
161
180
  mask = data.properties.get("collision_mask", 0xFFFF)
162
181
  self.layer_sidebar.set_layer(layer)
163
182
  self.layer_sidebar.set_mask(mask)
164
183
 
184
+ def _get_save_path(self) -> Path:
185
+ """Full path for saving/loading collision data."""
186
+ collision_dir = self._get_collision_dir()
187
+ return collision_dir / self._get_save_name()
188
+
189
+ def _get_load_path(self) -> Path:
190
+ """Path to load from — name-priority, fallback to default."""
191
+ collision_dir = self._get_collision_dir()
192
+ name_path = collision_dir / self._get_save_name()
193
+ if name_path.exists():
194
+ return name_path
195
+ # Fallback to default
196
+ return collision_dir / "character.collision.json"
197
+
165
198
  def _get_collision_dir(self) -> Path:
166
199
  """Get collision data directory (data_root/character_collision)"""
167
200
  if self._data_root is None:
@@ -189,11 +222,17 @@ class CharacterCollisionEditor:
189
222
  except Exception as e:
190
223
  error_handler.capture(e, context="load_character_collision")
191
224
 
225
+ def _name_input_rect(self) -> Rect:
226
+ """Screen rect for the editable name field in the toolbar."""
227
+ return Rect(self.rect.x + 62, self.rect.y + 10, 175, 28)
228
+
192
229
  def handle_event(self, event: pygame.event.Event) -> bool:
193
230
  """Handle input events"""
194
231
  if not self.visible:
195
232
  return False
196
233
 
234
+ mouse = pygame.mouse.get_pos()
235
+
197
236
  # Layer/mask sidebar handles events when open
198
237
  if self.layer_sidebar.handle_event(event):
199
238
  return True
@@ -202,19 +241,40 @@ class CharacterCollisionEditor:
202
241
  if self.layer_sidebar.handle_toggle_event(event):
203
242
  return True
204
243
 
205
- # Keyboard shortcut: L to toggle sidebar
206
- if event.type == pygame.KEYDOWN and event.key == pygame.K_l:
244
+ # Keyboard shortcut: L to toggle sidebar (skip when name input is focused)
245
+ if event.type == pygame.KEYDOWN and event.key == pygame.K_l and not self._name_input.is_focused:
207
246
  mods = pygame.key.get_mods()
208
247
  if not (mods & (pygame.KMOD_CTRL | pygame.KMOD_LMETA)):
209
248
  self.layer_sidebar.toggle()
210
249
  return True
211
250
 
251
+ # Name input handling
252
+ if self._name_input.is_focused:
253
+ if event.type == pygame.KEYDOWN:
254
+ if event.key == pygame.K_RETURN:
255
+ self._name_input.is_focused = False
256
+ return True
257
+ elif event.key == pygame.K_ESCAPE:
258
+ self._name_input.is_focused = False
259
+ return True
260
+ if self._name_input.handle_event(event, self._font):
261
+ return True
262
+ # Tab/click outside handled below
263
+
264
+ # Click-to-focus name input
265
+ if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
266
+ if self._name_input_rect().collidepoint(mouse):
267
+ self._name_input.is_focused = True
268
+ self._name_input.cursor_pos = len(self._name_input.text)
269
+ self._name_input.selection_start = None
270
+ return True
271
+ elif self._name_input.is_focused:
272
+ self._name_input.is_focused = False
273
+
212
274
  # Let shape editor handle events next
213
275
  if self.shape_editor.handle_event(event):
214
276
  return True
215
277
 
216
- mouse = pygame.mouse.get_pos()
217
-
218
278
  # Shape type button clicks
219
279
  if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
220
280
  for shape_type, button_rect in self.shape_buttons.items():
@@ -249,13 +309,30 @@ class CharacterCollisionEditor:
249
309
  toolbar_rect = Rect(self.rect.x, self.rect.y, self.rect.w, self.toolbar_height)
250
310
  draw_panel(screen, toolbar_rect, COLORS.header, COLORS.border)
251
311
 
252
- # Title
253
- title = self._font.render(
254
- f"Character Collision Editor {self.character_name}",
255
- True,
256
- COLORS.text
312
+ # "Name:" label
313
+ label = self._font_sm.render("Name:", True, COLORS.text)
314
+ screen.blit(label, (toolbar_rect.x + 10, toolbar_rect.y + 17))
315
+
316
+ # Editable name field
317
+ name_rect = self._name_input_rect()
318
+ bg_color = COLORS.panel if self._name_input.is_focused else COLORS.panel_alt
319
+ pygame.draw.rect(screen, bg_color, name_rect, border_radius=4)
320
+ pygame.draw.rect(
321
+ screen, COLORS.accent if self._name_input.is_focused else COLORS.border,
322
+ name_rect, 1, border_radius=4,
257
323
  )
258
- screen.blit(title, (toolbar_rect.x + 10, toolbar_rect.y + 15))
324
+
325
+ # Render input text
326
+ display_name = self._name_input.text or "character"
327
+ txt = self._font_sm.render(display_name, True, COLORS.text)
328
+ screen.blit(txt, (name_rect.x + 4, name_rect.y + 5))
329
+
330
+ # Cursor when focused
331
+ if self._name_input.is_focused and (pygame.time.get_ticks() // 400) % 2:
332
+ pre = self._font_sm.render(self._name_input.text[:self._name_input.cursor_pos], True, (0, 0, 0))
333
+ cx = name_rect.x + 4 + pre.get_width()
334
+ cy = name_rect.y + 5
335
+ pygame.draw.line(screen, COLORS.text, (cx, cy), (cx, cy + txt.get_height()), 1)
259
336
 
260
337
  # Shape type buttons
261
338
  for shape_type, button_rect in self.shape_buttons.items():
@@ -352,15 +429,14 @@ class CharacterCollisionEditor:
352
429
  # Ctrl+S / Cmd+S to save
353
430
  collision_dir = self._get_collision_dir()
354
431
  collision_dir.mkdir(parents=True, exist_ok=True)
355
- save_path = collision_dir / "character_collision.json"
432
+ save_path = self._get_save_path()
356
433
  self.save_to_file(save_path)
357
434
  print(f"Saved collision data to {save_path}")
358
435
  elif event.key == pygame.K_l and (
359
436
  pygame.key.get_mods() & (pygame.KMOD_LCTRL | pygame.KMOD_LMETA)
360
437
  ):
361
438
  # Ctrl+L / Cmd+L to load
362
- collision_dir = self._get_collision_dir()
363
- load_path = collision_dir / "character_collision.json"
439
+ load_path = self._get_load_path()
364
440
  if load_path.exists():
365
441
  self.load_from_file(load_path)
366
442
  print(f"Loaded collision data from {load_path}")
@@ -1367,7 +1367,7 @@ class SpriteAnimationEditor:
1367
1367
  self.preview.set_surface(self._surface, self._tile_size)
1368
1368
  self.timeline.surface = self._surface
1369
1369
  self.timeline.tile_size = self._tile_size
1370
- self.timeline._thumb_cache.clear()
1370
+ self.timeline.invalidate_cache()
1371
1371
 
1372
1372
  # Update input fields to show clamped values
1373
1373
  self._frame_width_input = str(width)
@@ -1404,7 +1404,7 @@ class SpriteAnimationEditor:
1404
1404
  if hasattr(self.timeline, "grid_offset_x"):
1405
1405
  self.timeline.grid_offset_x = offset_x
1406
1406
  self.timeline.grid_offset_y = offset_y
1407
- self.timeline._thumb_cache.clear()
1407
+ self.timeline.invalidate_cache()
1408
1408
 
1409
1409
  # Update preview with offset (if it has the attribute)
1410
1410
  if hasattr(self.preview, "grid_offset_x"):
@@ -1420,6 +1420,43 @@ class SpriteAnimationEditor:
1420
1420
  self._offset_x_input = str(self._grid_offset_x)
1421
1421
  self._offset_y_input = str(self._grid_offset_y)
1422
1422
 
1423
+ def _apply_library_grid_settings(self) -> None:
1424
+ """Sync tile_size and grid_offset from the loaded library to all widgets."""
1425
+ tw, th = self.library.tile_size
1426
+ self._tile_size = (tw, th)
1427
+ self.library.tile_size = (tw, th)
1428
+
1429
+ # Update frame picker
1430
+ self.frame_picker.set_surface(self._surface, self._tile_size)
1431
+
1432
+ # Update preview and timeline
1433
+ self.preview.set_surface(self._surface, self._tile_size)
1434
+ self.timeline.surface = self._surface
1435
+ self.timeline.tile_size = self._tile_size
1436
+ self.timeline.invalidate_cache()
1437
+
1438
+ # Update frame size input fields
1439
+ self._frame_width_input = str(tw)
1440
+ self._frame_height_input = str(th)
1441
+
1442
+ # Sync grid offset from library
1443
+ gx, gy = self.library.grid_offset
1444
+ self._grid_offset_x = gx
1445
+ self._grid_offset_y = gy
1446
+ self._offset_x_input = str(gx)
1447
+ self._offset_y_input = str(gy)
1448
+
1449
+ # Propagate offset to all widgets
1450
+ if hasattr(self.frame_picker, "set_grid_offset"):
1451
+ self.frame_picker.set_grid_offset(gx, gy)
1452
+ if hasattr(self.timeline, "grid_offset_x"):
1453
+ self.timeline.grid_offset_x = gx
1454
+ self.timeline.grid_offset_y = gy
1455
+ self.timeline.invalidate_cache()
1456
+ if hasattr(self.preview, "grid_offset_x"):
1457
+ self.preview.grid_offset_x = gx
1458
+ self.preview.grid_offset_y = gy
1459
+
1423
1460
  def _sync_active_animation(self) -> None:
1424
1461
  """Push current animation data to sub-widgets."""
1425
1462
  anim = self._get_active()
@@ -1843,6 +1880,7 @@ class SpriteAnimationEditor:
1843
1880
  print(f"Warning: Could not import FileManager: {e}")
1844
1881
  path = self._default_save_path()
1845
1882
  try:
1883
+ self.library.grid_offset = (self._grid_offset_x, self._grid_offset_y)
1846
1884
  self.library.save(path, base_path=path.parent)
1847
1885
  self._last_saved_path = path
1848
1886
  print(f"Animations saved to {path}")
@@ -1888,6 +1926,7 @@ class SpriteAnimationEditor:
1888
1926
  if self._last_saved_path:
1889
1927
  # Save to existing path
1890
1928
  try:
1929
+ self.library.grid_offset = (self._grid_offset_x, self._grid_offset_y)
1891
1930
  self.library.save(
1892
1931
  self._last_saved_path,
1893
1932
  base_path=self._last_saved_path.parent,
@@ -1913,6 +1952,7 @@ class SpriteAnimationEditor:
1913
1952
  try:
1914
1953
  self.library = AnimationLibrary.load(path)
1915
1954
  self._resolve_library_paths(path)
1955
+ self._apply_library_grid_settings()
1916
1956
  names = self.library.animation_names()
1917
1957
  self._active_anim_name = names[0] if names else None
1918
1958
  if not names:
@@ -1948,6 +1988,8 @@ class SpriteAnimationEditor:
1948
1988
  def _on_save_file_selected(self, path: Path) -> None:
1949
1989
  """Callback when user selects a file to save to."""
1950
1990
  try:
1991
+ # Sync current grid offset into library before saving
1992
+ self.library.grid_offset = (self._grid_offset_x, self._grid_offset_y)
1951
1993
  self.library.save(path, base_path=path.parent)
1952
1994
  self._last_saved_path = path # Track for quick save
1953
1995
  print(f"Animations saved to {path}")
@@ -1968,6 +2010,7 @@ class SpriteAnimationEditor:
1968
2010
  self.library = AnimationLibrary.load(path)
1969
2011
  self._resolve_library_paths(path)
1970
2012
  self._last_saved_path = path # Track loaded file as save location
2013
+ self._apply_library_grid_settings()
1971
2014
  names = self.library.animation_names()
1972
2015
  self._active_anim_name = names[0] if names else None
1973
2016
  if not names:
@@ -2110,6 +2153,7 @@ class SpriteAnimationEditor:
2110
2153
  def load_animation_data(self, data: dict) -> None:
2111
2154
  """Load animation library from a dict (e.g. from project JSON)."""
2112
2155
  self.library = AnimationLibrary.from_dict(data)
2156
+ self._apply_library_grid_settings()
2113
2157
  names = self.library.animation_names()
2114
2158
  self._active_anim_name = names[0] if names else None
2115
2159
  if not names:
@@ -167,6 +167,7 @@ class AnimationLibrary:
167
167
  animations: Dict[str, Animation] = field(default_factory=dict)
168
168
  spritesheet_path: Optional[str] = None
169
169
  tile_size: Tuple[int, int] = (32, 32)
170
+ grid_offset: Tuple[int, int] = (0, 0)
170
171
 
171
172
  def add_animation(self, anim: Animation) -> None:
172
173
  self.animations[anim.name] = anim
@@ -199,6 +200,7 @@ class AnimationLibrary:
199
200
  return {
200
201
  "spritesheet_path": spritesheet_path,
201
202
  "tile_size": list(self.tile_size),
203
+ "grid_offset": list(self.grid_offset),
202
204
  "animations": {
203
205
  name: anim.to_dict() for name, anim in self.animations.items()
204
206
  },
@@ -209,6 +211,7 @@ class AnimationLibrary:
209
211
  lib = AnimationLibrary(
210
212
  spritesheet_path=data.get("spritesheet_path"),
211
213
  tile_size=tuple(data.get("tile_size", [32, 32])),
214
+ grid_offset=tuple(data.get("grid_offset", [0, 0])),
212
215
  )
213
216
  for name, anim_data in data.get("animations", {}).items():
214
217
  lib.animations[name] = Animation.from_dict(anim_data)
@@ -140,6 +140,10 @@ class Timeline:
140
140
  self.tile_size = tile_size
141
141
  self._thumb_cache.clear()
142
142
 
143
+ def invalidate_cache(self) -> None:
144
+ """Clear the thumbnail cache. Call after external changes to surface, tile_size, or grid offset."""
145
+ self._thumb_cache.clear()
146
+
143
147
  def resize(self, rect: Rect) -> None:
144
148
  self.rect = rect
145
149
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tilemap-editor
3
- Version: 3.2.1
3
+ Version: 3.2.3
4
4
  Summary: Pygame tilemap editor with SVG icons, professional UI, and sprite animation tools
5
5
  Author: tilemap editor contributors
6
6
  License: Proprietary