metafun-gadgets.tex /size: 16 Kb    last modification: 2023-12-21 09:43
1% language=us runpath=texruns:manuals/metafun
2
3\startcomponent metafun-gadgets
4
5\environment metafun-environment
6
7\startchapter[title={Shapes, symbols and buttons}]
8
9\startintro
10
11One can use \METAPOST\ to define symbols and enhance buttons. Here we introduce
12some of the gadgets that come with \CONTEXT, as well as explain how to integrate
13such gadgets yourself.
14
15\stopintro
16
17\startsection[title={Interfacing to \TEX}]
18
19\index {interfacing}
20
21\startbuffer[a]
22\setupMPvariables
23  [EnglishRule]
24  [height=1ex,
25   width=\availablehsize,
26   color=darkgray]
27
28\startuniqueMPgraphic{EnglishRule}{height,width,color}
29  numeric height ; height = \MPvar{height} ;
30  x1 = 0 ; x3 = \MPvar{width} ; x2 = x4 = .5x3 ;
31  y1 = y3 = 0 ; y2 := -y4 = height/2 ;
32  fill z1 .. z2 .. z3 & z3 .. z4 .. z1 & cycle
33    withcolor \MPvar{color} ;
34\stopuniqueMPgraphic
35\stopbuffer
36
37\startbuffer[b]
38\defineblank
39  [EnglishRule]
40  [medium]
41
42\unexpanded\def\EnglishRule
43  {\start
44   \dontcomplain
45   \startlinecorrection[EnglishRule]
46     \noindent \reuseMPgraphic{EnglishRule}
47   \stoplinecorrection
48   \stop}
49\stopbuffer
50
51\getbuffer[a,b]
52
53In the early days of \METAPOST\ support in \CONTEXT, Tobias Burnus asked me if it
54was possible to define English rules. What exactly does an english rule look
55like? Here is one:
56
57\EnglishRule
58
59As you can see, such a rule has to adapt itself to the current text width,
60normally \type {\hsize} in \TEX, or on request \type {\availablehsize} in
61\CONTEXT. We need to set the height to a reasonable size, related to the font
62size, and we also need to take care of proper spacing. Of course we want to run
63\METAPOST\ as less times as possible, so we need to use unique graphics. Let's
64start with the graphic.
65
66\typebuffer[a]
67
68As you can see, we pass two arguments to the graphic definition. The first
69argument is the name, the second argument is a comma separated list of variables.
70This list serves two purposes. First this list is used to create a unique profile
71for the graphic. This means that when we change the value of a variable, a new
72graphic is generated that reflects the change. A second purpose of the list is to
73convert \TEX\ data structures into \METAPOST\ ones, especially dimensions and
74colors. The graphic itself is not that spectacular. We use \type {&} because we
75don't want smooth connections.
76
77\typebuffer[b]
78
79When setting the variables, we used \type {\availablehsize}. We need to use \type
80{\noindent}, a rather familiar \TEX\ primitive, that we use here to start a non
81indented paragraph, being the graphic. The line correction is needed to get the
82spacing around the rule (graphic) right. We pass a blank skip identifier that is
83mapped to a convenient medium skip.
84
85\startbuffer[c]
86Why is this called an English line?
87
88\startnarrower
89  \EnglishRule
90    Is it because they cannot draw a straight one? This could be true
91    after a few strong beers, but then, how do Germans draw a line?
92  \EnglishRule
93\stopnarrower
94\stopbuffer
95
96\typebuffer[c]
97
98As expected, the rule adapts itself to the current width of the text. The height
99of the rule in the middle matches the height of a character with no ascenders and
100descenders.
101
102\getbuffer[c]
103
104\stopsection
105
106\startsection[title={Random graphics}]
107
108\index{randomization}
109
110\startbuffer[a]
111\startuseMPgraphic{fuzzycount}
112   begingroup
113   save height, vstep, hsize, span, drift, d, cp ;
114   height := 3/ 4 * \the \bodyfontsize * \currentfontscale ;
115   span   := 1/ 3 * height ;
116   drift  := 1/10 * height ;
117   hsize  := \the\hsize ;
118   vstep  := \the\lineheight ;
119   xmax   := hsize div 5span ;
120   pickup pencircle scaled (1/12 * height) ;
121   def d = (uniformdeviate drift) enddef ;
122   for i := 1 upto \MPvar{n} :
123     xpos := ((i-1) mod (5*xmax))*span ;
124     ypos := ((i-1) div (5*xmax))*vstep ;
125     draw
126       if (i mod 5)=0 : ((-d-4.5span,d)--(+d-0.5span,height-d))
127       else           : ((-d,+d)--(+d,height-d)) fi
128       shifted (xpos,-ypos+d-drift) ;
129   endfor;
130   picture cp ; cp := currentpicture ;
131   if (ypart ulcorner cp - ypart llcorner cp) <= vstep :
132     setbounds currentpicture to
133       (llcorner cp shifted (0,-ypart llcorner cp) --
134        lrcorner cp shifted (0,-ypart lrcorner cp) --
135        urcorner cp -- ulcorner cp -- cycle) ;
136   fi
137   endgroup ;
138\stopuseMPgraphic
139\stopbuffer
140
141\startbuffer[b]
142\useMPgraphic{fuzzycount}{n=1001}
143\stopbuffer
144
145Given enough time and paper, we can probably give you some
146
147\startlinecorrection[blank]
148\getbuffer[a,b]
149\stoplinecorrection
150
151reasons why \METAPOST\ is fun. To mention a few: you can enhance the layout with
152graphic ornaments, you can tune your graphics at runtime, and simple high quality
153graphics can be very effective.
154
155\startbuffer[c]
156\startuseMPgraphic{fuzzycount}
157   begingroup
158   save height, span, drift, d, cp ;
159   height := 3/ 5 * \baselinedistance ;
160   span   := 1/ 3 * height ;
161   drift  := 1/10 * height ;
162   pickup pencircle scaled (1/12 * height) ;
163   def d = (uniformdeviate drift) enddef ;
164   for i := 1 upto \MPvar{n} :
165     draw
166       if (i mod 5)=0 : ((-d-4.5span,d)--(+d-0.5span,height-d))
167       else           : ((-d,+d)--(+d,height-d)) fi
168       shifted (span*i,d-drift) ;
169   endfor;
170   picture cp ; cp := currentpicture ; % for readability
171   setbounds currentpicture to
172     (llcorner cp shifted (0,-ypart llcorner cp) --
173      lrcorner cp shifted (0,-ypart lrcorner cp) --
174      urcorner cp -- ulcorner cp -- cycle) ;
175   endgroup ;
176\stopuseMPgraphic
177\stopbuffer
178
179\startbuffer[d]
180\setupMPvariables[fuzzycount][n=10]
181\stopbuffer
182
183\getbuffer[c,d]
184
185The previous graphics draws exactly 1001 lines in a scratch||numbers||in||a||wall
186fashion. In 1998, the \NTG\ did a survey among its members, and in the report, we
187used this fuzzy counter to enhance the rather dull tables.
188
189\startbuffer
190\starttabulate[|l|c|l|]
191\HL
192\NC system  \NC \%   \NC \# users                        \NC\NR
193\HL
194\NC Atari   \NC 10.4 \NC \useMPgraphic{fuzzycount}{n=11} \NC\NR
195\NC MSDOS   \NC 49.1 \NC \useMPgraphic{fuzzycount}{n=52} \NC\NR
196\NC OS/2    \NC ~9.4 \NC \useMPgraphic{fuzzycount}{n=10} \NC\NR
197\NC MacOS   \NC ~5.7 \NC \useMPgraphic{fuzzycount}{n= 6} \NC\NR
198\NC UNIX    \NC 51.9 \NC \useMPgraphic{fuzzycount}{n=55} \NC\NR
199\NC WINDOWS \NC 64.2 \NC \useMPgraphic{fuzzycount}{n=68} \NC\NR
200\HL
201\stoptabulate
202\stopbuffer
203
204\placetable
205  [here][tab:fuzzy]
206  {Operating system (n=106).}{\getbuffer}
207
208\in {Table} [tab:fuzzy] demonstrates how scratch numbers can be used. An
209interesting side effect is that when you look long enough to these kind of
210graphics, it looks like the lines are no longer horizontal. This table is defined
211as follows:
212
213\typebuffer
214
215You will notice that we pass a variable to the graphic using a second argument.
216We can access this variable with \type {\MPvar}. The graphic is defined as usable
217graphic, because we want to generate a unique random one each time.
218
219\typebuffer[c]
220
221The core of the macro is the \type {for} loop. Within this loop, we draw groups
222of four plus one lines. The draw path's look a bit complicated, but this has to
223do with the fact that a \type {mod} returns $0-4$ while we like to deal with
224$1-5$.
225
226The height adapts itself to the height of the line. The bounding box correction
227at the end ensures that the baseline is consistent and that the random vertical
228offsets fall below the baseline.
229
230Because we want to be sure that \type {n} has a value, we preset it by saying:
231
232\typebuffer[d]
233
234In the table, it makes sense to adapt the drawing to the lineheight, but a more
235general solution is to adapt the height to the fontsize.
236
237\starttyping
238height := 3/ 4 * \the \bodyfontsize * \currentfontscale ;
239\stoptyping
240
241\getbuffer[a]
242
243In the table we called the graphic directly, but how about making it available as
244a conversion macro? In \CONTEXT\ this is not that hard:
245
246\startbuffer
247\def\fuzzycount#1{{\tx\useMPgraphic{fuzzycount}{n=#1}}}
248\defineconversion[fuzzy][\fuzzycount]
249\stopbuffer
250
251\typebuffer \getbuffer
252
253Because such a counter should not be that large, we use \type {\tx} to switch to
254a smaller font. This also demonstrates how the graphic adapts itself to the font
255size.
256
257We can now use this conversion for instance in an itemize. To save space we use
258three columns and no white space between the lines. The \type {2*broad} directive
259makes sure that we have enough room for the number.
260
261\startbuffer
262\startitemize[fuzzy,pack,2*broad,columns,three]
263\item one   \item two   \item three
264\item four  \item five  \item six
265\item seven \item eight \item nine
266\stopitemize
267\stopbuffer
268
269\getbuffer
270
271\typebuffer
272
273A careful reader will have noticed that the previous definition of the fuzzy
274counter drawing is not suited to generate the graphics we started with.
275
276\typebuffer[b]
277
278This time we want to limit the width to the current \type {\hsize}. We only need
279to add a few lines of code. Watch how we don't recalculate the bounding box when
280more lines are used.
281
282\typebuffer[a]
283
284\stopsection
285
286\startsection[title={Graphic variables}]
287
288\index{graphics+variables}
289\index{variables}
290
291In the previous sections we have seen that we can pass information to the graphic
292by means of variables. How exactly does this mechanism work?
293
294\startbuffer[def]
295\setupMPvariables[smile][type=1,height=1.25ex,color=darkred]
296
297\startuniqueMPgraphic{smile}{type,height,color}
298  numeric size ; size := \MPvar{height} ;
299  drawoptions(withcolor \MPvar{color}) ;
300  pickup pencircle xscaled (size/6) yscaled (size/12) ;
301  draw halfcircle rotated -90 scaled size ;
302  pickup pencircle scaled (size/4) ;
303  if     \MPvar{type}=1 :
304    for i=-1,+1 : draw origin shifted (0,i*size/4) ; endfor ;
305  elseif \MPvar{type}=2 :
306    for i=-1,+1 : draw origin shifted (-size/2,i*size/4) ; endfor ;
307    pickup pencircle scaled (size/6) ;
308    draw (size/4,0) -- (-size/4,0) ;
309  fi ;
310\stopuniqueMPgraphic
311\stopbuffer
312
313\startbuffer[sym]
314\definesymbol[smile]    [\uniqueMPgraphic{smile}{type=1}]
315\definesymbol[smilemore][\uniqueMPgraphic{smile}{type=2}]
316\stopbuffer
317
318\startbuffer[exa]
319Say it with a \symbol [smile]\ or maybe even a \symbol
320[smilemore], although seeing too many \dorecurse {10}
321{\symbol [smile]\ } \unskip in one text may make you cry.
322\stopbuffer
323
324\getbuffer[def,sym]
325
326A nice application of setting up variables for a specific graphic (or class of
327graphics) is the following. In an email message the author can express his own or
328the readers expected emotions with so called smilies like: \symbol [smile]. If
329you want them in print, you can revert to combinations of characters in a font,
330but as a \TEX\ user you may want to include nicer graphics.
331
332A convenient way to implement these is to make them into symbols, one reason
333being that in that case they will adapt themselves to the current font size.
334
335\typebuffer[exa] \getbuffer[exa]
336
337Because we want an efficient implementation, we will use unique graphics, because
338these will only be generated when the circumstances change.
339
340\typebuffer[sym]
341
342The definition itself then becomes:
343
344\typebuffer[def]
345
346We can now change some characteristics of the smilies without the need to
347redefine the graphic.
348
349\startbuffer[set]
350\setupMPvariables[smile][height=1ex,color=darkred]
351\stopbuffer
352
353\typebuffer[set]
354
355\getbuffer[set,exa]
356
357In order to keep the smilies unique there is some magic involved, watch the
358second argument in the next line:
359
360\starttyping
361\startuniqueMPgraphic{smile}{type,height,color}
362    % the image
363\stopuniqueMPgraphic
364\stoptyping
365
366Because unique graphics often are used in backgrounds, its uniqueness is
367determined by the overlay characteristics. In our case however the uniqueness is
368determined by the smilies type, height and color. By explicitly specifying these,
369we make sure that they count in the creation of the uniqueness stamp.
370
371\startbuffer[exa]
372\midaligned{\switchtobodyfont[60pt]\symbol[smile]}
373\stopbuffer
374
375\typebuffer[exa]
376
377Because we use the ex||height, the previous call works as expected.
378
379\startlinecorrection[blank]
380\getbuffer[exa]
381\stoplinecorrection
382
383\stopsection
384
385\startsection[title={Shape libraries}]
386
387\index{graphics+libraries}
388
389Unfortunately it takes some effort to define graphics, attach them to an overlay,
390and invoke the background. However, the good news is that since in many cases we
391want a consistent layout, we only have to do it once. The next table has some
392hashed backgrounds. (More information about how to define tables can be found in
393the \CONTEXT\ documentation and Up||To||Date documents.)
394
395\startbuffer
396\bTABLE[frame=off,meta:hash:linecolor=darkyellow,offset=3ex]
397  \bTR
398    \bTD[background=meta:hash:right]      right      \eTD
399    \bTD[background=meta:hash:left]       left       \eTD
400    \bTD[background=meta:hash:horizontal] horizontal \eTD
401    \bTD[background=meta:hash:vertical]   vertical   \eTD
402  \eTR
403\eTABLE
404\stopbuffer
405
406\getbuffer[shape-a,shape-b,shape-c]
407
408\placetable
409  {A hashed table.}
410  {\getbuffer}
411
412This table is defined as:
413
414\typebuffer
415
416The graphics themselves are defined in a \METAPOST\ module. In this particular
417example, the macro \type {some_hash} is defined in the file \type {mp-back.mp}.
418This macro takes six arguments:
419
420\starttyping
421some_hash (width, height, linewidth, linecolor, angle, gap) ;
422\stoptyping
423
424Because we don't want to define a specific overlay for each color and linewidth,
425we will use variables in the definition of the unique graphic.
426
427\typebuffer[shape-a]
428
429These variables are preset using \type {\setupMPvariables}:
430
431\typebuffer[shape-b]
432
433The last step in this process is to define the different
434alternatives as overlays:
435
436\typebuffer[shape-c]
437
438As we can see in the definition of the table, we can pass settings to the \type
439{\bTABLE} command. Actually, we can pass such settings to each command that
440supports backgrounds, or more precisely \type {\framed}. \in {Table} [tab:hashes]
441is for instance defined as:
442
443\startbuffer
444\bTABLE[frame=off,meta:hash:linewidth=.4pt,align=middle,offset=2ex]
445  \bTR
446    \bTD[background={meta:hash:left,meta:hash:right},
447         meta:hash:linecolor=darkyellow]
448        left        \par \& \par right    \eTD
449    \bTD[background={meta:hash:horizontal,meta:hash:vertical},
450         meta:hash:linecolor=darkred]
451         horizontal \par \& \par vertical \eTD
452  \eTR
453\eTABLE
454\stopbuffer
455
456\typebuffer
457
458The long names are somewhat cumbersome, but in that way we can prevent name
459clashes. Also, since the \METAPOST\ interface is english, the variables are also
460english.
461
462\placetable
463  [here][tab:hashes]
464  {A double hashed table.}
465  {\getbuffer}
466
467\stopsection
468
469\startsection[title={Symbol collections}]
470
471\index{graphics+symbols}
472\index{symbols}
473
474In \CONTEXT, a symbol can be defined without much coding. The advantage of using
475symbols is that you can redefine them depending on the situation. So,
476
477\starttyping
478\definesymbol [yes] [\em Yes!]
479\stoptyping
480
481creates a symbol, that lets \type {\symbol[yes]} expand into {\em Yes!} Since
482nearly anything can be a symbol, we can also say:
483
484\starttyping
485\definesymbol [yes] [\mathematics{\star}]
486\stoptyping
487
488or even the already defined symbol \symbol[star], by saying:
489
490\starttyping
491\definesymbol [yes] [{\symbol[star]}]
492\stoptyping
493
494It may be clear that we can use a graphic as well:
495
496\typebuffer[symb-c]
497
498Since we have collected some nice buttons in a \METAPOST\ file already, we can
499use a rather simple definition:
500
501\typebuffer[symb-a]
502
503This leaves a few settings:
504
505\typebuffer[symb-b]
506
507These symbols are collected in \in {table} [tab:symbols], and are called up with
508the \CONTEXT\ commands like \type {\symbol[menu:left]}. If needed, we can collect
509these button symbols in a so called symbol set, which permits us to instantly
510switch between sets with similar symbols.
511
512\startbuffer
513\bTABLE[frame=off,width=36pt,align=middle]
514  \bTR \bTD \dontleavehmode \symbol[menu:left]   \eTD
515       \bTD \dontleavehmode \symbol[menu:right]  \eTD
516       \bTD \dontleavehmode \symbol[menu:list]   \eTD
517       \bTD \dontleavehmode \symbol[menu:index]  \eTD
518       \bTD \dontleavehmode \symbol[menu:person] \eTD
519       \bTD \dontleavehmode \symbol[menu:stop]   \eTD
520       \bTD \dontleavehmode \symbol[menu:info]   \eTD
521       \bTD \dontleavehmode \symbol[menu:down]   \eTD
522       \bTD \dontleavehmode \symbol[menu:up]     \eTD
523       \bTD \dontleavehmode \symbol[menu:print]  \eTD \eTR
524  \bTR \bTD left   \eTD
525       \bTD right  \eTD
526       \bTD list   \eTD
527       \bTD index  \eTD
528       \bTD person \eTD
529       \bTD stop   \eTD
530       \bTD info   \eTD
531       \bTD down   \eTD
532       \bTD up     \eTD
533       \bTD print  \eTD \eTR
534\eTABLE
535\stopbuffer
536
537\getbuffer[symb-a,symb-b,symb-c]
538
539\placetable
540  [here][tab:symbols]
541  {A collection of button symbols.}
542  {\getbuffer}
543
544\stopsection
545
546\stopchapter
547
548\stopcomponent
549