99(m:: Model )(args... ; kw... ) = m. f (args... ; kw... )
1010
1111using MLStyle
12+
1213function connector_macro (mod, name, body)
1314 if ! Meta. isexpr (body, :block )
1415 err = """
@@ -23,19 +24,26 @@ function connector_macro(mod, name, body)
2324 error (err)
2425 end
2526 vs = Num[]
27+ icon = Ref {Union{String, URI}} ()
2628 dict = Dict {Symbol, Any} ()
2729 for arg in body. args
2830 arg isa LineNumberNode && continue
31+ if arg. head == :macrocall && arg. args[1 ] == Symbol (" @icon" )
32+ parse_icon! (icon, dict, dict, arg. args[end ])
33+ continue
34+ end
2935 push! (vs, Num (parse_variable_def! (dict, mod, arg, :variables )))
3036 end
3137 iv = get (dict, :independent_variable , nothing )
3238 if iv === nothing
3339 error (" $name doesn't have a independent variable" )
3440 end
41+ gui_metadata = isassigned (icon) ? GUIMetadata (GlobalRef (mod, name), icon[]) :
42+ nothing
3543 quote
3644 $ name = $ Model ((; name) -> begin
3745 var"#___sys___" = $ ODESystem ($ (Equation[]), $ iv, $ vs, $ ([]);
38- name)
46+ name, gui_metadata = $ gui_metadata )
3947 $ Setfield. @set! (var"#___sys___" . connector_type= $ connector_type (var"#___sys___" ))
4048 end , $ dict)
4149 end
123131macro model (name:: Symbol , expr)
124132 esc (model_macro (__module__, name, expr))
125133end
134+
126135function model_macro (mod, name, expr)
127136 exprs = Expr (:block )
128137 dict = Dict {Symbol, Any} ()
@@ -131,25 +140,29 @@ function model_macro(mod, name, expr)
131140 vs = Symbol[]
132141 ps = Symbol[]
133142 eqs = Expr[]
143+ icon = Ref {Union{String, URI}} ()
134144 for arg in expr. args
135145 arg isa LineNumberNode && continue
136146 arg. head == :macrocall || error (" $arg is not valid syntax. Expected a macro call." )
137- parse_model! (exprs. args, comps, ext, eqs, vs, ps, dict, mod, arg)
147+ parse_model! (exprs. args, comps, ext, eqs, vs, ps, icon, dict, mod, arg)
138148 end
139149 iv = get (dict, :independent_variable , nothing )
140150 if iv === nothing
141151 iv = dict[:independent_variable ] = variable (:t )
142152 end
153+ gui_metadata = isassigned (icon) > 0 ? GUIMetadata (GlobalRef (mod, name), icon[]) :
154+ nothing
143155 sys = :($ ODESystem ($ Equation[$ (eqs... )], $ iv, [$ (vs... )], [$ (ps... )];
144- systems = [$ (comps... )], name))
156+ systems = [$ (comps... )], name, gui_metadata = $ gui_metadata ))
145157 if ext[] === nothing
146158 push! (exprs. args, sys)
147159 else
148160 push! (exprs. args, :($ extend ($ sys, $ (ext[]))))
149161 end
150162 :($ name = $ Model ((; name) -> $ exprs, $ dict))
151163end
152- function parse_model! (exprs, comps, ext, eqs, vs, ps, dict, mod, arg)
164+
165+ function parse_model! (exprs, comps, ext, eqs, vs, ps, icon, dict, mod, arg)
153166 mname = arg. args[1 ]
154167 body = arg. args[end ]
155168 if mname == Symbol (" @components" )
@@ -162,10 +175,13 @@ function parse_model!(exprs, comps, ext, eqs, vs, ps, dict, mod, arg)
162175 parse_variables! (exprs, ps, dict, mod, body, :parameters )
163176 elseif mname == Symbol (" @equations" )
164177 parse_equations! (exprs, eqs, dict, body)
178+ elseif mname == Symbol (" @icon" )
179+ parse_icon! (icon, dict, mod, body)
165180 else
166181 error (" $mname is not handled." )
167182 end
168183end
184+
169185function parse_components! (exprs, cs, dict, body)
170186 expr = Expr (:block )
171187 push! (exprs, expr)
@@ -187,6 +203,7 @@ function parse_components!(exprs, cs, dict, body)
187203 end
188204 dict[:components ] = comps
189205end
206+
190207function parse_extend! (exprs, ext, dict, body)
191208 expr = Expr (:block )
192209 push! (exprs, expr)
@@ -213,6 +230,7 @@ function parse_extend!(exprs, ext, dict, body)
213230 _ => error (" `@extend` only takes an assignment expression. Got $body " )
214231 end
215232end
233+
216234function parse_variables! (exprs, vs, dict, mod, body, varclass)
217235 expr = Expr (:block )
218236 push! (exprs, expr)
@@ -225,6 +243,7 @@ function parse_variables!(exprs, vs, dict, mod, body, varclass)
225243 push! (expr. args, :($ name = $ v))
226244 end
227245end
246+
228247function parse_equations! (exprs, eqs, dict, body)
229248 for arg in body. args
230249 arg isa LineNumberNode && continue
@@ -233,3 +252,30 @@ function parse_equations!(exprs, eqs, dict, body)
233252 # TODO : does this work with TOML?
234253 dict[:equations ] = readable_code .(eqs)
235254end
255+
256+ function parse_icon! (icon, dict, mod, body:: String )
257+ icon_dir = get (ENV , " MTK_ICONS_DIR" , joinpath (DEPOT_PATH [1 ], " mtk_icons" ))
258+ dict[:icon ] = icon[] = if isfile (body)
259+ URI (" file:///" * abspath (body))
260+ elseif (iconpath = joinpath (icon_dir, body); isfile (iconpath))
261+ URI (" file:///" * abspath (iconpath))
262+ elseif try
263+ Base. isvalid (URI (body))
264+ catch e
265+ false
266+ end
267+ URI (body)
268+ else
269+ error (" $body is not a valid icon" )
270+ end
271+ end
272+
273+ function parse_icon! (icon, dict, mod, body:: Expr )
274+ _icon = body. args[end ]
275+ dict[:icon ] = icon[] = MLStyle. @match _icon begin
276+ :: Symbol => get_var (mod, _icon)
277+ :: String => _icon
278+ Expr (:call , read, a... ) => eval (_icon)
279+ _ => error (" $_icon isn't a valid icon" )
280+ end
281+ end
0 commit comments