diff --git a/src/LiveCards.jl b/src/LiveCards.jl index d8ebc3d..12a4bf5 100644 --- a/src/LiveCards.jl +++ b/src/LiveCards.jl @@ -1025,20 +1025,25 @@ _selection_objects(s::_ShapeChange) = isnothing(s.old) ? Any[s.new] : Any[s.new, _shape_changed!(gui, obj, old, new) An input on the card of `obj` changed the code of its constructor from `old` to `new`: the code of -its `origin` becomes `new` (the autosave writes it to the line of `obj`, see `_project_parts`), the -handles of `obj` in the pool draw it again (`BeamletOptics.rerender!`), and the change is recorded -in the undo history, see `_ShapeChange`. +its `origin` becomes `new` in the `gui` and in every window linked with it that shows `obj` (see +`open_system`), such that the window of the project saves it (the autosave writes it to the line of +`obj`, see `_project_parts`); the handles of `obj` in the pools of these windows draw it again +(`BeamletOptics.rerender!`), and the change is recorded in the undo history of the `gui`, see +`_ShapeChange`. """ function _shape_changed!(gui::LiveView, @nospecialize(obj), old::String, new::String) - comp = gui.components # e.g. removed by the input - haskey(comp.origin, obj) || return nothing - comp.origin[obj] = merge(comp.origin[obj], (; code = new)) - for oh in _pool_handles(gui, obj) - Base.invokelatest(BMO.rerender!, oh) + haskey(gui.components.origin, obj) || return nothing + for v in unique(objectid, Any[gui, gui.links.views...]) + origin = v.components.origin + haskey(origin, obj) || continue + origin[obj] = merge(origin[obj], (; code = new)) + for oh in _pool_handles(v, obj) + Base.invokelatest(BMO.rerender!, oh) + end + _update_selection_box!(v.controls) end - _update_selection_box!(gui.controls) - comp.recording && _record_shape!(gui, obj, old) + gui.components.recording && _record_shape!(gui, obj, old) return nothing end diff --git a/src/LiveLinks.jl b/src/LiveLinks.jl index 91211da..7fecd16 100644 --- a/src/LiveLinks.jl +++ b/src/LiveLinks.jl @@ -219,6 +219,11 @@ function _link!(gui::LiveView, new::LiveView, system) to.system[obj] = system to.origin[obj] = get(from.origin, obj, nothing) end + # the code of the objects and sources that the view started with as well, e.g. of a project: + # a change of their shape in `new` reaches the code of every view, see `_shape_changed!` + for obj in Iterators.flatten((system.objects, _sources_of(gui, system))) + haskey(from.origin, obj) && !haskey(to.origin, obj) && (to.origin[obj] = from.origin[obj]) + end for obj in from.removed if haskey(from.source_systems, obj) _has(from.source_systems[obj], system) || continue diff --git a/test/TestLiveProjectOwnTypes.jl b/test/TestLiveProjectOwnTypes.jl index f739719..010e077 100644 --- a/test/TestLiveProjectOwnTypes.jl +++ b/test/TestLiveProjectOwnTypes.jl @@ -129,6 +129,32 @@ end close(gui) end + @testset "a change of the shape in a second window is saved (#88)" begin + dir = project() + gui = open_project(dir; display = false, const_kw...) + k1 = obj(gui, :K1) + second = open_system(gui, only(GUI._systems(gui)); display = false) + select!(second, k1) + Makie.set_close_to!(card_widget(second, k1, :width), 40.0) + @test k1.shape.diameter ≈ 0.04 + # the code in both windows, saved by the window of the project + @test second.components.origin[k1].code == "Block(0.04, 0.005)" + @test gui.components.origin[k1].code == "Block(0.04, 0.005)" + @test GUI._autosave!(gui; force = true) === :saved + @test startswith(line(dir, :K1), "@component K1 = Block(0.04, 0.005)") + # undo in the second window: the old shape again, also in the files + @test GUI._undo!(second.controls) + old = obj(gui, :K1) + @test old !== k1 && old.shape.diameter == 0.025 + @test GUI._autosave!(gui; force = true) === :saved + @test startswith(line(dir, :K1), "@component K1 = Block(0.025, 0.005)") + @test GUI._redo!(second.controls) + @test GUI._autosave!(gui; force = true) === :saved + @test startswith(line(dir, :K1), "@component K1 = Block(0.04, 0.005)") + close(second) + close(gui) + end + @testset "a type without constructor_code" begin dir = project() gui = open_project(dir; display = false, const_kw...)