luametafun-interface.tex /size: 10 Kb    last modification: 2025-02-21 11:03
1% language=us runpath=texruns:manuals/luametafun
2
3\environment luametafun-style
4
5\startcomponent luametafun-interface
6
7\startchapter[title={Interface}]
8
9\startsection[title=Macros]
10
11Because graphic solutions are always kind of personal or domain driven it makes not
12much sense to cook up very generic solutions. If you have a project where \METAPOST\
13can be of help, it also makes sense to spend some time on implementing the basics that
14you need. In that case you can just copy and tweak what is there. The easiest way to
15do that is to make a test file and use:
16
17\starttyping[option=TEX]
18\startMPpage
19    % your code
20\stopMPpage
21\stoptyping
22
23Often you don't need to write macros, and standard drawing commands will do the
24job, but when you find yourself repeating code, a wapper might make sense. And
25this is why we have this key|/|value interface: it's easier to abstract your
26settings than to pass them as (expression or text) arguments to a macro,
27especially when there are many.
28
29You can find many examples of the key|/|value driven user interface in the source
30files and these are actually not that hard to understand when you know a bit of
31\METAPOST\ and the additional macros that come with \METAFUN. In case you wonder
32about overhead: the performance of this mechanism is pretty good.
33
34Although the parameter handler runs on top of the \LUA\ interface, you don't need
35to use \LUA\ unless you find that \METAPOST\ can't do the job. I won't give
36examples of coding because I think that the source of \METAFUN\ provides enough
37clues, especially the file \type {mp-lmtx.mpxl}. As the name suggests this is
38part of the \CONTEXT\ version \LMTX, which runs on top of \LUAMETATEX. I leave it
39open if I will backport this functionality to \LUATEX\ and therefore \MKIV.
40
41An excellent explanation of this interface can be found at:
42
43\starttyping
44https://adityam.github.io/context-blog/post/new-metafun-interface/
45\stoptyping
46
47So (at least for now) here I can stick to just mentioning the currently stable
48interface macros:
49
50\starttabulate[|T|l|pl|]
51\FL
52\NC presetparameters \NC \type {name [...]} \NC
53    Assign default values to a category of parameters. Sometimes it makes sense
54    not to set a default, because then you can check if a parameter has been set
55    at all.
56    \NC \NR
57\NC applyparameters \NC \type {name macro} \NC
58    This prepares the parameter handler for the given category and calls the
59    given macro when that is done.
60    \NC \NR
61\NC getparameters \NC \type {name [...]} \NC
62    The parameters given after the category name are set.
63    \NC \NR
64\ML
65\NC hasparameter \NC \type {names} \NC
66    Returns \type {true} when a parameter is set, and \type {false} otherwise.
67    \NC \NR
68\NC hasoption \NC \type {names options} \NC
69    Returns \type {true} when there is overlap in given options, and \type
70    {false} otherwise.
71    \NC \NR
72\ML
73\NC getparameter \NC \type {names} \NC
74    Resolves the parameter with the given name. because a parameter itself can
75    have a parameter list you can pass additional names to reach the final
76    destination.
77    \NC \NR
78\NC getparameterdefault \NC \type {names} \NC
79    Resolves the parameter with the given name. because a parameter itself can
80    have a parameter list you can pass additional names to reach the final
81    destination. The last value is used when no parameter is found.
82    \NC \NR
83\ML
84\NC getparametercount \NC \type {names} \NC
85    Returns the size if a list (array).
86    \NC \NR
87\NC getmaxparametercount \NC \type {names} \NC
88    Returns the size if a list (array) but descends into lists to find the largest size
89    of a sublist.
90    \NC \NR
91\ML
92\NC getparameterpath \NC \type {names string boolean} \NC
93    Returns the parameter as path. The optional string is one of \type {--},
94    \type {..} or \type {...} and the also optional boolean will force a closed
95    path.
96    \NC \NR
97\NC getparameterpen \NC \type {names} \NC
98    Returns the parameter as pen (path).
99    \NC \NR
100\NC getparametertext \NC \type {names boolean} \NC
101    Returns the parameter as string. The boolean can be used to force prepending
102    a so called \type {\strut}.
103    \NC \NR
104\ML
105\NC pushparameters \NC \type {category} \NC
106    Pushed the given (sub) category onto the stack so that we don't need to give
107    the category each time.
108    \NC \NR
109\NC popparameters \NC \NC
110    Pops the current (sub) category from the stack.
111    \NC \NR
112\LL
113\stoptabulate
114
115Most commands accept a list of strings separated by one or more spaces, The
116resolved will then stepwise descend into the parameter tree. This means that a
117parameter itself can refer to a list. When a value is an array and the last name
118is a number, the value at the given index will be returned.
119
120\starttyping
121"category" "name" ... "name"
122"category" "name" ... number
123\stoptyping
124
125The \type {category} is not used when we have pushed a (sub) category which can
126save you some typing and also is more efficient. Of course than can mean that you
127need to store values at a higher level when you need them at a deeper level.
128
129There are quite some extra helpers that relate to this mechanism, at the
130\METAPOST\ end as well as at the \LUA\ end. They aim for instance at efficiently
131dealing with paths and can be seen at work in the mentioned module.
132
133There is one thing you should notice. While \METAPOST\ has numeric, string,
134boolean and path variables that can be conveniently be passed to and from \LUA,
135communicating colors is a bit of a hassle. This is because \RGB\ and \CMYK\
136colors and gray scales use different types. For this reason it is strongly
137recommended to use strings that refer to predefined colors instead. This also
138enforces consistency with the \TEX\ end. As convenience you can define colors at
139the \METAFUN\ end.
140
141\startbuffer
142\startMPcode
143    definecolor [ name = "MyColor", r = .5, g = .25, b = .25 ]
144
145    fill fullsquare xyscaled (TextWidth,5mm) withcolor "MyColor" ;
146\stopMPcode
147\stopbuffer
148
149\typebuffer[option=TEX]
150
151\startlinecorrection
152\getbuffer
153\stoplinecorrection
154
155\stopsection
156
157\startsection[title=Units]
158
159Many dimensions used at the \TEX\ end are also available in \METAFUN. Examples
160are \typ {TextWidth}, \typ {EmHeight} and \typ {StrutHeight}. In \MKIV\ they are
161numeric variables that get set every graphic but in \MKXL\ these are not numeric
162variables but (hidden) \LUA\ calls so they can't be set at the \METAPOST\ end;
163but they are injected as numeric quantities so you can efficiently them in
164calculations.
165
166In \METAPOST\ examples you often find \type {u} being used as unit, like:
167
168\starttyping
169u := 1cm ; draw (u,0) -- (u,u) -- (3u,0);
170\stoptyping
171
172However, what if you want to set such a unit at the \TEX\ end? For this purpose
173we have a dedicated variable, which is demonstrated in the following examples.
174First we set a variable:
175
176\starttyping[option=TEX]
177\uunit=1cm
178\stoptyping
179
180\typebuffer[option=TEX]
181
182and next we apply it:
183
184\startbuffer
185\framed[offset=.2uu,strut=no]
186    \bgroup
187        \startMPcode
188            fill fullcircle scaled (2uu) withcolor "darkblue" ;
189            fill fullcircle scaled (8mm) withcolor "middlegray" ;
190        \stopMPcode
191    \egroup
192\stopbuffer
193
194\typebuffer[option=TEX]
195
196The \type {\uunit} dimension register is hooked into \TEX's unit parser as type
197{uu} (user unit). At the \METAPOST\ end \type {uu} is effectively a \LUA\ call
198that fetches the of the dimension from the \TEX end and presents it a a numeric.
199
200\startlinecorrection \uunit=1cm \getbuffer \stoplinecorrection
201
202When we set
203
204\starttyping[option=TEX]
205\uunit=5mm
206\stoptyping
207
208The same code gives::
209
210\startlinecorrection \uunit=5mm \getbuffer \stoplinecorrection
211
212\startbuffer
213\framed[offset=.1uu,strut=no]
214    \bgroup
215        \startMPcode
216            save uu ; numeric uu ; uu := 5mm ;
217            fill fullcircle scaled (3uu) withcolor "darkred"  ;
218            fill fullcircle scaled (2uu) withcolor "middlegray" ;
219        \stopMPcode
220    \egroup
221\stopbuffer
222
223\typebuffer[option=TEX]
224
225This demonstrates that we can overload \type {uu} but make sure to save it first
226so that later it is available again.
227
228\startlinecorrection \getbuffer \stoplinecorrection
229
230\stopsection
231
232\startsection[title=Paths from \LUA]
233
234Passing paths to \METAPOST\ using specific properties is sort of tricky because
235once the points are set, the solver will be applied. This translates curls,
236tensions and|/|or explicit control points into the final control points.
237
238In the next example we show a few interfaces. Not all of that might be perfect
239yes but in most cases it works out.
240
241\startbuffer
242\startluacode
243    local shapes = { }
244    shapes[1] = { {0,0}, {-1,-1}, {-1, 0}, {0,0}, "cycle" }
245    shapes[2] = { {0,1}, { 1, 0}, { 1,-1}, {0,1}, "cycle" }
246    shapes[3] = { {0,2}, { 2, 0}, { 2, 1}, {0,2}, "cycle" }
247    shapes[4] = {
248        {0,0}, {-1,-1}, {-1, 0}, {0,0}, "cycle", "append",
249        {0,1}, { 1, 0}, { 1,-1}, {0,1}, "cycle", "append",
250        {0,2}, { 2, 0}, { 2, 1}, {0,2}, "cycle", "append",
251    }
252    shapes[5] = {
253        { path = shapes[1], append = true },
254        { path = shapes[2], append = true },
255        { path = shapes[3], append = true },
256    }
257    function mp.getshapepath(n)
258        mp.inject.path(shapes[n])
259    end
260\stopluacode
261\stopbuffer
262
263\typebuffer[option=TEX] \getbuffer
264
265\startbuffer
266\startMPcode
267    path p ;
268    p := lua.mp.getshapepath(1) scaled 1cm ;
269    draw p withpen pencircle scaled 2pt withcolor red ;
270    p := lua.mp.getshapepath(2) scaled 1cm ;
271    draw p withpen pencircle scaled 2pt withcolor blue ;
272    p := lua.mp.getshapepath(3) scaled 1cm ;
273    draw p withpen pencircle scaled 2pt withcolor green ;
274    p := lua.mp.getshapepath(4) scaled 1cm &&cycle ;
275    fill p withcolor 0.9 ;
276    draw p withpen pencircle scaled 1pt withcolor 0.7 ;
277    p := lua.mp.getshapepath(5) scaled 1cm ;
278    draw p withpen pencircle scaled .25pt withcolor 0.2 ;
279\stopMPcode
280\stopbuffer
281
282\typebuffer[option=TEX]
283
284Especially cycling and appending needs to be done precisely in order not to get
285redundant (or bad) points.
286
287\startlinecorrection \getbuffer \stoplinecorrection
288
289This combines the first three paths similar to the fourth and fifths. If you
290doubt what you get you can always \type {show} the path and look for \type
291{{begin}} and \type {{end}} indicators.
292
293\startbuffer
294\startMPcode
295    path p ;
296    p := lua.mp.getshapepath(1) scaled 1cm &&
297         lua.mp.getshapepath(2) scaled 1cm &&
298         lua.mp.getshapepath(3) scaled 1cm ;
299    draw p withpen pencircle scaled 1pt withcolor 0.7 ;
300  % show(p);
301\stopMPcode
302\stopbuffer
303
304\typebuffer[option=TEX]
305
306We draw the result and see that they are decoupled indeed thanks to some \type
307{&&} magic:
308
309\startlinecorrection \getbuffer \stoplinecorrection
310
311\stopsection
312
313\stopchapter
314
315\stopcomponent
316