diff --git a/AGENTS.md b/AGENTS.md index b4d3ce6..ebb9b77 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -60,6 +60,11 @@ describe it as available in docs or the skill. `card_rows` method, not a branch in the card code. - **Layout-independent code does not know the layouts.** Shared logic calls the hooks of `AbstractLiveLayout`; a new widget must not depend on `CompactLayout` or `AppLayout` (P3). +- **A layout hook dispatches on `gui.layout`, never on the view type.** `LiveView` has no type + parameter. A hook is called as `_pin!(gui, obj)`; its barrier passes `gui.layout` on to + `_pin!(gui::LiveView, layout::AppLayout, obj)` or to the fallback on `::AbstractLiveLayout` (see + the docstring of `AbstractLiveLayout`). Code of one layout that is no hook takes `gui::LiveView` + and reads `_app(gui)` or `_compact(gui)`. ## Code map @@ -70,7 +75,7 @@ describe it as available in docs or the skill. `gui.pool`: the one handle that renders every object of the view once, also an object of several systems; the `LiveSystemHandle` of a system holds the object handles of its members, which are the pool's, see `_render_members!`), and small pose helpers. -- `src/LiveView.jl`: `LiveView{L}` and its state structs (`_TraceState`, `_ClipState`, +- `src/LiveView.jl`: `LiveView` and its state structs (`_TraceState`, `_ClipState`, `_MeasureState`, `_CameraState`, `_CardState`, `_ObjectState`, `_DetectorStates`, `_LayoutWidgets`), `live_view`, and the docstring of `AbstractLiveLayout` (the layout interface). - `src/LiveScroll.jl`: scroll areas (`_ScrollArea`), e.g. the sidebars of the app layout: Makie has @@ -222,6 +227,8 @@ loading GLMakie invalidates a part of what it compiled. The one of the GLMakie e A script of a user holds types that no workload has seen, e.g. a lens with its own glass. The behavior per type stays dispatch (`card_rows` etc.). `live_view` and `kinematic_controls!` are not specialized on their arguments either. +- **The GUI is not compiled per layout either**: `LiveView` has no layout parameter, and what + differs per layout dispatches on `gui.layout` (see "Design principles"). - **Measure** with `benchmark/jit_probe.jl` (see its header): it replays a session step by step and prints the compile time of each step; `benchmark/jit_trace_summary.jl` lists the methods of a trace. The scene `other` holds types that no workload has seen. A step of a new action that diff --git a/src/LiveApp.jl b/src/LiveApp.jl index 599a234..b9a404e 100644 --- a/src/LiveApp.jl +++ b/src/LiveApp.jl @@ -76,8 +76,8 @@ mutable struct AppLayout <: AbstractLiveLayout AppLayout(theme::NamedTuple) = new(theme) end -"""`LiveView` with the app layout, i.e. `live_view(...; layout = :app)`.""" -const AppView = LiveView{AppLayout} +# The layout of a `LiveView` made with `layout = :app`, for the helpers of the app layout +_app(gui::LiveView) = gui.layout::AppLayout _layout_name(::AppLayout) = :app @@ -141,8 +141,7 @@ and the dock of the `gui` have now, see `_part_size_kwargs`: a dock that was nei nor dragged keeps following the window (`nothing`), a higher one than a window of the default size allows gets its largest height there. """ -function _part_size_kwargs(gui::AppView) - layout = gui.layout +function _part_size_kwargs(::LiveView, layout::AppLayout) dock = layout.dock.size hi = last(_dock_height_limits(_default_size(layout)[2])) return (; sidebar_width = (Float64(layout.left.size.x), Float64(layout.right.size.x)), @@ -175,7 +174,7 @@ function _add_toolbar_entry!(layout::AppLayout, group::Symbol) end return grid[1, length(grid.content) + 1] end -_add_toolbar_entry!(gui::AppView, group::Symbol) = _add_toolbar_entry!(gui.layout, group) +_add_toolbar_entry!(::LiveView, layout::AppLayout, group::Symbol) = _add_toolbar_entry!(layout, group) """ _add_sidebar_section!(layout::AppLayout, side::Symbol, title; grow = false) -> GridLayout @@ -218,8 +217,8 @@ function _add_sidebar_section!(layout::AppLayout, side::Symbol, title::AbstractS end return content end -_add_sidebar_section!(gui::AppView, side::Symbol, title::AbstractString; kwargs...) = - _add_sidebar_section!(gui.layout, side, title; kwargs...) +_add_sidebar_section!(::LiveView, layout::AppLayout, side::Symbol, title::AbstractString; kwargs...) = + _add_sidebar_section!(layout, side, title; kwargs...) # `_add_dock_panel!` is defined with the tabs of the dock in `LiveDock.jl` @@ -236,8 +235,7 @@ collapsed, such that the 3D view fills the window (see `_set_shown!`); afterward again as its toggle says, i.e. a sidebar that was collapsed stays collapsed, and the inspector and the dock are refreshed, which are not updated while they are collapsed. """ -function _set_spectator_ui!(gui::AppView, on::Bool) - layout = gui.layout +function _set_spectator_ui!(gui::LiveView, layout::AppLayout, on::Bool) layout.ui_hidden = on foreach(p -> _set_shown!(p, !on), (layout.bar, layout.status_bar)) _set_shown!(layout.left, !on && layout.collapse.left.active[]) @@ -452,29 +450,29 @@ Connections and status # The inspector follows the selection via `_update_inspector!`, called right before. The rows of all # objects of a selection of several are shown and highlighted, see `_selection_objects` -function _on_selected!(gui::AppView) +function _on_selected!(gui::LiveView, layout::AppLayout) sel = gui.controls.selected[] objs = _selection_objects(sel) for obj in objs _reveal!(gui, obj) end - _set_selected!(gui.layout.tree, _is_multi(sel) ? objs : sel) + _set_selected!(layout.tree, _is_multi(sel) ? objs : sel) return nothing end -_on_clip_planes_changed!(gui::AppView) = _update_tree!(gui) -_on_hidden!(gui::AppView) = _update_tree!(gui) +_on_clip_planes_changed!(gui::LiveView, ::AppLayout) =_update_tree!(gui) +_on_hidden!(gui::LiveView, ::AppLayout) =_update_tree!(gui) # Also the name in the head of the inspector: a component that takes the place of another one gets # its name after it was selected, see `_replace!` -function _on_components_changed!(gui::AppView) +function _on_components_changed!(gui::LiveView, layout::AppLayout) _update_tree!(gui) - gui.layout.right.shown && _show_header!(gui, gui.layout.inspector.shown) + layout.right.shown && _show_header!(gui, layout.inspector.shown) return nothing end -_show_hint(::AppView) = "click its eye in the object tree to show it again" +_show_hint(::LiveView, ::AppLayout) = "click its eye in the object tree to show it again" -function _on_clipping!(gui::AppView) - active = gui.layout.clip_toggle.active +function _on_clipping!(gui::LiveView, layout::AppLayout) + active = layout.clip_toggle.active active[] == gui.clip.enabled || (active[] = gui.clip.enabled) return nothing end @@ -484,8 +482,7 @@ Connects the entries of the app layout that are not fields of `LiveView`: the cl the help in the 3D view (see `_connect_help!`), the collapse toggles, the info label, the object tree and the inspector. All updates are driven by events. """ -function _connect_layout!(gui::AppView) - layout = gui.layout +function _connect_layout!(gui::LiveView, layout::AppLayout) ctrl = gui.controls listeners = ctrl.listeners # The listeners of the sidebars that scroll end with those of the controls, see `_ScrollArea` @@ -520,7 +517,7 @@ function _connect_layout!(gui::AppView) end """ - _build_splitters!(gui::AppView) + _build_splitters!(gui::LiveView) Builds and connects the splitters of the app layout of the `gui`, see `_Splitters`: the edges of the left and the right sidebar towards the 3D view, which change their widths within @@ -534,8 +531,8 @@ are resized with the right sidebar (see `_resize_docked_views!`). When a drag en catalog is laid out again for the width of the left sidebar (see `_resize_catalog_dock!`) and the inspector fits its texts to the width of the right one (see `_on_inspector_resized!`). """ -function _build_splitters!(gui::AppView) - layout = gui.layout +function _build_splitters!(gui::LiveView) + layout = _app(gui) scene = gui.fig.scene active = () -> !layout.ui_hidden sidebar = () -> Float64.(_SIDEBAR_WIDTH_LIMITS) @@ -555,25 +552,25 @@ end # The help lies over the 3D view: the floating cards keep off it, its clicks are not clicks into the # 3D view -_layout_obstacles(gui::AppView) = - [_overlay_rect(gui.layout.help.pill); _help_rects(gui.layout.help)] -_over_layout(gui::AppView) = - _over_help(gui.layout.help, Point2f(events(gui.ax.scene).mouseposition[])) +_layout_obstacles(::LiveView, layout::AppLayout) = + [_overlay_rect(layout.help.pill); _help_rects(layout.help)] +_over_layout(gui::LiveView, layout::AppLayout) = + _over_help(layout.help, Point2f(events(gui.ax.scene).mouseposition[])) #= App layout: panels as tabs of the analysis dock, controls as sections of the left sidebar, tools in the toolbar group `:user` at the end of the toolbar =# -_mark_panel_stale!(gui::AppView, p::_UserPanel) = (push!(gui.layout.tabs.stale, p); nothing) +_mark_panel_stale!(::LiveView, layout::AppLayout, p::_UserPanel) = (push!(layout.tabs.stale, p); nothing) # A panel whose tab is opened later reads the detectors and beams of the last solve: not after a # cancelled or failed one, whose hits are incomplete -_results_valid(gui::AppView) = gui.detectors.hits_valid && !_running(gui) && !gui.trace.preview +_results_valid(gui::LiveView, ::AppLayout) = gui.detectors.hits_valid && !_running(gui) && !gui.trace.preview # A panel that is updated is not stale anymore, e.g. one whose tab was opened while a solve ran -function _update_user_panel!(gui::AppView, p::_UserPanel) - delete!(gui.layout.tabs.stale, p) - return invoke(_update_user_panel!, Tuple{LiveView, _UserPanel}, gui, p) +function _update_user_panel!(gui::LiveView, layout::AppLayout, p::_UserPanel) + delete!(layout.tabs.stale, p) + return invoke(_update_user_panel!, Tuple{LiveView, AbstractLiveLayout, _UserPanel}, gui, layout, p) end """ @@ -581,8 +578,7 @@ Adds the panel as a tab of the dock: the content is built into the shown tab, th active tab is shown again, unless `select` (or there was none). The panel is updated when its tab is opened, see `_refresh_tab!`. """ -function _add_user_panel!(f, gui::AppView, title::String, select::Bool) - layout = gui.layout +function _add_user_panel!(f, ::LiveView, layout::AppLayout, title::String, select::Bool) tabs = layout.tabs old = tabs.active content = _add_dock_panel!(layout, title; icon = :chart) @@ -597,16 +593,16 @@ function _add_user_panel!(f, gui::AppView, title::String, select::Bool) return p end -function _refresh_tab!(gui::AppView, p::_UserPanel) +function _refresh_tab!(gui::LiveView, p::_UserPanel) _results_valid(gui) || return nothing _update_user_panel!(gui, p) return nothing end -_controls_slot!(gui::AppView, title::String) = _add_sidebar_section!(gui, :left, title) +_controls_slot!(gui::LiveView, ::AppLayout, title::String) = _add_sidebar_section!(gui, :left, title) """ - _catalog_dock_slot!(gui::AppView, title) + _catalog_dock_slot!(gui::LiveView, layout::AppLayout, title) The dock of the component catalog in the app layout: the section `title` of the left sidebar, below the object tree. Its content is a collapsible part, the buttons of the dock are at the right of its @@ -614,8 +610,7 @@ title (see `_section_header`), and `reveal` switches the toggle of the sidebar o that of the sidebar at the start; the catalog is laid out again when the sidebar was resized, see `_build_splitters!`. """ -function _catalog_dock_slot!(gui::AppView, title::AbstractString) - layout = gui.layout +function _catalog_dock_slot!(gui::LiveView, layout::AppLayout, title::AbstractString) left = layout.left content = _add_sidebar_section!(layout, :left, title) stack = left.grid @@ -631,8 +626,8 @@ end # The left sidebar, the place of `add_controls!`, may be collapsed by its toggle: it is attached to # the figure while blocks are added to it, see `_with_ui` of all layouts -function _with_ui(f, gui::AppView) - left = gui.layout.left +function _with_ui(f, gui::LiveView, layout::AppLayout) + left = layout.left function attached() shown = left.shown _set_shown!(left, true) @@ -642,7 +637,7 @@ function _with_ui(f, gui::AppView) _set_shown!(left, shown) end end - return invoke(_with_ui, Tuple{Any, LiveView}, attached, gui) + return invoke(_with_ui, Tuple{Any, LiveView, AbstractLiveLayout}, attached, gui, layout) end -_on_controls_added!(gui::AppView) = _hide_collapsed!(gui.layout.left) +_on_controls_added!(::LiveView, layout::AppLayout) = _hide_collapsed!(layout.left) diff --git a/src/LiveAppTree.jl b/src/LiveAppTree.jl index 4ff7592..4ba96d8 100644 --- a/src/LiveAppTree.jl +++ b/src/LiveAppTree.jl @@ -95,9 +95,9 @@ end # Clip planes are switched off, not hidden, see `_toggle_hidden!` _tree_visible(::LiveView, _, ::LiveClipPlane) = nothing -function _push_tree_rows!(rows, gui::AppView, drawn, @nospecialize(obj), depth; count::Int = 0) +function _push_tree_rows!(rows, gui::LiveView, drawn, @nospecialize(obj), depth; count::Int = 0) children = _children(obj) - expanded = get(gui.layout.expanded, obj, false) + expanded = get(_app(gui).expanded, obj, false) push!(rows, _TreeRow(obj, _label(gui, obj), depth, _tree_kind(obj), !isempty(children), expanded, _tree_visible(gui, drawn, obj); count)) expanded && foreach(c -> _push_tree_rows!(rows, gui, drawn, c, depth + 1), children) @@ -105,7 +105,7 @@ function _push_tree_rows!(rows, gui::AppView, drawn, @nospecialize(obj), depth; end """ - _tree_rows(gui::AppView) -> Vector{_TreeRow} + _tree_rows(gui::LiveView) -> Vector{_TreeRow} Returns the rows of the object tree of the `gui`, which lists the members of each system: per system a row (key: its system handle) followed by its sources (see `_sources_of`) and its objects @@ -122,7 +122,7 @@ expanded, and groups collapsed, by default. Objects whose plots are all hidden ( The row of a system has the buttons "+" and "−", which pick its members with the mouse, see `_tree_button!`; the one of the pick that is going on (see `_member_pick`) is highlighted. """ -function _tree_rows(gui::AppView) +function _tree_rows(gui::LiveView) drawn = Base.IdSet{Any}(rendered(oh) for oh in AbstractTrees.children(gui.controls.h)) rows = _TreeRow[] pick = _member_pick(gui) @@ -144,10 +144,10 @@ end # The row of the system (or of "No system") of `h` with the icon of the `kind` and the `buttons` # (see `_TreeRow`), then its `sources` and its objects -function _push_system_rows!(rows, gui::AppView, drawn, h::AbstractSystemRenderHandle, kind::Symbol, +function _push_system_rows!(rows, gui::LiveView, drawn, h::AbstractSystemRenderHandle, kind::Symbol, sources, buttons) tops = _top_levels(h) - expanded = get(gui.layout.expanded, h, true) + expanded = get(_app(gui).expanded, h, true) push!(rows, _TreeRow(h, _label(gui, h), 0, kind, !isempty(tops) || !isempty(sources), expanded, _tree_visible(gui, drawn, h); buttons)) expanded || return rows @@ -160,14 +160,14 @@ function _push_system_rows!(rows, gui::AppView, drawn, h::AbstractSystemRenderHa end """Sets the rows of the object tree of the `gui`, only called on events, see `_tree_rows`.""" -function _update_tree!(gui::AppView) - _set_rows!(gui.layout.tree, _tree_rows(gui)) +function _update_tree!(gui::LiveView) + _set_rows!(_app(gui).tree, _tree_rows(gui)) return nothing end """Expands or collapses the row `key` of the object tree, see `_tree_rows`.""" -function _toggle_expanded!(gui::AppView, key) - expanded = gui.layout.expanded +function _toggle_expanded!(gui::LiveView, key) + expanded = _app(gui).expanded expanded[key] = !get(expanded, key, key isa AbstractSystemRenderHandle) _update_tree!(gui) return nothing @@ -180,7 +180,7 @@ Handles a click on the button "+" (`button == :add`) or "−" (`:remove`) of the of `h` in the object tree: starts picking its members with the mouse, or ends it if exactly this is going on, see `_set_member_pick!`. The button of the pick is highlighted, see `_tree_rows`. """ -function _tree_button!(gui::AppView, h::AbstractSystemRenderHandle, button::Symbol) +function _tree_button!(gui::LiveView, h::AbstractSystemRenderHandle, button::Symbol) _set_member_pick!(gui, rendered(h), button === :add) _update_tree!(gui) return nothing @@ -194,9 +194,9 @@ Handles a click on the label of a row of the object tree: selects the object lik inspects it instead, i.e. shows its card in the inspector without selecting it, see `_inspect!`; the expander of a system expands or collapses it. """ -_tree_click!(gui::AppView, h::AbstractSystemRenderHandle) = _inspect!(gui, h) +_tree_click!(gui::LiveView, h::AbstractSystemRenderHandle) = _inspect!(gui, h) -function _tree_click!(gui::AppView, @nospecialize(obj)) +function _tree_click!(gui::LiveView, @nospecialize(obj)) _is_movable(gui.controls, obj) ? _select!(gui, obj) : _inspect!(gui, obj) return nothing end @@ -209,18 +209,18 @@ Handles a click with `Ctrl` (`Cmd` on macOS) on the label of a row of the object `Ctrl`+click in the 3D view, see `_toggle_select!`. On any other row, e.g. of a system or of an object that is not movable, it is a plain click, see `_tree_click!`. """ -_tree_toggle!(gui::AppView, h::AbstractSystemRenderHandle) = _tree_click!(gui, h) +_tree_toggle!(gui::LiveView, h::AbstractSystemRenderHandle) = _tree_click!(gui, h) -function _tree_toggle!(gui::AppView, @nospecialize(obj)) +function _tree_toggle!(gui::LiveView, @nospecialize(obj)) _is_movable(gui.controls, obj) ? _toggle_select!(gui, obj) : _tree_click!(gui, obj) return nothing end # The row of the inspected object is highlighted like the selected one, see `_on_selected!` -_show_inspected!(::AppView, ::Nothing) = nothing -function _show_inspected!(gui::AppView, @nospecialize(obj)) +_show_inspected!(::LiveView, ::AppLayout, ::Nothing) = nothing +function _show_inspected!(gui::LiveView, layout::AppLayout, @nospecialize(obj)) _reveal!(gui, obj) - _set_selected!(gui.layout.tree, _row_key(gui, obj)) + _set_selected!(layout.tree, _row_key(gui, obj)) return nothing end @@ -229,12 +229,12 @@ Expands the groups that contain `obj` and a system that lists it (or "No system" of it is shown in the object tree: of an object of several systems the first one, unless one of them is expanded. The rows are only set again if a row was expanded. """ -_reveal!(::AppView, ::Nothing) = nothing +_reveal!(::LiveView, ::Nothing) = nothing # The rows of the systems are always shown -_reveal!(::AppView, ::BMO.AbstractSystem) = nothing +_reveal!(::LiveView, ::BMO.AbstractSystem) = nothing -function _reveal!(gui::AppView, @nospecialize(obj)) - expanded = gui.layout.expanded +function _reveal!(gui::LiveView, @nospecialize(obj)) + expanded = _app(gui).expanded chain = _chain(gui.controls, obj) changed = false for group in chain[2:end] @@ -254,10 +254,10 @@ The handles of the systems of the `gui` whose rows list the top-level object or in the object tree, in the order of the tree; `gui.extras` for one without a system. Empty for what is listed under no system, e.g. a clip plane. """ -_listing_handles(gui::AppView, @nospecialize(obj)) = AbstractSystemRenderHandle[ +_listing_handles(gui::LiveView, @nospecialize(obj)) = AbstractSystemRenderHandle[ h for h in (gui.system_handles..., gui.extras) if _has(_top_levels(h), obj)] -function _listing_handles(gui::AppView, src::Union{BMO.AbstractBeam, BMO.AbstractBeamGroup}) +function _listing_handles(gui::LiveView, src::Union{BMO.AbstractBeam, BMO.AbstractBeamGroup}) sys = _system_of_source(gui, src) h = isnothing(sys) ? gui.extras : _system_handle(gui, sys) return isnothing(h) ? AbstractSystemRenderHandle[] : AbstractSystemRenderHandle[h] @@ -291,8 +291,8 @@ Returns the tooltip of the object tree of the `gui` (see `_TreeTip`), `nothing` `_connect_tree_tips!`. A field of the layout and not an entry of a global registry, which would keep every closed window alive, see `_highlight`. """ -_tree_tip_state(gui::AppView) = - isdefined(gui.layout, :tree_tip) ? gui.layout.tree_tip::_TreeTip : nothing +_tree_tip_state(gui::LiveView) = + isdefined(_app(gui), :tree_tip) ? _app(gui).tree_tip::_TreeTip : nothing """ _tree_tip(gui) -> Union{Nothing, NamedTuple} @@ -303,8 +303,8 @@ eye of a row hides or shows its object, "+" and "−" of a system pick its membe (see `_set_member_pick!`) and the counter is the number of systems of an object. `nothing` for a label, an expander and beside the rows. """ -function _tree_tip(gui::AppView) - tree = gui.layout.tree +function _tree_tip(gui::LiveView) + tree = _app(gui).tree _mouse_in_tree(tree) || return nothing hit = _hit(tree) isnothing(hit) && return nothing @@ -324,7 +324,7 @@ function _tree_tip(gui::AppView) end """Hides the tooltip of the object tree of the `gui` and forgets what it was for.""" -function _hide_tree_tip!(gui::AppView) +function _hide_tree_tip!(gui::LiveView) tip = _tree_tip_state(gui) isnothing(tip) && return nothing isnothing(tip.timer) || (close(tip.timer); tip.timer = nothing) @@ -337,7 +337,7 @@ end Shows the tooltip of the part of the object tree of the `gui` under the mouse (see `_tree_tip`), if the mouse still rests on the part that the tooltip waits for. """ -function _show_tree_tip!(gui::AppView) +function _show_tree_tip!(gui::LiveView) tip = _tree_tip_state(gui) isnothing(tip) && return nothing info = _tree_tip(gui) @@ -352,7 +352,7 @@ end The mouse moved in the window of the `gui`: the tooltip of the object tree waits for `_TREE_TIP_DELAY` on another eye, button or counter, and is hidden elsewhere. """ -function _on_tree_hover!(gui::AppView) +function _on_tree_hover!(gui::LiveView) tip = _tree_tip_state(gui) isnothing(tip) && return nothing info = _tree_tip(gui) @@ -372,17 +372,17 @@ function _on_tree_hover!(gui::AppView) end """ - _connect_tree_tips!(gui::AppView) + _connect_tree_tips!(gui::LiveView) Gives the eyes, the buttons "+" and "−" and the counters of the object tree of the `gui` tooltips like those of the icons of the toolbar: the tree draws them as markers of one plot, which have no tooltip of their own. A click, scrolling and the closed window hide the tooltip. """ -function _connect_tree_tips!(gui::AppView) +function _connect_tree_tips!(gui::LiveView) scene = gui.fig.scene - t = gui.layout.theme + t = _app(gui).theme tip = _TreeTip(Observable(""), Observable(Point2f(0)), Observable(false), nothing, nothing) - gui.layout.tree_tip = tip + _app(gui).tree_tip = tip plot = Makie.tooltip!(scene, tip.pos, tip.text; placement = :below, visible = tip.visible, backgroundcolor = t.tooltip, textcolor = t.tooltip_text, outline_linewidth = 0, triangle_size = 6, offset = 4, fontsize = 13, textpadding = (6, 6, 4, 4), overdraw = true, diff --git a/src/LiveBackground.jl b/src/LiveBackground.jl index caeb9c2..2b0464a 100644 --- a/src/LiveBackground.jl +++ b/src/LiveBackground.jl @@ -20,7 +20,6 @@ end _points(x::_BackgroundItem) = [x.point] _label(gui::LiveView, x::_BackgroundItem) = _label(gui, x.obj) -_label(gui::AppView, x::_BackgroundItem) = _label(gui, x.obj) _tree_kind(x::_BackgroundItem) = _tree_kind(x.obj) _keep_plots!(::LiveView, ::_BackgroundItem) = nothing _forget!(::LiveView, ::_BackgroundItem) = nothing diff --git a/src/LiveCards.jl b/src/LiveCards.jl index d8ebc3d..68675de 100644 --- a/src/LiveCards.jl +++ b/src/LiveCards.jl @@ -34,13 +34,15 @@ _has_open_menu(c::_AbstractCard) = any(b -> !isnothing(_open_menu(b)), c.blocks) Whether a menu of a card of the `gui` is open: its options may reach beyond the card, hence presses are left to it and the keys to its search, see `_connect_cards!` and `_typing`. """ -_card_menu_open(gui::LiveView) = any(_has_open_menu, gui.cards.all) +_card_menu_open(gui::LiveView) = _card_menu_open(gui, gui.layout) +_card_menu_open(gui::LiveView, ::AbstractLiveLayout) = any(_has_open_menu, gui.cards.all) """ Returns the textboxes of the `gui` outside of the cards, e.g. of the inspector of the app layout, which take the keyboard like those of the cards, see `_typing`. None by default. """ -_layout_boxes(::LiveView) = () +_layout_boxes(gui::LiveView) = _layout_boxes(gui, gui.layout) +_layout_boxes(::LiveView, ::AbstractLiveLayout) = () """Shows `s` in the textbox `tb` without triggering its listeners, `""` shows the placeholder.""" function _set_box!(tb::Textbox, s::String) @@ -66,7 +68,8 @@ end Refreshes the parts of the layout of the `gui` that show the selected object besides the cards, e.g. the inspector of the app layout; nothing by default. """ -_refresh_inspector!(::LiveView; force::Bool = false) = nothing +_refresh_inspector!(gui::LiveView; kw...) = _refresh_inspector!(gui, gui.layout; kw...) +_refresh_inspector!(::LiveView, ::AbstractLiveLayout; force::Bool = false) = nothing #= Values of the pose card in the frame of the controls, see `pose_card_rows` and `_PoseDisplay` @@ -445,7 +448,8 @@ The rectangles [figure px] of the parts of the layout of the `gui` that lie over are shown, e.g. the overlay of the compact layout (see `_CompactOverlay`), which the floating cards keep off like the view cube; none by default. """ -_layout_obstacles(::LiveView) = Rect2f[] +_layout_obstacles(gui::LiveView) = _layout_obstacles(gui, gui.layout) +_layout_obstacles(::LiveView, ::AbstractLiveLayout) = Rect2f[] """ _over_layout(gui) -> Bool @@ -454,14 +458,16 @@ Returns `true` if the mouse is over a part of the layout of the `gui` that lies whose presses and scrolling the camera must not get, like those over the cards (see `_shield_cards!`), e.g. the overlay of the compact layout; `false` by default. """ -_over_layout(::LiveView) = false +_over_layout(gui::LiveView) = _over_layout(gui, gui.layout) +_over_layout(::LiveView, ::AbstractLiveLayout) = false """ Returns `true` if the layout of the `gui` shows the card of the selection (`gui.cards.selection`) next to the selected object; layouts that show the card elsewhere, e.g. docked in the inspector of the app layout, return `false`. Pinned cards are shown in all layouts. """ -_selection_card_shown(::LiveView) = true +_selection_card_shown(gui::LiveView) = _selection_card_shown(gui, gui.layout) +_selection_card_shown(::LiveView, ::AbstractLiveLayout) = true """ _update_card!(gui, c, obj, obstacles) @@ -1383,10 +1389,12 @@ function _reset_pages!(gui::LiveView, c::_ComponentCard) end """Unpins the cards of the `gui` that are pinned to `obj`, e.g. a removed clip plane.""" -_unpin!(gui::LiveView, @nospecialize(obj)) = foreach(c -> _toggle_pinned!(gui, c), _floating_cards(gui, obj)) +_unpin!(gui::LiveView, @nospecialize(obj)) = _unpin!(gui, gui.layout, obj) +_unpin!(gui::LiveView, ::AbstractLiveLayout, @nospecialize(obj)) = foreach(c -> _toggle_pinned!(gui, c), _floating_cards(gui, obj)) """Returns `true` if a card of the `gui` is pinned to `obj`: the pinned cards float by default.""" -_is_pinned(gui::LiveView, @nospecialize(obj)) = _is_floating(gui, obj) +_is_pinned(gui::LiveView, @nospecialize(obj)) = _is_pinned(gui, gui.layout, obj) +_is_pinned(gui::LiveView, ::AbstractLiveLayout, @nospecialize(obj)) = _is_floating(gui, obj) """Returns the pinned cards of the `gui` that float next to `obj` in the 3D view.""" _floating_cards(gui::LiveView, @nospecialize(obj)) = filter(c -> c.pinned && c.obj === obj, gui.cards.all) @@ -1402,15 +1410,17 @@ Hand the cards pinned to `old` over to `new`, which takes its place, see `_repla `_take_pins!` detaches them from `old` before it is removed, which would unpin them, and `_give_pins!` pins them to `new` once it is in the view. A floating card keeps its spot, its page, if `new` has it, and whether it is collapsed; until then it is pinned to no object and hidden. A -layout that docks pinned cards hands those over as well, see `_take_pins!(::AppView, old)`. +layout that docks pinned cards hands those over as well, see `_take_pins!(gui, ::AppLayout, old)`. """ -function _take_pins!(gui::LiveView, @nospecialize(old)) +_take_pins!(gui::LiveView, @nospecialize(old)) = _take_pins!(gui, gui.layout, old) +function _take_pins!(gui::LiveView, ::AbstractLiveLayout, @nospecialize(old)) floating = _floating_cards(gui, old) foreach(c -> c.obj = nothing, floating) return (; floating, docked = ()) end -function _give_pins!(gui::LiveView, pins, @nospecialize(new)) +_give_pins!(gui::LiveView, pins, @nospecialize(new)) = _give_pins!(gui, gui.layout, pins, new) +function _give_pins!(gui::LiveView, ::AbstractLiveLayout, pins, @nospecialize(new)) # the card builds its rows for `new`, see `_update_card!` foreach(c -> (c.obj, c.key, c.pose) = (new, nothing, nothing), pins.floating) isempty(pins.floating) || _update_cards!(gui) @@ -1425,8 +1435,10 @@ Moves the card pinned to `obj` from the sidebar into the 3D view, next to `obj`, layout that docks the pinned cards, e.g. the app layout, implements them; by default, e.g. in the compact layout, which has no sidebar, the pinned cards always float and these do nothing. """ -_float!(::LiveView, _) = nothing -_dock!(::LiveView, _) = nothing +_float!(gui::LiveView, @nospecialize(x)) = _float!(gui, gui.layout, x) +_float!(::LiveView, ::AbstractLiveLayout, _) = nothing +_dock!(gui::LiveView, @nospecialize(x)) = _dock!(gui, gui.layout, x) +_dock!(::LiveView, ::AbstractLiveLayout, _) = nothing """ _toggle_pin!(gui, obj) @@ -1452,7 +1464,8 @@ also if the mouse moved it before. The card `c` keeps its `page`, if `obj` has i `view_expanded` and the size `view_size` of its view, which a caller may set before, e.g. to those of a docked card. """ -function _pin!(gui::LiveView, @nospecialize(obj)) +_pin!(gui::LiveView, @nospecialize(obj)) = _pin!(gui, gui.layout, obj) +function _pin!(gui::LiveView, ::AbstractLiveLayout, @nospecialize(obj)) c = _spare_card!(gui) c.page = _default_page(obj) return _pin!(gui, c, obj) @@ -1465,7 +1478,8 @@ function _pin!(gui::LiveView, c::_ComponentCard, @nospecialize(obj)) end # Called after a card was pinned or unpinned, see `AbstractLiveLayout` -_on_pinned!(::LiveView) = nothing +_on_pinned!(gui::LiveView) = _on_pinned!(gui, gui.layout) +_on_pinned!(::LiveView, ::AbstractLiveLayout) = nothing """Returns a card of the `gui` that is neither pinned nor the card of the selection, or a new one.""" function _spare_card!(gui::LiveView) @@ -1683,7 +1697,8 @@ Returns `true` if the mouse is over a part of the layout of the `gui` whose pres into the 3D view, see `ignore_mouse` of the controls: the controls neither select nor deselect on them. By default none, see `AbstractLiveLayout`. """ -_outside_view(::LiveView) = false +_outside_view(gui::LiveView) = _outside_view(gui, gui.layout) +_outside_view(::LiveView, ::AbstractLiveLayout) = false """ _connect_cards!(gui) diff --git a/src/LiveCatalogWindow.jl b/src/LiveCatalogWindow.jl index b51ddff..0ed637a 100644 --- a/src/LiveCatalogWindow.jl +++ b/src/LiveCatalogWindow.jl @@ -26,7 +26,8 @@ layout with such a place, e.g. a section of a sidebar, returns Part of the layout interface, see `AbstractLiveLayout`. """ -_catalog_dock_slot!(::LiveView, _) = nothing +_catalog_dock_slot!(gui::LiveView, w) = _catalog_dock_slot!(gui, gui.layout, w) +_catalog_dock_slot!(::LiveView, ::AbstractLiveLayout, _) = nothing """ _CatalogDock diff --git a/src/LiveCompact.jl b/src/LiveCompact.jl index a4def26..6883b45 100644 --- a/src/LiveCompact.jl +++ b/src/LiveCompact.jl @@ -37,8 +37,8 @@ mutable struct CompactLayout <: AbstractLiveLayout CompactLayout(theme::NamedTuple) = new(theme, nothing, nothing, nothing, nothing) end -"""`LiveView` with the compact layout, i.e. `live_view(...; layout = :compact)`.""" -const CompactView = LiveView{CompactLayout} +# The compact layout of the `gui`, for the helpers that only this layout has +_compact(gui::LiveView) = gui.layout::CompactLayout _layout_name(::CompactLayout) = :compact @@ -121,8 +121,8 @@ _has_tool(::CompactLayout, ::Union{Val{:fit_button}, Val{:views_button}}) = true Connects the parts of the compact layout that are not fields of `LiveView`: the fit button, the help (see `_connect_help!`) and the overlay, see `_connect_overlay!`. """ -function _connect_layout!(gui::CompactView) - o = gui.layout.overlay +function _connect_layout!(gui::LiveView, layout::CompactLayout) + o = layout.overlay ctrl = gui.controls push!(ctrl.listeners, on(_ -> _zoom_to_selection!(gui), o.fit_button.clicks)) _connect_help!(gui) @@ -132,7 +132,7 @@ function _connect_layout!(gui::CompactView) return nothing end -_show_hint(::CompactView) = "choose it in the component menu of ⋯ to show it again" +_show_hint(::LiveView, ::CompactLayout) = "choose it in the component menu of ⋯ to show it again" #= Tools: the built-in tools in the tool rail or the camera popover, the tools of `add_tool!` in the @@ -186,11 +186,11 @@ Panels below the detector panels in `fig[1, 2]`, controls as sections of the too Returns the grid of the panels in `fig[1, 2]` of the compact layout, created without detector panels. """ -_panel_grid!(gui::CompactView) = _panel_grid!(gui, gui.layout.panels) -_panel_grid!(::CompactView, grid::GridLayout) = grid -_panel_grid!(gui::CompactView, ::Nothing) = _panel_part!(gui.layout, gui.fig.layout) +_panel_grid!(gui::LiveView) = _panel_grid!(gui, _compact(gui).panels) +_panel_grid!(::LiveView, grid::GridLayout) = grid +_panel_grid!(gui::LiveView, ::Nothing) = _panel_part!(_compact(gui), gui.fig.layout) -function _add_user_panel!(f, gui::CompactView, title::String, ::Bool) +function _add_user_panel!(f, gui::LiveView, ::CompactLayout, title::String, ::Bool) grid = _panel_grid!(gui) nrows, ncols = size(grid) # Below all panels, over all columns of their grid @@ -203,5 +203,5 @@ function _add_user_panel!(f, gui::CompactView, title::String, ::Bool) end # An entry of the tool rail per section of controls, which opens them in a popover next to the rail -_controls_slot!(gui::CompactView, title::String) = _add_section!(gui.layout.overlay, title) -_on_controls_added!(gui::CompactView) = _on_overlay_changed!(gui.layout.overlay) +_controls_slot!(::LiveView, layout::CompactLayout, title::String) = _add_section!(layout.overlay, title) +_on_controls_added!(::LiveView, layout::CompactLayout) = _on_overlay_changed!(layout.overlay) diff --git a/src/LiveCustom.jl b/src/LiveCustom.jl index e58082e..da3cab0 100644 --- a/src/LiveCustom.jl +++ b/src/LiveCustom.jl @@ -25,7 +25,8 @@ The slot of [`add_panel!`](@ref) in the layout of the `gui`: creates the place o `title`, builds its content via `f(layout)` (see `_user_panel`) and returns the panel. `select` shows it at once in layouts that show one panel at a time. """ -_add_user_panel!(_, gui::LiveView, ::String, ::Bool) = _slot_error(gui, "place for panels") +_add_user_panel!(f, gui::LiveView, title::String, select::Bool) = _add_user_panel!(f, gui, gui.layout, title, select) +_add_user_panel!(_, gui::LiveView, ::AbstractLiveLayout, ::String, ::Bool) = _slot_error(gui, "place for panels") """ Returns the `_UserPanel` named `title` with the content `layout`, built by `f(layout)`: its result @@ -46,7 +47,8 @@ _update_function(::Observables.ObserverFunction) = nothing Whether the panel `p` of the `gui` is shown, i.e. updated after a solve: always, unless the layout hides panels, see `_mark_panel_stale!`. """ -_panel_shown(::LiveView, _) = true +_panel_shown(gui::LiveView, @nospecialize(p)) = _panel_shown(gui, gui.layout, p) +_panel_shown(::LiveView, ::AbstractLiveLayout, _) = true """ _mark_panel_stale!(gui, p) @@ -54,13 +56,15 @@ _panel_shown(::LiveView, _) = true Marks the hidden panel `p` of the `gui` as stale, i.e. to be updated once it is shown; nothing in layouts that show all panels, see `_panel_shown`. """ -_mark_panel_stale!(::LiveView, _) = nothing +_mark_panel_stale!(gui::LiveView, @nospecialize(p)) = _mark_panel_stale!(gui, gui.layout, p) +_mark_panel_stale!(::LiveView, ::AbstractLiveLayout, _) = nothing """ Whether the detectors and beams of the `gui` hold the result of a full solve, which the `update` of a panel may read: not while a solve runs in the background or after a preview solve. """ -_results_valid(gui::LiveView) = !_running(gui) && !gui.trace.preview +_results_valid(gui::LiveView) = _results_valid(gui, gui.layout) +_results_valid(gui::LiveView, ::AbstractLiveLayout) = !_running(gui) && !gui.trace.preview """ _update_user_panels!(gui) @@ -89,7 +93,8 @@ function _refresh_user_panel!(gui::LiveView, p::_UserPanel) end """Calls the `update` of the panel `p`, errors are logged once per distinct message.""" -_update_user_panel!(gui::LiveView, p::_UserPanel) = _run_update!(gui, p, p.update) +_update_user_panel!(gui::LiveView, p::_UserPanel) = _update_user_panel!(gui, gui.layout, p) +_update_user_panel!(gui::LiveView, ::AbstractLiveLayout, p::_UserPanel) = _run_update!(gui, p, p.update) """ _run_update!(gui, p, update) @@ -135,8 +140,10 @@ end The slot of [`add_controls!`](@ref) in the layout of the `gui`: the layout of a new, titled group of widgets. `_on_controls_added!(gui)` is called once the widgets are built. """ -_controls_slot!(gui::LiveView, ::String) = _slot_error(gui, "place for controls") -_on_controls_added!(::LiveView) = nothing +_controls_slot!(gui::LiveView, title::String) = _controls_slot!(gui, gui.layout, title) +_controls_slot!(gui::LiveView, ::AbstractLiveLayout, ::String) = _slot_error(gui, "place for controls") +_on_controls_added!(gui::LiveView) = _on_controls_added!(gui, gui.layout) +_on_controls_added!(::LiveView, ::AbstractLiveLayout) = nothing #= Widgets that take the keyboard diff --git a/src/LiveDetectors.jl b/src/LiveDetectors.jl index 0d77681..475df05 100644 --- a/src/LiveDetectors.jl +++ b/src/LiveDetectors.jl @@ -94,7 +94,8 @@ _card_view(_) = nothing The detector views shown by the layout of the `gui` outside the floating cards, each with its detector, e.g. on the docked cards of the app layout; none by default, see `AbstractLiveLayout`. """ -_layout_views(::LiveView) = () +_layout_views(gui::LiveView) = _layout_views(gui, gui.layout) +_layout_views(::LiveView, ::AbstractLiveLayout) = () """ _shown_views(gui) -> Vector{Tuple{Any, Any}} @@ -527,7 +528,8 @@ Pins a card to the detector `pd` that shows its page "Results", with the view `e collapsed to its thumbnail: a floating card next to the detector by default; a layout that docks the pinned cards, e.g. the app layout, docks it, see `AbstractLiveLayout`. """ -function _pin_view!(gui::LiveView, pd; expanded::Bool = true) +_pin_view!(gui::LiveView, pd; kw...) = _pin_view!(gui, gui.layout, pd; kw...) +function _pin_view!(gui::LiveView, ::AbstractLiveLayout, pd; expanded::Bool = true) c = _spare_card!(gui) c.page, c.view_expanded = :results, expanded _pin!(gui, c, pd) diff --git a/src/LiveDock.jl b/src/LiveDock.jl index 106d04d..bb2409b 100644 --- a/src/LiveDock.jl +++ b/src/LiveDock.jl @@ -324,8 +324,8 @@ function _add_dock_panel!(layout::AppLayout, title::AbstractString; icon::Symbol _update_dock!(layout) return part.grid end -_add_dock_panel!(gui::AppView, title::AbstractString; kwargs...) = - _add_dock_panel!(gui.layout, title; kwargs...) +_add_dock_panel!(::LiveView, layout::AppLayout, title::AbstractString; kwargs...) = + _add_dock_panel!(layout, title; kwargs...) """ _select_tab!(layout::AppLayout, i) @@ -353,35 +353,35 @@ Lazy panels, see `_DockTabs` =# """Whether the panel `p` is shown, i.e. its tab is active and the dock is not collapsed.""" -_panel_shown(gui::AppView, p) = gui.layout.dock.shown && _active_panel(gui.layout.tabs) === p +_panel_shown(::LiveView, layout::AppLayout, p) = layout.dock.shown && _active_panel(layout.tabs) === p """ - _activate_tab!(gui::AppView, i) + _activate_tab!(gui::LiveView, i) Switches the dock to the tab `i` after a click on it: shows its content and updates its panel if it is stale, see `_refresh_dock!`. A panel that is left while the live view shows a preview (coarse grid or preview solve) becomes stale. """ -function _activate_tab!(gui::AppView, i::Int) - tabs = gui.layout.tabs +function _activate_tab!(gui::LiveView, i::Int) + tabs = _app(gui).tabs (1 <= i <= length(tabs.parts) && i != tabs.active) || return nothing old = _active_panel(tabs) (gui.trace.coarse || gui.trace.preview) && !isnothing(old) && push!(tabs.stale, old) - _select_tab!(gui.layout, i) + _select_tab!(_app(gui), i) _refresh_dock!(gui) return nothing end """ - _refresh_dock!(gui::AppView) + _refresh_dock!(gui::LiveView) Updates the panel of the active tab if it is stale and shown, see `_refresh_tab!`. Nothing is updated while a solve runs or after a cancelled solve, the next solve updates the panel. """ -function _refresh_dock!(gui::AppView) - tabs = gui.layout.tabs +function _refresh_dock!(gui::LiveView) + tabs = _app(gui).tabs p = _active_panel(tabs) - (gui.layout.dock.shown && !isnothing(p) && p in tabs.stale) || return nothing + (_app(gui).dock.shown && !isnothing(p) && p in tabs.stale) || return nothing _refresh_tab!(gui, p) return nothing end @@ -390,8 +390,8 @@ end # `_UserPanel` of `add_panel!` is called, see LiveApp.jl """Connects the tab bar and the collapse toggle of the dock of the `gui`, see `_DockTabs`.""" -function _connect_dock!(gui::AppView) - layout = gui.layout +function _connect_dock!(gui::LiveView) + layout = _app(gui) listeners = gui.controls.listeners push!(listeners, on(i -> _activate_tab!(gui, i), layout.tabs.bar.clicked)) # After `_update_dock!`, which shows or collapses the dock diff --git a/src/LiveEdit.jl b/src/LiveEdit.jl index a194a41..46cf55f 100644 --- a/src/LiveEdit.jl +++ b/src/LiveEdit.jl @@ -45,8 +45,9 @@ _edit_field(i::Int, k::Int) = k == 1 ? _edit_box(i) : k == 2 ? Symbol(:edit_, i, Symbol(:edit_, i, :_A, _SURFACE_ORDERS[k - 2]) """The cards of the `gui` that can show the page "Edit": the floating ones, and docked ones of a layout.""" -_edit_cards(gui::LiveView) = Any[gui.cards.all...] -_edit_cards(gui::AppView) = Any[gui.cards.all..., _docked_cards(gui)...] +_edit_cards(gui::LiveView) = _edit_cards(gui, gui.layout) +_edit_cards(gui::LiveView, ::AbstractLiveLayout) = Any[gui.cards.all...] +_edit_cards(gui::LiveView, ::AppLayout) = Any[gui.cards.all..., _docked_cards(gui)...] """ _read_edit_inputs!(gui, obj) diff --git a/src/LiveInfo.jl b/src/LiveInfo.jl index bea359e..cc619ea 100644 --- a/src/LiveInfo.jl +++ b/src/LiveInfo.jl @@ -42,7 +42,6 @@ _title(::_Measurement) = "Measurement" # The item takes the place of an object on a card: its label, icon, pose and bounding box _label(::LiveView, x::_InfoItem) = _title(x) -_label(::AppView, x::_InfoItem) = _title(x) _tree_kind(::_BeamPoint) = :trace _tree_kind(::_Measurement) = :measure _pose(x::_InfoItem) = (Point3{Float64}(sum(_points(x)) / length(_points(x))), Matrix{Float64}(I, 3, 3)) @@ -122,7 +121,8 @@ Keeps the transient card `c` of the `gui` when its pin is clicked: it becomes a the next inspection or measurement does not replace. In the app layout, whose pinned cards are docked (see `_pin!`), the item is pinned there and the floating card is removed. """ -function _keep_info!(gui::LiveView, c::_ComponentCard) +_keep_info!(gui::LiveView, c::_ComponentCard) = _keep_info!(gui, gui.layout, c) +function _keep_info!(gui::LiveView, ::AbstractLiveLayout, c::_ComponentCard) _keepable(c.obj) || return _release_info!(gui, _InfoItem) _keep_plots!(gui, c.obj) c.transient = false @@ -131,7 +131,7 @@ function _keep_info!(gui::LiveView, c::_ComponentCard) _on_pinned!(gui) return nothing end -function _keep_info!(gui::AppView, c::_ComponentCard) +function _keep_info!(gui::LiveView, ::AppLayout, c::_ComponentCard) x = c.obj _keepable(x) || return _release_info!(gui, _InfoItem) _keep_plots!(gui, x) @@ -174,8 +174,8 @@ _forget!(::LiveView, _) = nothing # The dock button of the transient card of `x` in the app layout keeps it, docked like its pin does, # see `_keep_info!`; a kept card moves like the card of a component, see `_dock!` -function _dock!(gui::AppView, x::_InfoItem) +function _dock!(gui::LiveView, layout::AppLayout, x::_InfoItem) c = _info_card(gui) !isnothing(c) && c.obj === x && return _keep_info!(gui, c) - return invoke(_dock!, Tuple{AppView, Any}, gui, x) + return invoke(_dock!, Tuple{LiveView, AppLayout, Any}, gui, layout, x) end diff --git a/src/LiveInspector.jl b/src/LiveInspector.jl index c5bd93e..14f2aa8 100644 --- a/src/LiveInspector.jl +++ b/src/LiveInspector.jl @@ -191,19 +191,19 @@ end # The rows of the layout of the card `c` that are shown: its head, its parts and, below the card of # the selection, the pinned cards -function _set_card_gaps!(gui::AppView, c::_DockedCard) +function _set_card_gaps!(gui::LiveView, c::_DockedCard) shown = Bool[fill(true, c.first_row - 1); [p.shown for p in _card_parts(c)]; _rows_below(gui, c)] _set_rowgaps!(c.parent, shown, c.gap) return nothing end -_rows_below(gui::AppView, c::_DockedCard) = c.pinned ? Bool[] : Bool[!isempty(gui.layout.inspector.pinned)] +_rows_below(gui::LiveView, c::_DockedCard) = c.pinned ? Bool[] : Bool[!isempty(_app(gui).inspector.pinned)] # The pages of the card of `obj`, none without an object _docked_pages(::LiveView, ::Nothing) = () _docked_pages(gui::LiveView, @nospecialize(obj)) = _card_pages(gui, obj) """ - _show_page!(gui::AppView, c::_DockedCard, obj) + _show_page!(gui::LiveView, c::_DockedCard, obj) Shows the page `c.page` of the docked card `c` for its object `obj` (`nothing`: no selection): the page bar if `obj` has several pages (see `_card_pages`), and of the parts of the card only those of @@ -211,7 +211,7 @@ the page, see `_DockedCard`. A collapsed card shows none of them. Without a sele the selection shows the keyboard step and the summary of the live view. Only changes update the layout. """ -function _show_page!(gui::AppView, c::_DockedCard, @nospecialize(obj)) +function _show_page!(gui::LiveView, c::_DockedCard, @nospecialize(obj)) pages = _docked_pages(gui, obj) (isempty(pages) || c.page in pages) || (c.page = first(pages)) open = !isnothing(obj) && !c.collapsed @@ -225,7 +225,7 @@ function _show_page!(gui::AppView, c::_DockedCard, @nospecialize(obj)) end # The page bar of the `pages`, `shown` if there are several -function _show_bar!(gui::AppView, c::_DockedCard, pages::Tuple, shown::Bool) +function _show_bar!(gui::LiveView, c::_DockedCard, pages::Tuple, shown::Bool) shown = shown && length(pages) > 1 if shown && (pages != c.pages || isnothing(c.bar)) # blocks can only be added to a part that is attached to the figure @@ -240,19 +240,19 @@ function _show_bar!(gui::AppView, c::_DockedCard, pages::Tuple, shown::Bool) return nothing end -function _docked_bar!(gui::AppView, c::_DockedCard, pages::Tuple) +function _docked_bar!(gui::LiveView, c::_DockedCard, pages::Tuple) bar = _page_bar!(c.bar_part.grid[1, 1], c.theme, pages; selected = c.page) on(page -> _set_page!(gui, c, page), bar.selected) return bar end """ - _set_page!(gui::AppView, c::_DockedCard, page::Symbol) + _set_page!(gui::LiveView, c::_DockedCard, page::Symbol) Shows the `page` of the docked card `c`, e.g. after a click on its page bar. The page stays while the card shows the same object. """ -function _set_page!(gui::AppView, c::_DockedCard, page::Symbol) +function _set_page!(gui::LiveView, c::_DockedCard, page::Symbol) c.page === page && return nothing # A focused box of the page that is left would keep the keyboard foreach(tb -> tb.focused[] && Makie.defocus!(tb), c.textboxes) @@ -277,7 +277,7 @@ function _show_step!(c::_DockedCard, part::_LayoutPart, shown::Bool) end # The properties of `obj` (the summary of the live view for `nothing`) while their page is shown -function _show_list!(gui::AppView, c::_DockedCard, @nospecialize(obj), shown::Bool) +function _show_list!(gui::LiveView, c::_DockedCard, @nospecialize(obj), shown::Bool) # an empty list has no height: emptied before its part is detached from the layout (shown || isempty(c.list.rows)) || _set_rows!(c.list, Tuple{String, String}[]) _set_shown!(c.properties_part, shown) @@ -290,20 +290,20 @@ Detector view on the page "Results" of a docked card =# # Inner width of the right sidebar [px], the width of the docked cards -function _docked_width(gui::AppView) - w = Float32(Makie.widths(gui.layout.inspector.grid.layoutobservables.computedbbox[])[1]) +function _docked_width(gui::LiveView) + w = Float32(Makie.widths(_app(gui).inspector.grid.layoutobservables.computedbbox[])[1]) return w > 1 ? w : 280.0f0 end """ - _show_view!(gui::AppView, c::_DockedCard, obj, shown::Bool) + _show_view!(gui::LiveView, c::_DockedCard, obj, shown::Bool) Shows the detector view of `obj` on the docked card `c`, or hides it: the view is built when it is first shown (see `_DetectorView`), in the state `c.view_expanded` and as wide as the sidebar; the card of the selection keeps its view for the next detector. The result is shown by `_announce_views!`. """ -function _show_view!(gui::AppView, c::_DockedCard, @nospecialize(obj), shown::Bool) +function _show_view!(gui::LiveView, c::_DockedCard, @nospecialize(obj), shown::Bool) _set_shown!(c.view_part, shown) shown || return nothing w = _docked_width(gui) @@ -318,11 +318,11 @@ function _show_view!(gui::AppView, c::_DockedCard, @nospecialize(obj), shown::Bo return nothing end -function _build_view!(gui::AppView, c::_DockedCard, w::Real) +function _build_view!(gui::LiveView, c::_DockedCard, w::Real) view = _DetectorView(c.view_part.grid, c.theme; expanded = c.view_expanded, width = w, height = w) c.view = view # the events of the sidebar: the view is scrolled with it, see `_ScrollArea` - c.view_listeners = _connect_view!(view, gui.layout.right.area.events; + c.view_listeners = _connect_view!(view, _app(gui).right.area.events; on_options = (; changes...) -> _set_view!(gui, c.view_obj; changes...), on_expanded = expanded -> _set_view_expanded!(gui, c, expanded)) append!(gui.controls.listeners, c.view_listeners) @@ -330,13 +330,13 @@ function _build_view!(gui::AppView, c::_DockedCard, w::Real) end """ - _resize_docked_views!(gui::AppView) + _resize_docked_views!(gui::LiveView) The detector views of the docked cards of the `gui` take the width of the inspector, e.g. while the right sidebar is resized: those that are shown, the others when their page is shown, see `_show_view!`. Their kind, their options and the limits that the mouse set are kept. """ -function _resize_docked_views!(gui::AppView) +function _resize_docked_views!(gui::LiveView) w = _docked_width(gui) for c in _docked_cards(gui) (c.view_part.shown && !isnothing(c.view)) && _resize_view!(c.view, w, w) @@ -345,16 +345,16 @@ function _resize_docked_views!(gui::AppView) end """ - _on_inspector_resized!(gui::AppView) + _on_inspector_resized!(gui::LiveView) Fits the inspector of the `gui` to the width of the right sidebar after it was resized: the detector views (see `_resize_docked_views!`) and the texts of the header and of the heads of the pinned cards, which are shortened to their room. Typed inputs are kept. """ -function _on_inspector_resized!(gui::AppView) - gui.layout.right.shown || return nothing +function _on_inspector_resized!(gui::LiveView) + _app(gui).right.shown || return nothing _resize_docked_views!(gui) - _show_header!(gui, gui.layout.inspector.shown) + _show_header!(gui, _app(gui).inspector.shown) _refresh_inspector!(gui) return nothing end @@ -364,7 +364,7 @@ Expands the view of the docked card `c` or collapses it to its thumbnail, by its click on the thumbnail. The card remembers the state. An expanded view is computed on its full grid, see `_view_needed!`. """ -function _set_view_expanded!(gui::AppView, c::_DockedCard, expanded::Bool) +function _set_view_expanded!(gui::LiveView, c::_DockedCard, expanded::Bool) c.view_expanded = expanded _set_expanded!(c.view, expanded) _refresh_inspector!(gui) @@ -373,7 +373,7 @@ function _set_view_expanded!(gui::AppView, c::_DockedCard, expanded::Bool) end """Removes the detector view of the docked card `c` with its listeners, see `_delete_view!`.""" -function _remove_view!(gui::AppView, c::_DockedCard) +function _remove_view!(gui::LiveView, c::_DockedCard) isnothing(c.view) && return nothing filter!(l -> !_has(c.view_listeners, l), gui.controls.listeners) _delete_view!(c.view) @@ -384,29 +384,29 @@ end # Whether the docked card `c` shows its detector view: on its page "Results", not collapsed, in a # sidebar that is shown -_view_shown(gui::AppView, c::_DockedCard) = - gui.layout.right.shown && c.view_part.shown && !isnothing(c.view) +_view_shown(gui::LiveView, c::_DockedCard) = + _app(gui).right.shown && c.view_part.shown && !isnothing(c.view) # The docked cards of the `gui`: the card of the selection and the pinned ones -_docked_cards(gui::AppView) = _DockedCard[gui.layout.inspector.card; gui.layout.inspector.pinned] +_docked_cards(gui::LiveView) = _DockedCard[_app(gui).inspector.card; _app(gui).inspector.pinned] # Also the menus of the docked cards -_card_menu_open(gui::AppView) = +_card_menu_open(gui::LiveView, ::AppLayout) = any(_has_open_menu, gui.cards.all) || any(_has_open_menu, _docked_cards(gui)) # The views of the inspector card and of the docked pinned cards that are shown, see `_shown_views` -_layout_views(gui::AppView) = +_layout_views(gui::LiveView, ::AppLayout) = Tuple{Any, Any}[(c.view_obj, c.view) for c in _docked_cards(gui) if _view_shown(gui, c)] """ - _announce_views!(gui::AppView) + _announce_views!(gui::LiveView) Shows the stored result in the views of the docked cards that became shown since the last refresh (built for another detector, page switched to "Results", card expanded, sidebar shown again, card pinned), see `_redraw_views!`, and computes it if it is stale, see `_view_needed!`. Views that stay shown are updated by the solves. """ -function _announce_views!(gui::AppView) +function _announce_views!(gui::LiveView) for c in _docked_cards(gui) pd = _view_shown(gui, c) ? c.view_obj : nothing pd === c.shown_view && continue @@ -517,7 +517,7 @@ Pinned cards of the app layout, docked below the inspector =# """ - _dock_pinned!(gui::AppView, obj) -> _DockedCard + _dock_pinned!(gui::LiveView, obj) -> _DockedCard Pins a card to `obj` in the app layout: a `_DockedCard` at the end of the pinned cards of the inspector, below a line, with its own head (icon, title, actions, float button, pin and collapse @@ -527,8 +527,8 @@ chevron, see the shared parts `_card_icon!`, `_card_title!`, `_card_float!`, `_c the pin unpins it, see `_unpin!`; the chevron collapses it to its head. Its widgets are built by `_refresh_inspector!`. """ -function _dock_pinned!(gui::AppView, @nospecialize(obj)) - insp, t = gui.layout.inspector, gui.layout.theme +function _dock_pinned!(gui::LiveView, @nospecialize(obj)) + insp, t = _app(gui).inspector, _app(gui).theme g = GridLayout(insp.pinned_grid[length(insp.pinned) + 1, 1]; default_rowgap = 4, tellwidth = false) line = Box(g[1, 1]; height = 1, color = t.border, strokewidth = 0) header = GridLayout(g[2, 1]; default_colgap = 6, tellwidth = false) @@ -577,8 +577,8 @@ _over_docked_view(::Nothing, ::Point2f) = false _over_docked_view(view::_DetectorView, p::Point2f) = _over_view(view, p) """Removes the pinned card `c` of the app layout of the `gui` with its widgets and listeners.""" -function _remove_pinned!(gui::AppView, c::_DockedCard) - insp = gui.layout.inspector +function _remove_pinned!(gui::LiveView, c::_DockedCard) + insp = _app(gui).inspector foreach(tb -> tb.focused[] && Makie.defocus!(tb), _card_boxes(c)) _clear_content!(c) foreach(off, c.head.listeners) @@ -612,7 +612,7 @@ end """ Collapses the pinned card `c` to its head and its actions, or expands it again. """ -function _toggle_collapsed!(gui::AppView, c::_DockedCard) +function _toggle_collapsed!(gui::LiveView, c::_DockedCard) _set_collapsed!(c, !c.collapsed) _refresh_inspector!(gui; force = true) return nothing @@ -627,12 +627,12 @@ function _set_collapsed!(c::_DockedCard, collapsed::Bool) end """ - _refresh_pinned!(gui::AppView, c::_DockedCard; force = false) + _refresh_pinned!(gui::LiveView, c::_DockedCard; force = false) Shows the object of the pinned card `c`: builds its widgets when it was pinned or collapsed (see `_build_content!`), then its page (see `_show_page!`), its title and the values of its widgets. """ -function _refresh_pinned!(gui::AppView, c::_DockedCard; force::Bool = false) +function _refresh_pinned!(gui::LiveView, c::_DockedCard; force::Bool = false) if c.pose === nothing # blocks can only be added to a part that is attached to the figure _set_shown!(c.rows_part, true) @@ -643,7 +643,7 @@ function _refresh_pinned!(gui::AppView, c::_DockedCard; force::Bool = false) title = c.head.title renamable = _renamable(c.obj) _show_pencil!(c.name, renamable) - w = Makie.widths(gui.layout.inspector.grid.layoutobservables.computedbbox[])[1] - + w = Makie.widths(_app(gui).inspector.grid.layoutobservables.computedbbox[])[1] - _CARD_ICON - 3 * _CARD_TOOL - 22 - _actions_width(c) - (renamable ? _CARD_PENCIL + 2 : 0) _set_text!(title, _fit_text(c.head.widths, _tree_font(title.blockscene, title.font[]), _CARD_TITLE_FONTSIZE, _label(gui, c.obj), w)) @@ -653,8 +653,8 @@ end # The card pinned to the object of the inspector opens on the page that the inspector shows, with # its view in the same state -function _pin!(gui::AppView, @nospecialize(obj)) - insp = gui.layout.inspector +function _pin!(gui::LiveView, layout::AppLayout, @nospecialize(obj)) + insp = layout.inspector c = _dock_pinned!(gui, obj) if insp.shown === obj c.page, c.view_expanded = insp.card.page, insp.card.view_expanded @@ -664,7 +664,7 @@ function _pin!(gui::AppView, @nospecialize(obj)) end # The card of a detector of the `detectors` kwarg starts docked, on its page "Results" -function _pin_view!(gui::AppView, pd; expanded::Bool = true) +function _pin_view!(gui::LiveView, ::AppLayout, pd; expanded::Bool = true) c = _dock_pinned!(gui, pd) c.page, c.view_expanded = :results, expanded _refresh_inspector!(gui; force = true) @@ -672,8 +672,8 @@ function _pin_view!(gui::AppView, pd; expanded::Bool = true) return nothing end -_is_pinned(gui::AppView, @nospecialize(obj)) = _is_docked(gui, obj) || _is_floating(gui, obj) -function _unpin!(gui::AppView, @nospecialize(obj)) +_is_pinned(gui::LiveView, ::AppLayout, @nospecialize(obj)) = _is_docked(gui, obj) || _is_floating(gui, obj) +function _unpin!(gui::LiveView, ::AppLayout, @nospecialize(obj)) foreach(c -> _remove_pinned!(gui, c), _docked_cards(gui, obj)) foreach(c -> _toggle_pinned!(gui, c), _floating_cards(gui, obj)) _forget!(gui, obj) @@ -683,18 +683,19 @@ end # The docked cards are built again for `new`, in their places, on their pages, collapsed if they # were, see `_take_pins!` -function _take_pins!(gui::AppView, @nospecialize(old)) - pinned = gui.layout.inspector.pinned +function _take_pins!(gui::LiveView, layout::AppLayout, @nospecialize(old)) + pinned = layout.inspector.pinned docked = [(; index = _index(pinned, c), c.page, c.collapsed, c.view_expanded) for c in _docked_cards(gui, old)] foreach(c -> _remove_pinned!(gui, c), _docked_cards(gui, old)) - return (; invoke(_take_pins!, Tuple{LiveView, Any}, gui, old).floating, docked) + floating = invoke(_take_pins!, Tuple{LiveView, AbstractLiveLayout, Any}, gui, layout, old).floating + return (; floating, docked) end -function _give_pins!(gui::AppView, pins, @nospecialize(new)) - invoke(_give_pins!, Tuple{LiveView, Any, Any}, gui, pins, new) +function _give_pins!(gui::LiveView, layout::AppLayout, pins, @nospecialize(new)) + invoke(_give_pins!, Tuple{LiveView, AbstractLiveLayout, Any, Any}, gui, layout, pins, new) isempty(pins.docked) && return nothing - insp = gui.layout.inspector + insp = layout.inspector for d in pins.docked c = _dock_pinned!(gui, new) d.page in _card_pages(gui, new) && (c.page = d.page) @@ -712,11 +713,11 @@ function _give_pins!(gui::AppView, pins, @nospecialize(new)) end """Returns the pinned cards of the app layout of the `gui` that are docked for `obj`.""" -_docked_cards(gui::AppView, @nospecialize(obj)) = filter(c -> c.obj === obj, gui.layout.inspector.pinned) -_is_docked(gui::AppView, @nospecialize(obj)) = any(c -> c.obj === obj, gui.layout.inspector.pinned) +_docked_cards(gui::LiveView, @nospecialize(obj)) = filter(c -> c.obj === obj, _app(gui).inspector.pinned) +_is_docked(gui::LiveView, @nospecialize(obj)) = any(c -> c.obj === obj, _app(gui).inspector.pinned) """ - _float!(gui::AppView, obj) + _float!(gui::LiveView, ::AppLayout, obj) Moves the card pinned to `obj` from the sidebar of the app layout into the 3D view: the docked card is removed, a floating card (see `_ComponentCard`) is pinned to `obj` like in the compact layout, @@ -724,7 +725,7 @@ collapsed if the docked card was, on the same page and with its detector view ex with the button that docks it again, see `_dock!`. The other docked cards keep their state; they are not expanded into the room that becomes free. """ -function _float!(gui::AppView, @nospecialize(obj)) +function _float!(gui::LiveView, ::AppLayout, @nospecialize(obj)) docked = _docked_cards(gui, obj) isempty(docked) && return nothing d = first(docked) @@ -738,13 +739,13 @@ function _float!(gui::AppView, @nospecialize(obj)) end """ - _dock!(gui::AppView, obj) + _dock!(gui::LiveView, ::AppLayout, obj) Moves the floating card pinned to `obj` back into the sidebar of the app layout, at the end of the pinned cards, collapsed if the floating card was (by its chevron), on the same page and with its detector view expanded if it was. """ -function _dock!(gui::AppView, @nospecialize(obj)) +function _dock!(gui::LiveView, ::AppLayout, @nospecialize(obj)) floating = _floating_cards(gui, obj) isempty(floating) && return nothing d = _dock_pinned!(gui, obj) @@ -764,7 +765,7 @@ function _card_tools!(layout::AppLayout, c::_ComponentCard) end """ - _refresh_inspector!(gui::AppView; force = false) + _refresh_inspector!(gui::LiveView, layout::AppLayout; force = false) Shows the selected object of the `gui` in the inspector (or the summary of the live view): header, docked card and its page. The widgets of the card are rebuilt only if the object declares others, @@ -775,8 +776,7 @@ the cards are higher than the window, see `_sidebar_part`. A collapsed inspector is not updated: its views count as not shown (see `_layout_views`), it is refreshed when it is shown again. """ -function _refresh_inspector!(gui::AppView; force::Bool = false) - layout = gui.layout +function _refresh_inspector!(gui::LiveView, layout::AppLayout; force::Bool = false) insp = layout.inspector if !layout.right.shown foreach(c -> c.shown_view = nothing, _docked_cards(gui)) @@ -800,19 +800,19 @@ function _refresh_inspector!(gui::AppView; force::Bool = false) end """ - _dock_card!(gui::AppView, c::_DockedCard, obj) + _dock_card!(gui::LiveView, c::_DockedCard, obj) Builds the widgets of the docked card `c` for its new object `obj`, see `_build_content!`, or removes them without a selection; the card opens on the page `_default_page(obj)`, which `_show_page!` shows. """ -function _dock_card!(gui::AppView, c::_DockedCard, ::Nothing) +function _dock_card!(gui::LiveView, c::_DockedCard, ::Nothing) _end_rename!(gui, c; refresh = false) _clear_content!(c) c.pose = nothing return nothing end -function _dock_card!(gui::AppView, c::_DockedCard, @nospecialize(obj)) +function _dock_card!(gui::LiveView, c::_DockedCard, @nospecialize(obj)) # A focused box of the old object would take the keyboard, and its input the new object _end_rename!(gui, c; refresh = false) foreach(tb -> tb.focused[] && Makie.defocus!(tb), c.textboxes) @@ -826,8 +826,8 @@ function _dock_card!(gui::AppView, c::_DockedCard, @nospecialize(obj)) end """Sets the pin of the inspector of the `gui` to whether a card is pinned to the selected object.""" -function _show_pin!(gui::AppView) - pin = gui.layout.inspector.pin +function _show_pin!(gui::LiveView) + pin = _app(gui).inspector.pin obj = _shown_object(gui) pinned = !isnothing(obj) && _is_pinned(gui, obj) pin.active[] == pinned || (pin.active[] = pinned) @@ -835,14 +835,14 @@ function _show_pin!(gui::AppView) visible = !isnothing(obj) && _pinnable(obj) pin.box.visible[] == visible || (pin.box.visible[] = visible) # "‹" for a part of another object, see `_part_parent` - insp = gui.layout.inspector + insp = _app(gui).inspector part = _shows_back(gui, obj) insp.back.box.visible[] == part || _show_back!(insp.card.header, insp.back, part) return nothing end # Whether the inspector shows the button "‹" for `obj`, i.e. for a part of another object -_shows_back(gui::AppView, @nospecialize(obj)) = !isnothing(obj) && !isnothing(_part_parent(gui, obj)) +_shows_back(gui::LiveView, @nospecialize(obj)) = !isnothing(obj) && !isnothing(_part_parent(gui, obj)) """ Shows or hides the button "‹" `back` in column 4 of the `header` of the inspector; hidden, the @@ -855,11 +855,11 @@ function _show_back!(header::GridLayout, back::_IconButton, shown::Bool) return nothing end -_on_pinned!(gui::AppView) = _show_pin!(gui) +_on_pinned!(gui::LiveView, ::AppLayout) = _show_pin!(gui) """Sets the icon, name and type of the header of the inspector for `obj` (`nothing`: no selection).""" -function _show_header!(gui::AppView, @nospecialize(obj)) - insp, t = gui.layout.inspector, gui.layout.theme +function _show_header!(gui::LiveView, @nospecialize(obj)) + insp, t = _app(gui).inspector, _app(gui).theme _show_kind!(insp.icon, insp.icon_color, t, obj) name = isnothing(obj) ? "No selection" : _label(gui, obj) # the line below the name: the subtitle of the object, e.g. of a system, else its type @@ -889,8 +889,8 @@ box and the mode control, see `_connect_selection_part!`), the pin, and a refres sidebar is collapsed or shown again. The widgets of the docked card are connected when they are built, see `_build_content!`, its page bar and its detector view likewise, see `_show_page!`. """ -function _connect_inspector!(gui::AppView) - layout = gui.layout +function _connect_inspector!(gui::LiveView) + layout = _app(gui) insp = layout.inspector ctrl = gui.controls listeners = ctrl.listeners @@ -929,19 +929,20 @@ end # The step box and the textboxes of the docked card take the keyboard like those of the floating # cards, see `_typing` -_layout_boxes(gui::AppView) = (gui.layout.inspector.step_box, _card_boxes(gui.layout.inspector.card)..., - (tb for c in gui.layout.inspector.pinned for tb in _card_boxes(c))...) +_layout_boxes(gui::LiveView, layout::AppLayout) = + (layout.inspector.step_box, _card_boxes(layout.inspector.card)..., + (tb for c in layout.inspector.pinned for tb in _card_boxes(c))...) # The name and the line below it follow the editing of the name on a docked card -_on_rename!(gui::AppView, ::_DockedCard) = _refresh_inspector!(gui) +_on_rename!(gui::LiveView, ::_DockedCard) = _refresh_inspector!(gui) # The card of the selection is docked in the inspector, only pinned cards float in the 3D view -_selection_card_shown(::AppView) = false +_selection_card_shown(::LiveView, ::AppLayout) = false # The toolbar, the sidebars, the dock and the status bar surround the 3D view: a click on their # widgets, e.g. the pin of the inspector, neither selects nor deselects (the release of the press # would clear the selection, and with it the inspector), like one on the help over the 3D view -_outside_view(gui::AppView) = !Makie.is_mouseinside(gui.ax.scene) || _over_layout(gui) +_outside_view(gui::LiveView, ::AppLayout) = !Makie.is_mouseinside(gui.ax.scene) || _over_layout(gui) #= Properties of the objects of the live view diff --git a/src/LiveLayout.jl b/src/LiveLayout.jl index 41623f3..977e322 100644 --- a/src/LiveLayout.jl +++ b/src/LiveLayout.jl @@ -24,21 +24,31 @@ _default_size(::AbstractLiveLayout) = (1400, 800) _figure(::AbstractLiveLayout, size) = Figure(; size) # Optional parts of the layout interface, see `AbstractLiveLayout` -_connect_layout!(::LiveView) = nothing -_close_layout!(::LiveView) = nothing -_on_selected!(::LiveView) = nothing -_on_clipping!(::LiveView) = nothing -_on_clip_planes_changed!(::LiveView) = nothing -_on_hidden!(::LiveView) = nothing -_on_components_changed!(::LiveView) = nothing +_connect_layout!(gui::LiveView) = _connect_layout!(gui, gui.layout) +_connect_layout!(::LiveView, ::AbstractLiveLayout) = nothing +_close_layout!(gui::LiveView) = _close_layout!(gui, gui.layout) +_close_layout!(::LiveView, ::AbstractLiveLayout) = nothing +_on_selected!(gui::LiveView) = _on_selected!(gui, gui.layout) +_on_selected!(::LiveView, ::AbstractLiveLayout) = nothing +_on_clipping!(gui::LiveView) = _on_clipping!(gui, gui.layout) +_on_clipping!(::LiveView, ::AbstractLiveLayout) = nothing +_on_clip_planes_changed!(gui::LiveView) = _on_clip_planes_changed!(gui, gui.layout) +_on_clip_planes_changed!(::LiveView, ::AbstractLiveLayout) = nothing +_on_hidden!(gui::LiveView) = _on_hidden!(gui, gui.layout) +_on_hidden!(::LiveView, ::AbstractLiveLayout) = nothing +_on_components_changed!(gui::LiveView) = _on_components_changed!(gui, gui.layout) +_on_components_changed!(::LiveView, ::AbstractLiveLayout) = nothing _slot_error(gui::LiveView, what) = _slot_error(gui.layout, what) function _slot_error(layout::AbstractLiveLayout, what) throw(ArgumentError("the $(nameof(typeof(layout))) of this live view has no $what")) end -_add_toolbar_entry!(gui::LiveView, _) = _slot_error(gui, "toolbar") -_add_sidebar_section!(gui::LiveView, _, _) = _slot_error(gui, "sidebars") -_add_dock_panel!(gui::LiveView, _) = _slot_error(gui, "dock") +_add_toolbar_entry!(gui::LiveView, group) = _add_toolbar_entry!(gui, gui.layout, group) +_add_toolbar_entry!(gui::LiveView, ::AbstractLiveLayout, _) = _slot_error(gui, "toolbar") +_add_sidebar_section!(gui::LiveView, side, title; kw...) = _add_sidebar_section!(gui, gui.layout, side, title; kw...) +_add_sidebar_section!(gui::LiveView, ::AbstractLiveLayout, _, _) = _slot_error(gui, "sidebars") +_add_dock_panel!(gui::LiveView, title; kw...) = _add_dock_panel!(gui, gui.layout, title; kw...) +_add_dock_panel!(gui::LiveView, ::AbstractLiveLayout, _) = _slot_error(gui, "dock") """ _step_box(layout, w, card) -> Textbox @@ -147,7 +157,8 @@ for the spectator mode, see `_on_spectator!`: the tools, the status, the sidebar Each part comes back as it was, e.g. a sidebar that was collapsed stays collapsed. Nothing by default, see `AbstractLiveLayout`. """ -_set_spectator_ui!(::LiveView, ::Bool) = nothing +_set_spectator_ui!(gui::LiveView, on::Bool) = _set_spectator_ui!(gui, gui.layout, on) +_set_spectator_ui!(::LiveView, ::AbstractLiveLayout, ::Bool) = nothing """ _on_spectator!(gui, on::Bool) @@ -209,7 +220,8 @@ the new blocks; nothing is drawn in between. Used by [`add_panel!`](@ref), [`add and [`add_tool!`](@ref), e.g. for a view that starts with `spectator = true`. A layout extends it for parts that its users collapse, e.g. the left sidebar of the app layout. """ -function _with_ui(f, gui::LiveView) +_with_ui(f, gui::LiveView) = _with_ui(f, gui, gui.layout) +function _with_ui(f, gui::LiveView, ::AbstractLiveLayout) hidden = gui.controls.spectator[] hidden && _set_spectator_ui!(gui, false) try diff --git a/src/LiveOverlay.jl b/src/LiveOverlay.jl index 0105b91..fb2ec79 100644 --- a/src/LiveOverlay.jl +++ b/src/LiveOverlay.jl @@ -603,9 +603,10 @@ Places the toast of the compact layout of the `gui` above the height `top` [px a the 3D view], e.g. the timeline of the activity of the others (`0`: at its place). Nothing in the app layout, whose status line is not over the view. """ -_lift_toast!(::LiveView, ::Real) = nothing -function _lift_toast!(gui::CompactView, top::Real) - o = gui.layout.overlay +_lift_toast!(gui::LiveView, top::Real) = _lift_toast!(gui, gui.layout, top) +_lift_toast!(::LiveView, ::AbstractLiveLayout, ::Real) = nothing +function _lift_toast!(::LiveView, layout::CompactLayout, top::Real) + o = layout.overlay lift = Float32(max(top, 0)) get(_TOAST_LIFT, o, 0.0f0) == lift && return nothing _TOAST_LIFT[o] = lift @@ -656,25 +657,24 @@ Hooks of the compact layout, see `AbstractLiveLayout` =# # A closed view leaves no timer behind, e.g. the one that hides the toast -_close_layout!(gui::CompactView) = - (foreach(_stop!, (gui.layout.overlay.toast_deadline, gui.layout.overlay.camera_deadline)); nothing) +_close_layout!(::LiveView, layout::CompactLayout) = + (foreach(_stop!, (layout.overlay.toast_deadline, layout.overlay.camera_deadline)); nothing) -_layout_obstacles(gui::CompactView) = - [_overlay_rects(gui.layout.overlay); _help_rects(gui.layout.help)] -function _over_layout(gui::CompactView) +_layout_obstacles(::LiveView, layout::CompactLayout) = + [_overlay_rects(layout.overlay); _help_rects(layout.help)] +function _over_layout(gui::LiveView, layout::CompactLayout) p = Point2f(events(gui.ax.scene).mouseposition[]) - return _over_overlay(gui.layout.overlay, p) || _over_help(gui.layout.help, p) + return _over_overlay(layout.overlay, p) || _over_help(layout.help, p) end # While a menu is open, a click into the 3D view only closes it -_outside_view(gui::CompactView) = _menu_open(gui) || _over_layout(gui) +_outside_view(gui::LiveView, ::CompactLayout) = _menu_open(gui) || _over_layout(gui) """ The spectator mode of the compact layout: the overlay keeps only its help pill (see `_CompactOverlay`), the panels right of the 3D view are collapsed, such that the 3D view fills the window, see `_panel_part!`. """ -function _set_spectator_ui!(gui::CompactView, on::Bool) - layout = gui.layout +function _set_spectator_ui!(gui::LiveView, layout::CompactLayout, on::Bool) layout.overlay.hidden = on layout.overlay.pill_hidden = on && !gui.controls.spectator_help isnothing(layout.panel_part) || _set_shown!(layout.panel_part, !on) @@ -691,8 +691,8 @@ is open or the press is on the help card, which takes it) and the key `Esc` clos popovers; the camera popover follows the mouse, the parts follow the size of the window and their content. """ -function _connect_overlay!(gui::CompactView) - o = gui.layout.overlay +function _connect_overlay!(gui::LiveView) + o = _compact(gui).overlay ctrl = gui.controls ev = events(gui.ax.scene) listeners = ctrl.listeners diff --git a/src/LiveSelection.jl b/src/LiveSelection.jl index afe7f3f..a1bd47b 100644 --- a/src/LiveSelection.jl +++ b/src/LiveSelection.jl @@ -308,7 +308,8 @@ end Shows the inspected object of the `gui` besides the cards, e.g. its row in the object tree of the app layout; nothing by default. """ -_show_inspected!(::LiveView, _) = nothing +_show_inspected!(gui::LiveView, @nospecialize(x)) = _show_inspected!(gui, gui.layout, x) +_show_inspected!(::LiveView, ::AbstractLiveLayout, _) = nothing _show_menu_selection!(::Nothing, _) = nothing function _show_menu_selection!(menu::Menu, i) @@ -462,7 +463,8 @@ end _all_hidden(gui::LiveView, @nospecialize(obj)) = all(leaf -> leaf in gui.objects.hidden, _leaves(obj)) """Returns how a hidden object of the `gui` is shown again, for the status line.""" -_show_hint(::LiveView) = "select it in the menu to show it again" +_show_hint(gui::LiveView) = _show_hint(gui, gui.layout) +_show_hint(::LiveView, ::AbstractLiveLayout) = "select it in the menu to show it again" """Shows all hidden objects of the `gui`.""" function _show_all!(gui::LiveView) diff --git a/src/LiveView.jl b/src/LiveView.jl index 6004aed..b35fcf5 100644 --- a/src/LiveView.jl +++ b/src/LiveView.jl @@ -49,7 +49,15 @@ Layout of a [`LiveView`](@ref), i.e. where its widgets are placed in the figure, camera, inspection) is shared by all layouts: it works on the observables of the widgets, e.g. `clicks` of a button, `active` of a toggle and `stored_string` of a textbox, never on their type or position. A layout `L` holds its own state (e.g. the slots of its sidebars) and is stored in -`gui.layout` of the `LiveView{L}`. +`gui.layout` of the `LiveView`, which has no type parameter: the code of the window is compiled once +for all layouts. + +The hooks below are called by the shared code with the view, e.g. `_pin!(gui, obj)`. Each hook has a +barrier that passes the layout on, `_pin!(gui, obj) = _pin!(gui, gui.layout, obj)`, and a fallback +for `::AbstractLiveLayout`; a layout implements the hook as a method with the layout as its second +argument, `_pin!(gui::LiveView, layout::L, obj)` (after `f` for the hooks that take a function first, +`_with_ui(f, gui, layout)` and `_add_user_panel!(f, gui, layout, title, select)`). Code of one layout +that is no hook takes `gui::LiveView` and reads its layout typed, e.g. `_app(gui)`. # Interface @@ -84,7 +92,7 @@ and optionally, with defaults for any layout, returns them as the layout uses them, in `spec.part_sizes` of `_build_layout`; a layout without such parts ignores them (the default). `_part_size_kwargs(gui)` returns these kwargs for the sizes that the parts have now, e.g. for a second window (none by default) -- `_connect_layout!(gui::LiveView{L})`: connects the widgets that only the layout has, e.g. +- `_connect_layout!(gui)`: connects the widgets that only the layout has, e.g. collapsing; its listeners belong in `gui.controls.listeners`; `_close_layout!(gui)` stops what runs besides them when the view is closed, e.g. timers - where the controls of the selected object are shown, i.e. the widgets that @@ -171,7 +179,8 @@ The `sidebar_width` and `dock_height` kwargs of [`live_view`](@ref) with the siz of the layout of the `gui` have now, e.g. after they were dragged, for a window that takes them over; none for a layout that ignores these kwargs, see `_part_sizes`. """ -_part_size_kwargs(_) = (;) +_part_size_kwargs(gui) = _part_size_kwargs(gui, gui.layout) +_part_size_kwargs(_, ::AbstractLiveLayout) = (;) """ _UserPanel @@ -739,10 +748,11 @@ they are rendered, selectable and movable, but not traced, see `_live_render_ext before), which `Ctrl+S` saves to, see [`save_project`](@ref) and [`open_project`](@ref); `sync` what the view knows of its files, which an agent may change meanwhile, see `_ProjectSync`. -The type parameter `L` is the type of the `layout`, see `AbstractLiveLayout`: `CompactView` and -`AppView` are the `LiveView`s of `live_view(...; layout = :compact)` and `layout = :app`. +`layout` is the `CompactLayout` of `live_view(...; layout = :compact)` or the `AppLayout` of +`layout = :app`, see `AbstractLiveLayout`. It is no type parameter, such that the code of the +window is compiled once for all layouts; what differs per layout dispatches on `gui.layout`. """ -Base.@kwdef mutable struct LiveView{L <: AbstractLiveLayout} +Base.@kwdef mutable struct LiveView fig::Figure ax::LScene pairs::Vector{Pair{BMO.AbstractSystem, Any}} @@ -781,12 +791,9 @@ Base.@kwdef mutable struct LiveView{L <: AbstractLiveLayout} activity::Any = nothing widgets::_LayoutWidgets # state of the layout, e.g. the slots of the app layout, see `AbstractLiveLayout` - layout::L + layout::AbstractLiveLayout end -# Infers the layout type like the constructor of a non-parametric type -LiveView(fields...) = LiveView{typeof(last(fields))}(fields...) - """ The systems of the `gui` in the order in which they are rendered: those of its pairs and those without a source, see `live_view`. diff --git a/test/TestLiveActivityHooks.jl b/test/TestLiveActivityHooks.jl index 53d6c40..937b2a7 100644 --- a/test/TestLiveActivityHooks.jl +++ b/test/TestLiveActivityHooks.jl @@ -120,7 +120,7 @@ end Makie.colorbuffer(screen) @test isnothing(a().shown_cursor) # the toast of the compact layout stands above the shown timeline - if gui isa GUI.CompactView && a().strip.shown + if gui.layout isa GUI.CompactLayout && a().strip.shown lift = get(GUI._TOAST_LIFT, gui.layout.overlay, 0.0f0) @test lift > 0 @test GUI._TOAST_LIFT[gui.layout.overlay] + minimum(gui.ax.scene.viewport[])[2] >= diff --git a/test/TestLiveApp.jl b/test/TestLiveApp.jl index d7a8f36..64b1540 100644 --- a/test/TestLiveApp.jl +++ b/test/TestLiveApp.jl @@ -36,7 +36,7 @@ const GUI = BeamletOpticsGUI m, pd = _fixture() gui = _live_app(System([m, pd]), Beam([0.0, 0, 0], [0.0, 1, 0]); sliders = ["a" => (0:0.1:1, v -> nothing)]) - @test gui isa GUI.AppView + @test gui.layout isa GUI.AppLayout @test gui isa GUI.LiveView @test gui.layout isa GUI.AppLayout @test Tuple(gui.fig.scene.viewport[].widths) == (1600, 950) @@ -67,7 +67,7 @@ const GUI = BeamletOpticsGUI # the compact layout is the default gui = live_view(System([m, pd]), Beam([0.0, 0, 0], [0.0, 1, 0]); trace_budget = Inf) - @test gui isa GUI.CompactView + @test gui.layout isa GUI.CompactLayout @test gui.widgets.menu isa Makie.Menu close(gui) diff --git a/test/TestLiveBeamColor.jl b/test/TestLiveBeamColor.jl index 5b2ef11..84ecb17 100644 --- a/test/TestLiveBeamColor.jl +++ b/test/TestLiveBeamColor.jl @@ -23,8 +23,7 @@ const GUI = BeamletOpticsGUI _beam(λ = 632.8e-9) = Beam([0.0, 0, 0], [0.0, 1, 0], λ) # The card of the selection: docked in the inspector of the app layout, else floating - _card(gui::GUI.AppView) = gui.layout.inspector.card - _card(gui) = gui.cards.selection + _card(gui) = gui.layout isa GUI.AppLayout ? (gui.layout.inspector.card) : (gui.cards.selection) _hex(c) = GUI._color_hex(Makie.to_color(c)) _wavelength_hex(λ) = _hex(Makie.RGBf(wavelength_color(λ)...)) _handles(gui, beam) = [h for (p, h) in zip(gui.pairs, gui.beam_handles) if p.second === beam] diff --git a/test/TestLiveBeamOverlays.jl b/test/TestLiveBeamOverlays.jl index d9d20bb..2212703 100644 --- a/test/TestLiveBeamOverlays.jl +++ b/test/TestLiveBeamOverlays.jl @@ -103,8 +103,7 @@ const GUI = BeamletOpticsGUI end @testset "card toggle ($layout)" for layout in (:compact, :app) - _card(gui::GUI.LiveView{GUI.AppLayout}) = gui.layout.inspector.card - _card(gui) = gui.cards.selection + _card(gui) = gui.layout isa GUI.AppLayout ? (gui.layout.inspector.card) : (gui.cards.selection) sys, pd = _system() g = _gauss() gui = _live_view(sys => g; layout) diff --git a/test/TestLiveCardRowWidth.jl b/test/TestLiveCardRowWidth.jl index aa6a199..3fcc7e0 100644 --- a/test/TestLiveCardRowWidth.jl +++ b/test/TestLiveCardRowWidth.jl @@ -47,13 +47,12 @@ BeamletOpticsGUI.card_rows(w::MyFilterWheel) = (pose_card_rows(w)..., @testset "Live card row width" begin _live_view(args...; kwargs...) = live_view(args...; merge((; trace_budget = Inf, detectors = []), kwargs)...) - _card(gui::GUI.LiveView{GUI.AppLayout}) = gui.layout.inspector.card - _card(gui) = gui.cards.selection + _card(gui) = gui.layout isa GUI.AppLayout ? (gui.layout.inspector.card) : (gui.cards.selection) function _select!(gui, obj) gui.controls.selected[] = obj GUI._update_selection_box!(gui.controls) GUI._update_cards!(gui) - gui isa GUI.LiveView{GUI.AppLayout} && GUI._update_inspector!(gui; force = true) + gui.layout isa GUI.AppLayout && GUI._update_inspector!(gui; force = true) return nothing end _w(gui, name) = GUI._card_widget(_card(gui), name) diff --git a/test/TestLiveCardRows.jl b/test/TestLiveCardRows.jl index 9cf7628..383fa0d 100644 --- a/test/TestLiveCardRows.jl +++ b/test/TestLiveCardRows.jl @@ -168,8 +168,7 @@ const GUI = BeamletOpticsGUI @testset "beam toggles ($layout)" for layout in (:compact, :app) # the card of the selection: floating (compact) or in the inspector (app) - _card(gui::GUI.LiveView{GUI.AppLayout}) = gui.layout.inspector.card - _card(gui) = gui.cards.selection + _card(gui) = gui.layout isa GUI.AppLayout ? (gui.layout.inspector.card) : (gui.cards.selection) _w(gui, name) = GUI._card_widget(_card(gui), name) _nhits(pd) = (h = BMO.hits(pd); isnothing(h) ? 0 : length(h)) m, pd = _fixture() @@ -248,8 +247,7 @@ const GUI = BeamletOpticsGUI end @testset "length of the final rays ($layout)" for layout in (:compact, :app) - _card(gui::GUI.LiveView{GUI.AppLayout}) = gui.layout.inspector.card - _card(gui) = gui.cards.selection + _card(gui) = gui.layout isa GUI.AppLayout ? (gui.layout.inspector.card) : (gui.cards.selection) _w(gui, name) = GUI._card_widget(_card(gui), name) # a mirror beside the beams, which all end in free space m = RoundPlanoMirror(25e-3, 5e-3) diff --git a/test/TestLiveComponents.jl b/test/TestLiveComponents.jl index b76899a..d1f8287 100644 --- a/test/TestLiveComponents.jl +++ b/test/TestLiveComponents.jl @@ -33,11 +33,9 @@ const GUI = BeamletOpticsGUI _rendered(gui, obj) = !isnothing(_handle(gui, obj)) _hit(gui, obj) = !isempty(GUI._hits(gui, obj)) _in_scene(gui, plots) = any(p -> _in(p, gui.ax.scene.plots), plots) - _listed(gui::GUI.AppView, obj) = _in(obj, [r.key for r in GUI._tree_rows(gui)]) - _listed(gui, obj) = _in(obj, gui.objects.menu) + _listed(gui, obj) = gui.layout isa GUI.AppLayout ? (_in(obj, [r.key for r in GUI._tree_rows(gui)])) : (_in(obj, gui.objects.menu)) # The card of the selection: docked in the inspector of the app layout, else floating - _card(gui::GUI.AppView) = gui.layout.inspector.card - _card(gui) = gui.cards.selection + _card(gui) = gui.layout isa GUI.AppLayout ? (gui.layout.inspector.card) : (gui.cards.selection) _message(f) = try f() "" diff --git a/test/TestLiveEdit.jl b/test/TestLiveEdit.jl index 8fa02db..5da918a 100644 --- a/test/TestLiveEdit.jl +++ b/test/TestLiveEdit.jl @@ -19,8 +19,7 @@ const GUI = BeamletOpticsGUI # A component or source of the catalog with the texts `strings` of its form _built(name, strings = _defaults(_entry(name))) = GUI._catalog_component(_entry(name), strings) - _card(gui::GUI.AppView) = gui.layout.inspector.card - _card(gui) = gui.cards.selection + _card(gui) = gui.layout isa GUI.AppLayout ? (gui.layout.inspector.card) : (gui.cards.selection) _names(card) = [w.name for (_, w) in card.widgets if !isnothing(w.name)] function _show!(gui, obj, page) gui.controls.selected[] = obj diff --git a/test/TestLiveGroupPivot.jl b/test/TestLiveGroupPivot.jl index 38d47aa..8eb6f10 100644 --- a/test/TestLiveGroupPivot.jl +++ b/test/TestLiveGroupPivot.jl @@ -37,7 +37,7 @@ const GUI = BeamletOpticsGUI _pose(obj) = (Vector{Float64}(position(obj)), Matrix{Float64}(BMO.orientation(obj))) _same_pose(obj, pose; atol = 1e-12) = _close(position(obj), pose[1]; atol) && norm(Matrix{Float64}(BMO.orientation(obj)) .- pose[2]) < atol - _card(gui) = gui isa GUI.AppView ? gui.layout.inspector.card : gui.cards.selection + _card(gui) = gui.layout isa GUI.AppLayout ? gui.layout.inspector.card : gui.cards.selection function _select!(gui, sel) select!(gui, sel) GUI._update_cards!(gui) diff --git a/test/TestLiveLinks.jl b/test/TestLiveLinks.jl index 1342f30..6dceba7 100644 --- a/test/TestLiveLinks.jl +++ b/test/TestLiveLinks.jl @@ -63,8 +63,7 @@ const GUI = BeamletOpticsGUI _key!(gui, Keyboard.up) return nothing end - _card(gui::GUI.AppView) = gui.layout.inspector.card - _card(gui) = gui.cards.selection + _card(gui) = gui.layout isa GUI.AppLayout ? (gui.layout.inspector.card) : (gui.cards.selection) _no_errors(guis...) = all(g -> isnothing(g.last_error), guis) _message(f) = try f() @@ -107,7 +106,7 @@ const GUI = BeamletOpticsGUI sys = System([_mirror(0.0, 0.1)]) gui = _live_view(sys; layout) new = open_system(gui, sys; display = false, layout = :app, theme = :dark, auto_trace = false) - @test new isa GUI.AppView && new.layout.theme === GUI._app_theme(:dark) + @test new.layout isa GUI.AppLayout && new.layout.theme === GUI._app_theme(:dark) @test isempty(new.pairs) && !new.trace.auto[] # the switch of the auto tracing is one for the linked windows, also the one of the kwarg @test !gui.trace.auto[] diff --git a/test/TestLivePick.jl b/test/TestLivePick.jl index 1e67b6f..346fe0c 100644 --- a/test/TestLivePick.jl +++ b/test/TestLivePick.jl @@ -67,8 +67,7 @@ const GUI = BeamletOpticsGUI end # The card of the selection: floating (compact) or in the inspector (app) - _card(gui::GUI.LiveView{GUI.AppLayout}) = gui.layout.inspector.card - _card(gui) = gui.cards.selection + _card(gui) = gui.layout isa GUI.AppLayout ? (gui.layout.inspector.card) : (gui.cards.selection) _w(gui, name) = GUI._card_widget(_card(gui), name) _text(gui, name) = _w(gui, name).text[] _push!(gui, name) = (_w(gui, name).clicks[] += 1; nothing) @@ -317,8 +316,7 @@ const GUI = BeamletOpticsGUI end # The line below the name of the card, whether it has a page bar and shows the step and the mode - _subtitle(gui::GUI.LiveView{GUI.AppLayout}) = gui.layout.inspector.type.text[] - _subtitle(gui) = (c = gui.cards.selection; c.subtitle_shown ? c.subtitle.text[] : nothing) + _subtitle(gui) = gui.layout isa GUI.AppLayout ? (gui.layout.inspector.type.text[]) : ((c = gui.cards.selection; c.subtitle_shown ? c.subtitle.text[] : nothing)) _has_bar(c::GUI._DockedCard) = c.bar_part.shown _has_bar(c::GUI._ComponentCard) = !isnothing(c.bar) _has_step(c::GUI._DockedCard) = c.step_part.shown diff --git a/test/TestLiveProjectClaims.jl b/test/TestLiveProjectClaims.jl index 5008868..44b8aab 100644 --- a/test/TestLiveProjectClaims.jl +++ b/test/TestLiveProjectClaims.jl @@ -292,7 +292,7 @@ mine(dir, me) = sort!([String(c.id) for c in values(BMOP.claims(dir)) if c.by == @test gui.status.text[] == "Bob is editing S1" # "+" and "Remove system" of the card of the system GUI._inspect!(gui, S1) - card = gui isa GUI.AppView ? gui.layout.inspector.card : gui.cards.selection + card = gui.layout isa GUI.AppLayout ? gui.layout.inspector.card : gui.cards.selection push(name) = (GUI._card_widget(card, name).clicks[] += 1; nothing) gui.status.text[] = "" push(:member_add) diff --git a/test/TestLiveScripting.jl b/test/TestLiveScripting.jl index f23ca09..beb4c1f 100644 --- a/test/TestLiveScripting.jl +++ b/test/TestLiveScripting.jl @@ -25,8 +25,10 @@ BMO.kinematic_trait_of(::FixedMirror) = BMO.Static() zrotate3d!(pd, -π / 2) translate3d!(pd, [0.1, 0.1, 0]) cs = CollimatedSource([0.0, 0, 0], [0.0, 1, 0], 2e-3, 1e-6; num_rings = 2, num_rays = 40) + # solved at once, also on a slow machine where a first solve compiles: a solve longer than + # `progress_delay` would continue in the background (a testset may ask for that) gui = live_view(System([m, pd]) => cs; trace_budget = Inf, throttle = false, - catalog = CatalogEntry[], constraints = constraints(m), kwargs...) + catalog = CatalogEntry[], constraints = constraints(m), merge((; progress_delay = Inf), kwargs)...) return gui, m, pd end diff --git a/test/TestLiveSelectionCard.jl b/test/TestLiveSelectionCard.jl index 807af55..7443fb3 100644 --- a/test/TestLiveSelectionCard.jl +++ b/test/TestLiveSelectionCard.jl @@ -44,7 +44,7 @@ const GUI = BeamletOpticsGUI picked[] = isnothing(leaf) ? nothing : _plot(gui, leaf) vp = gui.ax.scene.viewport[] # the edge of the view of the app layout is the splitter of its sidebar, see `_Splitter` - inset = gui isa GUI.AppView ? 6 : 3 + inset = gui.layout isa GUI.AppLayout ? 6 : 3 _move!(gui, (vp.origin[1] + vp.widths[1] - inset, vp.origin[2] + vp.widths[2] / 2)) @assert !GUI._over_browse_card(gui) _press!(gui) @@ -73,8 +73,7 @@ const GUI = BeamletOpticsGUI return minimum(r) .+ Makie.widths(r) ./ 2 end # The card of the selection shows the selected object: floating (compact) or in the inspector (app) - _component_card_shown(gui::GUI.LiveView{GUI.AppLayout}) = !isnothing(GUI._shown_object(gui)) - _component_card_shown(gui) = gui.cards.selection.scene.visible[] + _component_card_shown(gui) = gui.layout isa GUI.AppLayout ? (!isnothing(GUI._shown_object(gui))) : (gui.cards.selection.scene.visible[]) @testset "the selection card of a group ($layout)" for layout in (:compact, :app) gui = _live_view(layout) diff --git a/test/TestLiveSources.jl b/test/TestLiveSources.jl index c12f325..c35767e 100644 --- a/test/TestLiveSources.jl +++ b/test/TestLiveSources.jl @@ -38,10 +38,8 @@ const GUI = BeamletOpticsGUI end # The number of hits of the detector, which has no list of hits before its first one _nhits(pd) = (hits = BMO.hits(pd); isnothing(hits) ? 0 : length(hits)) - _listed(gui::GUI.AppView, obj) = _in(obj, [r.key for r in GUI._tree_rows(gui)]) - _listed(gui, obj) = _in(obj, gui.objects.menu) - _card(gui::GUI.AppView) = gui.layout.inspector.card - _card(gui) = gui.cards.selection + _listed(gui, obj) = gui.layout isa GUI.AppLayout ? (_in(obj, [r.key for r in GUI._tree_rows(gui)])) : (_in(obj, gui.objects.menu)) + _card(gui) = gui.layout isa GUI.AppLayout ? (gui.layout.inspector.card) : (gui.cards.selection) _message(f) = try f() "" diff --git a/test/TestLiveSplitter.jl b/test/TestLiveSplitter.jl index 6f343e0..2de15d5 100644 --- a/test/TestLiveSplitter.jl +++ b/test/TestLiveSplitter.jl @@ -125,14 +125,14 @@ const GUI = BeamletOpticsGUI m, pd, beam = _fixture() gui = live_view(System([m, pd]), beam; trace_budget = Inf, sidebar_width = (320, 280), dock_height = 200) - @test gui isa GUI.CompactView + @test gui.layout isa GUI.CompactLayout @test GUI._part_size_kwargs(gui) == (;) close(gui) # also values that the app layout rejects m, pd, beam = _fixture() gui = live_view(System([m, pd]), beam; trace_budget = Inf, layout = :compact, sidebar_width = 10, dock_height = 5000) - @test gui isa GUI.CompactView + @test gui.layout isa GUI.CompactLayout close(gui) end diff --git a/test/TestLiveWidgetRecipe.jl b/test/TestLiveWidgetRecipe.jl index dd9ec6d..fd21c7d 100644 --- a/test/TestLiveWidgetRecipe.jl +++ b/test/TestLiveWidgetRecipe.jl @@ -206,8 +206,7 @@ end # The widget `name` on the card of the object of the card of the selection: floating (compact) or # docked in the inspector (app) -_card(gui) = gui.cards.selection -_card(gui::GUI.LiveView{GUI.AppLayout}) = gui.layout.inspector.card +_card(gui) = gui.layout isa GUI.AppLayout ? gui.layout.inspector.card : gui.cards.selection _widget(gui, name) = GUI._card_widget(_card(gui), name) @testset "Live view widget recipes" begin