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,250 @@
1
+ """
2
+ Generate type stub files (.pyi) for IDE autocomplete support.
3
+
4
+ This module generates stub files that IDEs can read to provide
5
+ autocomplete and type hints for dynamically generated shader methods.
6
+ """
7
+ from pathlib import Path
8
+ from typing import Any
9
+
10
+ from meltygui.graphics.base import GLType
11
+ from meltygui.graphics.registry import get_registry
12
+
13
+
14
+ def _gltype_to_python_type(gltype: GLType) -> str:
15
+ """Map GLType to Python type hint string."""
16
+ type_map = {
17
+ GLType.FLOAT: 'float',
18
+ GLType.INT: 'int',
19
+ GLType.BOOL: 'bool',
20
+ GLType.VEC2: 'Tuple[float, float]',
21
+ GLType.VEC3: 'Tuple[float, float, float]',
22
+ GLType.VEC4: 'Tuple[float, float, float, float]',
23
+ GLType.IVEC2: 'Tuple[int, int]',
24
+ GLType.IVEC3: 'Tuple[int, int, int]',
25
+ GLType.IVEC4: 'Tuple[int, int, int, int]',
26
+ GLType.MAT3: 'Tuple[float, ...]',
27
+ GLType.MAT4: 'Tuple[float, ...]',
28
+ }
29
+ return type_map.get(gltype, 'Any')
30
+
31
+
32
+ def _format_default_value(value: Any) -> str:
33
+ """Format a default value for use in type stub."""
34
+ if isinstance(value, str):
35
+ return f'"{value}"'
36
+ elif isinstance(value, (list, tuple)):
37
+ return str(tuple(value))
38
+ elif isinstance(value, bool):
39
+ return str(value)
40
+ elif isinstance(value, (int, float)):
41
+ return str(value)
42
+ else:
43
+ return repr(value)
44
+
45
+
46
+ def generate_filter_stub(output_path: str = None) -> str:
47
+ """
48
+ Generate a type stub file for the Filter class.
49
+
50
+ Args:
51
+ output_path: Optional path to write the stub file.
52
+ If None, returns the stub content as a string.
53
+
54
+ Returns:
55
+ The generated stub content
56
+ """
57
+ registry = get_registry()
58
+
59
+ # Header
60
+ lines = [
61
+ '"""',
62
+ 'Type stub file for Filter class.',
63
+ '',
64
+ 'This file is auto-generated to provide IDE autocomplete for',
65
+ 'dynamically created shader methods.',
66
+ '',
67
+ 'To regenerate: python -m shader_manager.stub_generator',
68
+ '"""',
69
+ '',
70
+ 'from typing import Optional, Dict, Any, Tuple, List',
71
+ 'from contextlib import AbstractContextManager',
72
+ 'from .shader_compiler import CompiledProgram',
73
+ 'from .registry import ShaderRegistry',
74
+ '',
75
+ '',
76
+ 'class Filter(AbstractContextManager):',
77
+ ' """',
78
+ ' Main interface for shader-based texture filtering.',
79
+ ' ',
80
+ ' All registered shaders are available as methods for IDE autocomplete.',
81
+ ' """',
82
+ ' ',
83
+ ' def __init__(self, auto_compile: bool = True) -> None: ...',
84
+ ' ',
85
+ ]
86
+
87
+ # Generate method stubs for each registered shader
88
+ for shader_name, shader in sorted(registry.shaders.items()):
89
+ # Build uniform parameter hints from shader definition
90
+ uniform_params = []
91
+ uniform_docs = []
92
+
93
+ for uname, (utype, default) in sorted(shader.uniforms.items()):
94
+ python_type = _gltype_to_python_type(utype)
95
+ default_str = _format_default_value(default)
96
+ uniform_params.append(f' {uname}: {python_type} = {default_str},')
97
+ uniform_docs.append(f' {uname}: Shader uniform ({python_type})')
98
+
99
+ # Build method signature
100
+ method_lines = [
101
+ f' def {shader_name}(',
102
+ ' self,',
103
+ ' texture_id: int = 0,',
104
+ ' in_place: bool = False,',
105
+ ]
106
+
107
+ # Add uniform parameters
108
+ method_lines.extend(uniform_params)
109
+
110
+ method_lines.append(' output_texture: Optional[int] = None,')
111
+ method_lines.append(' output_framebuffer: Optional[int] = None,')
112
+ method_lines.append(' input_framebuffer: Optional[int] = None,')
113
+ method_lines.append(' output_size: Optional[Tuple[int, int]] = None,')
114
+
115
+ # Close signature
116
+ method_lines.append(' ) -> int:')
117
+
118
+ # Add docstring
119
+ method_lines.extend([
120
+ ' """',
121
+ f' Apply {shader_name} shader to a texture or framebuffer.',
122
+ ' ',
123
+ ' Args:',
124
+ ' texture_id: Input texture ID (ignored if input_framebuffer set)',
125
+ ' in_place: If True, modify the input texture directly',
126
+ ])
127
+
128
+ # Add uniform documentation
129
+ if uniform_docs:
130
+ method_lines.extend(uniform_docs)
131
+
132
+ method_lines.extend([
133
+ ' output_texture: Optional specific output texture to render to',
134
+ ' output_framebuffer: Optional framebuffer to render to (e.g., 0 for main screen)',
135
+ ' input_framebuffer: Optional framebuffer to read from (e.g., 0 for main screen)',
136
+ ' output_size: Optional (width, height) render resolution; runs the shader',
137
+ ' at a lower resolution while sampling the full-res input',
138
+ ' ',
139
+ ' Returns:',
140
+ ' Output texture ID (0 if rendering to framebuffer)',
141
+ ' """',
142
+ ' ...',
143
+ ' ',
144
+ ])
145
+
146
+ lines.extend(method_lines)
147
+
148
+ # # Add the rest of the Filter class methods
149
+ # lines.extend([
150
+ # ' def apply(',
151
+ # ' self,',
152
+ # ' shader_name: str,',
153
+ # ' texture_id: int,',
154
+ # ' in_place: bool = False,',
155
+ # ' output_texture: Optional[int] = None,',
156
+ # ' **uniforms',
157
+ # ' ) -> int: ...',
158
+ # ' ',
159
+ # ' def chain(self) -> FilterChain: ...',
160
+ # ' ',
161
+ # ' def compile_shader(self, name: str) -> CompiledProgram: ...',
162
+ # ' ',
163
+ # ' def compile_all(self) -> Dict[str, CompiledProgram]: ...',
164
+ # ' ',
165
+ # ' def has_shader(self, name: str) -> bool: ...',
166
+ # ' ',
167
+ # ' def list_shaders(self) -> List[str]: ...',
168
+ # ' ',
169
+ # ' def list_shader_types(self) -> List[str]: ...',
170
+ # ' ',
171
+ # ' def get_shader_info(self, name: str) -> Optional[Dict[str, Any]]: ...',
172
+ # ' ',
173
+ # ' def use_shader(self, name: str) -> AbstractShaderProgram: ...',
174
+ # ' ',
175
+ # ' def clear_texture_cache(self) -> None: ...',
176
+ # ' ',
177
+ # ' def clear_fbo_cache(self) -> None: ...',
178
+ # ' ',
179
+ # ' def get_cache_stats(self) -> Dict[str, Any]: ...',
180
+ # ' ',
181
+ # ' def cleanup(self) -> None: ...',
182
+ # ' ',
183
+ # ' def __enter__(self) -> Filter: ...',
184
+ # ' ',
185
+ # ' def __exit__(self, exc_type, exc_val, exc_tb) -> None: ...',
186
+ # '',
187
+ # '',
188
+ # 'class FilterChain:',
189
+ # ' """Builder pattern for chaining multiple filters."""',
190
+ # ' ',
191
+ # ' def __init__(self, filter_instance: Filter) -> None: ...',
192
+ # ' ',
193
+ # ])
194
+ #
195
+ # # Add chain methods for each chain
196
+ # for shader_name, shader in sorted(registry.shaders.items()):
197
+ # # Build uniform parameters for chain method
198
+ # chain_params = []
199
+ # for uname, (utype, default) in sorted(shader.uniforms.items()):
200
+ # python_type = _gltype_to_python_type(utype)
201
+ # default_str = _format_default_value(default)
202
+ # chain_params.append(f'{uname}: {python_type} = {default_str}')
203
+ #
204
+ # # Build method signature
205
+ # if chain_params:
206
+ # params_str = ', '.join(chain_params)
207
+ # lines.extend([
208
+ # f' def {shader_name}(self, {params_str}) -> FilterChain: ...',
209
+ # ' ',
210
+ # ])
211
+ # else:
212
+ # lines.extend([
213
+ # f' def {shader_name}(self) -> FilterChain: ...',
214
+ # ' ',
215
+ # ])
216
+ #
217
+ # lines.extend([
218
+ # ' def apply(self, texture_id: int, in_place: bool = False) -> int: ...',
219
+ # ' ',
220
+ # ' def clear(self) -> FilterChain: ...',
221
+ # ' ',
222
+ # ' def __call__(self) -> int: ...',
223
+ # '',
224
+ # ])
225
+
226
+ stub_content = '\n'.join(lines)
227
+
228
+ # Write to file if path provided
229
+ if output_path:
230
+ path = Path(output_path)
231
+ path.write_text(stub_content)
232
+ print(f"Generated stub file: {path}")
233
+
234
+ return stub_content
235
+
236
+
237
+ def main():
238
+ """Generate stub file when run as a module."""
239
+ import os
240
+ import sys
241
+
242
+ from meltygui.graphics import Filter # noqa: F401
243
+
244
+ # Generate stub file next to filter.py
245
+ stub_path = os.path.join(os.path.dirname(__file__), 'filter.pyi')
246
+ generate_filter_stub(stub_path)
247
+
248
+
249
+ if __name__ == '__main__':
250
+ main()
@@ -0,0 +1,170 @@
1
+ import threading
2
+ from dataclasses import dataclass
3
+
4
+ import numpy
5
+ from OpenGL.GL import (
6
+ glGenTextures, glBindTexture, glTexImage2D, glTexParameteri,
7
+ glDeleteTextures, glGetTexImage, glActiveTexture,
8
+ GL_TEXTURE_2D, GL_RGBA, GL_RGB, GL_RED, GL_RG, GL_UNSIGNED_BYTE,
9
+ GL_SRGB8_ALPHA8, GL_SRGB8,
10
+ )
11
+ from PIL import Image
12
+ import io
13
+ from typing import Any
14
+
15
+ from meltygui.core.windowing.glfw_utils import print_stack_trace
16
+ from meltygui.core.rendering.core_decoration import defaults
17
+
18
+ # Map PIL modes to GL formats
19
+ PIL_TO_GL_FORMAT = {
20
+ "L": GL_RED, # Grayscale
21
+ "LA": GL_RG, # Grayscale + Alpha
22
+ "RGB": GL_RGB,
23
+ "RGBA": GL_RGBA,
24
+ }
25
+
26
+ # Reverse mapping for dumps
27
+ GL_TO_PIL_MODE = {v: k for k, v in PIL_TO_GL_FORMAT.items()}
28
+
29
+ from OpenGL.GL import (
30
+ glGenTextures, glBindTexture, glTexImage2D, glTexParameteri,
31
+ glDeleteTextures, glGetTexImage, glActiveTexture,
32
+ GL_TEXTURE_2D, GL_RGBA, GL_UNSIGNED_BYTE,
33
+ GL_TEXTURE_MIN_FILTER, GL_TEXTURE_MAG_FILTER, GL_LINEAR,
34
+ GL_TEXTURE_WRAP_S, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE,
35
+ GL_LINEAR_MIPMAP_LINEAR, glGenerateMipmap, GL_TEXTURE0, glGetIntegerv
36
+ )
37
+
38
+ @dataclass
39
+ class PendingTexture:
40
+ """Decoded image data awaiting GL upload on main thread.
41
+
42
+ ``name`` / ``tex_width`` / ``tex_height`` / ``gl_format`` / ``data`` are
43
+ populated at decode time off the GL thread (e.g. by ``PngCodec.loads``).
44
+ ``tint`` is overwritten with the avg color after construction. ``texture_id``
45
+ is filled in once ``upload_to_gl`` runs on the GL thread.
46
+ """
47
+ name: str
48
+ tex_width: int
49
+ tex_height: int
50
+ gl_format: int
51
+ data: bytes
52
+ tint: tuple[float, float, float] = (1.0, 1.0, 1.0)
53
+ texture_id: numpy.uint32 | None = None # Filled after upload
54
+
55
+ def pending_upload(self) -> int:
56
+ if self.texture_id is not None:
57
+ return False
58
+
59
+ """Upload using Melty library. MUST be called from GL thread."""
60
+ # Texture manager singleton
61
+ texture_manager = TextureManager()
62
+ texture_id = texture_manager.upload_to_gl(self)
63
+ self.texture_id = texture_id
64
+ return True
65
+
66
+ class TextureManager:
67
+ """Manages GL texture lifecycle with path-based caching and deferred uploads."""
68
+
69
+ _instance = None
70
+
71
+ def __new__(cls):
72
+ if cls._instance is None:
73
+ cls._instance = super().__new__(cls)
74
+ cls._instance._cache = {} # path -> texture_id
75
+ cls._instance._pending = {} # path -> PendingTexture
76
+ cls._instance._ref_counts = {} # path -> count
77
+ cls._instance._metadata = {} # path -> (width, height, gl_format)
78
+ cls._instance._lock = threading.Lock()
79
+ return cls._instance
80
+
81
+ def upload_to_gl(self, pending: PendingTexture) -> int:
82
+ """Create the GL texture. MUST be called from GL thread."""
83
+ texture_id = glGenTextures(1)
84
+ glBindTexture(GL_TEXTURE_2D, texture_id)
85
+ # 8-bit images are sRGB-encoded; an sRGB internal format decodes
86
+ # to linear at sample time, which is what the linear scRGB scene
87
+ # (scene_color.py) composites.
88
+ internal = {GL_RGBA: GL_SRGB8_ALPHA8, GL_RGB: GL_SRGB8}.get(pending.gl_format, pending.gl_format)
89
+ glTexImage2D(
90
+ GL_TEXTURE_2D, 0, internal,
91
+ pending.tex_width, pending.tex_height, 0,
92
+ pending.gl_format, GL_UNSIGNED_BYTE, pending.data
93
+ )
94
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
95
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
96
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
97
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
98
+
99
+ glBindTexture(GL_TEXTURE_2D, 0)
100
+ pending.texture_id = texture_id
101
+
102
+ return texture_id
103
+
104
+ def get(self, path: str) -> int | None:
105
+ """Get a cached texture ID by path, or None if not yet uploaded."""
106
+ with self._lock:
107
+ return self._cache.get(path)
108
+
109
+ def put_pending(self, path: str, pending: PendingTexture):
110
+ """Queue decoded image data for later GL upload. Thread-safe."""
111
+ with self._lock:
112
+ if path in self._cache:
113
+ pending.texture_id = self._cache[path]
114
+ return
115
+ self._pending[path] = pending
116
+
117
+ def is_pending(self, path: str) -> bool:
118
+ """Check if a texture is queued but not yet uploaded."""
119
+ with self._lock:
120
+ return path in self._pending
121
+
122
+ def get_metadata(self, path: str) -> tuple[int, int, int] | None:
123
+ """Get (width, height, gl_format) for an uploaded texture."""
124
+ with self._lock:
125
+ return self._metadata.get(path)
126
+
127
+ def acquire(self, path: str) -> int | None:
128
+ """Increment ref count and return texture ID."""
129
+ with self._lock:
130
+ if path in self._cache:
131
+ self._ref_counts[path] = self._ref_counts.get(path, 0) + 1
132
+ return self._cache[path]
133
+ return None
134
+
135
+ def release(self, path: str):
136
+ """Decrement ref count, delete texture when it hits 0."""
137
+ with self._lock:
138
+ if path not in self._cache:
139
+ return
140
+ self._ref_counts[path] -= 1
141
+ if self._ref_counts[path] <= 0:
142
+ texture_id = self._cache.pop(path, None)
143
+ self._ref_counts.pop(path, None)
144
+ self._metadata.pop(path, None)
145
+ # Must delete outside lock if GL calls can block
146
+
147
+ if texture_id:
148
+ try:
149
+ glDeleteTextures([texture_id])
150
+ except Exception:
151
+ pass
152
+
153
+ def clear(self):
154
+ """Release all textures and pending uploads."""
155
+ with self._lock:
156
+ texture_ids = list(self._cache.values())
157
+ self._cache.clear()
158
+ self._pending.clear()
159
+ self._ref_counts.clear()
160
+ self._metadata.clear()
161
+
162
+ for texture_id in texture_ids:
163
+ try:
164
+ glDeleteTextures([texture_id])
165
+ except Exception:
166
+ pass
167
+
168
+ def __contains__(self, path: str) -> bool:
169
+ with self._lock:
170
+ return path in self._cache or path in self._pending