meltygui 0.1.0__py3-none-any.whl

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 (372) hide show
  1. meltygui/__init__.py +107 -0
  2. meltygui/accounts/__init__.py +0 -0
  3. meltygui/accounts/internet_accounts.py +1355 -0
  4. meltygui/chat/__init__.py +91 -0
  5. meltygui/chat/activity.py +75 -0
  6. meltygui/chat/backends.py +36 -0
  7. meltygui/chat/chat_interface.py +732 -0
  8. meltygui/chat/chat_proxy.py +352 -0
  9. meltygui/chat/codex_proxy.py +592 -0
  10. meltygui/chat/codex_settings.py +100 -0
  11. meltygui/chat/codex_transport.py +60 -0
  12. meltygui/chat/command_parser.py +204 -0
  13. meltygui/chat/images.py +227 -0
  14. meltygui/chat/messages.py +417 -0
  15. meltygui/chat/metadata.py +139 -0
  16. meltygui/chat/writer_locks.py +64 -0
  17. meltygui/code/__init__.py +0 -0
  18. meltygui/code/basic_converters.py +533 -0
  19. meltygui/code/chain_converters.py +2111 -0
  20. meltygui/code/code_checks.py +2209 -0
  21. meltygui/code/core_syntax.py +1430 -0
  22. meltygui/code/file_converters.py +1933 -0
  23. meltygui/code/fileref.py +702 -0
  24. meltygui/code/hotswap_guard.py +144 -0
  25. meltygui/code/libcst_conversion.py +9724 -0
  26. meltygui/code/live_instrument.py +392 -0
  27. meltygui/code/live_view.py +2490 -0
  28. meltygui/code/melty_scan.py +2684 -0
  29. meltygui/code/new_codecs.py +1255 -0
  30. meltygui/code/new_converters.py +3017 -0
  31. meltygui/code/project_code.py +278 -0
  32. meltygui/code/source_context.py +63 -0
  33. meltygui/code/symbol_roster.py +1588 -0
  34. meltygui/code/syntax_check.py +34 -0
  35. meltygui/code/syntax_check_worker.py +114 -0
  36. meltygui/completion/__init__.py +0 -0
  37. meltygui/completion/fim.py +1232 -0
  38. meltygui/completion/fim_context.py +481 -0
  39. meltygui/completion/providers/__init__.py +0 -0
  40. meltygui/completion/providers/anthropic_oauth.py +446 -0
  41. meltygui/completion/providers/anthropic_requests.py +69 -0
  42. meltygui/completion/providers/claude.py +203 -0
  43. meltygui/completion/providers/claude_usage.py +499 -0
  44. meltygui/completion/providers/codex_accounts.py +180 -0
  45. meltygui/completion/providers/copilot.py +617 -0
  46. meltygui/completion/providers/oauth_popup.py +220 -0
  47. meltygui/completion/providers/ollama.py +320 -0
  48. meltygui/completion/providers/profiles.py +23 -0
  49. meltygui/core/README.md +88 -0
  50. meltygui/core/__init__.py +1 -0
  51. meltygui/core/automation/__init__.py +1 -0
  52. meltygui/core/automation/action_core.py +153 -0
  53. meltygui/core/automation/collection_action.py +45 -0
  54. meltygui/core/automation/mcp_eval.py +167 -0
  55. meltygui/core/automation/mcp_hotswap.py +107 -0
  56. meltygui/core/automation/mcp_query.py +552 -0
  57. meltygui/core/automation/mcp_server.py +657 -0
  58. meltygui/core/automation/orchestration_core.py +2636 -0
  59. meltygui/core/automation/query_core.py +124 -0
  60. meltygui/core/automation/search_core.py +26 -0
  61. meltygui/core/automation/selector_core.py +340 -0
  62. meltygui/core/automation/value_core.py +1752 -0
  63. meltygui/core/cache/__init__.py +1 -0
  64. meltygui/core/cache/cache_diagnostics.py +0 -0
  65. meltygui/core/cache/invalidation_decoration.py +153 -0
  66. meltygui/core/cache/invalidation_tracker.py +43 -0
  67. meltygui/core/cache/tile_cache.py +5968 -0
  68. meltygui/core/conversion/__init__.py +1 -0
  69. meltygui/core/conversion/bubbling.py +599 -0
  70. meltygui/core/conversion/cache_tree.py +188 -0
  71. meltygui/core/conversion/chain.py +113 -0
  72. meltygui/core/conversion/converter_register.py +145 -0
  73. meltygui/core/conversion/data_decoration.py +67 -0
  74. meltygui/core/conversion/dict_conversion.py +1815 -0
  75. meltygui/core/conversion/dict_conversion_util.py +177 -0
  76. meltygui/core/conversion/dynamic_obj.py +89 -0
  77. meltygui/core/conversion/graph_compare.py +183 -0
  78. meltygui/core/conversion/load_save_v2.py +1032 -0
  79. meltygui/core/conversion/missing_saved_class.py +39 -0
  80. meltygui/core/conversion/path_finder.py +606 -0
  81. meltygui/core/conversion/render_host.py +1083 -0
  82. meltygui/core/core_render.py +6537 -0
  83. meltygui/core/definition_hotswap.py +231 -0
  84. meltygui/core/diagnostics/__init__.py +1 -0
  85. meltygui/core/diagnostics/attribute_churn.py +38 -0
  86. meltygui/core/diagnostics/fps_counter.py +39 -0
  87. meltygui/core/diagnostics/gpu_frame_timer.py +103 -0
  88. meltygui/core/diagnostics/inspection_core.py +169 -0
  89. meltygui/core/diagnostics/monitor_core.py +105 -0
  90. meltygui/core/diagnostics/notifications.py +706 -0
  91. meltygui/core/diagnostics/perf_trace.py +281 -0
  92. meltygui/core/diagnostics/profile_decoration.py +88 -0
  93. meltygui/core/diagnostics/resize_trace.py +62 -0
  94. meltygui/core/diagnostics/screenshot_core.py +247 -0
  95. meltygui/core/diagnostics/session_status.py +98 -0
  96. meltygui/core/diagnostics/trace_core.py +445 -0
  97. meltygui/core/files/__init__.py +1 -0
  98. meltygui/core/files/file_core.py +208 -0
  99. meltygui/core/files/file_explorer_core.py +104 -0
  100. meltygui/core/files/file_tree_core.py +198 -0
  101. meltygui/core/files/file_watch_core.py +43 -0
  102. meltygui/core/files/import_graph_core.py +43 -0
  103. meltygui/core/files/metadata_core.py +51 -0
  104. meltygui/core/graphics/__init__.py +1 -0
  105. meltygui/core/graphics/cuda_context_core.py +166 -0
  106. meltygui/core/graphics/cuda_interop_core.py +136 -0
  107. meltygui/core/graphics/cuda_kernel_core.py +91 -0
  108. meltygui/core/graphics/framebuffer_recorder.py +337 -0
  109. meltygui/core/graphics/gl_state.py +658 -0
  110. meltygui/core/graphics/lut_core.py +52 -0
  111. meltygui/core/graphics/overlay_renderer.py +984 -0
  112. meltygui/core/graphics/scene_target.py +180 -0
  113. meltygui/core/graphics/screenshot.py +439 -0
  114. meltygui/core/graphics/shader_func.py +478 -0
  115. meltygui/core/graphics/tensor_core.py +45 -0
  116. meltygui/core/graphics/text_texture.py +329 -0
  117. meltygui/core/graphics/wayland_color.py +635 -0
  118. meltygui/core/input/__init__.py +1 -0
  119. meltygui/core/input/collision.py +165 -0
  120. meltygui/core/input/drag_drop_core.py +1525 -0
  121. meltygui/core/input/hypr_left_drag.py +323 -0
  122. meltygui/core/input/input_core.py +245 -0
  123. meltygui/core/input/input_handler.py +1101 -0
  124. meltygui/core/input/mouse_cursor.py +355 -0
  125. meltygui/core/input/pynput_backend.py +1054 -0
  126. meltygui/core/input/space_mouse.py +338 -0
  127. meltygui/core/input/touchpad_backend.py +393 -0
  128. meltygui/core/input/view_selection.py +177 -0
  129. meltygui/core/layout/__init__.py +1 -0
  130. meltygui/core/layout/column_core.py +2153 -0
  131. meltygui/core/layout/cursor_core.py +161 -0
  132. meltygui/core/layout/dropdown_core.py +278 -0
  133. meltygui/core/layout/edge_constraints.py +155 -0
  134. meltygui/core/layout/grid_core.py +117 -0
  135. meltygui/core/layout/header_core.py +23 -0
  136. meltygui/core/layout/header_runtime.py +67 -0
  137. meltygui/core/layout/layout_core.py +87 -0
  138. meltygui/core/layout/tile_manager_core.py +591 -0
  139. meltygui/core/melty.py +6726 -0
  140. meltygui/core/module_map.json +896 -0
  141. meltygui/core/module_names.py +19 -0
  142. meltygui/core/rendering/__init__.py +1 -0
  143. meltygui/core/rendering/core_decoration.py +431 -0
  144. meltygui/core/rendering/core_render_helpers.py +328 -0
  145. meltygui/core/rendering/func_metadata.py +398 -0
  146. meltygui/core/rendering/mode.py +818 -0
  147. meltygui/core/rendering/mode_defaults.py +41 -0
  148. meltygui/core/rendering/modes.py +136 -0
  149. meltygui/core/rendering/parameter_core.py +1665 -0
  150. meltygui/core/rendering/render_dispatch.py +1891 -0
  151. meltygui/core/rendering/render_funcs.py +273 -0
  152. meltygui/core/rendering/shaped.py +312 -0
  153. meltygui/core/rendering/window_decoration.py +25 -0
  154. meltygui/core/runtime/__init__.py +1 -0
  155. meltygui/core/runtime/app.py +735 -0
  156. meltygui/core/runtime/app_session.py +140 -0
  157. meltygui/core/runtime/background.py +564 -0
  158. meltygui/core/runtime/extensions.py +53 -0
  159. meltygui/core/runtime/gc_manager.py +1163 -0
  160. meltygui/core/runtime/lifecycle.py +21 -0
  161. meltygui/core/runtime/paths.py +27 -0
  162. meltygui/core/runtime/settings.py +14 -0
  163. meltygui/core/runtime/singleton.py +16 -0
  164. meltygui/core/runtime/thread_safe_bool.py +24 -0
  165. meltygui/core/runtime/thread_signal.py +30 -0
  166. meltygui/core/runtime/toggles.py +3115 -0
  167. meltygui/core/services/__init__.py +1 -0
  168. meltygui/core/services/account_core.py +10 -0
  169. meltygui/core/services/chat_core.py +19 -0
  170. meltygui/core/services/claude_terminal_core.py +346 -0
  171. meltygui/core/services/terminal_core.py +458 -0
  172. meltygui/core/services/terminal_runtime.py +78 -0
  173. meltygui/core/styling/__init__.py +1 -0
  174. meltygui/core/styling/color_core.py +46 -0
  175. meltygui/core/styling/fonts.py +639 -0
  176. meltygui/core/styling/global_style.py +338 -0
  177. meltygui/core/styling/style.py +198 -0
  178. meltygui/core/styling/style_core.py +522 -0
  179. meltygui/core/styling/warm_start.py +149 -0
  180. meltygui/core/windowing/__init__.py +1 -0
  181. meltygui/core/windowing/backends/PYIMGUI_LICENSE +28 -0
  182. meltygui/core/windowing/backends/__init__.py +1 -0
  183. meltygui/core/windowing/backends/imgui_renderer.py +138 -0
  184. meltygui/core/windowing/backends/native_wayland.py +850 -0
  185. meltygui/core/windowing/backends/protocols/xdg-decoration-unstable-v1.xml +156 -0
  186. meltygui/core/windowing/backends/protocols/xdg-shell.xml +1420 -0
  187. meltygui/core/windowing/backends/wayland_protocol.py +101 -0
  188. meltygui/core/windowing/dock_core.py +182 -0
  189. meltygui/core/windowing/frame_geometry.py +42 -0
  190. meltygui/core/windowing/geometry_feed.py +864 -0
  191. meltygui/core/windowing/glfw_utils.py +1343 -0
  192. meltygui/core/windowing/os_frame.py +1552 -0
  193. meltygui/core/windowing/surface.py +643 -0
  194. meltygui/core/windowing/titlebar.py +1560 -0
  195. meltygui/core/windowing/titlebar_buttons.py +281 -0
  196. meltygui/core/windowing/wayland_move.py +932 -0
  197. meltygui/core/windowing/window_api.py +62 -0
  198. meltygui/core/windowing/window_constants.py +339 -0
  199. meltygui/core/windowing/window_visibility.py +162 -0
  200. meltygui/debug/__init__.py +0 -0
  201. meltygui/debug/app_view_utils.py +9 -0
  202. meltygui/editor/__init__.py +0 -0
  203. meltygui/editor/bash_syntax.py +30 -0
  204. meltygui/editor/code_line_fast.py +152 -0
  205. meltygui/editor/diff.py +139 -0
  206. meltygui/editor/external_changes.py +159 -0
  207. meltygui/editor/file_header.py +41 -0
  208. meltygui/editor/live_usage.py +169 -0
  209. meltygui/editor/live_view_views.py +1803 -0
  210. meltygui/editor/pending_save.py +1351 -0
  211. meltygui/editor/roster_tints.py +547 -0
  212. meltygui/editor/source_preview.py +16 -0
  213. meltygui/editor/source_tools.py +10 -0
  214. meltygui/editor/source_ui.py +70 -0
  215. meltygui/editor/spell_check.py +77 -0
  216. meltygui/editor/text_editor.py +9076 -0
  217. meltygui/editor/usage_picker.py +538 -0
  218. meltygui/events/__init__.py +0 -0
  219. meltygui/events/example.py +118 -0
  220. meltygui/examples/__init__.py +0 -0
  221. meltygui/examples/columns_demo.py +33 -0
  222. meltygui/examples/columns_window_demo.py +60 -0
  223. meltygui/examples/context_menu_demo.py +24 -0
  224. meltygui/examples/context_menu_window_demo.py +49 -0
  225. meltygui/examples/gui_playground.py +127 -0
  226. meltygui/examples/live_view_playground.py +256 -0
  227. meltygui/examples/lora.py +43 -0
  228. meltygui/examples/lora_data.py +59 -0
  229. meltygui/examples/lora_policies.py +67 -0
  230. meltygui/examples/mode_demo.py +49 -0
  231. meltygui/examples/modifies_demo.py +119 -0
  232. meltygui/examples/scalar_policies.py +60 -0
  233. meltygui/examples/style_layouts.py +149 -0
  234. meltygui/examples/tile_manager_demo.py +74 -0
  235. meltygui/examples/tint_demo.py +160 -0
  236. meltygui/examples/tint_functions.py +56 -0
  237. meltygui/examples/trace_demo.py +88 -0
  238. meltygui/examples/two_windows.py +36 -0
  239. meltygui/files/__init__.py +0 -0
  240. meltygui/files/fast_file_explorer.py +439 -0
  241. meltygui/gnome_extension/lsd-window-geometry@latent-descent/extension.js +237 -0
  242. meltygui/gnome_extension/lsd-window-geometry@latent-descent/lsd-window-geometry@latent-descent.iml +9 -0
  243. meltygui/gnome_extension/lsd-window-geometry@latent-descent/metadata.json +7 -0
  244. meltygui/graphics/__init__.py +6 -0
  245. meltygui/graphics/base.py +85 -0
  246. meltygui/graphics/examples.py +507 -0
  247. meltygui/graphics/executor.py +520 -0
  248. meltygui/graphics/filter.py +667 -0
  249. meltygui/graphics/filter.pyi +856 -0
  250. meltygui/graphics/generate_stubs.py +22 -0
  251. meltygui/graphics/registry.py +203 -0
  252. meltygui/graphics/shader_compiler.py +155 -0
  253. meltygui/graphics/shaders.py +1302 -0
  254. meltygui/graphics/stub_generator.py +250 -0
  255. meltygui/graphics/texture_manager.py +170 -0
  256. meltygui/graphics/texture_min_max.py +295 -0
  257. meltygui/hdr_color.py +757 -0
  258. meltygui/image_load.py +308 -0
  259. meltygui/model/__init__.py +1 -0
  260. meltygui/model/account_model.py +142 -0
  261. meltygui/model/camera_model.py +159 -0
  262. meltygui/model/chat_model.py +86 -0
  263. meltygui/model/code_model.py +62 -0
  264. meltygui/model/code_proxy_model.py +876 -0
  265. meltygui/model/collection_model.py +41 -0
  266. meltygui/model/color_model.py +127 -0
  267. meltygui/model/cuda_tensor_model.py +36 -0
  268. meltygui/model/cuda_texture_model.py +149 -0
  269. meltygui/model/dropdown_model.py +137 -0
  270. meltygui/model/file_metadata_model.py +73 -0
  271. meltygui/model/file_model.py +289 -0
  272. meltygui/model/format_model.py +390 -0
  273. meltygui/model/graph_model.py +98 -0
  274. meltygui/model/icon_model.py +1024 -0
  275. meltygui/model/import_graph_model.py +468 -0
  276. meltygui/model/layout_model.py +15 -0
  277. meltygui/model/lut_model.py +266 -0
  278. meltygui/model/search_model.py +173 -0
  279. meltygui/model/tensor_model.py +402 -0
  280. meltygui/model/terminal_model.py +329 -0
  281. meltygui/model/texture_model.py +146 -0
  282. meltygui/model/tile_model.py +24 -0
  283. meltygui/model/trace_model.py +198 -0
  284. meltygui/model/trace_report_model.py +146 -0
  285. meltygui/models/__init__.py +0 -0
  286. meltygui/models/file_meta.py +613 -0
  287. meltygui/models/function_console.py +184 -0
  288. meltygui/models/orchestration.py +48 -0
  289. meltygui/pbr.py +1576 -0
  290. meltygui/png_unfilter.c +49 -0
  291. meltygui/resources/JetBrainsMono-Regular.ttf +0 -0
  292. meltygui/resources/THIRD_PARTY_NOTICES.md +21 -0
  293. meltygui/resources/dejavu/DejaVuSans-Bold.ttf +0 -0
  294. meltygui/resources/dejavu/DejaVuSans-ExtraLight.ttf +0 -0
  295. meltygui/resources/dejavu/DejaVuSans.ttf +0 -0
  296. meltygui/resources/dejavu/LICENSE.txt +78 -0
  297. meltygui/resources/fontawesome-LICENSE.txt +121 -0
  298. meltygui/resources/fontawesome-webfont.ttf +0 -0
  299. meltygui/resources/hdri/studio_small_09_1k.hdr +0 -0
  300. meltygui/resources/jetbrains-weights/JetBrainsMono-Bold.ttf +0 -0
  301. meltygui/resources/jetbrains-weights/JetBrainsMono-ExtraBold.ttf +0 -0
  302. meltygui/resources/jetbrains-weights/JetBrainsMono-ExtraLight.ttf +0 -0
  303. meltygui/resources/jetbrains-weights/JetBrainsMono-Light.ttf +0 -0
  304. meltygui/resources/jetbrains-weights/JetBrainsMono-Medium.ttf +0 -0
  305. meltygui/resources/jetbrains-weights/JetBrainsMono-SemiBold.ttf +0 -0
  306. meltygui/resources/jetbrains-weights/JetBrainsMono-Thin.ttf +0 -0
  307. meltygui/resources/jetbrains-weights/OFL.txt +93 -0
  308. meltygui/resources/jetbrains-weights/README.md +2 -0
  309. meltygui/state/__init__.py +0 -0
  310. meltygui/state/account_state.py +22 -0
  311. meltygui/state/animation_state.py +97 -0
  312. meltygui/state/annotation_state.py +22 -0
  313. meltygui/state/chat_state.py +36 -0
  314. meltygui/state/code_state.py +10 -0
  315. meltygui/state/core_enums.py +59 -0
  316. meltygui/state/core_markers.py +115 -0
  317. meltygui/state/core_undo.py +1075 -0
  318. meltygui/state/file_state.py +75 -0
  319. meltygui/state/graph_state.py +26 -0
  320. meltygui/state/inspection_state.py +47 -0
  321. meltygui/state/menu_state.py +10 -0
  322. meltygui/state/model_enums.py +11 -0
  323. meltygui/state/new_core_model.py +2394 -0
  324. meltygui/state/orchestration_state.py +14 -0
  325. meltygui/state/query_state.py +24 -0
  326. meltygui/state/tensor_state.py +10 -0
  327. meltygui/state/terminal_state.py +23 -0
  328. meltygui/state/trace_state.py +32 -0
  329. meltygui/state/voxel_state.py +12 -0
  330. meltygui/text_index.py +816 -0
  331. meltygui/utils/__init__.py +0 -0
  332. meltygui/utils/jump_to_code.py +344 -0
  333. meltygui/utils/pkl_inspect.py +90 -0
  334. meltygui/utils/render_utils.py +1419 -0
  335. meltygui/view/__init__.py +1 -0
  336. meltygui/view/account_view.py +524 -0
  337. meltygui/view/action_view.py +73 -0
  338. meltygui/view/chat_decoration_view.py +112 -0
  339. meltygui/view/chat_view.py +1703 -0
  340. meltygui/view/code_view.py +2677 -0
  341. meltygui/view/collection_view.py +1185 -0
  342. meltygui/view/color_view.py +824 -0
  343. meltygui/view/control_view.py +559 -0
  344. meltygui/view/decoration_view.py +439 -0
  345. meltygui/view/diagnostic_view.py +177 -0
  346. meltygui/view/dropdown_view.py +1082 -0
  347. meltygui/view/file_view.py +1599 -0
  348. meltygui/view/graph_cuda_view.py +105 -0
  349. meltygui/view/graph_view.py +882 -0
  350. meltygui/view/header_view.py +848 -0
  351. meltygui/view/input_view.py +238 -0
  352. meltygui/view/inspection_view.py +1783 -0
  353. meltygui/view/layout_view.py +596 -0
  354. meltygui/view/lut_view.py +45 -0
  355. meltygui/view/menu_view.py +212 -0
  356. meltygui/view/orchestration_view.py +658 -0
  357. meltygui/view/query_view.py +118 -0
  358. meltygui/view/search_view.py +342 -0
  359. meltygui/view/tab_view.py +258 -0
  360. meltygui/view/tensor_view.py +430 -0
  361. meltygui/view/terminal_view.py +355 -0
  362. meltygui/view/text_view.py +8031 -0
  363. meltygui/view/texture_view.py +480 -0
  364. meltygui/view/tile_view.py +38 -0
  365. meltygui/view/trace_view.py +923 -0
  366. meltygui/view/voxel_cuda_view.py +824 -0
  367. meltygui/view/voxel_view.py +1860 -0
  368. meltygui/view/window_view.py +111 -0
  369. meltygui-0.1.0.dist-info/METADATA +143 -0
  370. meltygui-0.1.0.dist-info/RECORD +372 -0
  371. meltygui-0.1.0.dist-info/WHEEL +4 -0
  372. meltygui-0.1.0.dist-info/licenses/LICENSE +202 -0
@@ -0,0 +1,818 @@
1
+ import types
2
+ from collections import defaultdict
3
+ from dataclasses import dataclass
4
+ from enum import Enum
5
+ from pathlib import Path, PosixPath
6
+ from typing import Optional, Any
7
+
8
+ from meltygui.state.new_core_model import Anchor
9
+ from meltygui.core.conversion.dict_conversion import DictConversion
10
+ from meltygui.core.rendering.render_funcs import RenderFuncs
11
+ from meltygui.core.runtime.toggles import WindowManager
12
+ from meltygui.code.chain_converters import module_to_address
13
+ from meltygui.code.chain_converters import address_to_general_parse
14
+ from meltygui.code.chain_converters import general_parse_to_address
15
+ from meltygui.code.chain_converters import address_to_module
16
+ from meltygui.code.chain_converters import class_to_address
17
+ from meltygui.code.chain_converters import address_to_class
18
+ from meltygui.code.chain_converters import function_to_address
19
+ from meltygui.code.chain_converters import address_to_function
20
+ from meltygui.code.chain_converters import general_parse_to_str
21
+ from meltygui.code.chain_converters import str_to_general_parse
22
+ from meltygui.code.chain_converters import focus
23
+ from meltygui.code.chain_converters import caller_to_address
24
+ from meltygui.code.chain_converters import address_to_call_parse
25
+ from meltygui.code.chain_converters import call_dict_to_save
26
+ from meltygui.code.chain_converters import class_to_address_incl_overrides
27
+ from meltygui.code.file_converters import path_to_dict
28
+ from meltygui.code.file_converters import rf_bytes_to_str
29
+
30
+ # Register built-in views used by lazy render-function handles in the modes.
31
+ import meltygui.view.color_view
32
+ import meltygui.view.decoration_view
33
+ import meltygui.view.diagnostic_view
34
+ import meltygui.view.search_view
35
+ import meltygui.view.tab_view
36
+ import meltygui.view.texture_view
37
+ import meltygui.view.window_view
38
+ from meltygui.code.file_converters import rf_dict_to_path
39
+ from meltygui.code.file_converters import rf_str_to_bytes
40
+ from meltygui.code.libcst_conversion import GeneralParse
41
+ from meltygui.code.libcst_conversion import Conditional
42
+ from meltygui.code.libcst_conversion import Comment
43
+ from meltygui.code.libcst_conversion import dict_to_cst
44
+ from meltygui.code.libcst_conversion import cst_module_to_str
45
+ from meltygui.code.libcst_conversion import str_to_cst_module
46
+ from meltygui.code.libcst_conversion import cst_module_to_dict
47
+ from meltygui.code.libcst_conversion import dict_to_cst_module
48
+ from meltygui.code.new_codecs import CallSite
49
+ from meltygui.code.new_codecs import Decorations
50
+ from meltygui.core.rendering.window_decoration import window
51
+ from meltygui.view.header_view import draw_footer
52
+ from meltygui.view.header_view import draw_header_end
53
+ from meltygui.view.header_view import draw_header
54
+ from meltygui.model.code_proxy_model import *
55
+ from meltygui.view.collection_view import draw_collection
56
+ from meltygui.view.code_view import draw_comment
57
+ from meltygui.core.rendering.render_dispatch import sort_dict_alphabetically
58
+ from meltygui.core.rendering.render_dispatch import unsort_dict_alphabetically
59
+ from meltygui.view.inspection_view import draw_with_modes
60
+ from meltygui.view.code_view import draw_type
61
+ from meltygui.core.rendering.render_dispatch import class_to_var_dict
62
+ from meltygui.core.rendering.render_dispatch import var_dict_to_class
63
+ from meltygui.view.dropdown_view import draw_drop_down_item
64
+ from meltygui.view.code_view import draw_type_name
65
+ from meltygui.core.rendering.render_dispatch import type_lens
66
+ from meltygui.view.text_view import draw_text
67
+ from meltygui.code.new_converters import code_file_io
68
+ from meltygui.code.new_converters import convert_in_and_out
69
+ from meltygui.code.new_converters import string_to_cst_module
70
+ from meltygui.code.new_converters import cst_module_to_string
71
+ from meltygui.view.code_view import draw_text_from_code_cache
72
+ from meltygui.view.code_view import draw_code_tabs_from_cache
73
+
74
+
75
+ def compute_height(draw_state):
76
+ if draw_state._parent is not None:
77
+ top_offset = draw_state.abs_top - draw_state._parent.abs_top
78
+ return draw_state._parent.height - top_offset - 40
79
+ else:
80
+ return 500
81
+
82
+
83
+ @dataclass
84
+ class ModeOverrides:
85
+ kwargs: Optional[dict] = None
86
+ func: Optional[callable] = None
87
+ recursive: Optional[bool] = True
88
+ route: Optional[dict] = None
89
+
90
+
91
+ @window
92
+ class Mode(Enum):
93
+ def __reduce_ex__(self, protocol):
94
+ # Pickle BY NAME. Enum's default pickles by VALUE, and the values are
95
+ # ModeOverrides dicts full of live functions/classes - unpicklable, so
96
+ # any structure holding a resolved Mode member (a cst-dict parse of a
97
+ # span saying `mode=Mode.X`) silently failed to serialize and disabled
98
+ # the cst-dict cache for that file (full cold parse every session).
99
+ # getattr(Mode, name) at load also drives hotswap's enum member
100
+ # reconcile: the loading session's live member is returned.
101
+ return (getattr, (self.__class__, self._name_))
102
+
103
+ def get_config_for(self, input_value=None, the_type=None):
104
+ if input_value is not None:
105
+ the_type = type(input_value)
106
+ config = self.unwrapped.get(the_type, None)
107
+ if config is not None:
108
+ return config
109
+
110
+ for super_type in type(input_value).__mro__:
111
+ config = self.unwrapped.get(super_type, None)
112
+ if config is not None:
113
+ return config
114
+
115
+ if Any in self.unwrapped:
116
+ return self.unwrapped[Any]
117
+ return None
118
+
119
+ def __init__(self, *args, **kwargs):
120
+ unwrapped = {}
121
+ if isinstance(self.value, dict):
122
+ for key, value in self.value.items():
123
+ if isinstance(key, tuple):
124
+ for sub_key in key:
125
+ unwrapped[sub_key] = value
126
+ else:
127
+ unwrapped[key] = value
128
+ self.unwrapped = unwrapped
129
+
130
+ # The code-host-cache route (vs inline convertors): code_file_io owns
131
+ # load/save of the span. draw_code_tabs_from_cache shows the structured |
132
+ # text tabs with the parse loaded from the shared dict_host
133
+ # (code_hosts_for). A class edit in the structured tab also drives the
134
+ # live type immediately (_live_apply_class_vars) ahead of any recompile.
135
+ NEW_CODE = {
136
+ (type, types.FunctionType, types.ModuleType, CallSite, Decorations): ModeOverrides(
137
+ kwargs={"auto_load_edits": True,
138
+ "auto_load": True,
139
+ "auto_save": True,
140
+ 'view_func': draw_code_tabs_from_cache,
141
+ "disable_scroll": True,
142
+ "with_header": draw_header,
143
+ "child_kwargs": {
144
+ 'column_widths': [358],
145
+ },
146
+ },
147
+ func=code_file_io
148
+ )
149
+ }
150
+
151
+ READ_ONLY = {
152
+ (Any): ModeOverrides(
153
+ kwargs={"show_bg": True, "selectable": False, "header_same_line": True, "show_header": True,
154
+ "show_add_delete": False, "bg_offset": -1,
155
+ "use_cache": True, "initial": {"expanded": False, "closed": False}},
156
+ recursive=True,
157
+ ),
158
+ (str, float, int, bool, types.NoneType): ModeOverrides(
159
+ kwargs={"show_bg": False, "selectable": False, "show_add_delete": False, "show_header": True,
160
+ "expanded": True, "use_cache": True, "shadow": False},
161
+ ),
162
+ (type): ModeOverrides(
163
+ func=draw_type_name,
164
+ kwargs={"show_bg": False, "selectable": False, "show_add_delete": False, "show_header": True,
165
+ 'is_tree': False, "use_cache": True, "shadow": False, 'tint': (0.8, 0.8, 0.6)},
166
+ ),
167
+
168
+ }
169
+
170
+ # [tint=(0.2,0.1,0.1)]
171
+ SORT = {
172
+ defaultdict: ModeOverrides(
173
+ kwargs={"show_bg": True, "selectable": False, "use_cache": True},
174
+ recursive=True,
175
+ func=(sort_dict_alphabetically,
176
+ (draw_collection, {"show_add_delete": False, "selectable": False, "show_bg": False}),
177
+
178
+ ))
179
+ }
180
+
181
+ DROPDOWN_WINDOW = {
182
+ (Any): ModeOverrides(
183
+ kwargs={"show_bg": False, "selectable": False, "min_width": -2, "min_height": 18, "wrap": True,
184
+ "z_offset": 0,
185
+ "shadow": False, "is_tree": False, "use_cache": True, "layer_offset": 1},
186
+ recursive=False,
187
+ func=draw_drop_down_item
188
+ ),
189
+ (dict, list, tuple): ModeOverrides(
190
+ kwargs={"show_bg": True, "selectable": False, "use_cache": True, "melty_window": False,
191
+ "closable": True,
192
+ "with_header_end": draw_header_end, "auto_resize": True, "draggable": True,
193
+ 'shadow': True, "return_item": True,
194
+ "show_tint": False, "show_header": False, 'indent_size': 5,
195
+ "disable_scroll": False, "searchable": True, "wrap": True,
196
+ "child_kwargs": {"force_initial": True, "initial": {"window_pos": (-20, -1), "closed": False},
197
+ "bg_offset": 2, "swoosh": False, "auto_resize": True, "closed": False,
198
+ "return_item": True,
199
+ "inline": True, "anchor": Anchor.TOP_LEFT, "parent_anchor": Anchor.TOP_LEFT},
200
+ "show_add_delete": False, "with_header": draw_header, "min_width": 10, "min_height": 20},
201
+ recursive=True,
202
+ )
203
+ }
204
+
205
+
206
+ WINDOW_MANAGER_SORTED = {
207
+ defaultdict: ModeOverrides(
208
+ kwargs={"show_bg": True, "selectable": False, "use_cache": True},
209
+ recursive=False,
210
+ func=(sort_dict_alphabetically,
211
+ (draw_collection, {"show_add_delete": False, "selectable": False, "show_bg": False,
212
+ "excluded": WindowManager.excluded_windows}),
213
+ unsort_dict_alphabetically)
214
+ )
215
+ }
216
+
217
+ WINDOW_NO_HEADER = {
218
+ Any: ModeOverrides(
219
+ kwargs={"show_bg": True, "selectable": False, "use_cache": True, "melty_window": False, "closable": True,
220
+ "with_header_end": draw_header_end, "auto_resize": False, "draggable": True, 'shadow': False,
221
+ "show_tint": False, "show_header": True, "with_footer": draw_footer, 'indent_size': 5,
222
+ "search_text": "",
223
+ "show_add_delete": False, "with_header": draw_header, "min_width": 200, "min_height": 60,
224
+ "initial": {"width": 319, "height": 600, "window_pos": (100, 500)}},
225
+
226
+ recursive=False
227
+ )
228
+ }
229
+ WINDOW_AUTO_FIT = {
230
+ Any: ModeOverrides(
231
+ kwargs={"use_cache": True, "melty_window": False, "closable": True, "layer_offset": 4,
232
+ "auto_resize": True, "draggable": True, 'min_width': 600, "swoosh": False,
233
+ "inline": True, "show_header": False,
234
+ "initial": {"width": 400, "height": 320}},
235
+
236
+ recursive=False
237
+ )
238
+ }
239
+
240
+ # WINDOW_AUTO_FIT's chrome without the auto-fit: the user sizes the window
241
+ # and content lays out to it (global search - its columns/rows wrap to the
242
+ # width you give it).
243
+ WINDOW_RESIZABLE = {
244
+ Any: ModeOverrides(
245
+ kwargs={"use_cache": True, "melty_window": False, "closable": True, "layer_offset": 4,
246
+ "auto_resize": False, "draggable": True, 'min_width': 600, "swoosh": False,
247
+ "inline": True, "show_header": False,
248
+ "initial": {"width": 400, "height": 320}},
249
+
250
+ recursive=False
251
+ )
252
+ }
253
+
254
+ WINDOW = {
255
+ Any: ModeOverrides(
256
+ kwargs={"show_bg": True, "selectable": False, "use_cache": True, "melty_window": False, "closable": True,
257
+ "with_header_end": draw_header_end, "auto_resize": False, "draggable": True, 'shadow': True,
258
+ "show_tint": True, "show_header": True, "with_footer": draw_footer, 'indent_size': 5,
259
+ "disable_scroll": False, "bg_offset": -1,
260
+ "min_width": 200, "min_height": 60,
261
+ "initial": {"width": 400, "height": 320, "window_pos": (100, 500)}},
262
+ recursive=False
263
+ )
264
+ }
265
+
266
+ LIVE_WINDOW = {
267
+ Any: ModeOverrides(
268
+ kwargs={"show_bg": True, "selectable": False, "use_cache": True, "melty_window": False, "closable": True,
269
+ "with_header_end": draw_header_end, "draggable": True, 'shadow': True,
270
+ "show_tint": True, "show_header": True, "with_footer": draw_footer,
271
+ "disable_scroll": False, "bg_offset": -1, "is_tree":False, 'show_add_delete':False,
272
+ "with_header": draw_header,
273
+ # No initial height: closable windows without one adopt
274
+ # their content's measured height on first render (the
275
+ # _height_from_content path in core_render), so live-view
276
+ # value windows open wrapped to their contents.
277
+ # max_height caps only that first-render adopt; the
278
+ # user's resize handle isn't bound by it.
279
+ "max_height": 800,
280
+ "initial": {"window_pos": (100, 500), "width": 400}},
281
+ recursive=False
282
+ )
283
+ }
284
+
285
+ WINDOW_PARAMS = {
286
+ Any: ModeOverrides(
287
+ kwargs={"show_bg": True, "selectable": False, "use_cache": True, "melty_window": False, "closable": True,
288
+ "with_header_end": draw_header_end, "auto_resize": False, "draggable": True, 'shadow': True,
289
+ "show_header": True, "with_footer": draw_footer, 'indent_size': 5,
290
+ "disable_scroll": False, "bg_offset": -1,
291
+ "with_header": draw_header, "min_width": 200, "min_height": 60,
292
+ "initial": {"width": 400, "height": 700, "window_pos": (500, 100)}},
293
+ recursive=False
294
+ )
295
+ }
296
+
297
+ # Lightweight anchored popover: a small auto-fitting, header-less, non-draggable
298
+ # temp window (like the dropdown menu). The caller supplies closed / window_pos /
299
+ # parent_window to anchor it to a trigger and toggle visibility. `popover` marks
300
+ # the window for Melty.popover_orphaned: it lives only while
301
+ # Melty.popover_focused_ds names it or one of its ancestors; end_frame
302
+ # discards it the moment the slot moves away, whether or not the view that
303
+ # drew it ever runs again (a tab switch, a cached spawner).
304
+ POPOVER = {
305
+ Any: ModeOverrides(
306
+ kwargs={"show_bg": True, "selectable": False, "use_cache": False, "melty_window": False,
307
+ "closable": True, "auto_resize": True, "draggable": False, "shadow": True,
308
+ "show_tint": False, "show_header": False, "with_header": None, "disable_scroll": True,
309
+ "temp": True, "swoosh": False, "indent_size": 2, "popover": True},
310
+ recursive=False
311
+ )
312
+ }
313
+
314
+ HOST_WINDOW = {
315
+ Any: ModeOverrides(
316
+ kwargs={"show_bg": True, "selectable": False, "use_cache": True, "melty_window": False, "closable": True,
317
+ "with_header_end": draw_header_end, "auto_resize": False, "draggable": True, 'shadow': False,
318
+ "show_tint": True, "show_header": True, "with_footer": draw_footer, 'indent_size': 5,
319
+ "disable_scroll": False, "bg_offset": -1,
320
+ "show_add_delete": False, "with_header": draw_header, "min_width": 50, "min_height": 60,
321
+ "initial": {"width": 400, "height": 320, "window_pos": (50, 40)}},
322
+
323
+ recursive=False
324
+ )
325
+ }
326
+
327
+ TERMINAL_WINDOW = {
328
+ Any: ModeOverrides(
329
+ kwargs={"show_bg": True, "selectable": False, "use_cache": True, "melty_window": False, "closable": True,
330
+ "with_header_end": draw_header_end, "auto_resize": False, "draggable": True, 'shadow': True,
331
+ "show_tint": True, "show_header": True, "with_footer": draw_footer, 'indent_size': 5, "bg_offset": -1,
332
+ "show_add_delete": False, "with_header": draw_header, "min_width": 200, "min_height": 60,
333
+ "initial": {"width": 750, "height": 1120, "closed": False, "disable_scroll":True, "swoosh": False}, "force_initial":True},
334
+
335
+ recursive=False
336
+ )
337
+ }
338
+
339
+ MODE_WINDOW = {
340
+ Any: ModeOverrides(
341
+ kwargs={"show_bg": True, "selectable": False, "use_cache": True, "melty_window": False, "closable": True,
342
+ "with_header_end": draw_header_end, "auto_resize": False, "draggable": True, 'shadow': True,
343
+ "show_tint": True, "show_header": True, "with_footer": draw_footer, 'indent_size': 5,
344
+ "show_add_delete": False, "with_header": draw_header,
345
+ "initial": {"width": 400, "height": 320, "window_pos": (100, 500)}, 'icon': None},
346
+
347
+ recursive=False
348
+ )
349
+ }
350
+
351
+ FLOATING = {
352
+ Any: ModeOverrides(
353
+ kwargs={"use_cache": True, "melty_window": False, "closable": True, "layer_offset": 0,
354
+ "auto_resize": True, "draggable": True, "window_pos": (0, 0), "swoosh": False,
355
+ "inline": True,
356
+ "initial": {"width": 400, "height": 320, "window_pos": (0, 0)}},
357
+
358
+ recursive=False
359
+ )
360
+ }
361
+
362
+ WINDOW_CLEAN = {
363
+ Any: ModeOverrides(
364
+ kwargs={"show_bg": True, "selectable": False, "use_cache": True, "shadow": True,
365
+ "melty_window": True, "closable": True, "width":500,
366
+ "auto_resize": True, "is_tree": False, "show_tint": False, "show_header": True,
367
+ "disable_scroll": False},
368
+ recursive=False
369
+ )
370
+ }
371
+
372
+ # WINDOW_CLEAN with the width left to the caller (a mode's kwargs win
373
+ # over the call's, so WINDOW_CLEAN's 500 cannot be overridden): the
374
+ # floating find pill (core_render's draw_search window) sizes itself
375
+ # to its one child.
376
+ WINDOW_PILL = {
377
+ Any: ModeOverrides(
378
+ kwargs={"show_bg": True, "selectable": False, "use_cache": True, "shadow": True,
379
+ "melty_window": True, "closable": True,
380
+ "auto_resize": True, "is_tree": False, "show_tint": False, "show_header": True,
381
+ "disable_scroll": False},
382
+ recursive=False
383
+ )
384
+ }
385
+
386
+ code_ui_auto_load = True
387
+ code_ui_params = {'save': True,
388
+ 'recompile': False}
389
+
390
+ CODE_UI = {
391
+ types.FunctionType: ModeOverrides(
392
+ recursive=True,
393
+ func=(function_to_address,
394
+ (address_to_general_parse, {'load': code_ui_auto_load}),
395
+ (draw_collection, {"show_add_delete": True}),
396
+ (general_parse_to_address, code_ui_params),
397
+ address_to_function),
398
+ ),
399
+ types.ModuleType: ModeOverrides(
400
+ recursive=True,
401
+ func=(module_to_address,
402
+ (address_to_general_parse, {'load': code_ui_auto_load}),
403
+ (draw_collection, {"show_add_delete": True}),
404
+ (general_parse_to_address, code_ui_params),
405
+ address_to_module),
406
+ ),
407
+ type: ModeOverrides(
408
+ func=(class_to_address,
409
+ (address_to_general_parse, {'load': code_ui_auto_load}),
410
+ (draw_collection, {"show_add_delete": False}),
411
+ (general_parse_to_address, code_ui_params),
412
+ address_to_class),
413
+ recursive=True
414
+ ),
415
+ Conditional: ModeOverrides(
416
+ kwargs={"tint": (0.2, 0.2, 0.1), 'show_add_delete': True, 'is_tree': False},
417
+ recursive=True,
418
+ ),
419
+ Comment: ModeOverrides(
420
+ kwargs={"tint": (0.1, 0.1, 0.1), "show_bg": False, "shadow": False, 'show_add_delete': True,
421
+ 'is_tree': False},
422
+ func=draw_comment,
423
+ recursive=True,
424
+ ),
425
+ GeneralParse: ModeOverrides(
426
+ kwargs={'show_add_delete': False, "disable_scroll": False, "is_tree": True},
427
+ recursive=True,
428
+ func=draw_collection
429
+ ),
430
+ }
431
+
432
+
433
+ code_plain_text_auto_load = True
434
+ code_plain_text_params = {'save': True,
435
+ 'recompile': False}
436
+ draw_text_funcs = ((address_to_general_parse,
437
+ {'load': code_plain_text_auto_load}),
438
+ general_parse_to_str,
439
+ draw_text,
440
+ str_to_general_parse,
441
+ (general_parse_to_address,
442
+ code_plain_text_params))
443
+
444
+ CODE_PLAIN_TEXT = {
445
+ types.FunctionType: ModeOverrides(
446
+ recursive=True,
447
+ route={function_to_address: "jump_to", address_to_general_parse: "code_tree"},
448
+ func=(function_to_address, *draw_text_funcs, address_to_function),
449
+ ),
450
+ types.ModuleType: ModeOverrides(
451
+ recursive=True,
452
+ route={module_to_address: "jump_to", address_to_general_parse: "code_tree"},
453
+ func=(module_to_address, *draw_text_funcs, address_to_module),
454
+ ),
455
+ type: ModeOverrides(
456
+ route={class_to_address: "jump_to", address_to_general_parse: "code_tree"},
457
+ func=(class_to_address, *draw_text_funcs, address_to_class),
458
+ recursive=True
459
+ ),
460
+ }
461
+
462
+ RUNNING = {
463
+ type: ModeOverrides(
464
+ func=(draw_type),
465
+ recursive=False
466
+ ),
467
+
468
+ }
469
+
470
+ # ── File metadata ────────────────────────────────────────
471
+ #
472
+ # Path on disk → metadata dict (name, size, modified, raw bytes).
473
+ # Good for: file browsers, file inspectors, drag-and-drop targets.
474
+
475
+ FILE_META = {
476
+ Path: ModeOverrides(
477
+ kwargs={"convert_in": [path_to_dict],
478
+ "convert_out": [rf_dict_to_path],
479
+ },
480
+ func=draw_collection,
481
+ recursive=True,
482
+ ),
483
+ bytes: ModeOverrides(
484
+ kwargs={"convert_in": [rf_bytes_to_str],
485
+ "convert_out": [rf_str_to_bytes]},
486
+ func=draw_text,
487
+ recursive=True,
488
+ ),
489
+ }
490
+
491
+ # ── Function parameters (draw_function) ─────────────────
492
+ #
493
+ # String parameter values draw with the text editor instead of the
494
+ # default type renderer.
495
+ FUNCTION_PARAMS = {
496
+ str: ModeOverrides(
497
+ func=draw_text,
498
+ recursive=True,
499
+ ),
500
+ }
501
+
502
+ # ── TEXT - reference mode for all mode-attached child kwargs ─────────
503
+ #
504
+ # A dict of strings: the dict entry draws the collection, the str entry
505
+ # sends each leaf by draw_text. The leaves' TEXT STYLE lives in this
506
+ # entry's child_kwargs - draw_collection merges child_kwargs into every
507
+ # recursive call, so line_height/wrap/syntax_highlight land in draw_text
508
+ # without every caller passing them.
509
+ #
510
+ # That is what the inputs tab's "child_kwargs (mode)" source row edits:
511
+ # open the tab on one of the string leaves and the row is backed by THIS
512
+ # enum, with the jump button pointing at the TEXT member below. A change
513
+ # round-trips through the Mode enum's code host straight back into
514
+ # mode.py - distinct from the plain "child_kwargs" row, which shows
515
+ # whichever NON-mode entry source (caller / @defaults) sets one.
516
+ #
517
+ # Live usage: tests/playground/mode_test_playground.py (draw_mode_test).
518
+ TEXT = {
519
+ dict: ModeOverrides(
520
+ kwargs={"show_bg": True, "use_cache": True, "show_header": True,
521
+ "child_kwargs": {"line_height": 1.35,
522
+ "wrap": True,
523
+ "syntax_highlight": False,
524
+ 'tint': (0.87, 0.604, 0.05)}},
525
+ recursive=True,
526
+ ),
527
+ str: ModeOverrides(
528
+ func=draw_text,
529
+ # Disjoint from child_kwargs above ON PURPOSE: mode kwargs win over
530
+ # call kwargs (`kwargs | override_kwargs`), so anything added here
531
+ # would shadow the child_kwargs entry and the source row would edit a
532
+ # value that never reaches the view.
533
+ kwargs={"use_cache": True, "show_header": True},
534
+ recursive=True,
535
+ ),
536
+ }
537
+
538
+ # ── File tree / cache-backed code editor ────────────────────────────
539
+ #
540
+ # THE main editor mode: code_file_io + draw_text_from_code_cache, with
541
+ # the parse pulled from the shared code-host cache (code_hosts_for) instead
542
+ # of a local convert chain. Each ref's codec owns its load/edit/save
543
+ # round-trip: a Path leaf in a folder tree (playground.folder_files,
544
+ # whole-file TextFileCodec), and equally a function / class / module /
545
+ # CallSite / Decorations span (the context menu's render-func and class
546
+ # tabs). Recursive so the route survives any depth of folder nesting.
547
+
548
+ FILE_TREE = {
549
+ (Path, type, types.FunctionType, types.ModuleType, CallSite, Decorations): ModeOverrides(
550
+ func=code_file_io,
551
+ # Pin the text editor: draw_any forwards a mode's func override as
552
+ # the `view_func` kwarg, which would otherwise hand code_file_io
553
+ # ITSELF as its nested view (str → "No codec"). Mode kwargs win
554
+ # over call kwargs (`kwargs | override_kwargs`), so this corrects it.
555
+ # draw_text_from_code_cache = draw_text fed the cst node from the
556
+ # global code-host cache (code_cache_for), so usage links and
557
+ # syntax-error highlighting work without an inline chain.
558
+ kwargs={"auto_load_edits": True, "disable_scroll":True, "view_func": draw_text_from_code_cache},
559
+ recursive=True,
560
+ ),
561
+ }
562
+
563
+ # ── File tree, names only ───────────────────────────────────────────
564
+ #
565
+ # The display-only sibling of FILE_TREE: a {name: Path} dict's folder tree
566
+ # where folders are plain collapsing draw_collection entries and each Path
567
+ # leaf renders as just its file name (double-click → open_file_tab).
568
+ # Nothing loads file content. Live usage: playground.file_tree
569
+ # (render_file_tree_melty).
570
+
571
+ # is_tree is STATIC - no expanded kwarg allowed: core_render's
572
+ # collapsed-view path (1226) rewrites is_tree=False whenever a falsy
573
+ # `expanded` flows through, which eats the tree style. PosixPath is the
574
+ # concrete leaf type folder_io's CodeHost hands back.
575
+ FILE_TREE_NAMES = {
576
+ (dict, defaultdict): ModeOverrides(
577
+ kwargs={"is_tree": True, "show_bg": False, "use_cache": True,
578
+ "show_add_delete": True, "indent_size": 8},
579
+ recursive=True,
580
+ ),
581
+ # (Path, PosixPath): ModeOverrides(
582
+ # func=draw_file_name,
583
+ # recursive=True,
584
+ # ),
585
+ }
586
+
587
+ # ── Inner modes for draw_with_modes children ────────────
588
+ # Each operates on a GeneralParse and wraps a simple renderer in just
589
+ # the converter chain it needs. Used as the `modes` arg to
590
+ # draw_with_modes in Mode.CODE so that load / save / file-watch
591
+ # registration happen ONCE upstream and are shared across columns.
592
+
593
+ CODE_INNER_TEXT = {
594
+ GeneralParse: ModeOverrides(
595
+ recursive=True,
596
+ func=(general_parse_to_str,
597
+ (draw_text, {}),
598
+ str_to_general_parse),
599
+ ),
600
+ }
601
+
602
+ CODE_INNER_UI = {
603
+ GeneralParse: ModeOverrides(
604
+ recursive=True,
605
+ func=((draw_collection, {"show_add_delete": True}),),
606
+ ),
607
+ }
608
+
609
+ # Outer code mode. Populated outside class body (via _populate_code_mode
610
+ # below) because the chain references Mode.CODE_INNER_TEXT /
611
+ # Mode.CODE_INNER_UI as enum members, which only exist post-finalization.
612
+ CODE = {}
613
+
614
+ def _populate_code_mode():
615
+ """Fill in Mode.CODE.value. Deferred until after the Mode class is
616
+ defined so the chain can reference Mode.CODE_INNER_TEXT /
617
+ Mode.CODE_INNER_UI as proper enum members.
618
+
619
+ The chain runs the address resolution + GeneralParse load/save ONCE per
620
+ Mode.CODE invocation. draw_with_modes then dispatches each selected tab
621
+ to its inner mode (text or UI), which receive the already-loaded
622
+ GeneralParse. One file-watcher registration, one cache, regardless of
623
+ how many columns are active.
624
+ """
625
+ inner_modes = (Mode.CODE_INNER_TEXT, Mode.CODE_INNER_UI)
626
+
627
+ def chain_for(address_in, address_out):
628
+ return ModeOverrides(
629
+ kwargs={"disable_scroll": True, "searchable": True},
630
+ recursive=True,
631
+
632
+ func=(address_in,
633
+ (address_to_general_parse, {'load': True, }),
634
+ (draw_with_modes, {'modes': inner_modes, 'disable_scroll': True, 'fill_height': compute_height}),
635
+ (general_parse_to_address, {'save': True, 'recompile': False}),
636
+ address_out),
637
+ )
638
+
639
+ Mode.CODE.unwrapped.update({
640
+ types.FunctionType: chain_for(function_to_address, address_to_function),
641
+ types.ModuleType: chain_for(module_to_address, address_to_module),
642
+ type: chain_for(class_to_address, address_to_class),
643
+ })
644
+
645
+
646
+ _populate_code_mode()
647
+
648
+ # ╔══════════════════════════════════════════════════════════════════════════════╗
649
+ # ║ Lenses - generic, field-parameterized accessors for "where does X live" ║
650
+ # ╚══════════════════════════════════════════════════════════════════════════════╝
651
+ #
652
+ # A Lens is a bidirectional accessor parameterized by a leaf NAME. The lens KIND
653
+ # encodes the storage space (and so the read/write mechanism); the name fills in
654
+ # which leaf. There is no "tint lens" vs "outline lens" - there's `class_var` and
655
+ # you call it `class_var("tint")` or `class_var("outline_color")`.
656
+ #
657
+ # Kinds (all generic over `name`):
658
+ #
659
+ # draw_state_attr(name) live attr on the draw_state → in place, ephemeral
660
+ # instance_attr(name) live attr on the data object → in place
661
+ # class_var(name) class-body assignment in source → parse → focus → save
662
+ # decoration(name) @defaults(name=...) decorator → parse → focus → save
663
+ # code_comment(name) # [name=...] override comment → parse → focus → save
664
+ #
665
+ # In-place kinds run `focus(root, path)` directly. Code kinds generate a
666
+ # parse→focus→save chain (CODE_UI with `focus` swapped for draw_collection) and
667
+ # run it via draw_any(root, chain=...). A class span parses to {<ClassName>: {...}}
668
+ # (cst_module_to_dict), so class-anchored paths are prefixed with the class name.
669
+ #
670
+ # `default` is what the "+ Add" affordance in focus stamps in when the source has
671
+ # no value yet. To add a source for an attribute: append one constructor call to
672
+ # its list in LENSES_BY_ATTR.
673
+
674
+ # Address-resolver pairs (load-side, save-side) per source-object type - the same
675
+ # pairs CODE_UI dispatches on. Generating from these keeps code lenses one-liners.
676
+ _ADDR_PAIRS = {
677
+ type: (class_to_address, address_to_class),
678
+ types.FunctionType: (function_to_address, address_to_function),
679
+ types.ModuleType: (module_to_address, address_to_module),
680
+ }
681
+ _CODE_SAVE = {'save': True, 'recompile': False}
682
+
683
+
684
+ def _owning_source(draw_state):
685
+ """The class / function / module whose source code owns this element — where a
686
+ class_var / decoration / comment would be parsed from. For a data instance
687
+ that's its (non-builtin) class; for a primitive it's None."""
688
+ raw = getattr(draw_state, "_raw_input_value", None)
689
+ if raw is None:
690
+ return None
691
+ if isinstance(raw, (types.FunctionType, type, types.ModuleType)):
692
+ return raw
693
+ the_type = type(raw)
694
+ if getattr(the_type, "__module__", None) in (None, "builtins", "_collections_abc"):
695
+ return None
696
+ return the_type
697
+
698
+
699
+ def _build_code_chain(root, tail, default, kind, prefix_class=True, ensure_import=None,
700
+ load_override=None):
701
+ """CODE_UI with `focus` in place of draw_collection: parse → focus → save.
702
+
703
+ A class span parses to {<ClassName>: {...}}, so things INSIDE the class
704
+ (class vars, decorator kwargs) need the class name prefixed onto the focus
705
+ path. An override `# [...]` comment, however, lives at the span's MODULE
706
+ level (above the class) and round-trips there — so code_comment passes
707
+ prefix_class=False to target the top-level __overrides__ directly.
708
+
709
+ ensure_import=(module, name) makes the save also insert that import if the
710
+ file lacks it (so a synthesized @defaults decorator resolves)."""
711
+ load_node, save_node = _ADDR_PAIRS.get(type(root), _ADDR_PAIRS[type])
712
+ if load_override is not None and isinstance(root, type):
713
+ load_node = load_override # e.g. extend the span to include a leading comment
714
+ prefix = (root.__name__,) if (prefix_class and isinstance(root, type)) else ()
715
+ save_kwargs = dict(_CODE_SAVE)
716
+ if ensure_import is not None:
717
+ save_kwargs['ensure_import'] = ensure_import
718
+ return (load_node,
719
+ (address_to_general_parse, {'load': True}),
720
+ (focus, {'path': prefix + tail, 'default': default, 'kind': kind}),
721
+ (general_parse_to_address, save_kwargs),
722
+ save_node)
723
+
724
+
725
+ @dataclass
726
+ class Lens:
727
+ label: str # unique row id (kind + name) - drives draw_collection identity
728
+ name: str # the field/leaf name this lens reads/writes
729
+ root: Any # draw_state -> the object the lens starts from
730
+ path: tuple # in-place kinds: root -> path to the leaf
731
+ default: Any = None # value the "+ Add" affordance stamps in
732
+ chain: Any = None # code kinds: root -> generated chain tuple; None for in-place
733
+ kind: str = "" # short, clean display name (no attr name, no internal keys)
734
+ tint: Optional[tuple] = None # optional override tint for this source
735
+
736
+
737
+ # ── Lens kinds (generic over `name`) ──────────────────────────────────────────
738
+
739
+ def draw_state_attr(name, default=None):
740
+ return Lens(f"Draw state · {name}", name, root=lambda ds: ds, path=(name,),
741
+ default=default, kind="Draw state", tint=(0.1, 0.1, 0.3))
742
+
743
+
744
+ def instance_attr(name, default=None):
745
+ return Lens(f"Instance attr · {name}", name,
746
+ root=lambda ds: getattr(ds, "_raw_input_value", None),
747
+ path=(name,), default=default, kind="Instance")
748
+
749
+
750
+ def class_var(name, default=None):
751
+ return Lens(f"Class variable · {name}", name, root=_owning_source, path=(name,),
752
+ default=default, kind="Class variable",
753
+ chain=lambda root: _build_code_chain(root, (name,), default, "Class variable"))
754
+
755
+
756
+ _DEFAULTS_IMPORT = ("meltygui.core.rendering.core_decoration", "defaults")
757
+
758
+
759
+ def decoration(name, default=None, decorator="defaults"):
760
+ tail = ("decorators", decorator, name)
761
+ # A synthesized @defaults needs its import; ensure it in the same save write.
762
+ imp = _DEFAULTS_IMPORT if decorator == "defaults" else None
763
+ return Lens(f"Decoration · {name}", name, root=_owning_source, path=tail,
764
+ default=default, kind="Decoration",
765
+ chain=lambda root: _build_code_chain(root, tail, default, "Decoration",
766
+ ensure_import=imp))
767
+
768
+
769
+ def code_comment(name, default=None):
770
+ # An override comment lives at the span's MODULE level (above the class), so
771
+ # no class-name prefix. The class span from getsourcelines excludes a comment
772
+ # above the class, so we load via class_to_address_incl_overrides, which
773
+ # extends the span up to include it - otherwise it never round-trips.
774
+ tail = ("__overrides__", name)
775
+ return Lens(f"Code comment · {name}", name, root=_owning_source, path=tail,
776
+ default=default, kind="Code comment",
777
+ chain=lambda root: _build_code_chain(root, tail, default, "Code comment",
778
+ prefix_class=False,
779
+ load_override=class_to_address_incl_overrides))
780
+
781
+
782
+ def caller_arg(name, default=None):
783
+ """Edit the literal a caller passed for `name`, e.g. draw_text(tint=(1,0,1)).
784
+ Anchored on the call site (draw_state._call_site — the (filename, lineno)
785
+ resolved once when frames were grabbed on menu-open), not on the data or its
786
+ class. The chain is fixed (independent of root type): site → call-statement
787
+ Address → parse the Call's kwargs → focus → save.
788
+
789
+ Reads the cached site rather than re-walking the live stack: during a tint
790
+ drag the stack changes (parents are skipped), so re-deriving would flip the
791
+ site mid-drag and cancel the edit."""
792
+ chain = (caller_to_address,
793
+ (address_to_call_parse, {'load': True}),
794
+ (focus, {'path': (name,), 'default': default, 'kind': "Caller"}),
795
+ (call_dict_to_save, {'save': True}))
796
+ return Lens(f"Caller arg · {name}", name,
797
+ root=lambda ds: getattr(ds, "_call_site", None),
798
+ path=(name,), default=default, kind="Caller",
799
+ chain=lambda root: chain)
800
+
801
+
802
+ # A list of lenses per attribute - draw_tint_context renders every entry, so you
803
+ # get one color picker (or "+ Add") per source. Append a constructor to extend.
804
+ _TINT_DEFAULT = (0.485, 0.61, 0.76)
805
+ LENSES_BY_ATTR = {
806
+ "tint": [
807
+ caller_arg("tint", _TINT_DEFAULT),
808
+ draw_state_attr("tint", _TINT_DEFAULT),
809
+ instance_attr("tint", _TINT_DEFAULT),
810
+ class_var("tint", _TINT_DEFAULT),
811
+ decoration("tint", _TINT_DEFAULT),
812
+ code_comment("tint", _TINT_DEFAULT),
813
+ ],
814
+ }
815
+
816
+
817
+ class ModeGroup:
818
+ CODE = (Mode.CODE_UI, Mode.CODE_PLAIN_TEXT)