From 153d6b9552e82b052ea1a14aaa685a2879e25d1f Mon Sep 17 00:00:00 2001
From: Michiel Cottaar <MichielCottaar@protonmail.com>
Date: Mon, 9 Sep 2024 14:44:23 +0100
Subject: [PATCH] Allow direct accessing and constraining of variables.

---
 src/variables.jl | 53 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)

diff --git a/src/variables.jl b/src/variables.jl
index 0551d2b..d5ddbe2 100644
--- a/src/variables.jl
+++ b/src/variables.jl
@@ -85,6 +85,59 @@ struct AlternateVariable <: AnyVariable
 end
 
 
+"""
+    base_variables([T])
+
+Return dictionary with all [`Variable`](@ref) objects defined for a specific sequence component/block `T`.
+
+This only returns those [`Variable`](@ref) directly defined for this component/block, not for any sub-components (through [`get_pulse`](@ref), [`get_gradient`][(@ref), etc.)
+
+If `T` is not provided, all [`Variable`](@ref) objects are returned.
+"""
+function base_variables()
+    all_members = (s => getproperty(variables, s) for s in names(variables, all=true))
+    return Dict{Symbol, Variable}(
+        s => v for (s, v) in all_members if v isa Variable
+    )
+end
+
+function base_variables(T::Type{<:AbstractBlock})
+    return Dict(
+        s => v for (s, v) in base_variables() if hasmethod(v.f, (T, ))
+    )
+end
+
+
+# Add Variables to the individual sequence components/blocks properties
+function Base.propertynames(::T) where {T <: AbstractBlock}
+    f = Base.fieldnames(T)
+    var_names = [k for k in keys(base_variables(T)) if !(k in f)]
+    return (f..., var_names...)
+end
+
+function Base.getproperty(block::T, v::Symbol) where T <: AbstractBlock
+    if v in Base.fieldnames(T)
+        return getfield(block, v)
+    end
+    vars = base_variables(T)
+    if v in keys(vars)
+        return vars[v](block)
+    end
+    error("Type $(T) has no field or variable $(v)")
+end
+
+function Base.setproperty!(block::T, v::Symbol, value) where T <: AbstractBlock
+    if v in Base.fieldnames(T)
+        return setfield!(block, v, value)
+    end
+    vars = base_variables(T)
+    if v in keys(vars)
+        orig = vars[v](block)
+        return apply_simple_constraint!(orig, value)
+    end
+    error("Type $(T) has no field or variable $(v)")
+end
+
 """
     variable_defined_for(var, Val(type))
 
-- 
GitLab