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,596 @@
|
|
|
1
|
+
"""Layout view functions and supporting definitions."""
|
|
2
|
+
from meltygui.core.layout.layout_core import dock_header
|
|
3
|
+
from meltygui.core.melty import Melty
|
|
4
|
+
from meltygui.model.layout_model import Columns
|
|
5
|
+
from meltygui.model.layout_model import Rows
|
|
6
|
+
from meltygui.core.core_render import render_func
|
|
7
|
+
from meltygui.core.rendering.core_decoration import Core
|
|
8
|
+
from meltygui.state.core_undo import NavUndo
|
|
9
|
+
from meltygui.core.runtime.toggles import Toggles
|
|
10
|
+
from meltygui.core.runtime.toggles import WindowManager
|
|
11
|
+
import meltygui_imgui as imgui
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@render_func(use_cache=True, show_bg=False, shadow=False, selectable=False,
|
|
15
|
+
is_default_for=Columns)
|
|
16
|
+
def draw_columns(input_value, column_widths=None, column_edges=None,
|
|
17
|
+
draw_state=None, resizable=True, child_kwargs=None, **kwargs):
|
|
18
|
+
"""Side-by-side cells lined up with shared draggable edges.
|
|
19
|
+
|
|
20
|
+
Edges are {"x": float} dicts in window coordinates (see the edge-model
|
|
21
|
+
comment above). This view owns its interior edges (auto-state
|
|
22
|
+
``column_edges``); when it renders as a cell of another columns view it
|
|
23
|
+
adopts the enclosing cell's two edge objects as its far edges
|
|
24
|
+
(``left_edge``/``right_edge`` kwargs, passed by reference). All edges
|
|
25
|
+
register on the ROOT WINDOW, which solves collisions once per frame and
|
|
26
|
+
drives its own frame from the direct row's far edges; this view just
|
|
27
|
+
queues drags and lines its cells up with its edges.
|
|
28
|
+
"""
|
|
29
|
+
from meltygui.model.layout_model import Rows
|
|
30
|
+
from meltygui.core.layout.column_core import ColumnLayout
|
|
31
|
+
from meltygui.core.rendering.render_dispatch import draw_any
|
|
32
|
+
|
|
33
|
+
if child_kwargs is None:
|
|
34
|
+
child_kwargs = {}
|
|
35
|
+
|
|
36
|
+
if isinstance(input_value, dict):
|
|
37
|
+
keys = [k for k in input_value
|
|
38
|
+
if not (isinstance(k, str) and (k.startswith("_") or k.endswith("_")))]
|
|
39
|
+
elif isinstance(input_value, (list, tuple)):
|
|
40
|
+
keys = list(range(len(input_value)))
|
|
41
|
+
else:
|
|
42
|
+
imgui.text(f"draw_columns: no view for {type(input_value).__name__}")
|
|
43
|
+
return False, input_value
|
|
44
|
+
|
|
45
|
+
if not keys:
|
|
46
|
+
return False, input_value
|
|
47
|
+
n_cols = len(keys)
|
|
48
|
+
|
|
49
|
+
cols = ColumnLayout(draw_state, n_cols, column_edges=column_edges,
|
|
50
|
+
column_widths=column_widths,
|
|
51
|
+
left_edge=kwargs.get("left_edge"),
|
|
52
|
+
right_edge=kwargs.get("right_edge"),
|
|
53
|
+
resizable=resizable)
|
|
54
|
+
|
|
55
|
+
# ----- cells: lined up with their edges; nested Columns get the cell's
|
|
56
|
+
# edge objects by reference -----
|
|
57
|
+
changed = False
|
|
58
|
+
for idx, key in enumerate(keys):
|
|
59
|
+
item = input_value[key]
|
|
60
|
+
with cols.cell(idx) as cell_width:
|
|
61
|
+
item_kwargs = {"name": f"{key}", "align_header": False,
|
|
62
|
+
"width": cell_width} | child_kwargs
|
|
63
|
+
if isinstance(item, Columns):
|
|
64
|
+
item_kwargs |= {"left_edge": cols.edges[idx],
|
|
65
|
+
"right_edge": cols.edges[idx + 1]}
|
|
66
|
+
if isinstance(item, (Columns, Rows)):
|
|
67
|
+
# Row edges pass THROUGH a Columns cell: a Rows nested in
|
|
68
|
+
# this cell adopts the enclosing row's edges (handed to us
|
|
69
|
+
# by draw_rows), so its cells will collide with them.
|
|
70
|
+
for key in ("top_edge", "bottom_edge"):
|
|
71
|
+
if kwargs.get(key) is not None:
|
|
72
|
+
item_kwargs[key] = kwargs[key]
|
|
73
|
+
item_changed, out_value, cell_ds = draw_any(
|
|
74
|
+
item, return_extras=True, **item_kwargs)
|
|
75
|
+
cols.note_child(idx, cell_ds) # border follows the child's corners
|
|
76
|
+
if item_changed:
|
|
77
|
+
changed = True
|
|
78
|
+
if isinstance(input_value, (dict, list)):
|
|
79
|
+
input_value[key] = out_value
|
|
80
|
+
|
|
81
|
+
cols.finish()
|
|
82
|
+
|
|
83
|
+
return changed, input_value
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
@render_func(use_cache=True, show_bg=False, shadow=False, selectable=False,
|
|
87
|
+
is_default_for=Rows)
|
|
88
|
+
def draw_rows(input_value, row_heights=None, row_edges=None,
|
|
89
|
+
draw_state=None, resizable=True, child_kwargs=None, **kwargs):
|
|
90
|
+
"""Stacked cells lined up with shared draggable edges — draw_columns
|
|
91
|
+
along y.
|
|
92
|
+
|
|
93
|
+
Edges are {"y": float} dicts in window coordinates. This view owns its
|
|
94
|
+
interior edges (auto-state ``row_edges``); as a cell of another rows
|
|
95
|
+
view it adopts the enclosing cell's two edge objects as its far edges
|
|
96
|
+
(``top_edge``/``bottom_edge`` kwargs, by reference); as the window's
|
|
97
|
+
rows view it adopts the window's top/bottom frame edges. Every cell is
|
|
98
|
+
pinned to its row's height AND the rows' width (a passed height alone
|
|
99
|
+
collapses a child's width), so a Columns cell fills its row.
|
|
100
|
+
"""
|
|
101
|
+
from meltygui.model.layout_model import Columns
|
|
102
|
+
from meltygui.core.layout.column_core import RowLayout
|
|
103
|
+
from meltygui.core.rendering.render_dispatch import draw_any
|
|
104
|
+
|
|
105
|
+
if child_kwargs is None:
|
|
106
|
+
child_kwargs = {}
|
|
107
|
+
|
|
108
|
+
if isinstance(input_value, dict):
|
|
109
|
+
keys = [k for k in input_value
|
|
110
|
+
if not (isinstance(k, str) and (k.startswith("_") or k.endswith("_")))]
|
|
111
|
+
elif isinstance(input_value, (list, tuple)):
|
|
112
|
+
keys = list(range(len(input_value)))
|
|
113
|
+
else:
|
|
114
|
+
imgui.text(f"draw_rows: no view for {type(input_value).__name__}")
|
|
115
|
+
return False, input_value
|
|
116
|
+
|
|
117
|
+
if not keys:
|
|
118
|
+
return False, input_value
|
|
119
|
+
n_rows = len(keys)
|
|
120
|
+
|
|
121
|
+
rows = RowLayout(draw_state, n_rows, row_edges=row_edges,
|
|
122
|
+
row_heights=row_heights,
|
|
123
|
+
top_edge=kwargs.get("top_edge"),
|
|
124
|
+
bottom_edge=kwargs.get("bottom_edge"),
|
|
125
|
+
resizable=resizable)
|
|
126
|
+
|
|
127
|
+
changed = False
|
|
128
|
+
cell_width = rows.inner_width()
|
|
129
|
+
for idx, key in enumerate(keys):
|
|
130
|
+
item = input_value[key]
|
|
131
|
+
with rows.cell(idx) as cell_height:
|
|
132
|
+
item_kwargs = {"name": f"{key}", "align_header": False,
|
|
133
|
+
"height": cell_height,
|
|
134
|
+
"width": cell_width} | child_kwargs
|
|
135
|
+
if isinstance(item, (Rows, Columns)):
|
|
136
|
+
# A nested Rows adopts this row's edges; a Columns carries
|
|
137
|
+
# them through to any Rows in ITS cells (draw_columns).
|
|
138
|
+
item_kwargs |= {"top_edge": rows.edges[idx],
|
|
139
|
+
"bottom_edge": rows.edges[idx + 1]}
|
|
140
|
+
# And column edges pass THROUGH a Rows cell to the_columns.
|
|
141
|
+
for key in ("left_edge", "right_edge"):
|
|
142
|
+
if kwargs.get(key) is not None:
|
|
143
|
+
item_kwargs[key] = kwargs[key]
|
|
144
|
+
item_changed, out_value, cell_ds = draw_any(
|
|
145
|
+
item, return_extras=True, **item_kwargs)
|
|
146
|
+
rows.note_child(idx, cell_ds)
|
|
147
|
+
if item_changed:
|
|
148
|
+
changed = True
|
|
149
|
+
if isinstance(input_value, (dict, list)):
|
|
150
|
+
input_value[key] = out_value
|
|
151
|
+
|
|
152
|
+
rows.finish()
|
|
153
|
+
|
|
154
|
+
return changed, input_value
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
@render_func(use_cache=True, selectable=False, show_add_delete=False, show_close=False, is_tree=False,
|
|
158
|
+
show_name=False, searchable=True, shadow=True, with_header=dock_header)
|
|
159
|
+
def draw_fast_dock(input_value, draw_state, style_manager=None, hide_internal=False,
|
|
160
|
+
dock_tab="all", left_mouse_down=False, search_text="", **kwargs):
|
|
161
|
+
# input_value is Melty.registered_windows - a plain defaultdict - so there
|
|
162
|
+
# is no is_default_for registration: the root calls this view explicitly.
|
|
163
|
+
from meltygui.core.styling.fonts import Font
|
|
164
|
+
from meltygui.core.windowing.glfw_utils import request_render
|
|
165
|
+
from meltygui.view.search_view import draw_search_highlight
|
|
166
|
+
from meltygui.core.cache.tile_cache import add_glow
|
|
167
|
+
from meltygui.core.cache.tile_cache import add_shadow
|
|
168
|
+
from meltygui.core.cache.tile_cache import clear_glows
|
|
169
|
+
from meltygui.core.windowing.dock_core import _color_u32
|
|
170
|
+
from meltygui.core.windowing.dock_core import _draw_glyph_ink_centered
|
|
171
|
+
from meltygui.core.windowing.dock_core import _floor_value
|
|
172
|
+
from meltygui.core.windowing.dock_core import _mix
|
|
173
|
+
from meltygui.core.windowing.dock_core import _row_icon
|
|
174
|
+
from meltygui.core.windowing.dock_core import _scale_saturation
|
|
175
|
+
from meltygui.core.windowing.dock_core import _summon
|
|
176
|
+
|
|
177
|
+
imgui.dummy(0, 10)
|
|
178
|
+
# ---- styling ----
|
|
179
|
+
open_bg_value, open_text_value = 0.16, 1.357 # name button, window open
|
|
180
|
+
open_factor, open_saturation = 0.659, 1.315
|
|
181
|
+
closed_bg_value, closed_text_value = 0.045, 0.463 # name button, window closed
|
|
182
|
+
closed_factor, closed_saturation = 0.46, 0.630
|
|
183
|
+
target_bg_value, target_text_value = 0.103, 1.269 # summon button
|
|
184
|
+
target_factor, target_saturation = 0.799, 0.764
|
|
185
|
+
hover_bg_boost, hover_text_boost = 0.05, 1.5
|
|
186
|
+
text_saturation = 0.8
|
|
187
|
+
# Important tab's tiles mix like APP ICONS: more raw window tint (lower
|
|
188
|
+
# factor keeps more of the tint's source rgb) at a higher saturation and
|
|
189
|
+
# value than the row buttons, so each tile reads as its window's colour.
|
|
190
|
+
icon_bg_value, icon_bg_saturation, icon_bg_factor = 0.32, 2.2, 0.45
|
|
191
|
+
icon_bg_closed_value = 0.12 # dimmer value for a closed window's icon
|
|
192
|
+
icon_bg_closed_saturation = 0.45 # closed tiles sit muted (multiplier on the saturation)
|
|
193
|
+
live_tint = (0.409, 0.1, 0.1) # the bolt on live rows (All tab)
|
|
194
|
+
# Important tab: live shows as a little circle badge riding the tile's
|
|
195
|
+
# top-right corner, iOS-notification style. Fixed design colour (rule 18).
|
|
196
|
+
live_badge_color = (0.86, 0.24, 0.2)
|
|
197
|
+
|
|
198
|
+
# ---- icons (glyph literals so the editor renders them as a picker) ----
|
|
199
|
+
target_icon = f"" # summon button
|
|
200
|
+
live_icon = f"" # live-row bolt
|
|
201
|
+
recent_fallback_icon = f"" # Recently added tile of a window with no icon
|
|
202
|
+
|
|
203
|
+
# ---- geometry, authored at ui_scale 1.0 and scaled once per frame ----
|
|
204
|
+
# The dock draws straight to the draw list, so nothing here follows the
|
|
205
|
+
# scale the way a laid-out widget does - every one of these goes through
|
|
206
|
+
# px(), or the rows lose their 31px boxes while the labels grow out of
|
|
207
|
+
# them.
|
|
208
|
+
px = Melty.px
|
|
209
|
+
important = dock_tab == "important"
|
|
210
|
+
# [tint=(0.939, 0.453, 0.245)]
|
|
211
|
+
row_height = px(40) if important else px(25.0)
|
|
212
|
+
# [tint=(0.939, 0.453, 0.245)]
|
|
213
|
+
icon_box = px(40) # Important tab: SQUARE tile around the icon
|
|
214
|
+
if important:
|
|
215
|
+
# The tile is always square (icon_box a constant): a tile taller than the
|
|
216
|
+
# row keeps the line spacing up here instead of squashing.
|
|
217
|
+
row_height = max(row_height, icon_box)
|
|
218
|
+
row_gap = px(12) if important else px(2.0)
|
|
219
|
+
row_stride = row_height + row_gap
|
|
220
|
+
# [tint=(0.35, 0.85, 0.94)]
|
|
221
|
+
# Rows' left inset: the All tab keeps it for the live bolt; the Important
|
|
222
|
+
# tab's live state rides the tile as a badge, so its rows sit flush left.
|
|
223
|
+
name_x = px(3.8) if important else px(20.0)
|
|
224
|
+
live_badge_inset = px(3.0) # live bolt's center in from the tile corner
|
|
225
|
+
target_width = px(20.0)
|
|
226
|
+
right_pad = px(1)
|
|
227
|
+
|
|
228
|
+
# Default radius for name/rows/summon, a custom one for the icon tiles
|
|
229
|
+
corner = px(6)
|
|
230
|
+
icon_corner = px(12) # Important tab's icon tile
|
|
231
|
+
# [tint=(0.939, 0.453, 0.245)]
|
|
232
|
+
icon_nudge_x, icon_nudge_y = px(0.0), px(0.0) # optical centering of the tile's glyph
|
|
233
|
+
text_nudge_x, text_nudge_y = px(2.0), px(-1.0) # optical centering of glyphs
|
|
234
|
+
name_target_gap = px(6.0) # gap between name and summon button
|
|
235
|
+
name_pad_x = px(10) # left inset for icon/name text
|
|
236
|
+
icon_gap = px(6) # gap between icon and name
|
|
237
|
+
manager_row_text_x, manager_row_text_y = px(8.0), px(7.0) # "Window Manager" label offsets
|
|
238
|
+
# Important tab's section headings ("Recently added" / "Important"):
|
|
239
|
+
# a small muted label on its own line above the section's tiles.
|
|
240
|
+
heading_height = px(18.0)
|
|
241
|
+
heading_gap = px(8.0) # space between a section's last tile and the next heading
|
|
242
|
+
heading_value, heading_saturation = 0.62, 0.4 # theme mix of the heading text
|
|
243
|
+
if style_manager is None:
|
|
244
|
+
style_manager = Melty.style_manager
|
|
245
|
+
draw_list = imgui.get_window_draw_list()
|
|
246
|
+
origin_x, origin_y = imgui.get_cursor_screen_pos()
|
|
247
|
+
content_width = draw_state.content_width or (draw_state.width or 200)
|
|
248
|
+
# Flipped whenever this frame mutated window state (a row click, a stale
|
|
249
|
+
# window pruned) - it is the view's `bool` return (style guide rule 10).
|
|
250
|
+
changed = False
|
|
251
|
+
# Clear this body run's glow group: the Important tab's open tiles re-emit
|
|
252
|
+
# below; a run that stops emitting (tab switch, window closed) sheds its
|
|
253
|
+
# retained marks, while cache-served frames keep glowing.
|
|
254
|
+
clear_glows(draw_state)
|
|
255
|
+
|
|
256
|
+
# ---- collect + sort rows (same grouping as WINDOW_MANAGER_SORTED) ----
|
|
257
|
+
# [tint=(0.989, 0.17, 0.497)]
|
|
258
|
+
rows = []
|
|
259
|
+
candidates = [] # every dock-visible row before the icon filter
|
|
260
|
+
for key, managed_window in list(input_value.items()):
|
|
261
|
+
window_draw_state = managed_window.draw_state
|
|
262
|
+
if window_draw_state is None:
|
|
263
|
+
continue
|
|
264
|
+
name = str(window_draw_state.name)
|
|
265
|
+
if name in WindowManager.excluded_windows or str(key) in WindowManager.excluded_windows:
|
|
266
|
+
continue
|
|
267
|
+
if hide_internal and not window_draw_state._kwargs.get("icon", None):
|
|
268
|
+
continue
|
|
269
|
+
if (not window_draw_state.persistent and not window_draw_state.seen
|
|
270
|
+
and window_draw_state.closed):
|
|
271
|
+
Core.melty.delete_window(window_draw_state)
|
|
272
|
+
changed = True
|
|
273
|
+
continue
|
|
274
|
+
# [tint=(0.85, 0.75, 0.05), show_tint=True]
|
|
275
|
+
icon = _row_icon(name, managed_window, window_draw_state)
|
|
276
|
+
candidates.append((name, managed_window, window_draw_state, icon))
|
|
277
|
+
if dock_tab == "important" and not icon:
|
|
278
|
+
continue
|
|
279
|
+
rows.append((name, managed_window, window_draw_state, icon))
|
|
280
|
+
rows.sort(key=lambda row: row[0].lower())
|
|
281
|
+
|
|
282
|
+
# ---- Important tab: "Recently added" = the newest first-seen names
|
|
283
|
+
# (AppModel.render_windows via melty.recent_windows), newest first, icon
|
|
284
|
+
# or not - a window with no icon wears recent_fallback_icon on its tile.
|
|
285
|
+
# Rows are placed as (row_top, row) so a heading can inter between the
|
|
286
|
+
# sections; the regular tiles follow under their own "Important" label.
|
|
287
|
+
# Names that no longer resolve to a registered window are skipped.
|
|
288
|
+
sections = [(None, rows)]
|
|
289
|
+
if important:
|
|
290
|
+
by_name = {row[0]: row for row in candidates}
|
|
291
|
+
recent_rows = []
|
|
292
|
+
for recent_name in Melty.recent_windows(Toggles.FastDock.recently_added_count):
|
|
293
|
+
row = by_name.get(recent_name)
|
|
294
|
+
if row is not None:
|
|
295
|
+
name, managed_window, window_draw_state, icon = row
|
|
296
|
+
recent_rows.append((name, managed_window, window_draw_state,
|
|
297
|
+
icon or recent_fallback_icon))
|
|
298
|
+
if recent_rows:
|
|
299
|
+
sections = [("Recently added", recent_rows), ("Important", rows)]
|
|
300
|
+
# [tint=(0.989, 0.17, 0.497)]
|
|
301
|
+
placed = [] # (row_top, row) in draw order
|
|
302
|
+
headings = [] # (heading_top, label)
|
|
303
|
+
cursor_y = origin_y
|
|
304
|
+
for section_label, section_rows in sections:
|
|
305
|
+
if section_label is not None:
|
|
306
|
+
if placed:
|
|
307
|
+
cursor_y += heading_gap
|
|
308
|
+
headings.append((cursor_y, section_label))
|
|
309
|
+
cursor_y += heading_height
|
|
310
|
+
for row in section_rows:
|
|
311
|
+
placed.append((cursor_y, row))
|
|
312
|
+
cursor_y += row_stride
|
|
313
|
+
|
|
314
|
+
# Dummy rows set the full content height so the window scrolls normally.
|
|
315
|
+
# Keep the trailing row_gap as bottom padding so the last row isn't clipped.
|
|
316
|
+
# The scroll clamp is content_height - clipped_height, but clipped_height
|
|
317
|
+
# spans the WHOLE window (header included) while rows start below the
|
|
318
|
+
# header - boost the content height by that top inset or the last row can
|
|
319
|
+
# never scroll fully into view.
|
|
320
|
+
top_inset = (origin_y + draw_state.scroll_offset[1]) - draw_state.abs_top
|
|
321
|
+
imgui.dummy(content_width, max(1.0, (cursor_y - origin_y) + max(0.0, top_inset)))
|
|
322
|
+
|
|
323
|
+
mouse_x, mouse_y = imgui.get_mouse_pos()
|
|
324
|
+
hover_ok = draw_state._bounding_hovered
|
|
325
|
+
press = left_mouse_down
|
|
326
|
+
# [tint=(0.62, 0.47, 0.95)]
|
|
327
|
+
click = (press.x, press.y) if (press and hasattr(press, "x")) else None
|
|
328
|
+
clip = getattr(draw_state, "abs_clip_rect", None)
|
|
329
|
+
|
|
330
|
+
# ---- tab switching (All / Important) ----
|
|
331
|
+
# The strip is drawn by dock_header in the HEADER band, where the body's
|
|
332
|
+
# left_mouse_down param never reaches (the window's own header handlers
|
|
333
|
+
# block that area). Each tab is therefore its own on_action sub-rect over
|
|
334
|
+
# the screen rect the header stamped: priority_delta=4 outranks the
|
|
335
|
+
# header chrome (flat_button's rule), and as body on_actions they replay
|
|
336
|
+
# on blit-cache hits, so tabs stay interactive on cached frames too.
|
|
337
|
+
for tab_key, tab_rect in (getattr(draw_state, "_dock_tab_rects", None) or ()):
|
|
338
|
+
pressed = draw_state.on_action("left_mouse_down", view_id="dock_tab_" + tab_key,
|
|
339
|
+
rect=tab_rect, priority_delta=4)
|
|
340
|
+
if pressed is not None and dock_tab != tab_key:
|
|
341
|
+
draw_state.dock_tab = tab_key # auto-update: persists + invalidates
|
|
342
|
+
changed = True
|
|
343
|
+
request_render()
|
|
344
|
+
|
|
345
|
+
# ---- name loop-geometry (loop-invariant; only y varies per row) ----
|
|
346
|
+
target_right = origin_x + content_width - right_pad
|
|
347
|
+
target_left = target_right - target_width
|
|
348
|
+
name_left, name_right = origin_x + name_x, target_left - name_target_gap
|
|
349
|
+
|
|
350
|
+
# ---- local find-bar search ----
|
|
351
|
+
# The window's find UI (searchable=True) counts matches by walking
|
|
352
|
+
# draw_states and calling each node's _search_matcher (meltygui.draw_walk)
|
|
353
|
+
# - rows here aren't draw_states, so this view is its own single matcher
|
|
354
|
+
# node claiming one slot per matching row name, in the same ordinal order
|
|
355
|
+
# the row loop draws them, keeping count and current-index aligned.
|
|
356
|
+
from meltygui.core.melty import SearchTerm
|
|
357
|
+
from meltygui.model.search_model import _fuzzy_key_match
|
|
358
|
+
from meltygui.editor.text_editor import _scroll_into_view
|
|
359
|
+
|
|
360
|
+
names_lower = tuple(row[0].split("##")[0].lower() for _, row in placed)
|
|
361
|
+
|
|
362
|
+
def _search_matcher(term, session, names=names_lower):
|
|
363
|
+
query = str(term).lower()
|
|
364
|
+
if query:
|
|
365
|
+
session.claim(sum(1 for name in names if _fuzzy_key_match(query, name)))
|
|
366
|
+
|
|
367
|
+
draw_state._search_matcher = _search_matcher
|
|
368
|
+
|
|
369
|
+
# Session resolution mirrors draw_collection: a forwarded SearchTerm in
|
|
370
|
+
# search_text, else our own session when this view hosts the find UI.
|
|
371
|
+
term = search_text or (draw_state.search_text if draw_state.search_active else "")
|
|
372
|
+
if isinstance(term, SearchTerm):
|
|
373
|
+
session = term
|
|
374
|
+
elif draw_state.search_active and draw_state._search_session is not None:
|
|
375
|
+
session = draw_state._search_session
|
|
376
|
+
else:
|
|
377
|
+
session = None
|
|
378
|
+
query = str(term).lower() if (session is not None and term) else ""
|
|
379
|
+
current_local = draw_state._search_active_local if query else None
|
|
380
|
+
match_ordinal = 0
|
|
381
|
+
# Required for Ctrl+Enter (search_activate_target): the current match's
|
|
382
|
+
# row rect, so the injected "click the target" lands on the row instead of
|
|
383
|
+
# the view's center.
|
|
384
|
+
draw_state._search_current_rect = None
|
|
385
|
+
|
|
386
|
+
# Highlights are deferred to a second pass AFTER the row loop: the current
|
|
387
|
+
# match's radial glow spills over neighbouring rows, so drawn in-row it gets
|
|
388
|
+
# painted over by the later row's background rect. draw_search_highlight
|
|
389
|
+
# clips its own font out of the glow, so drawing it on top stays legible.
|
|
390
|
+
highlight_rects = []
|
|
391
|
+
|
|
392
|
+
# ---- section headings (Important tab with a Recently added section) ----
|
|
393
|
+
heading_color = _color_u32(style_manager.make_color_rgb(
|
|
394
|
+
0.0, 0.0, 0.0, value=heading_value, factor=1.0, saturation_scale=heading_saturation))
|
|
395
|
+
for heading_top, heading_label in headings:
|
|
396
|
+
if clip is not None and (heading_top + heading_height < clip[1] or heading_top > clip[3]):
|
|
397
|
+
continue
|
|
398
|
+
heading_size = imgui.calc_text_size(heading_label)
|
|
399
|
+
draw_list.add_text(name_left + text_nudge_x,
|
|
400
|
+
heading_top + (heading_height - heading_size[1]) / 2.0 + text_nudge_y,
|
|
401
|
+
heading_color, heading_label)
|
|
402
|
+
|
|
403
|
+
for row_top, (name, managed_window, window_draw_state, icon) in placed:
|
|
404
|
+
row_bottom = row_top + row_height
|
|
405
|
+
|
|
406
|
+
# Match bookkeeping runs for EVERY row - clipped ones too - so the
|
|
407
|
+
# ordinal sequence stays aligned with the matcher's count, and the
|
|
408
|
+
# current match can scroll into view from off-screen.
|
|
409
|
+
display = name.split("##")[0]
|
|
410
|
+
is_match = bool(query) and _fuzzy_key_match(query, display.lower())
|
|
411
|
+
is_current = is_match and current_local is not None and match_ordinal == current_local
|
|
412
|
+
if is_match:
|
|
413
|
+
match_ordinal += 1
|
|
414
|
+
if is_current:
|
|
415
|
+
draw_state._search_current_rect = (name_left, row_top,
|
|
416
|
+
name_right - name_left, row_height)
|
|
417
|
+
if session.scroll_to:
|
|
418
|
+
_scroll_into_view(draw_state, row_top, row_bottom, center=True)
|
|
419
|
+
|
|
420
|
+
if clip is not None and (row_bottom < clip[1] or row_top > clip[3]):
|
|
421
|
+
continue
|
|
422
|
+
|
|
423
|
+
tint = window_draw_state.locate_tint
|
|
424
|
+
|
|
425
|
+
if name == "Window Manager":
|
|
426
|
+
text_color = _mix(style_manager, tint, target_text_value, 1.0, text_saturation)
|
|
427
|
+
draw_list.add_text(origin_x + name_x + manager_row_text_x,
|
|
428
|
+
row_top + manager_row_text_y, _color_u32(text_color), name)
|
|
429
|
+
continue
|
|
430
|
+
|
|
431
|
+
# ---- hit-testing (x is loop-invariant, hoisted above) ----
|
|
432
|
+
in_target = target_left <= mouse_x <= target_right and row_top <= mouse_y <= row_bottom
|
|
433
|
+
in_name = name_left <= mouse_x <= name_right and row_top <= mouse_y <= row_bottom
|
|
434
|
+
|
|
435
|
+
# ---- name button (open vs closed styling from the old dock) ----
|
|
436
|
+
is_open = not window_draw_state.closed
|
|
437
|
+
name_hovered = hover_ok and in_name
|
|
438
|
+
if is_open:
|
|
439
|
+
factor, bg_value, text_value, saturation = (open_factor, open_bg_value,
|
|
440
|
+
open_text_value, open_saturation)
|
|
441
|
+
else:
|
|
442
|
+
factor, bg_value, text_value, saturation = (closed_factor, closed_bg_value,
|
|
443
|
+
closed_text_value, closed_saturation)
|
|
444
|
+
bg_color = _mix(style_manager, tint, bg_value + (hover_bg_boost if name_hovered else 0.0),
|
|
445
|
+
factor, saturation)
|
|
446
|
+
text_color = _mix(style_manager, tint,
|
|
447
|
+
text_value + (hover_text_boost if name_hovered else 0.0),
|
|
448
|
+
factor, text_saturation)
|
|
449
|
+
# Legibility floor on the text's hsv value: a dark window tint would
|
|
450
|
+
# otherwise scale it toward black. Change the floors in Toggles.FastDock.
|
|
451
|
+
text_color = _floor_value(text_color, Toggles.FastDock.active_text_min_brightness if is_open
|
|
452
|
+
else Toggles.FastDock.inactive_text_min_brightness)
|
|
453
|
+
if important:
|
|
454
|
+
# An Important tab: the background is a rounded tile around the
|
|
455
|
+
# icon alone; the name rides outside it to the right, bare. Open
|
|
456
|
+
# tiles get a shadow AND emit light (add_glow), so the active set
|
|
457
|
+
# reads at a glance. The icon draws a glyph up through the
|
|
458
|
+
# DEJAVU_SANS_24 group (its merged FONTAWESOME_18).
|
|
459
|
+
box_left = name_left
|
|
460
|
+
box_right = box_left + icon_box
|
|
461
|
+
box_top = row_top + (row_height - icon_box) / 2.0
|
|
462
|
+
box_bottom = box_top + icon_box
|
|
463
|
+
# The tile always shows; a CLOSED window's is dimmer and flat -
|
|
464
|
+
# no shadow, no glow - so the lit, floating tiles read as open.
|
|
465
|
+
tile_color = _mix(style_manager, tint,
|
|
466
|
+
(icon_bg_value if is_open else icon_bg_closed_value)
|
|
467
|
+
+ (hover_bg_boost if name_hovered else 0.0),
|
|
468
|
+
icon_bg_factor, icon_bg_saturation)
|
|
469
|
+
|
|
470
|
+
# todo take the tint and boost the saturation
|
|
471
|
+
glow_color = _mix(style_manager, tint,
|
|
472
|
+
0.0, 0.5, 1.0)
|
|
473
|
+
|
|
474
|
+
if not is_open:
|
|
475
|
+
# Post-mix desaturation - the _mix saturation knob only
|
|
476
|
+
# touches the tint half of the blend (see _scale_saturation).
|
|
477
|
+
tile_color = _scale_saturation(tile_color, icon_bg_closed_saturation)
|
|
478
|
+
if is_open:
|
|
479
|
+
add_shadow((box_left, box_top, icon_box, icon_box), offset=11,
|
|
480
|
+
corner_radius=icon_corner, clip=clip)
|
|
481
|
+
# offset=0: the glow's receiver band tops out at emitter
|
|
482
|
+
# offset + Toggles.glow_mask_upper_offset (8 steps); at the
|
|
483
|
+
# default offset 2 that reached +10 - one quantized step
|
|
484
|
+
# under the tile's's +11 mark - so glow bled onto the
|
|
485
|
+
# tile box and icon. At 0 the band ends at +8 and the glow
|
|
486
|
+
# is cast on the WINDOW around the tile, never over it.
|
|
487
|
+
glow_padding = -1
|
|
488
|
+
add_glow((box_left + glow_padding, box_top + glow_padding,
|
|
489
|
+
icon_box - glow_padding*2, icon_box-glow_padding*2), glow_color[:3],
|
|
490
|
+
offset=0.0, corner_radius=icon_corner, clip=clip,
|
|
491
|
+
draw_state=draw_state)
|
|
492
|
+
draw_list.add_rect_filled(box_left, box_top, box_right, box_bottom,
|
|
493
|
+
_color_u32(tile_color), rounding=icon_corner)
|
|
494
|
+
if is_match:
|
|
495
|
+
highlight_rects.append((row_top, row_bottom, is_current))
|
|
496
|
+
icon_font = Melty.font_mgr.get(Font.DEJAVU_SANS_24) if Melty.font_mgr is not None else None
|
|
497
|
+
if icon_font is not None:
|
|
498
|
+
imgui.push_font(icon_font)
|
|
499
|
+
# The glyph's INK rect (not its line box) centers on the tile -
|
|
500
|
+
# see _draw_glyph_ink_centered; the ridges stay inside optical trim.
|
|
501
|
+
_draw_glyph_ink_centered(draw_list, icon,
|
|
502
|
+
box_left + icon_box / 2.0 + icon_nudge_x,
|
|
503
|
+
box_top + icon_box / 2.0 + icon_nudge_y,
|
|
504
|
+
_color_u32(text_color))
|
|
505
|
+
if icon_font is not None:
|
|
506
|
+
imgui.pop_font()
|
|
507
|
+
# ---- live indicator: a bare red bolt over the tile corner ----
|
|
508
|
+
if window_draw_state.live:
|
|
509
|
+
_draw_glyph_ink_centered(draw_list, live_icon,
|
|
510
|
+
box_right - live_badge_inset,
|
|
511
|
+
box_top + live_badge_inset,
|
|
512
|
+
_color_u32(live_badge_color, alpha=1.0))
|
|
513
|
+
text_x = box_right + icon_gap
|
|
514
|
+
else:
|
|
515
|
+
if is_open:
|
|
516
|
+
# Shadow under the open row's name button - a visible presence
|
|
517
|
+
# mark (rows aren't draw_states the compositor can use). Clipped
|
|
518
|
+
# to the dock's rect: partially scrolled rows still draw here.
|
|
519
|
+
add_shadow((name_left, row_top, name_right - name_left, row_height), offset=11,
|
|
520
|
+
corner_radius=corner, clip=clip)
|
|
521
|
+
|
|
522
|
+
# [tint=(0.444, 0.427, 0.393, 1.0), show_tint=True]
|
|
523
|
+
show_inactive_bg = False
|
|
524
|
+
if is_open or show_inactive_bg:
|
|
525
|
+
draw_list.add_rect_filled(name_left, row_top, name_right, row_bottom,
|
|
526
|
+
_color_u32(bg_color), rounding=corner)
|
|
527
|
+
|
|
528
|
+
if is_match:
|
|
529
|
+
highlight_rects.append((row_top, row_bottom, is_current))
|
|
530
|
+
|
|
531
|
+
text_x = name_left + name_pad_x + text_nudge_x
|
|
532
|
+
|
|
533
|
+
if icon:
|
|
534
|
+
icon_size = imgui.calc_text_size(icon)
|
|
535
|
+
draw_list.add_text(text_x, row_top + (row_height - icon_size[1]) / 2.0 + text_nudge_y,
|
|
536
|
+
_color_u32(text_color), icon)
|
|
537
|
+
text_x += icon_size[0] + icon_gap
|
|
538
|
+
|
|
539
|
+
text_size = imgui.calc_text_size(display)
|
|
540
|
+
draw_list.add_text(text_x, row_top + (row_height - text_size[1]) / 2.0 + text_nudge_y,
|
|
541
|
+
_color_u32(text_color), display)
|
|
542
|
+
|
|
543
|
+
# ---- target (summon) button - open windows, and only while the
|
|
544
|
+
# pointer is on the row (the row tile re-renders on the hover
|
|
545
|
+
# edges, so the button appears/disappears with the pointer) ----
|
|
546
|
+
row_hovered = hover_ok and row_top <= mouse_y <= row_bottom
|
|
547
|
+
if is_open and row_hovered:
|
|
548
|
+
target_hovered = hover_ok and in_target
|
|
549
|
+
target_bg_color = _mix(style_manager, tint,
|
|
550
|
+
target_bg_value + (hover_bg_boost if target_hovered else 0.0),
|
|
551
|
+
target_factor, target_saturation)
|
|
552
|
+
target_text_color = _mix(style_manager, tint,
|
|
553
|
+
target_text_value + (hover_text_boost if target_hovered else 0.0),
|
|
554
|
+
target_factor, text_saturation)
|
|
555
|
+
add_shadow((target_left, row_top, target_right - target_left, row_height),
|
|
556
|
+
corner_radius=corner, clip=clip)
|
|
557
|
+
draw_list.add_rect_filled(target_left, row_top, target_right, row_bottom,
|
|
558
|
+
_color_u32(target_bg_color), rounding=corner)
|
|
559
|
+
target_icon_size = imgui.calc_text_size(target_icon)
|
|
560
|
+
draw_list.add_text(target_left + (target_width - target_icon_size[0]) / 2.0 + text_nudge_x,
|
|
561
|
+
row_top + (row_height - target_icon_size[1]) / 2.0 + text_nudge_y,
|
|
562
|
+
_color_u32(target_text_color), target_icon)
|
|
563
|
+
|
|
564
|
+
# ---- live indicator (All tab's bolt; Important has the badge) ----
|
|
565
|
+
if window_draw_state.live and not important:
|
|
566
|
+
live_icon_size = imgui.calc_text_size(live_icon)
|
|
567
|
+
draw_list.add_text(origin_x + (name_x - live_icon_size[0]) / 2.0,
|
|
568
|
+
row_top + (row_height - live_icon_size[1]) / 2.0 + text_nudge_y,
|
|
569
|
+
_color_u32(live_tint), live_icon)
|
|
570
|
+
|
|
571
|
+
# ---- clicks ----
|
|
572
|
+
if click is not None and row_top <= click[1] <= row_bottom:
|
|
573
|
+
click_x = click[0]
|
|
574
|
+
if name_left <= click_x <= name_right:
|
|
575
|
+
was_closed = window_draw_state.closed
|
|
576
|
+
if window_draw_state.closed:
|
|
577
|
+
window_draw_state.closed = False
|
|
578
|
+
_summon(window_draw_state, draw_state, row_top)
|
|
579
|
+
else:
|
|
580
|
+
window_draw_state.closed = True
|
|
581
|
+
NavUndo.record_window(window_draw_state, was_closed, window_draw_state.closed)
|
|
582
|
+
Core.melty.cache.invalidate_up_by_obj(managed_window)
|
|
583
|
+
changed = True
|
|
584
|
+
request_render()
|
|
585
|
+
elif is_open and target_left <= click_x <= target_right:
|
|
586
|
+
_summon(window_draw_state, draw_state, row_top)
|
|
587
|
+
Core.melty.cache.invalidate_up_by_obj(managed_window)
|
|
588
|
+
changed = True
|
|
589
|
+
request_render()
|
|
590
|
+
|
|
591
|
+
# ---- search highlights (second pass, over every row's background) ----
|
|
592
|
+
for highlight_top, highlight_bottom, highlight_current in highlight_rects:
|
|
593
|
+
draw_search_highlight(draw_list, name_left, highlight_top, name_right, highlight_bottom,
|
|
594
|
+
current=highlight_current, rounding=corner)
|
|
595
|
+
|
|
596
|
+
return changed, input_value
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""Reusable palette selection and preview functions."""
|
|
2
|
+
import meltygui_imgui as imgui
|
|
3
|
+
from meltygui.core.core_render import render_func
|
|
4
|
+
from meltygui.hdr_color import pack_color
|
|
5
|
+
from meltygui.model.lut_model import Lut
|
|
6
|
+
from meltygui.view.header_view import draw_header
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@render_func(is_default_for="Lut", show_bg=False, is_tree=False,
|
|
10
|
+
header_same_line=True, with_header=draw_header)
|
|
11
|
+
def draw_lut(input_value: Lut = None, draw_state=None, unique=0, luts=None, **kwargs):
|
|
12
|
+
"""Choose a palette from supplied data and preserve the Lut string type."""
|
|
13
|
+
from meltygui.view.dropdown_view import draw_dropdown
|
|
14
|
+
|
|
15
|
+
names = [str(k) for k in luts]
|
|
16
|
+
current = str(input_value) if input_value else "jet"
|
|
17
|
+
changed, picked = draw_dropdown(
|
|
18
|
+
current, collection={n: n for n in names},
|
|
19
|
+
name=f"lut##{unique}", show_header=False, width=140)
|
|
20
|
+
if changed and picked:
|
|
21
|
+
return True, Lut(picked)
|
|
22
|
+
return False, input_value
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@render_func(show_bg=False, tint=(0.45, 0.55, 0.7))
|
|
26
|
+
def draw_luts(input_value: dict, draw_state=None):
|
|
27
|
+
"""Preview supplied flat RGB lists; edits use the ordinary collection views."""
|
|
28
|
+
luts = input_value if isinstance(input_value, dict) else {}
|
|
29
|
+
draw_list = imgui.get_window_draw_list()
|
|
30
|
+
bar_w, bar_h, segs = 160.0, 13.0, 48
|
|
31
|
+
for name, lut in luts.items():
|
|
32
|
+
if not isinstance(lut, (list, tuple)) or len(lut) < 6 or len(lut) % 3:
|
|
33
|
+
imgui.text(f"{name}: not a flat [r,g,b,...] list")
|
|
34
|
+
continue
|
|
35
|
+
n = len(lut) // 3
|
|
36
|
+
x, y = imgui.get_cursor_screen_pos()
|
|
37
|
+
for s in range(segs):
|
|
38
|
+
i = min(n - 1, int(s * (n - 1) / max(1, segs - 1))) * 3
|
|
39
|
+
col = pack_color(lut[i], lut[i + 1], lut[i + 2], 1.0)
|
|
40
|
+
draw_list.add_rect_filled(x + bar_w * s / segs, y,
|
|
41
|
+
x + bar_w * (s + 1) / segs, y + bar_h, col)
|
|
42
|
+
imgui.dummy(bar_w, bar_h)
|
|
43
|
+
imgui.same_line()
|
|
44
|
+
imgui.text(f"{name} ({n})")
|
|
45
|
+
return False, input_value
|