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,118 @@
1
+ """Query view functions and supporting definitions."""
2
+ from meltygui.core.core_render import render_func
3
+ from meltygui.core.rendering.render_funcs import RenderFuncs
4
+ from meltygui.state.query_state import MCPQueryState
5
+ import meltygui_imgui as imgui
6
+
7
+
8
+ @render_func(tint=(0.20, 0.60, 0.90), use_cache=True, selectable=False,
9
+ show_bg=False)
10
+ def draw_mcp_query(input_value=None, draw_state=None,
11
+ panel_state: MCPQueryState = None):
12
+ # ── knobs ────────────────────────────────────────────────────────────
13
+ # [tint=(0.95, 0.75, 0.20)]
14
+ from meltygui.view.header_view import flat_button
15
+ from meltygui.core.automation.query_core import _TOOL_ARGS
16
+ from meltygui.core.automation.query_core import _pointer
17
+ from meltygui.core.automation.query_core import _run
18
+ from meltygui.core.automation.query_core import _seed_args
19
+
20
+ button_height = 26 # toolbar buttons; the rows size off this
21
+ # [tint=(0.95, 0.75, 0.20)]
22
+ json_height = 420 # the JSON pane's own scroll box
23
+ # [tint=(0.95, 0.75, 0.20)]
24
+ corner_radius = 5.0
25
+ # [tint=(0.55, 0.80, 0.45)]
26
+ tool_color = (0.16, 0.42, 0.62) # unselected tool buttons + Run
27
+ # [tint=(0.85, 0.45, 0.35)]
28
+ live_color = (0.62, 0.30, 0.16) # follow pointer, while it is on
29
+ icon_run = "" # fa bolt
30
+ icon_tree = "" # fa sitemap
31
+ icon_json = "" # fa code
32
+ icon_pointer = "" # fa mouse-pointer
33
+
34
+ _seed_args(panel_state)
35
+ tool = panel_state.tool
36
+ args = panel_state.args[tool]
37
+ rerun = False
38
+
39
+ # ── one button per collector ─────────────────────────────────────────
40
+ # A selected button is the same colour, lit: same shape, no second color
41
+ # to keep in sync.
42
+ for name in _TOOL_ARGS:
43
+ selected = name == tool
44
+ if flat_button(name, draw_state, f"mcp_tool_{name}", height=button_height,
45
+ color=tool_color, corner_radius=corner_radius,
46
+ tint_value=0.42 if selected else 0.14,
47
+ max_bg_brightness=0.55 if selected else 0.22,
48
+ text_value=1.15 if selected else 0.85):
49
+ panel_state.tool = tool = name
50
+ args = panel_state.args[tool]
51
+ rerun = True
52
+ imgui.same_line()
53
+
54
+ # ── run + how to read the answer ─────────────────────────────────────
55
+ if flat_button(f"{icon_run} Run", draw_state, "mcp_run", height=button_height,
56
+ color=tool_color, corner_radius=corner_radius, tint_value=0.30):
57
+ rerun = True
58
+ imgui.same_line()
59
+ view_label = f"{icon_tree} Tree" if panel_state.as_json else f"{icon_json} JSON"
60
+ if flat_button(view_label, draw_state, "mcp_view_mode", height=button_height,
61
+ color=tool_color, corner_radius=corner_radius, tint_value=0.20):
62
+ panel_state.as_json = not panel_state.as_json
63
+ if tool == "hit_test":
64
+ imgui.same_line()
65
+ following = panel_state.follow_pointer
66
+ if flat_button(f"{icon_pointer} follow pointer", draw_state, "mcp_follow",
67
+ height=button_height, corner_radius=corner_radius,
68
+ color=live_color if following else tool_color,
69
+ tint_value=0.45 if following else 0.18,
70
+ max_bg_brightness=0.60 if following else 0.22):
71
+ panel_state.follow_pointer = following = not following
72
+ rerun = True
73
+ # Following the pointer means re-collecting wherever it goes, which
74
+ # is the `live=True` contract: the body has to run every frame to see
75
+ # a pointer that is nowhere near this window. The collect itself is
76
+ # skipped while the pointer holds steady, so a parked mouse costs one
77
+ # immediate run and nothing else. Off by default - rule 12.
78
+ if following:
79
+ draw_state.invalidate()
80
+ pointer = _pointer()
81
+ if pointer != (args["x"], args["y"]):
82
+ args["x"], args["y"] = pointer
83
+ rerun = True
84
+
85
+ # ── arguments: the dict IS the form ──────────────────────────────────
86
+ changed, _ = RenderFuncs.draw_collection(
87
+ args, name=f"{tool} arguments", width=draw_state.content_width,
88
+ show_bg=True, show_add_delete=False, initial={"expanded": True})
89
+
90
+ # Re-collect on any edit, and whenever the arguments differ from the ones
91
+ # the held answer was collected with (a tool switch, a hot-swapped
92
+ # default). The signature is a repr of a tuple of scalars - never a
93
+ # digest of the ANSWER, which is the expensive half.
94
+ signature = repr((tool, sorted(args.items(), key=lambda item: item[0])))
95
+ if rerun or changed or signature != panel_state._signature:
96
+ _run(panel_state, tool, args)
97
+ panel_state._signature = signature
98
+
99
+ # ── the answer ───────────────────────────────────────────────────────
100
+ if panel_state._stamp:
101
+ imgui.text_disabled(panel_state._stamp)
102
+ if panel_state._error:
103
+ RenderFuncs.draw_text(panel_state._error, name="collector raised",
104
+ show_name=True, focusable=False, wrap=True,
105
+ autocomplete=False, show_jump_bar=False,
106
+ show_file_header=False)
107
+ if panel_state.as_json:
108
+ # focusable=False: this is the tool's output, not a buffer to type in.
109
+ RenderFuncs.draw_text(panel_state._json, name=f"{tool} json",
110
+ show_name=True, height=json_height, focusable=False,
111
+ autocomplete=False, show_jump_bar=False,
112
+ show_file_header=False)
113
+ else:
114
+ RenderFuncs.draw_collection(panel_state._result, name=f"{tool} result",
115
+ width=draw_state.content_width, show_bg=True,
116
+ show_add_delete=False,
117
+ initial={"expanded": True})
118
+ return False, None
@@ -0,0 +1,342 @@
1
+ """Search view functions and supporting definitions."""
2
+ from meltygui.hdr_color import pack_color
3
+ from meltygui.core.melty import Melty
4
+ from meltygui.core.core_render import render_func
5
+ from meltygui.core.runtime.toggles import Toggles
6
+ import meltygui_imgui as imgui
7
+ import math
8
+
9
+
10
+ @render_func(use_cache=True, layer_offset=1, searchable=False)
11
+ def draw_search(input_value=None, draw_state=None, unique=0):
12
+ """Floating find pill for searchable views that have no header. Rendered
13
+ as a Mode.WINDOW_CLEAN from core_render when search is active, pinned to
14
+ the owning view's bottom-right corner (the file browser's search pill):
15
+ one row — the search icon, the query box, "n of m" (or "no match"), and
16
+ the close button. Up / Down, Enter / Shift+Enter step the matches (the
17
+ row has no arrow buttons), Esc closes. State — search_text, count,
18
+ current index — lives on the owning view's draw_state (search_owner)."""
19
+ from meltygui.core.windowing.glfw_utils import request_render
20
+ import meltygui.core.windowing.window_api as glfw
21
+
22
+ owner = input_value
23
+ # draw_search(owner, unique=owner._tile_id, draw_state=draw_state)
24
+ search_ds = owner
25
+ regrab_focus = True
26
+
27
+ from meltygui.view.text_view import draw_text
28
+ # Re-grab gated on this search still being active (focused_ds is the owner):
29
+ # a deliberate click away clears focused_ds (via clear_focus) so the box
30
+ # releases focus and stays open-but-unfocused, while a spurious clear during
31
+ # typing leaves focused_ds intact so the box reclaims focus.
32
+ focus_search = ((not search_ds._search_was_active)
33
+ or (regrab_focus and Melty.text_focused_ds is None
34
+ and Melty.focused_ds is search_ds)
35
+ or search_ds._search_focus_pending)
36
+ # One-shot open/Ctrl+F frame (NOT the spurious-clear regrab): select the
37
+ # whole term so typing replaces, and a single delete clears it.
38
+ focus_fresh = ((not search_ds._search_was_active)
39
+ or search_ds._search_focus_pending)
40
+ search_ds._search_focus_pending = False
41
+ search_ds._search_was_active = True
42
+ search_icon = ""
43
+ imgui.align_text_to_frame_padding()
44
+ imgui.text(search_icon)
45
+ imgui.same_line()
46
+ x_width = 30
47
+ count_width = 84
48
+ box_width, _pill_w = search_pill_layout(search_ds.search_text, search_ds.width)
49
+
50
+ # Laid out left to right at fixed offsets (never off the pill's own
51
+ # width - core_render sizes the window to search_pill_layout too). The
52
+ # box draws no background of its own: the query sits flat on the pill.
53
+ box_left, row_top = imgui.get_cursor_screen_pos()
54
+ _box = draw_text(search_ds.search_text, searchable=False, is_search_box=True,
55
+ width=box_width, max_width=box_width, show_bg=False,
56
+ shadow=False, name=search_icon + str(unique),
57
+ with_header_end=None, wrap=False, z_offset=-1, single_line=True,
58
+ with_footer=None, tint=search_ds.tint,
59
+ show_name=False, show_header=False,
60
+ request_focus=focus_search, select_all_on_focus=focus_fresh,
61
+ return_extras=True)
62
+ search_change, new_search = _box[0], _box[1]
63
+ _box_ds = _box[2] if len(_box) > 2 else None
64
+ # While the find box holds text focus, mark this search as the active one so
65
+ # Enter/arrow nav goes here - including after clicking back into the box.
66
+ if _box_ds is not None and Melty.text_focused_ds is _box_ds:
67
+ Melty.focused_ds = search_ds
68
+ if search_change:
69
+ search_ds.search_text = new_search
70
+ # Re-render the owner's whole subtree so every child view recomputes its
71
+ # matches against the new term and the combined index stays in sync.
72
+ Melty.cache.invalidate_up(search_ds._tile_id, force=True, max_depth=12)
73
+ request_render()
74
+ # The count, on the same row: "n of m" while there are matches, "no
75
+ # match" for a term that finds nothing, populated by the owner's pre-body
76
+ # search walk (core_render). The keys below step the current match.
77
+ total = search_ds.text_search_count
78
+ imgui.same_line()
79
+ count_left = box_left + box_width + 10
80
+ imgui.set_cursor_screen_pos((count_left, imgui.get_cursor_screen_pos()[1]))
81
+ imgui.align_text_to_frame_padding()
82
+ if total > 0:
83
+ imgui.text_colored(f"{search_ds.text_search_current + 1} of {total}",
84
+ 0.62, 0.68, 0.76, 1.0)
85
+ elif search_ds.search_text:
86
+ imgui.text_colored("no match", 0.95, 0.55, 0.5, 1.0)
87
+ else:
88
+ imgui.text_colored("", 0.62, 0.68, 0.76, 1.0)
89
+
90
+ imgui.same_line()
91
+ fa_x_icon = ""
92
+
93
+ # The close button: a glyph, dim until hovered, with a click rect on
94
+ # the pill (no button chrome).
95
+ close_left = count_left + count_width
96
+ row_h = max(imgui.get_frame_height(), 24.0)
97
+ close_rect = (close_left, row_top, close_left + x_width, row_top + row_h)
98
+ _mx, _my = imgui.get_mouse_pos()
99
+ _close_hover = (close_rect[0] <= _mx < close_rect[2] and close_rect[1] <= _my < close_rect[3]
100
+ and draw_state._bounding_hovered)
101
+ _glyph_w = imgui.calc_text_size(fa_x_icon).x
102
+ imgui.get_window_draw_list().add_text(
103
+ close_left + (x_width - _glyph_w) * 0.5, row_top + (row_h - imgui.get_font_size()) * 0.5,
104
+ pack_color(1.0, 1.0, 1.0, 0.9 if _close_hover else 0.35), fa_x_icon)
105
+ imgui.set_cursor_screen_pos((close_left, row_top))
106
+ imgui.dummy(x_width, row_h)
107
+ if draw_state.on_action("left_mouse_down", view_id=f"find_close{unique}",
108
+ rect=close_rect, priority_delta=4) is not None:
109
+ search_ds.search_active = False
110
+ search_ds._search_was_active = False
111
+ # Keep search_text so reopening the find bar restores the last query.
112
+ Melty.text_focused_ds = None
113
+ request_render()
114
+
115
+ if total > 0:
116
+ nav = 0
117
+ # Enter / Down = find next, Shift+Enter / Up = find prev, Ctrl+Enter =
118
+ # "click" the selected result - but only while the FIND BOX (not the
119
+ # underlying editor) holds text focus, so Enter still inserts newlines
120
+ # when you click into the editor. We gate on the box holding text focus
121
+ # directly rather than on `focused_ds is search_ds`: clicking back into
122
+ # the box runs clear_focus, which nulls focused_ds (the searched view
123
+ # isn't under the mouse to be protected), so keying off focused_ds
124
+ # silently dropped Enter-nav after a mouse refocus. text_focused_ds is
125
+ # set straight by the box's own key handler, so it survives that.
126
+ # The find box is single-line, so Up/Down don't move its cursor and are
127
+ # free for stepping matches. Drained from the frame-callback key queue
128
+ # (not imgui.is_key_pressed) so it isn't dropped on slow frames.
129
+ if _box_ds is not None and Melty.text_focused_ds is _box_ds:
130
+ if any(k == glfw.KEY_DOWN for k, _ in Melty.frame_key_events):
131
+ nav = 1
132
+ elif any(k == glfw.KEY_UP for k, _ in Melty.frame_key_events):
133
+ nav = -1
134
+ # Enter steps to the next match, Shift+Enter to the previous, and
135
+ # HOLDING Enter rapid-fires - imgui's synthesized auto-repeat
136
+ # (io.key_repeat_delay/rate) is read here because GLFW's REPEAT events
137
+ # don't reach the key queue on every platform (Wayland); keep the loop
138
+ # rendering while it is held so that cadence is sampled. Ctrl+Enter
139
+ # "clicks" the selected result and stays single-shot (from the queue).
140
+ _enter = [m for k, m in Melty.frame_key_events
141
+ if k in (glfw.KEY_ENTER, glfw.KEY_KP_ENTER)]
142
+ _enter_repeat = (imgui.is_key_pressed(glfw.KEY_ENTER, repeat=True)
143
+ or imgui.is_key_pressed(glfw.KEY_KP_ENTER, repeat=True))
144
+ if imgui.is_key_down(glfw.KEY_ENTER) or imgui.is_key_down(glfw.KEY_KP_ENTER):
145
+ request_render()
146
+ if _enter or _enter_repeat:
147
+ if _enter and (_enter[-1] & glfw.MOD_CONTROL):
148
+ # "Click" the selected result: hit-test the BVH at the center
149
+ # of the current match's rect and send a mouse down to the
150
+ # front-most view there (the actual target, e.g. a managed
151
+ # window's name label) - exactly what a real click resolves
152
+ # to. The view's own click handling does the rest (toggle a
153
+ # window, focus an input, ...). Queued + the view invalidated so
154
+ # it re-renders and reads the click next frame (the find UI
155
+ # renders too late to inject for this frame).
156
+ from meltygui.core.automation.search_core import search_activate_target
157
+ from meltygui.core.input.input_handler import InputEvent
158
+ _target = search_activate_target(Melty.search_current_node)
159
+ if _target is not None and _target.width and _target.height:
160
+ _cx = _target.abs_left + _target.width / 2.0
161
+ _cy = _target.abs_top + _target.height / 2.0
162
+ _hits = [h for h in Melty.bvh_query(_cx, _cy)
163
+ if h._tile_id is not None and not h.just_shadow]
164
+ _top = _hits[0] if _hits else _target
165
+ Melty.search_click_pending = (
166
+ _top._tile_id,
167
+ InputEvent("left_mouse", "down", tile_id=_top._tile_id, x=_cx, y=_cy))
168
+ # Re-render the owner's subtree next frame (same as nav) so
169
+ # the top view actually re-runs and reads the injection.
170
+ Melty.cache.invalidate_up(search_ds._tile_id, force=True, max_depth=12)
171
+ request_render()
172
+ elif not imgui.get_io().key_ctrl:
173
+ nav = -1 if imgui.get_io().key_shift else 1
174
+
175
+ if nav != 0:
176
+ # total is the combined count across all views; stepping wraps over
177
+ # the whole result set. Flag a scroll and invalidate the owner's
178
+ # subtree so every child view recomputes and the one holding the new
179
+ # global-current match scrolls to it.
180
+ search_ds.text_search_current = (search_ds.text_search_current + nav) % total
181
+ search_ds._search_nav_pending = True
182
+ Melty.cache.invalidate_up(search_ds._tile_id, force=True, max_depth=12)
183
+ request_render()
184
+ elif search_ds.search_text:
185
+ # Enter with the find box focused force-recomputes the result set. "No
186
+ # results" can be stale - the searched views may have been rebuilt since
187
+ # the count was last done (e.g. a fresh load from disk) - so re-run the
188
+ # sub-view walk on demand rather than leaving it stuck at zero. Flagging
189
+ # _search_nav_pending makes the owner's pre-body walk re-count next frame
190
+ # (same key source + box-focus gate as the nav block above).
191
+ if _box_ds is not None and Melty.text_focused_ds is _box_ds:
192
+ if any(k in (glfw.KEY_ENTER, glfw.KEY_KP_ENTER)
193
+ for k, _ in Melty.frame_key_events):
194
+ search_ds._search_nav_pending = True
195
+ Melty.cache.invalidate_up(search_ds._tile_id, force=True, max_depth=12)
196
+ request_render()
197
+ else:
198
+ imgui.align_text_to_frame_padding()
199
+ imgui.text_colored("", 0.74, 0.5, 0.5, 1.0)
200
+
201
+ if not input_value.search_active:
202
+ draw_state.closed = True
203
+
204
+ return False, input_value
205
+
206
+
207
+ def draw_search_highlight_multi(draw_list, segs, *, current):
208
+ """Highlight a match made of per-line segments (a multi-line search term).
209
+ One glow radiates around the segments' BOUNDING box — per-segment glows
210
+ overlap into an unreadable blob — while each segment keeps its own thin
211
+ outline so the exact matched text stays delineated."""
212
+
213
+ if len(segs) == 1:
214
+ x0, y0, x1, y1 = segs[0]
215
+ draw_search_highlight(draw_list, x0, y0, x1, y1, current=current)
216
+ return
217
+ # Same pixel-snap as draw_search_highlight - see the comment there.
218
+ segs = [(round(x0), round(y0), round(x1), round(y1))
219
+ for (x0, y0, x1, y1) in segs]
220
+ spec = (Toggles.SearchSettings.ActiveElement if current
221
+ else Toggles.SearchSettings.InactiveElements)
222
+ bx0 = min(s[0] for s in segs)
223
+ bx1 = max(s[2] for s in segs)
224
+ _draw_glow(draw_list, bx0, segs[0][1], bx1, segs[-1][3], spec)
225
+ a = float(spec.outline_alpha)
226
+ if a > 0.0:
227
+ oc = spec.outline_color
228
+ col = pack_color(oc[0], oc[1], oc[2], a)
229
+ for x0, y0, x1, y1 in segs:
230
+ draw_list.add_rect(x0, y0, x1, y1, col,
231
+ rounding=float(spec.cutout_radius),
232
+ thickness=float(spec.outline_thickness))
233
+
234
+
235
+ def draw_search_highlight(draw_list, x0, y0, x1, y1, *, current, rounding=0.0):
236
+ """Highlight a search match with its glow (rect cut out) plus an optional
237
+ thin outline. The current match uses the ActiveElement spec; the rest use
238
+ InactiveElements, so both states are tuned independently."""
239
+
240
+ # Pixel-snap: the rect usually derives from the live flow cursor at bake
241
+ # time, and sub-pixel drift between bakes makes the gradient triangles
242
+ # shimmer (glyphs don't - they're pixel-snapped). Rounding pins the whole
243
+ # halo to the pixel grid, so successive bakes bake identically.
244
+ x0, y0, x1, y1 = round(x0), round(y0), round(x1), round(y1)
245
+ spec = (Toggles.SearchSettings.ActiveElement if current
246
+ else Toggles.SearchSettings.InactiveElements)
247
+ _draw_glow(draw_list, x0, y0, x1, y1, spec)
248
+ a = float(spec.outline_alpha)
249
+ if a > 0.0:
250
+ oc = spec.outline_color
251
+ draw_list.add_rect(x0, y0, x1, y1, pack_color(oc[0], oc[1], oc[2], a),
252
+ rounding=max(float(rounding), float(spec.cutout_radius)),
253
+ thickness=float(spec.outline_thickness))
254
+
255
+
256
+
257
+ def search_pill_layout(term, owner_width=None):
258
+ """The find pill's geometry for `term`: ``(box_width, window_width)``.
259
+ The query box grows with the term (a long term stays readable instead
260
+ of scrolling inside a fixed box) from a 200px floor up to what the
261
+ owning view's width leaves for it (`owner_width` minus the pill's
262
+ other parts and a margin), and the window is the row: pad, icon, box,
263
+ gap, count, close, pad. Shared by draw_search (the row) and
264
+ core_render (the window it floats in), so the two always agree."""
265
+ text_w = imgui.calc_text_size(term or "").x
266
+ cap = 520.0 if owner_width is None else max(200.0, owner_width - 220.0)
267
+ box = max(200.0, min(cap, text_w + 40.0))
268
+ return box, box + 158.0
269
+
270
+
271
+ def _perimeter_samples(x0, y0, x1, y1, cseg, r):
272
+ """Walk a rounded-rect perimeter clockwise as (base_x, base_y, nx, ny).
273
+
274
+ `r` is the cutout corner radius. The corners are quarter-arc fans of `cseg`
275
+ segments centred on the rect's inset corners, so each sample already sits on
276
+ the rounded cutout; offsetting it by ``base + normal * d`` grows the rounded
277
+ rect by `d` (the corner radius becomes ``r + d``). The straight edges need no
278
+ interior samples: the single quad spanning one corner's exit sample to the
279
+ next corner's entry sample (same outward normal) is geometrically exact.
280
+ """
281
+ r = max(0.0, min(r, (x1 - x0) * 0.5, (y1 - y0) * 0.5))
282
+ half = math.pi / 2.0
283
+ # (inset corner centre, start angle, end angle) - screen space, y points
284
+ # down, so angle 0 = +x (right), +pi/2 = down, -pi/2 = up.
285
+ corners = (
286
+ ((x1 - r, y0 + r), -half, 0.0), # top-right: up -> right
287
+ ((x1 - r, y1 - r), 0.0, half), # bottom-right: right -> down
288
+ ((x0 + r, y1 - r), half, math.pi), # bottom-left: down -> left
289
+ ((x0 + r, y0 + r), math.pi, math.pi + half), # top-left: left -> up
290
+ )
291
+ out = []
292
+ for (cx, cy), a0, a1 in corners:
293
+ for s in range(cseg + 1):
294
+ ang = a0 + (a1 - a0) * (s / cseg)
295
+ nx, ny = math.cos(ang), math.sin(ang)
296
+ out.append((cx + nx * r, cy + ny * r, nx, ny))
297
+ return out
298
+
299
+
300
+ def _draw_glow(draw_list, x0, y0, x1, y1, spec):
301
+ """Radial gradient halo around (x0,y0,x1,y1) with a rounded rect cut out."""
302
+ falloff = float(spec.falloff)
303
+ opacity = float(spec.opacity)
304
+ if falloff <= 0.0 or opacity <= 0.0:
305
+ return
306
+
307
+ cr, cg, cb = spec.gradient_color
308
+ rings = max(1, int(spec.rings))
309
+ exp = float(spec.falloff_exp)
310
+ pad = float(spec.inner_pad)
311
+ cseg = max(1, int(spec.corner_segments))
312
+ radius = float(spec.cutout_radius)
313
+
314
+ samples = _perimeter_samples(x0 - pad, y0 - pad, x1 + pad, y1 + pad, cseg, radius)
315
+ n = len(samples)
316
+
317
+ # Anti-aliased fill feathers every triangle edge, which leaves visible seams
318
+ # where the gradient triangles meet; turn it off for a clean radial gradient
319
+ # (same trick the swoosh ribbon uses), then restore the previous flags.
320
+ flags = draw_list.flags
321
+ draw_list.flags = flags & ~imgui.DRAW_LIST_ANTI_ALIASED_FILL
322
+ try:
323
+ inner = [(bx, by) for (bx, by, _nx, _ny) in samples] # cutout edge, d=0
324
+ a_inner = opacity
325
+ for k in range(1, rings + 1):
326
+ t = k / rings
327
+ d = t * falloff
328
+ a_outer = opacity * (1.0 - t) ** exp
329
+ outer = [(bx + nx * d, by + ny * d) for (bx, by, nx, ny) in samples]
330
+ col = pack_color(cr, cg, cb, (a_inner + a_outer) * 0.5)
331
+ for i in range(n):
332
+ j = i + 1 if i + 1 < n else 0
333
+ ix0, iy0 = inner[i]
334
+ ix1, iy1 = inner[j]
335
+ ox0, oy0 = outer[i]
336
+ ox1, oy1 = outer[j]
337
+ draw_list.add_triangle_filled(ix0, iy0, ix1, iy1, ox1, oy1, col)
338
+ draw_list.add_triangle_filled(ix0, iy0, ox1, oy1, ox0, oy0, col)
339
+ inner = outer
340
+ a_inner = a_outer
341
+ finally:
342
+ draw_list.flags = flags