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,266 @@
1
+ """Editable palette dictionaries and integer-like LUT texture values."""
2
+ import math
3
+ import weakref
4
+
5
+ from meltygui.core.conversion.bubbling import _BubblingDictMixin, install_bubbling
6
+ from meltygui.model.texture_model import TextureId
7
+
8
+
9
+ class Lut(str):
10
+ """A LUT NAME that is still a str everywhere it matters (dict keys,
11
+ comparisons, GLSL host lookups) but carries its own TYPE, so meltygui routes
12
+ it to its own renderer — a dropdown of the available LUTs rather than a
13
+ text field. Same contract as TensorDim: the renderer must return
14
+ Lut(...) or the first edit stores a plain str and the row falls back to
15
+ the generic str renderer."""
16
+
17
+ __slots__ = ()
18
+
19
+ def __repr__(self):
20
+ return f"Lut({str(self)!r})"
21
+
22
+
23
+ def _bake_lut(fn, n=256, clamp=True):
24
+ """Sample fn(v ∈ [0,1]) → (r, g, b) into the flat-list LUT shape.
25
+ Entries are EXTENDED sRGB (hdr_color.py): `clamp=False` keeps values
26
+ past [0, 1] — above 1 is brighter than the desktop's white, negative is
27
+ outside the sRGB gamut (P3) — for a table that is HDR on its own."""
28
+ out = []
29
+ for i in range(n):
30
+ rgb = fn(i / (n - 1))
31
+ if clamp:
32
+ rgb = (min(1.0, max(0.0, float(c))) for c in rgb)
33
+ out += [float(c) for c in rgb]
34
+ return out
35
+
36
+ def hdr_ramp(hue_at, peak=16.0, chroma=1.0, white_from=0.55, n=1024):
37
+ """Build an HDR colour scale as a flat LUT list: ``n`` entries spaced
38
+ UNIFORMLY in Oklab lightness from black to ``peak`` × the desktop's
39
+ white, each the most saturated colour of hue ``hue_at(u)`` (u = the
40
+ lightness fraction, 0 → 1; radians) that fits the P3 box that tall,
41
+ times ``chroma``. That is what "a bigger LUT" means: an SDR scale
42
+ (``hot``: black → red → yellow → white) runs the max-chroma edges of a
43
+ box ONE white tall; this runs the same kind of path up a box ``peak``
44
+ whites tall, so the scale has log2(peak) extra stops of distinguishable
45
+ levels — not a brighter table, a longer one. Entries are extended sRGB,
46
+ unclamped (P3 reaches below 0, HDR above 1).
47
+
48
+ Whitening is a SECOND axis of information, not a side effect: past
49
+ ``white_from`` the chroma eases to zero at the peak (smoothstep), so
50
+ the top of the range reads as saturated → pale → white while the
51
+ lightness keeps climbing — the box alone would keep a P3 yellow fully
52
+ saturated to within a few percent of the peak and then snap to white,
53
+ since a pure yellow fits a 16× box until its two channels hit 16. The
54
+ ease also lands the scale inside what the panel can show: a 12× white
55
+ saturated yellow is past any panel's peak and the compositor would
56
+ desaturate it anyway (Hyprland's luminance-preserving rule)."""
57
+ from meltygui.hdr_color import _cbrt
58
+ from meltygui.hdr_color import linear_to_srgb
59
+ from meltygui.hdr_color import oklab_max_chroma
60
+ from meltygui.hdr_color import oklab_to_linear
61
+ peak_lightness = _cbrt(peak)
62
+ out = []
63
+ for i in range(n):
64
+ u = i / (n - 1)
65
+ lightness = u * peak_lightness
66
+ hue = hue_at(u)
67
+ w = min(1.0, max(0.0, (u - white_from) / (1.0 - white_from)))
68
+ envelope = 1.0 - w * w * (3.0 - 2.0 * w)
69
+ c = chroma * envelope * oklab_max_chroma(lightness, hue, peak)
70
+ lin = oklab_to_linear((lightness, c * math.cos(hue), c * math.sin(hue)))
71
+ out += [linear_to_srgb(v) for v in lin]
72
+ return out
73
+
74
+ def _hot_hdr_hue(u):
75
+ """`hot`'s hue path for hdr_ramp: P3 red through the lower half of the
76
+ lightness range, turning to P3 yellow across the middle, yellow above
77
+ (the box then whitens it toward the peak). The SDR `hot` is untouched:
78
+ an HDR scale is its own picker entry, never a scaled SDR one, so a
79
+ colour scale people know keeps meaning what it meant (Lukas 09-08)."""
80
+ from meltygui.hdr_color import linear_p3_to_srgb
81
+ from meltygui.hdr_color import oklab_hue
82
+ # [tint=(0.95, 0.35, 0.1)]
83
+ red_until = 0.4 # lightness fraction that stays pure red
84
+ # [tint=(0.95, 0.75, 0.2)]
85
+ yellow_from = 0.7 # ... and where it has fully turned yellow
86
+ red = oklab_hue(linear_p3_to_srgb((1.0, 0.0, 0.0)))
87
+ yellow = oklab_hue(linear_p3_to_srgb((1.0, 1.0, 0.0)))
88
+ t = min(1.0, max(0.0, (u - red_until) / (yellow_from - red_until)))
89
+ t = t * t * (3.0 - 2.0 * t) # smoothstep
90
+ return red + (yellow - red) * t
91
+
92
+ def _poly(coeffs):
93
+ """Per-channel polynomial in t (Horner); rows are (r, g, b) coefficients
94
+ in ascending order — the shape of Matt Zucker's matplotlib colormap fits
95
+ (shadertoy WlfXRN) and of Google's turbo fit."""
96
+
97
+ def fn(t):
98
+ r = g = b = 0.0
99
+ for cr, cg, cb in reversed(coeffs):
100
+ r, g, b = r * t + cr, g * t + cg, b * t + cb
101
+ return r, g, b
102
+
103
+ return fn
104
+
105
+ def _seismic(v):
106
+ """Diverging blue-white-red with dark ends (matplotlib's seismic) —
107
+ strong negative coverage: zero is white, sign maps to hue, magnitude
108
+ to saturation/darkness. Pair with the `centered` param."""
109
+ if v < 0.25:
110
+ t = v / 0.25
111
+ return (0.0, 0.0, 0.3 + 0.7 * t)
112
+ if v < 0.5:
113
+ t = (v - 0.25) / 0.25
114
+ return (t, t, 1.0)
115
+ if v < 0.75:
116
+ t = (v - 0.5) / 0.25
117
+ return (1.0, 1.0 - t, 1.0 - t)
118
+ t = (v - 0.75) / 0.25
119
+ return (1.0 - 0.5 * t, 0.0, 0.0)
120
+
121
+ def _coolwarm(v):
122
+ """Cool-to-warm diverging ramp: blue → near-white → red."""
123
+ if v < 0.5:
124
+ t, a, b = v * 2.0, (0.230, 0.299, 0.754), (0.865, 0.865, 0.865)
125
+ else:
126
+ t, a, b = v * 2.0 - 1.0, (0.865, 0.865, 0.865), (0.706, 0.016, 0.150)
127
+ return tuple(x + (y - x) * t for x, y in zip(a, b))
128
+
129
+ _VIRIDIS = [
130
+ (0.2777273272234177, 0.005407344544966578, 0.3340998053353061),
131
+ (0.1050930431085774, 1.404613529898575, 1.384590162594685),
132
+ (-0.3308618287255563, 0.214847559468213, 0.09509516302823659),
133
+ (-4.634230498983486, -5.799100973351585, -19.33244095627987),
134
+ (6.228269936347081, 14.17993336680509, 56.69055260068105),
135
+ (4.776384997670288, -13.74514537774601, -65.35303263337234),
136
+ (-5.435455855934631, 4.645852612178535, 26.3124352495832),
137
+ ]
138
+
139
+ _PLASMA = [
140
+ (0.05873234392399702, 0.02333670892565664, 0.5433401826748754),
141
+ (2.176514634195958, 0.2383834171260182, 0.7539604599784036),
142
+ (-2.689460476458034, -7.455851135738909, 3.110799939717086),
143
+ (6.130348345893603, 42.3461881477227, -28.51885465332158),
144
+ (-11.10743619062271, -82.66631109428045, 60.13984767418263),
145
+ (10.02306557647065, 71.41361770095349, -54.07218655560067),
146
+ (-3.658713842777788, -22.93153465461149, 18.19190778539828),
147
+ ]
148
+
149
+ _MAGMA = [
150
+ (-0.002136485053939582, -0.000749655052795221, -0.005386127855323933),
151
+ (0.2516605407371642, 0.6775232436837668, 2.494026599312351),
152
+ (8.353717279216625, -3.577719514958484, 0.3144679030132573),
153
+ (-27.66873308576866, 14.26473078096533, -13.64921318813922),
154
+ (52.17613981234068, -27.94360607168351, 12.94416944238394),
155
+ (-50.76852536473588, 29.04658282127291, 4.23415299384598),
156
+ (18.65570506591883, -11.48977351997711, -5.601961508734096),
157
+ ]
158
+
159
+ _INFERNO = [
160
+ (0.0002189403691192265, 0.001651004631001012, -0.01948089843709184),
161
+ (0.1065134194856116, 0.5639564367884091, 3.932712388889277),
162
+ (11.60249308247187, -3.972853965665698, -15.9423941062914),
163
+ (-41.70399613139459, 17.43639888205313, 44.35414519872813),
164
+ (77.162935699427, -33.40235894210092, -81.80730925738993),
165
+ (-71.31942824499214, 32.62606426397723, 73.20951985803202),
166
+ (25.13112622477341, -12.24266895238567, -23.07032500287172),
167
+ ]
168
+
169
+ _TURBO = [
170
+ (0.13572138, 0.09140261, 0.10667330),
171
+ (4.61539260, 2.19418839, 12.64194608),
172
+ (-42.66032258, 4.84296658, -60.58204836),
173
+ (132.13108234, -14.18503333, 110.36276771),
174
+ (-152.94239396, 4.27729857, -89.90310912),
175
+ (59.28637943, 2.82956604, 27.34824973),
176
+ ]
177
+
178
+
179
+ def make_luts():
180
+ """A fresh editable dictionary of flat RGB lists, including HDR palettes."""
181
+ return {
182
+ # the original custom jet, baked from the exact formula the shader uses
183
+ "jet": _bake_lut(lambda v: (1.5 - abs(4.0 * v - 3.0),
184
+ 1.5 - abs(4.0 * v - 2.0),
185
+ 1.5 - abs(4.0 * v - 1.0))),
186
+ "viridis": _bake_lut(_poly(_VIRIDIS)),
187
+ "plasma": _bake_lut(_poly(_PLASMA)),
188
+ "magma": _bake_lut(_poly(_MAGMA)),
189
+ "inferno": _bake_lut(_poly(_INFERNO)),
190
+ "turbo": _bake_lut(_poly(_TURBO)),
191
+ "grey": _bake_lut(lambda v: (v, v, v)),
192
+ "hot": _bake_lut(lambda v: (3.0 * v, 3.0 * v - 1.0, 3.0 * v - 2.0)),
193
+ "coolwarm": _bake_lut(_coolwarm),
194
+ "seismic": _bake_lut(_seismic),
195
+ # ── HDR ramps get their own entries (hdr_ramp - uniform Oklab lightness
196
+ # up a 16× box, max chroma that fits, 4 stops longer than the SDR one)
197
+ "hot_hdr": hdr_ramp(_hot_hdr_hue, peak=16.0),
198
+ }
199
+
200
+
201
+ def lut_values(luts, name):
202
+ """Resolve a named palette from supplied data, falling back to its jet entry."""
203
+ return luts.get(str(name), luts.get("jet", (0.0, 0.0, 0.0, 1.0, 1.0, 1.0)))
204
+
205
+
206
+ class LutTexture(TextureId):
207
+ """A flat RGB palette that behaves as its current OpenGL texture ID."""
208
+
209
+ def __init__(self, colors):
210
+ from OpenGL.GL import GL_TEXTURE_1D
211
+ super().__init__(GL_TEXTURE_1D)
212
+ self.colors = colors
213
+
214
+ def _upload(self, state):
215
+ return state.texture1d('texture', self.colors, version=hash(tuple(self.colors)))
216
+
217
+ def cuda(self, device):
218
+ """The same palette on the tensor's device, refreshed when colours change."""
219
+ import torch
220
+ return self._state().get(
221
+ ('cuda_lut', str(device)),
222
+ lambda: torch.tensor(self.colors, dtype=torch.float32, device=device).reshape(-1, 3),
223
+ deps=tuple(self.colors))
224
+
225
+
226
+ class LutPalette(_BubblingDictMixin, dict):
227
+ """An ordinary editable palette dictionary with stable texture proxies.
228
+
229
+ List/dictionary edits bubble through the existing mutation mechanism.
230
+ Subscribers are weak bound callbacks; no host, rendering loop or GL work
231
+ is needed to hold or edit the values.
232
+ """
233
+
234
+ def __init__(self, colors=None):
235
+ dict.__init__(self, make_luts() if colors is None else colors)
236
+ self._textures = {}
237
+ self._callbacks = {}
238
+ install_bubbling(self, self)
239
+
240
+ def texture(self, name):
241
+ name = str(name)
242
+ colors = lut_values(self, name)
243
+ texture = self._textures.get(name)
244
+ if texture is None:
245
+ texture = LutTexture(colors)
246
+ self._textures[name] = texture
247
+ else:
248
+ texture.colors = colors
249
+ return texture
250
+
251
+ def watch(self, callback, **kwargs):
252
+ key = (id(callback.__self__), callback.__func__)
253
+ self._callbacks[key] = (weakref.WeakMethod(callback), kwargs)
254
+
255
+ def _mark_changed(self):
256
+ for name in list(self._textures):
257
+ if name not in self:
258
+ del self._textures[name]
259
+ else:
260
+ self._textures[name].colors = self[name]
261
+ for key, (reference, kwargs) in list(self._callbacks.items()):
262
+ callback = reference()
263
+ if callback is None:
264
+ del self._callbacks[key]
265
+ else:
266
+ callback(**kwargs)
@@ -0,0 +1,173 @@
1
+ """Search model functions and supporting definitions."""
2
+
3
+
4
+
5
+ def _fuzzy_substring_distance(q, k):
6
+ """Min edit distance between `q` and any substring of `k` (the k-differences
7
+ DP: row 0 is all zeros so the match may start anywhere in k). Damerau/OSA, so
8
+ an adjacent transposition — the most common typo — costs 1, not 2. Both
9
+ lowercase."""
10
+ m, n = len(q), len(k)
11
+ if m == 0:
12
+ return 0
13
+ prev2 = None
14
+ prev = [0] * (n + 1)
15
+ for i in range(1, m + 1):
16
+ qi = q[i - 1]
17
+ cur = [i] + [0] * n
18
+ for j in range(1, n + 1):
19
+ cost = 0 if qi == k[j - 1] else 1
20
+ v = min(prev[j] + 1, cur[j - 1] + 1, prev[j - 1] + cost)
21
+ if (prev2 is not None and j > 1
22
+ and qi == k[j - 2] and q[i - 2] == k[j - 1]):
23
+ v = min(v, prev2[j - 2] + 1)
24
+ cur[j] = v
25
+ prev2 = prev
26
+ prev = cur
27
+ return min(prev)
28
+
29
+
30
+ def _fuzzy_key_match(q, k):
31
+ """Does query `q` match candidate `k` (both lowercase), tolerating a few
32
+ typos? Exact substring first (fast, also covers short queries); for longer
33
+ queries fall back to approximate substring matching with a small edit budget
34
+ that scales with length (~1 typo per 4 chars). The single predicate the key
35
+ match's count, current index and highlight all share, so they stay in sync."""
36
+ if not q:
37
+ return False
38
+ if q in k:
39
+ return True
40
+ if len(q) < 4:
41
+ return False
42
+ return _fuzzy_substring_distance(q, k) <= max(1, len(q) // 4)
43
+
44
+
45
+ def _split_words(s):
46
+ """Lowercased word tuple of an identifier / label: separators (`_`, `.`,
47
+ `/`, ` `, `-`, ...) and camelCase boundaries both split; digits are their
48
+ own words. ("draw_any" -> ("draw", "any"), "GLState" -> ("gl", "state"),
49
+ "new_core_view.py" -> ("new", "core", "view", "py"))."""
50
+ from meltygui.core.rendering.render_dispatch import _WORD_RE
51
+
52
+ return tuple(w.lower() for w in _WORD_RE.findall(s))
53
+
54
+
55
+ def _edit_distance(a, b, cap):
56
+ """Damerau/OSA edit distance, capped (returns cap + 1 once exceeded)."""
57
+ m, n = len(a), len(b)
58
+ if abs(m - n) > cap:
59
+ return cap + 1
60
+ prev2 = None
61
+ prev = list(range(n + 1))
62
+ for i in range(1, m + 1):
63
+ ai = a[i - 1]
64
+ cur = [i] + [0] * n
65
+ row_min = i
66
+ for j in range(1, n + 1):
67
+ cost = 0 if ai == b[j - 1] else 1
68
+ v = min(prev[j] + 1, cur[j - 1] + 1, prev[j - 1] + cost)
69
+ if (prev2 is not None and j > 1
70
+ and ai == b[j - 2] and a[i - 2] == b[j - 1]):
71
+ v = min(v, prev2[j - 2] + 1)
72
+ cur[j] = v
73
+ if v < row_min:
74
+ row_min = v
75
+ if row_min > cap:
76
+ return cap + 1
77
+ prev2 = prev
78
+ prev = cur
79
+ return prev[n]
80
+
81
+
82
+ def _word_edits(w, tw, budget):
83
+ """Cost of query word `w` claiming target word `tw`: 0 for an exact
84
+ prefix or a >=2-char exact substring; the edit distance of a fuzzy
85
+ PREFIX (same first char, >=3 chars, ~1 typo per 3 chars) when within
86
+ `budget`; None when it can't claim it."""
87
+ if tw.startswith(w):
88
+ return 0
89
+ if len(w) >= 2 and w in tw:
90
+ return 0
91
+ if budget <= 0 or len(w) < 3 or w[0] != tw[0]:
92
+ return None
93
+ tol = min(budget, 1 + (len(w) - 3) // 3)
94
+ best = None
95
+ for L in (len(w) - 1, len(w), len(w) + 1):
96
+ if 0 < L <= len(tw):
97
+ d = _edit_distance(w, tw[:L], tol)
98
+ if d <= tol and (best is None or d < best):
99
+ best = d
100
+ return best
101
+
102
+
103
+ def _assign_words(qws, twords, budget):
104
+ """Min total cost of every query word claiming a distinct target word
105
+ (any order), or None. Tiny backtracking -- a handful of words a side."""
106
+ n = len(twords)
107
+ used = [False] * n
108
+ best = [None]
109
+
110
+ def rec(i, cost):
111
+ if best[0] is not None and cost >= best[0]:
112
+ return
113
+ if i == len(qws):
114
+ best[0] = cost
115
+ return
116
+ w = qws[i]
117
+ for j in range(n):
118
+ if used[j]:
119
+ continue
120
+ e = _word_edits(w, twords[j], budget - cost)
121
+ if e is None:
122
+ continue
123
+ used[j] = True
124
+ rec(i + 1, cost + e)
125
+ used[j] = False
126
+
127
+ rec(0, 0)
128
+ return best[0]
129
+
130
+
131
+ def _segment_match(q, twords, budget):
132
+ """Min cost of segmenting separator-less `q` into consecutive pieces
133
+ that each claim a distinct target word (rules of _word_edits), or None.
134
+ ("anydraw" -> any + draw; "drawamy" -> draw + amy~any.)"""
135
+ n = len(twords)
136
+ used = [False] * n
137
+ best = [None]
138
+ L = len(q)
139
+
140
+ def rec(pos, cost):
141
+ if best[0] is not None and cost >= best[0]:
142
+ return
143
+ if pos == L:
144
+ best[0] = cost
145
+ return
146
+ for j in range(n):
147
+ if used[j]:
148
+ continue
149
+ tw = twords[j]
150
+ used[j] = True
151
+ for k in range(pos + 1, L + 1):
152
+ e = _word_edits(q[pos:k], tw, budget - cost)
153
+ if e is not None:
154
+ rec(k, cost + e)
155
+ used[j] = False
156
+
157
+ rec(0, 0)
158
+ return best[0]
159
+
160
+
161
+ def _word_match(q, qws, twords, budget):
162
+ """Total edit cost of query `q` (lowercased; `qws` its words) against a
163
+ target's words, or None. Word-form queries assign words; a single-word
164
+ query tries a straight word claim, then segmentation."""
165
+ if not twords:
166
+ return None
167
+ if len(qws) > 1:
168
+ return _assign_words(qws, twords, budget)
169
+ if len(qws) == 1:
170
+ e = _assign_words(qws, twords, budget)
171
+ if e is not None:
172
+ return e
173
+ return _segment_match(q, twords, budget)