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.
- meltygui/__init__.py +107 -0
- meltygui/accounts/__init__.py +0 -0
- meltygui/accounts/internet_accounts.py +1355 -0
- meltygui/chat/__init__.py +91 -0
- meltygui/chat/activity.py +75 -0
- meltygui/chat/backends.py +36 -0
- meltygui/chat/chat_interface.py +732 -0
- meltygui/chat/chat_proxy.py +352 -0
- meltygui/chat/codex_proxy.py +592 -0
- meltygui/chat/codex_settings.py +100 -0
- meltygui/chat/codex_transport.py +60 -0
- meltygui/chat/command_parser.py +204 -0
- meltygui/chat/images.py +227 -0
- meltygui/chat/messages.py +417 -0
- meltygui/chat/metadata.py +139 -0
- meltygui/chat/writer_locks.py +64 -0
- meltygui/code/__init__.py +0 -0
- meltygui/code/basic_converters.py +533 -0
- meltygui/code/chain_converters.py +2111 -0
- meltygui/code/code_checks.py +2209 -0
- meltygui/code/core_syntax.py +1430 -0
- meltygui/code/file_converters.py +1933 -0
- meltygui/code/fileref.py +702 -0
- meltygui/code/hotswap_guard.py +144 -0
- meltygui/code/libcst_conversion.py +9724 -0
- meltygui/code/live_instrument.py +392 -0
- meltygui/code/live_view.py +2490 -0
- meltygui/code/melty_scan.py +2684 -0
- meltygui/code/new_codecs.py +1255 -0
- meltygui/code/new_converters.py +3017 -0
- meltygui/code/project_code.py +278 -0
- meltygui/code/source_context.py +63 -0
- meltygui/code/symbol_roster.py +1588 -0
- meltygui/code/syntax_check.py +34 -0
- meltygui/code/syntax_check_worker.py +114 -0
- meltygui/completion/__init__.py +0 -0
- meltygui/completion/fim.py +1232 -0
- meltygui/completion/fim_context.py +481 -0
- meltygui/completion/providers/__init__.py +0 -0
- meltygui/completion/providers/anthropic_oauth.py +446 -0
- meltygui/completion/providers/anthropic_requests.py +69 -0
- meltygui/completion/providers/claude.py +203 -0
- meltygui/completion/providers/claude_usage.py +499 -0
- meltygui/completion/providers/codex_accounts.py +180 -0
- meltygui/completion/providers/copilot.py +617 -0
- meltygui/completion/providers/oauth_popup.py +220 -0
- meltygui/completion/providers/ollama.py +320 -0
- meltygui/completion/providers/profiles.py +23 -0
- meltygui/core/README.md +88 -0
- meltygui/core/__init__.py +1 -0
- meltygui/core/automation/__init__.py +1 -0
- meltygui/core/automation/action_core.py +153 -0
- meltygui/core/automation/collection_action.py +45 -0
- meltygui/core/automation/mcp_eval.py +167 -0
- meltygui/core/automation/mcp_hotswap.py +107 -0
- meltygui/core/automation/mcp_query.py +552 -0
- meltygui/core/automation/mcp_server.py +657 -0
- meltygui/core/automation/orchestration_core.py +2636 -0
- meltygui/core/automation/query_core.py +124 -0
- meltygui/core/automation/search_core.py +26 -0
- meltygui/core/automation/selector_core.py +340 -0
- meltygui/core/automation/value_core.py +1752 -0
- meltygui/core/cache/__init__.py +1 -0
- meltygui/core/cache/cache_diagnostics.py +0 -0
- meltygui/core/cache/invalidation_decoration.py +153 -0
- meltygui/core/cache/invalidation_tracker.py +43 -0
- meltygui/core/cache/tile_cache.py +5968 -0
- meltygui/core/conversion/__init__.py +1 -0
- meltygui/core/conversion/bubbling.py +599 -0
- meltygui/core/conversion/cache_tree.py +188 -0
- meltygui/core/conversion/chain.py +113 -0
- meltygui/core/conversion/converter_register.py +145 -0
- meltygui/core/conversion/data_decoration.py +67 -0
- meltygui/core/conversion/dict_conversion.py +1815 -0
- meltygui/core/conversion/dict_conversion_util.py +177 -0
- meltygui/core/conversion/dynamic_obj.py +89 -0
- meltygui/core/conversion/graph_compare.py +183 -0
- meltygui/core/conversion/load_save_v2.py +1032 -0
- meltygui/core/conversion/missing_saved_class.py +39 -0
- meltygui/core/conversion/path_finder.py +606 -0
- meltygui/core/conversion/render_host.py +1083 -0
- meltygui/core/core_render.py +6537 -0
- meltygui/core/definition_hotswap.py +231 -0
- meltygui/core/diagnostics/__init__.py +1 -0
- meltygui/core/diagnostics/attribute_churn.py +38 -0
- meltygui/core/diagnostics/fps_counter.py +39 -0
- meltygui/core/diagnostics/gpu_frame_timer.py +103 -0
- meltygui/core/diagnostics/inspection_core.py +169 -0
- meltygui/core/diagnostics/monitor_core.py +105 -0
- meltygui/core/diagnostics/notifications.py +706 -0
- meltygui/core/diagnostics/perf_trace.py +281 -0
- meltygui/core/diagnostics/profile_decoration.py +88 -0
- meltygui/core/diagnostics/resize_trace.py +62 -0
- meltygui/core/diagnostics/screenshot_core.py +247 -0
- meltygui/core/diagnostics/session_status.py +98 -0
- meltygui/core/diagnostics/trace_core.py +445 -0
- meltygui/core/files/__init__.py +1 -0
- meltygui/core/files/file_core.py +208 -0
- meltygui/core/files/file_explorer_core.py +104 -0
- meltygui/core/files/file_tree_core.py +198 -0
- meltygui/core/files/file_watch_core.py +43 -0
- meltygui/core/files/import_graph_core.py +43 -0
- meltygui/core/files/metadata_core.py +51 -0
- meltygui/core/graphics/__init__.py +1 -0
- meltygui/core/graphics/cuda_context_core.py +166 -0
- meltygui/core/graphics/cuda_interop_core.py +136 -0
- meltygui/core/graphics/cuda_kernel_core.py +91 -0
- meltygui/core/graphics/framebuffer_recorder.py +337 -0
- meltygui/core/graphics/gl_state.py +658 -0
- meltygui/core/graphics/lut_core.py +52 -0
- meltygui/core/graphics/overlay_renderer.py +984 -0
- meltygui/core/graphics/scene_target.py +180 -0
- meltygui/core/graphics/screenshot.py +439 -0
- meltygui/core/graphics/shader_func.py +478 -0
- meltygui/core/graphics/tensor_core.py +45 -0
- meltygui/core/graphics/text_texture.py +329 -0
- meltygui/core/graphics/wayland_color.py +635 -0
- meltygui/core/input/__init__.py +1 -0
- meltygui/core/input/collision.py +165 -0
- meltygui/core/input/drag_drop_core.py +1525 -0
- meltygui/core/input/hypr_left_drag.py +323 -0
- meltygui/core/input/input_core.py +245 -0
- meltygui/core/input/input_handler.py +1101 -0
- meltygui/core/input/mouse_cursor.py +355 -0
- meltygui/core/input/pynput_backend.py +1054 -0
- meltygui/core/input/space_mouse.py +338 -0
- meltygui/core/input/touchpad_backend.py +393 -0
- meltygui/core/input/view_selection.py +177 -0
- meltygui/core/layout/__init__.py +1 -0
- meltygui/core/layout/column_core.py +2153 -0
- meltygui/core/layout/cursor_core.py +161 -0
- meltygui/core/layout/dropdown_core.py +278 -0
- meltygui/core/layout/edge_constraints.py +155 -0
- meltygui/core/layout/grid_core.py +117 -0
- meltygui/core/layout/header_core.py +23 -0
- meltygui/core/layout/header_runtime.py +67 -0
- meltygui/core/layout/layout_core.py +87 -0
- meltygui/core/layout/tile_manager_core.py +591 -0
- meltygui/core/melty.py +6726 -0
- meltygui/core/module_map.json +896 -0
- meltygui/core/module_names.py +19 -0
- meltygui/core/rendering/__init__.py +1 -0
- meltygui/core/rendering/core_decoration.py +431 -0
- meltygui/core/rendering/core_render_helpers.py +328 -0
- meltygui/core/rendering/func_metadata.py +398 -0
- meltygui/core/rendering/mode.py +818 -0
- meltygui/core/rendering/mode_defaults.py +41 -0
- meltygui/core/rendering/modes.py +136 -0
- meltygui/core/rendering/parameter_core.py +1665 -0
- meltygui/core/rendering/render_dispatch.py +1891 -0
- meltygui/core/rendering/render_funcs.py +273 -0
- meltygui/core/rendering/shaped.py +312 -0
- meltygui/core/rendering/window_decoration.py +25 -0
- meltygui/core/runtime/__init__.py +1 -0
- meltygui/core/runtime/app.py +735 -0
- meltygui/core/runtime/app_session.py +140 -0
- meltygui/core/runtime/background.py +564 -0
- meltygui/core/runtime/extensions.py +53 -0
- meltygui/core/runtime/gc_manager.py +1163 -0
- meltygui/core/runtime/lifecycle.py +21 -0
- meltygui/core/runtime/paths.py +27 -0
- meltygui/core/runtime/settings.py +14 -0
- meltygui/core/runtime/singleton.py +16 -0
- meltygui/core/runtime/thread_safe_bool.py +24 -0
- meltygui/core/runtime/thread_signal.py +30 -0
- meltygui/core/runtime/toggles.py +3115 -0
- meltygui/core/services/__init__.py +1 -0
- meltygui/core/services/account_core.py +10 -0
- meltygui/core/services/chat_core.py +19 -0
- meltygui/core/services/claude_terminal_core.py +346 -0
- meltygui/core/services/terminal_core.py +458 -0
- meltygui/core/services/terminal_runtime.py +78 -0
- meltygui/core/styling/__init__.py +1 -0
- meltygui/core/styling/color_core.py +46 -0
- meltygui/core/styling/fonts.py +639 -0
- meltygui/core/styling/global_style.py +338 -0
- meltygui/core/styling/style.py +198 -0
- meltygui/core/styling/style_core.py +522 -0
- meltygui/core/styling/warm_start.py +149 -0
- meltygui/core/windowing/__init__.py +1 -0
- meltygui/core/windowing/backends/PYIMGUI_LICENSE +28 -0
- meltygui/core/windowing/backends/__init__.py +1 -0
- meltygui/core/windowing/backends/imgui_renderer.py +138 -0
- meltygui/core/windowing/backends/native_wayland.py +850 -0
- meltygui/core/windowing/backends/protocols/xdg-decoration-unstable-v1.xml +156 -0
- meltygui/core/windowing/backends/protocols/xdg-shell.xml +1420 -0
- meltygui/core/windowing/backends/wayland_protocol.py +101 -0
- meltygui/core/windowing/dock_core.py +182 -0
- meltygui/core/windowing/frame_geometry.py +42 -0
- meltygui/core/windowing/geometry_feed.py +864 -0
- meltygui/core/windowing/glfw_utils.py +1343 -0
- meltygui/core/windowing/os_frame.py +1552 -0
- meltygui/core/windowing/surface.py +643 -0
- meltygui/core/windowing/titlebar.py +1560 -0
- meltygui/core/windowing/titlebar_buttons.py +281 -0
- meltygui/core/windowing/wayland_move.py +932 -0
- meltygui/core/windowing/window_api.py +62 -0
- meltygui/core/windowing/window_constants.py +339 -0
- meltygui/core/windowing/window_visibility.py +162 -0
- meltygui/debug/__init__.py +0 -0
- meltygui/debug/app_view_utils.py +9 -0
- meltygui/editor/__init__.py +0 -0
- meltygui/editor/bash_syntax.py +30 -0
- meltygui/editor/code_line_fast.py +152 -0
- meltygui/editor/diff.py +139 -0
- meltygui/editor/external_changes.py +159 -0
- meltygui/editor/file_header.py +41 -0
- meltygui/editor/live_usage.py +169 -0
- meltygui/editor/live_view_views.py +1803 -0
- meltygui/editor/pending_save.py +1351 -0
- meltygui/editor/roster_tints.py +547 -0
- meltygui/editor/source_preview.py +16 -0
- meltygui/editor/source_tools.py +10 -0
- meltygui/editor/source_ui.py +70 -0
- meltygui/editor/spell_check.py +77 -0
- meltygui/editor/text_editor.py +9076 -0
- meltygui/editor/usage_picker.py +538 -0
- meltygui/events/__init__.py +0 -0
- meltygui/events/example.py +118 -0
- meltygui/examples/__init__.py +0 -0
- meltygui/examples/columns_demo.py +33 -0
- meltygui/examples/columns_window_demo.py +60 -0
- meltygui/examples/context_menu_demo.py +24 -0
- meltygui/examples/context_menu_window_demo.py +49 -0
- meltygui/examples/gui_playground.py +127 -0
- meltygui/examples/live_view_playground.py +256 -0
- meltygui/examples/lora.py +43 -0
- meltygui/examples/lora_data.py +59 -0
- meltygui/examples/lora_policies.py +67 -0
- meltygui/examples/mode_demo.py +49 -0
- meltygui/examples/modifies_demo.py +119 -0
- meltygui/examples/scalar_policies.py +60 -0
- meltygui/examples/style_layouts.py +149 -0
- meltygui/examples/tile_manager_demo.py +74 -0
- meltygui/examples/tint_demo.py +160 -0
- meltygui/examples/tint_functions.py +56 -0
- meltygui/examples/trace_demo.py +88 -0
- meltygui/examples/two_windows.py +36 -0
- meltygui/files/__init__.py +0 -0
- meltygui/files/fast_file_explorer.py +439 -0
- meltygui/gnome_extension/lsd-window-geometry@latent-descent/extension.js +237 -0
- meltygui/gnome_extension/lsd-window-geometry@latent-descent/lsd-window-geometry@latent-descent.iml +9 -0
- meltygui/gnome_extension/lsd-window-geometry@latent-descent/metadata.json +7 -0
- meltygui/graphics/__init__.py +6 -0
- meltygui/graphics/base.py +85 -0
- meltygui/graphics/examples.py +507 -0
- meltygui/graphics/executor.py +520 -0
- meltygui/graphics/filter.py +667 -0
- meltygui/graphics/filter.pyi +856 -0
- meltygui/graphics/generate_stubs.py +22 -0
- meltygui/graphics/registry.py +203 -0
- meltygui/graphics/shader_compiler.py +155 -0
- meltygui/graphics/shaders.py +1302 -0
- meltygui/graphics/stub_generator.py +250 -0
- meltygui/graphics/texture_manager.py +170 -0
- meltygui/graphics/texture_min_max.py +295 -0
- meltygui/hdr_color.py +757 -0
- meltygui/image_load.py +308 -0
- meltygui/model/__init__.py +1 -0
- meltygui/model/account_model.py +142 -0
- meltygui/model/camera_model.py +159 -0
- meltygui/model/chat_model.py +86 -0
- meltygui/model/code_model.py +62 -0
- meltygui/model/code_proxy_model.py +876 -0
- meltygui/model/collection_model.py +41 -0
- meltygui/model/color_model.py +127 -0
- meltygui/model/cuda_tensor_model.py +36 -0
- meltygui/model/cuda_texture_model.py +149 -0
- meltygui/model/dropdown_model.py +137 -0
- meltygui/model/file_metadata_model.py +73 -0
- meltygui/model/file_model.py +289 -0
- meltygui/model/format_model.py +390 -0
- meltygui/model/graph_model.py +98 -0
- meltygui/model/icon_model.py +1024 -0
- meltygui/model/import_graph_model.py +468 -0
- meltygui/model/layout_model.py +15 -0
- meltygui/model/lut_model.py +266 -0
- meltygui/model/search_model.py +173 -0
- meltygui/model/tensor_model.py +402 -0
- meltygui/model/terminal_model.py +329 -0
- meltygui/model/texture_model.py +146 -0
- meltygui/model/tile_model.py +24 -0
- meltygui/model/trace_model.py +198 -0
- meltygui/model/trace_report_model.py +146 -0
- meltygui/models/__init__.py +0 -0
- meltygui/models/file_meta.py +613 -0
- meltygui/models/function_console.py +184 -0
- meltygui/models/orchestration.py +48 -0
- meltygui/pbr.py +1576 -0
- meltygui/png_unfilter.c +49 -0
- meltygui/resources/JetBrainsMono-Regular.ttf +0 -0
- meltygui/resources/THIRD_PARTY_NOTICES.md +21 -0
- meltygui/resources/dejavu/DejaVuSans-Bold.ttf +0 -0
- meltygui/resources/dejavu/DejaVuSans-ExtraLight.ttf +0 -0
- meltygui/resources/dejavu/DejaVuSans.ttf +0 -0
- meltygui/resources/dejavu/LICENSE.txt +78 -0
- meltygui/resources/fontawesome-LICENSE.txt +121 -0
- meltygui/resources/fontawesome-webfont.ttf +0 -0
- meltygui/resources/hdri/studio_small_09_1k.hdr +0 -0
- meltygui/resources/jetbrains-weights/JetBrainsMono-Bold.ttf +0 -0
- meltygui/resources/jetbrains-weights/JetBrainsMono-ExtraBold.ttf +0 -0
- meltygui/resources/jetbrains-weights/JetBrainsMono-ExtraLight.ttf +0 -0
- meltygui/resources/jetbrains-weights/JetBrainsMono-Light.ttf +0 -0
- meltygui/resources/jetbrains-weights/JetBrainsMono-Medium.ttf +0 -0
- meltygui/resources/jetbrains-weights/JetBrainsMono-SemiBold.ttf +0 -0
- meltygui/resources/jetbrains-weights/JetBrainsMono-Thin.ttf +0 -0
- meltygui/resources/jetbrains-weights/OFL.txt +93 -0
- meltygui/resources/jetbrains-weights/README.md +2 -0
- meltygui/state/__init__.py +0 -0
- meltygui/state/account_state.py +22 -0
- meltygui/state/animation_state.py +97 -0
- meltygui/state/annotation_state.py +22 -0
- meltygui/state/chat_state.py +36 -0
- meltygui/state/code_state.py +10 -0
- meltygui/state/core_enums.py +59 -0
- meltygui/state/core_markers.py +115 -0
- meltygui/state/core_undo.py +1075 -0
- meltygui/state/file_state.py +75 -0
- meltygui/state/graph_state.py +26 -0
- meltygui/state/inspection_state.py +47 -0
- meltygui/state/menu_state.py +10 -0
- meltygui/state/model_enums.py +11 -0
- meltygui/state/new_core_model.py +2394 -0
- meltygui/state/orchestration_state.py +14 -0
- meltygui/state/query_state.py +24 -0
- meltygui/state/tensor_state.py +10 -0
- meltygui/state/terminal_state.py +23 -0
- meltygui/state/trace_state.py +32 -0
- meltygui/state/voxel_state.py +12 -0
- meltygui/text_index.py +816 -0
- meltygui/utils/__init__.py +0 -0
- meltygui/utils/jump_to_code.py +344 -0
- meltygui/utils/pkl_inspect.py +90 -0
- meltygui/utils/render_utils.py +1419 -0
- meltygui/view/__init__.py +1 -0
- meltygui/view/account_view.py +524 -0
- meltygui/view/action_view.py +73 -0
- meltygui/view/chat_decoration_view.py +112 -0
- meltygui/view/chat_view.py +1703 -0
- meltygui/view/code_view.py +2677 -0
- meltygui/view/collection_view.py +1185 -0
- meltygui/view/color_view.py +824 -0
- meltygui/view/control_view.py +559 -0
- meltygui/view/decoration_view.py +439 -0
- meltygui/view/diagnostic_view.py +177 -0
- meltygui/view/dropdown_view.py +1082 -0
- meltygui/view/file_view.py +1599 -0
- meltygui/view/graph_cuda_view.py +105 -0
- meltygui/view/graph_view.py +882 -0
- meltygui/view/header_view.py +848 -0
- meltygui/view/input_view.py +238 -0
- meltygui/view/inspection_view.py +1783 -0
- meltygui/view/layout_view.py +596 -0
- meltygui/view/lut_view.py +45 -0
- meltygui/view/menu_view.py +212 -0
- meltygui/view/orchestration_view.py +658 -0
- meltygui/view/query_view.py +118 -0
- meltygui/view/search_view.py +342 -0
- meltygui/view/tab_view.py +258 -0
- meltygui/view/tensor_view.py +430 -0
- meltygui/view/terminal_view.py +355 -0
- meltygui/view/text_view.py +8031 -0
- meltygui/view/texture_view.py +480 -0
- meltygui/view/tile_view.py +38 -0
- meltygui/view/trace_view.py +923 -0
- meltygui/view/voxel_cuda_view.py +824 -0
- meltygui/view/voxel_view.py +1860 -0
- meltygui/view/window_view.py +111 -0
- meltygui-0.1.0.dist-info/METADATA +143 -0
- meltygui-0.1.0.dist-info/RECORD +372 -0
- meltygui-0.1.0.dist-info/WHEEL +4 -0
- 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
|