calculator.tex /size: 52 Kb    last modification: 2020-07-01 14:35
1%D The calculator
2%D
3%D This document was made in 1998 as demonstration of widgets in \CONTEXT in \MKII.
4%D It has been adapted to run in \MKIV. Not many changes were needed. The macro
5%D definitions are layout a bit more readable and we use official scratch variables.
6%D
7%D The \JAVASCRIPT\ interpeter has changes and also became more strict. So, I
8%D reformatted the code bit and added some more semicolons and vars.
9%D
10%D We changed to font from a Helvetica lookalike to Dejavu but kept the colors as
11%D in the original. We also kept the \JAVASCRIPT\ and \METAPOST\ code (although
12%D we had to add some initalizations for \METAPOST\ due to the runtime graphic
13%D generation. I didn't check the functionality.
14%D
15%D Should I do it different nowaways? For sure. I might use layers of make nicer
16%D \METAPOST\ code but it's also a demonstration of how thinsg were done in 1998.
17
18% acrobat 3->4 : different field initialization
19% acrobat 4->5 : typecasting fails [switch"2" vs 2]
20% acrobat 6->  : more strict interpreter
21
22\starttext
23
24\dontcomplain
25
26\setuppapersize
27  [S6][S6]
28
29\setupwhitespace
30  [medium]
31
32\setupbodyfont
33  [dejavu,9pt]
34
35\setuptyping
36  [margin=standard]
37
38\setuplayout
39  [backspace=1cm,
40   topspace=1cm,
41   header=0pt,
42   footer=0pt,
43   width=middle,
44   height=middle]
45
46\setupinteraction
47  [page=yes,
48   state=start,
49   author=Hans Hagen,
50   title=The Calculator,
51   color=keyboard]
52
53\setupinteractionscreen
54  [option=max]
55
56\definecolor [action]   [r= 1, g=.9, b=.5]
57\definecolor [keyboard] [r= 0, g=.7, b=.7]
58\definecolor [stack]    [r=.7, g=.6, b=.8]
59
60\useURL[pragma-mail][mailto:pragma@xs4all.nl][][pragma@xs4all.nl]
61
62%D We have to use \type {String(...)=""} otherwise zero is regarded
63%D as non|-|entry (empty). This is a bit fuzzy.
64
65\def\MinLevel{50}
66\def\MaxLevel {8}
67
68\startJSpreamble {variables} used now
69
70    var Growing        = false ;
71    var MinLevel       = -50 ;
72    var MaxLevel       = 8 ;
73    var Level          = 1 ;
74    var NoErrorFound   = ">ok" ;
75    var NoValueError   = ">invalid" ;
76    var WhateverError  = ">error" ;
77    var OverflowError  = ">overflow" ;
78    var ExhaustedError = ">exhausted" ;
79
80    var Stack          = new Array() ;
81    var Stats          = new Array() ;
82
83 // console.clear() ;
84
85 // console.println("preamble loaded: variables") ;
86
87\stopJSpreamble
88
89\startJSpreamble {housekeeping} used now
90
91    function do_reset_all () {
92        if (Growing) {
93            Level = 1 ;
94        } else {
95            Level = MaxLevel ;
96        }
97        for (var i=MinLevel ; i<=MaxLevel ; i++) {
98            Stack[i] = "" ;
99        }
100        do_mark (NoErrorFound) ;
101    }
102
103    function do_refresh (i) {
104        var vv = this.getField("Stack." + String(i)) ;
105        if (vv) {
106            vv.value    = Stack[i] ;
107            vv.readonly = (i != Level) ;
108            this.dirty  = false ;
109        }
110    }
111
112    function do_refresh_all () {
113        for (var i=1 ; i<=MaxLevel ; i++) {
114            do_refresh(i) ;
115        }
116    }
117
118    function do_update_A () {
119        if (Stack[1] == "") {
120            for (var i=1 ; i<=MaxLevel ; i++) {
121                vv = this.getField("Stack." + String(i)) ;
122                if (vv) {
123                    Level = i ;
124                    if (valid_number(vv.value)) {
125                        Stack[Level] = String(vv.value)
126                    } else {
127                        vv.value = "" ;
128                        this.dirty = false ;
129                        return ;
130                    }
131                }
132            }
133        }
134    }
135
136    function do_update_B () {
137        if (String(Stack[MaxLevel-1]) == "") {
138            for (var i=1 ; i<=MaxLevel ; i++) {
139                vv = this.getField("Stack." + String(i)) ;
140                if (vv) {
141                    if (valid_number(vv.value)) {
142                        Stack[Level] = String(vv.value) ;
143                    } else {
144                        vv.value = "" ;
145                        this.dirty = false ;
146                        return ;
147                    }
148                }
149            }
150        }
151    }
152
153    function do_update () {
154        if (Growing) {
155            do_update_A() ;
156        } else {
157            do_update_B() ;
158        }
159    }
160
161    function do_mark (s) {
162        var vv = this.getField("Stack." + String(Level)) ;
163        if (vv) {
164            vv.value = s ;
165            this.dirty = false ;
166        }
167    }
168
169 // console.println("preamble loaded: housekeeping") ;
170\stopJSpreamble
171
172\startJSpreamble {handling} used now
173
174    function do_enter () {
175        do_update() ;
176        var vv = this.getField("Stack." + String(Level)) ;
177        if ((vv.value!=Stack[Level]) && (String(vv.value).search(/>/)==-1)) {
178            do_push (vv.value) ;
179        } else {
180            do_push (Stack[Level]) ;
181        }
182    }
183
184    function do_push_A (Value) {
185        do_update() ;
186        Stack[Level] = String(Value) ;
187        do_parse(Level) ;
188        if (String(Stack[Level])!="") {
189            if (Level<MaxLevel) {
190                ++Level ;
191                do_mark (ErrorString) ;
192            } else {
193                for (var i=MinLevel ; i<MaxLevel ; i++) {
194                    Stack[i] = Stack[i+1] ;
195                }
196                Stack[MaxLevel] = "" ;
197                do_refresh_all() ;
198                if (String(Stack[MinLevel])!="") {
199                    ErrorString = ExhaustedError ;
200                }
201                do_mark (ErrorString) ;
202            }
203        }
204    }
205
206    function do_push_B (Value) {
207        do_update() ;
208        Stack[MaxLevel] = String(Value) ;
209        do_parse(MaxLevel) ;
210        if (String(Stack[MaxLevel])!="") {
211            for (var i=MinLevel ; i<MaxLevel ; i++) {
212                Stack[i] = Stack[i+1] ;
213            }
214            Stack[MaxLevel] = "" ;
215            do_refresh_all() ;
216            if (Stack[MinLevel]!="") {
217                ErrorString = ExhaustedError ;
218            }
219            do_mark (ErrorString) ;
220        }
221    }
222
223    function do_push (Value) {
224        if (Growing) {
225            do_push_A (Value) ;
226        } else {
227            do_push_B (Value) ;
228        }
229    }
230
231    function do_pop_A () {
232        do_update() ;
233        if (String(Stack[0])!="") {
234            for (var i=MaxLevel ; i>MinLevel ; i--) {
235                Stack[i] = Stack[i-1] ;
236            }
237            Stack[MinLevel] = "" ;
238            do_refresh_all() ;
239            Level = MaxLevel ;
240        } else {
241            while ((Level>1) && (String(Stack[Level])=="")) {
242                do_refresh(Level) ;
243                --Level ;
244            }
245        }
246        if (String(Stack[Level])=="") {
247            return("") ;
248        } else {
249            Value = Number(Stack[Level]) ;
250            Stack[Level] = "" ;
251            do_refresh(Level) ;
252            return(Value) ;
253        }
254    }
255
256    function do_pop_B () {
257        do_update() ;
258        if (String(Stack[MaxLevel])=="") {
259            for (var i=MaxLevel ; i>MinLevel ; i--) {
260                Stack[i] = Stack[i-1] ;
261            }
262            Stack[MinLevel] = "" ;
263            do_refresh_all() ;
264        }
265        if (String(Stack[MaxLevel])=="") {
266            return("") ;
267        } else {
268            Value = Number(Stack[MaxLevel]) ;
269            Stack[MaxLevel] = "" ;
270            return(Value) ;
271        }
272    }
273
274    function do_pop () {
275        if (Growing) {
276            return(do_pop_A()) ;
277        } else {
278            return(do_pop_B()) ;
279        }
280    }
281
282    function do_dup () {
283        var X = do_pop() ;
284        if (valid_number(X)) {
285            do_push(X) ;
286            do_push(X) ;
287        } else {
288            do_mark (ErrorString) ;
289        }
290    }
291
292    function do_parse ( i ) {
293        if (valid_number(Stack[i])) {
294            Stack[i] = parseFloat(Stack[i]) ;
295            do_refresh(i) ;
296        } else {
297            Stack[i] = "" ;
298            do_refresh(i) ;
299            do_mark (ErrorString) ;
300        }
301    }
302
303    function do_digit ( d ) {
304        Stack[Level] += String(d) ;
305        do_refresh(Level) ;
306    }
307
308    function valid_number ( x ) {
309        if (String(x) == "") {
310            ErrorString = NoValueError ;
311            return(false) ;
312        } else if (isNaN(x)) {
313            ErrorString = NoValueError ;
314            return(false) ;
315        } else if (isFinite(x)) {
316            ErrorString = NoErrorFound ;
317            return(true) ;
318        } else {
319            ErrorString = OverflowError ;
320            return(false) ;
321        }
322    }
323
324 // console.println("preamble loaded: handling") ;
325
326\stopJSpreamble
327
328\startJSpreamble {operations} used now
329
330    function do_calculate (Operator) {
331        do_enter() ;
332        var Y = do_pop() ;
333        var X = 0 ;
334        if (valid_number(Y)) {
335            X = do_pop() ;
336            if (valid_number(X)) {
337                switch (Number(Operator)) {
338                    case 1 :
339                        if (Y) {
340                            X /= Y ;
341                        }
342                        break ;
343                    case 2 :
344                        X *= Y ;
345                        break ;
346                    case 3 :
347                        X -= Y ;
348                        break ;
349                    case 4 :
350                        X += Y ;
351                        break ;
352                    case 5 :
353                        X = Math.max(X,Y) ;
354                        break ;
355                    case 6 :
356                        X = Math.min(X,Y) ;
357                        break ;
358                    case 7 :
359                        X = Math.pow(X,Y) ;
360                        break
361                }
362                do_push(X) ;
363            } else {
364                do_push(Y) ;
365                ErrorString = NoValueError ;
366            }
367        }
368        do_mark(ErrorString) ;
369    }
370
371 // console.println("preamble loaded: operations") ;
372\stopJSpreamble
373
374\startJSpreamble {functions} used now
375
376    function do_facultate (Value) {
377        var n = Math.min(Math.round(Value),500) ;
378        if (n <= 1) {
379            return(1) ;
380        } else {
381            var m = 1 ;
382            for (m=1, i=1 ; i<=n ; i++) {
383                m = m * i ;
384            }
385            return(m) ;
386        }
387    }
388
389    function do_constant (Operation) {
390        do_update() ;
391        switch (Number(Operation)) {
392            case 1 :
393                do_push(Math.PI) ;
394                break ;
395            case 2 :
396                do_push(Math.E) ;
397                break ;
398            case 3 :
399                do_push(Math.random(1)) ;
400                break ;
401            case 4 :
402                do_dup() ;
403                break ;
404        }
405    }
406
407    function do_do_memory (mv, Sign) {
408        var X = do_pop() ;
409        if (valid_number(X)) {
410            mv.value += Sign*X ;
411            if (!valid_number(mv.value)) {
412                mv.value = "" ;
413            }
414            this.dirty = false ;
415        }
416        do_mark(ErrorString) ;
417    }
418
419    function do_memory (Operation) {
420        var mv = this.getField("Stats.mem") ;
421        if (mv) {
422            switch (Number(Operation)) {
423                case 1 :
424                    mv.value = "" ;
425                    break ;
426                case 2 :
427                    do_do_memory(mv, 1) ;
428                    break ;
429                case 3 :
430                    do_do_memory(mv, -1) ;
431                    break ;
432                case 4 :
433                    if (mv.value == "") {
434                        ErrorString = NoValueError ;
435                        do_mark(ErrorString) ;
436                    } else {
437                        do_push(mv.value) ;
438                    }
439                   break ;
440               }
441            this.dirty = false ;
442        }
443    }
444
445    function do_operation (Operator) {
446        do_enter() ;
447        var X = do_pop() ;
448        if (valid_number(X)) {
449            switch (Number(Operator)) {
450                case  1 :
451                    do_push(Math.sin(X)) ;
452                    break ;
453                case  2 :
454                    do_push(Math.cos(X)) ;
455                    break ;
456                case  3 :
457                    do_push(Math.tan(X)) ;
458                    break ;
459                case  4 :
460                    do_push(Math.exp(X)) ;
461                    break ;
462                case  5 :
463                    do_push(Math.ceil(X)) ;
464                    break ;
465                case  6 :
466                    do_push(Math.pow(X,2)) ;
467                    break ;
468                case  7 :
469                    do_push(do_facultate(X)) ;
470                        break ;
471                case  8 :
472                    do_push(Math.asin(X)) ;
473                        break ;
474                case  9 :
475                    do_push(Math.acos(X)) ;
476                    break ;
477                case 10 :
478                    do_push(Math.atan(X)) ;
479                    break ;
480                case 11 :
481                    do_push(Math.log(X)) ;
482                    break ;
483                case 12 :
484                    do_push(Math.floor(X)) ;
485                    break ;
486                case 13 :
487                    do_push(Math.sqrt(X)) ;
488                    break ;
489                case 14 :
490                    do_push(Math.round(X)) ;
491                    break ;
492                case 15 :
493                    do_push(Math.pow(X,-1)) ;
494                    break ;
495                case 16 :
496                    do_push(X*(2*Math.PI/360)) ;
497                    break ;
498                case 17 :
499                    do_push(X/(2*Math.PI/360)) ;
500                    break ;
501                case 18 :
502                    do_push(-X) ;
503                    break ;
504            }
505        }
506        do_mark(ErrorString) ;
507    }
508
509 // console.println("preamble loaded: functions") ;
510\stopJSpreamble
511
512\startJSpreamble {statistics} used now
513
514    var s_min_max = 1 ;
515    var s_sqrt    = 0 ;
516
517    function do_statcalcs (Sign, X) {
518        s_n.value     += Sign ;
519        s_sqrt        += Sign*X*X ;
520        s_total.value += Sign*X ;
521        s_mean.value   = s_total.value / s_n.value ;
522        s_temp         = Math.max(s_sqrt - 2*s_total.value*s_mean.value +
523                         s_n.value*s_mean.value*s_mean.value, 0) ;
524        s_sdev.value   = Math.sqrt(s_temp/s_n.value) ;
525        if (!(valid_number(X) && valid_number(s_sqrt) &&
526            valid_number(s_sdev.value) && valid_number(s_total.value) &&
527            valid_number(s_mean.value))) {
528                do_statistics(1) ;
529            }
530        this.dirty = false ;
531    }
532
533    function do_statistics(Operator) {
534        var s_n     = this.getField("Stats.n")     ;
535        var s_min   = this.getField("Stats.min")   ;
536        var s_max   = this.getField("Stats.max")   ;
537        var s_total = this.getField("Stats.total") ;
538        var s_mean  = this.getField("Stats.mean")  ;
539        var s_sdev  = this.getField("Stats.sdev")  ;
540        if ((s_sqrt==0) && (s_n.value!="") && (s_n.value>0)) {
541            s_min_max = 1 ;
542            s_sqrt = s_n.value*s_sdev.value*s_sdev.value +
543                     2*s_total.value*s_mean.value -
544                     s_n.value*s_mean.value*s_mean.value ;
545         }
546        switch (Number(Operator)) {
547            case 1 :
548                s_min_max     =  1 ;
549                s_n.value     = "" ;
550                s_min.value   = "" ;
551                s_max.value   = "" ;
552                s_total.value = "" ;
553                s_mean.value  = "" ;
554                s_sdev.value  = "" ;
555                s_sqrt        =  0 ;
556                break ;
557          case 2 :
558                do_enter() ;
559                var X = do_pop() ;
560                if (valid_number(X)) {
561                    if (s_n.value=="") {
562                        s_n.value     = 0 ;
563                        s_total.value = 0 ;
564                        s_mean.value  = 0 ;
565                        if (s_min_max) {
566                            s_min.value = X ;
567                            s_max.value = X ;
568                       }
569                    } else {
570                        if ((s_min_max) && (X<s_min.value)) {
571                            s_min.value = X ;
572                        }
573                        if ((s_min_max) && (X>s_max.value)) {
574                            s_max.value = X ;
575                        }
576                    }
577                   do_statcalcs(1,X) ;
578                }
579                break ;
580          case 3 :
581                do_enter() ;
582                var X = do_pop() ;
583                if (valid_number(X)) {
584                    s_min.value = "" ;
585                    s_max.value = "" ;
586                    s_min_max   =  0 ;
587                    if (s_n.value>0) {
588                        do_statcalcs(-1,X) ;
589                    } else {
590                        do_statistics(1) ;
591                    }
592                }
593                break ;
594        }
595        do_mark(ErrorString) ;
596        this.dirty = false ;
597    }
598
599    function do_copystat (Field) {
600        var sv = this.getField("Stats.".concat(Field)) ;
601        do_push(sv.value) ;
602    }
603
604 // console.println("preamble loaded: statistics") ;
605\stopJSpreamble
606
607\startJSpreamble {initialization} used now
608    do_reset_all() ;
609    do_update() ;
610    do_refresh_all() ;
611    do_mark (NoErrorFound) ;
612
613 // console.println("preamble loaded: initialization") ;
614\stopJSpreamble
615
616%D We could use functions instead but this demonstrates inline
617%D code. We also could use predefined references.
618
619\startJScode{period}
620    if (Stack[Level].search(/[.|e]/)==-1) {
621        do_digit(".") ;
622    }
623\stopJScode
624
625\startJScode{sign}
626    L = Stack[Level].length ;
627    if ((L==0) || (Stack[Level].charAt(L-1)=="e")) {
628        do_digit("-") ;
629    }
630\stopJScode
631
632\startJScode{exponent}
633    L = Stack[Level].length ;
634    if ((L>0) && valid_number(Stack[Level]) && (Stack[Level].search(/[e]/)==-1)) {
635        do_digit("e") ;
636    }
637\stopJScode
638
639\startJScode{reset}
640    do_reset_all() ;
641    do_refresh_all() ;
642    do_mark (NoErrorFound) ;
643\stopJScode
644
645\startJScode{clear}
646    do_update() ;
647    Stack[Level] = String(Stack[Level]).substring(0,String(Stack[Level]).length-1) ;
648    do_refresh(Level) ;
649\stopJScode
650
651\startJScode{pop}
652    X = do_pop() ;
653    do_mark(NoErrorFound) ;
654\stopJScode
655
656\startJScode{push}
657    do_enter() ;
658\stopJScode
659
660\startJScode{grow}
661    Growing = !Growing ;
662    do_reset_all() ;
663    do_refresh_all() ;
664    do_mark (NoErrorFound) ;
665\stopJScode
666
667% graphics
668
669\startuniqueMPgraphic{page}
670    fill OverlayBox
671        withcolor .4white ;
672    draw OverlayBox enlarged -10pt
673        withpen pencircle scaled 5pt
674        withcolor .8white ;
675\stopuniqueMPgraphic
676
677\startuniqueMPgraphic{shape}
678    path p ; color c ;
679    p := OverlayBox ;
680    c := \overlaycolor ;
681    fill p withcolor c ;
682    draw p withpen pencircle scaled 1.5pt withcolor .8c ;
683\stopuniqueMPgraphic
684
685\defineoverlay [page]  [\uniqueMPgraphic{page}]
686\defineoverlay [shape] [\uniqueMPgraphic{shape}]
687
688\setupbackgrounds
689  [page]
690  [background=page]
691
692\definemeasure[ButtonWidth][\makeupwidth/15]
693
694\setupbuttons
695  [width=\measured{ButtonWidth},
696   height=\measured{ButtonWidth},
697   background=shape,
698   backgroundcolor=\MPcolor{keyboard},
699   frame=off,
700   style=,
701   color=]
702
703\setupfield
704  [Results]
705  [horizontal,frame]
706  [width=fit,
707   align={lohi},
708   height=.5\measured{ButtonWidth},
709   background=shape,
710   backgroundcolor=\MPcolor{stack},
711   frame=off]
712  [width=3.5\measured{ButtonWidth},
713   frame=off]
714  [width=3.5\measured{ButtonWidth},
715   height=.45\measured{ButtonWidth},
716   option=readonly,
717   frame=off]
718
719\starttexdefinition unexpanded Star
720    \lower.65ex\hbox {
721        *
722    }
723\stoptexdefinition
724
725\starttexdefinition unexpanded InfoButton #1
726    \setbox\scratchbox\hbox {
727        \lower .5cm \hbox {
728            \button [
729                     width=\dimexpr\overlaywidth  + .5cm\relax,
730                    height=\dimexpr\overlayheight + .5cm\relax,
731                     strut=no,
732                     frame=off,
733                background=
734            ] {
735            } [
736                info:#1
737            ]
738        }
739    }
740    \wd\scratchbox\overlaywidth
741    \ht\scratchbox\overlayheight
742    \box\scratchbox
743\stoptexdefinition
744
745\starttexdefinition unexpanded SomeKey #1#2#3
746
747    \bgroup
748
749    \doifelsenothing {#2} {
750        \button[background=]{#2}[#3]
751    } {
752        \defineoverlay
753            [infobutton]
754            [\InfoButton{#1}]
755      % \button
756      %   [background={infobutton,shape}]
757      %   {#2}
758      %   [#3]
759        \framed
760           [offset=overlay,
761            frame=off,
762            background=infobutton,
763            backgroundcolor=red]
764           {\button{#2}[#3]}
765    }
766
767    \egroup
768
769    \ignorespaces
770
771\stoptexdefinition
772
773\starttexdefinition unexpanded StatField #1
774    \hbox \bgroup
775        \doifelsenothing {#1} {
776            \framed [
777                height=.5\measured{ButtonWidth},
778                width=3.5\measured{ButtonWidth},
779                frame=off
780            ] {
781            }
782        } {
783            \definefield[Stats.#1][line][Results]
784            \field[Stats.#1][option=readonly]
785        }
786    \egroup
787    \ignorespaces
788\stoptexdefinition
789
790\setbox\scratchboxone=\hbox to .4\makeupwidth \bgroup
791    \ss
792    \SomeKey {7}      {\ssb 7}     {JS(do_digit{7})}     \hss
793    \SomeKey {8}      {\ssb 8}     {JS(do_digit{8})}     \hss
794    \SomeKey {9}      {\ssb 9}     {JS(do_digit{9})}     \hss
795    \SomeKey {div}    {\ssb /}     {JS(do_calculate{1})} \hss
796    \SomeKey {del}    {del}        {JS(clear)}
797\egroup
798
799\setbox\scratchboxtwo=\hbox to \wd\scratchboxone \bgroup
800    \ss
801    \SomeKey {4}      {\ssb 4}     {JS(do_digit{4})}     \hss
802    \SomeKey {5}      {\ssb 5}     {JS(do_digit{5})}     \hss
803    \SomeKey {6}      {\ssb 6}     {JS(do_digit{6})}     \hss
804    \SomeKey {mul}    {\ssb \Star} {JS(do_calculate{2})} \hss
805    \SomeKey {E}      {E}          {JS(exponent)}
806\egroup
807
808\setbox\scratchboxthree=\hbox to \wd\scratchboxone \bgroup
809    \ss
810    \SomeKey {1}      {\ssb 1}     {JS(do_digit{1})}     \hss
811    \SomeKey {2}      {\ssb 2}     {JS(do_digit{2})}     \hss
812    \SomeKey {3}      {\ssb 3}     {JS(do_digit{3})}     \hss
813    \SomeKey {sub}    {\ssb --}    {JS(do_calculate{3})} \hss
814    \SomeKey {pop}    {pop}        {JS(pop)}
815\egroup
816
817\setbox\scratchboxfour=\hbox to \wd\scratchboxone \bgroup
818    \ss
819    \SomeKey {0}      {\ssb 0}     {JS(do_digit{0})}     \hss
820    \SomeKey {period} {\ssb .}     {JS(period)}          \hss
821    \SomeKey {sign}   {\ssb -}     {JS(sign)}            \hss
822    \SomeKey {add}    {\ssb +}     {JS(do_calculate{4})} \hss
823    \SomeKey {push}   {push}       {JS(push)}
824\egroup
825
826\setbox\scratchboxone=\vbox to .8\wd\scratchboxone \bgroup
827    \box\scratchboxone  \vss
828    \box\scratchboxtwo  \vss
829    \box\scratchboxthree\vss
830    \box\scratchboxfour
831\egroup
832
833\setbox\scratchboxtwo=\vbox to \ht\scratchboxone \bgroup
834    \dostepwiserecurse {\MaxLevel} {1} {-1} {
835        \definefield[Stack.\recurselevel][line][Results]
836        \hbox \bgroup
837            \field[Stack.\recurselevel][option=readonly]%
838        \egroup
839        \vfill
840    }
841    \unskip
842\egroup
843
844\setbox\scratchboxthree=\vbox to \ht\scratchboxone \bgroup
845    \StatField {n}     \vfill
846    \StatField {min}   \vfill
847    \StatField {max}   \vfill
848    \StatField {total} \vfill
849    \StatField {mean}  \vfill
850    \StatField {sdev}  \vfill
851    \StatField {}      \vfill
852    \StatField {}
853\egroup
854
855\setbox\scratchboxfour=\vbox to \ht\scratchboxone \bgroup
856   \ss\setstrut
857   \setupbuttons
858     [width=\measured{ButtonWidth},
859      height=.5\measured{ButtonWidth},
860      backgroundcolor=\MPcolor{action}]%
861   \SomeKey {sn}     {n}     {JS(do_copystat{n})}     \vfill
862   \SomeKey {smin}   {min}   {JS(do_copystat{min})}   \vfill
863   \SomeKey {smax}   {max}   {JS(do_copystat{max})}   \vfill
864   \SomeKey {stotal} {total} {JS(do_copystat{total})} \vfill
865   \SomeKey {smean}  {mean}  {JS(do_copystat{mean})}  \vfill
866   \SomeKey {ssdev}  {sdev}  {JS(do_copystat{sdev})}  \vfill
867   \SomeKey {}       {}      {}                       \vfill
868   \SomeKey {}       {}      {}
869\egroup
870
871\setbox\scratchboxone=\hbox to \hsize \bgroup
872    \box\scratchboxone  \hss
873    \box\scratchboxtwo  \hss
874    \box\scratchboxthree\hss
875    \box\scratchboxfour
876\egroup
877
878\setupbuttons
879  [width=1.5cm,
880   height=1cm,
881   backgroundcolor=\MPcolor{action}]
882
883\setbox\scratchboxtwo=\hbox to \wd\scratchboxone \bgroup
884    \ss\setstrut
885    \SomeKey {sin}  {sin}       {JS(do_operation{1})}  \hss
886    \SomeKey {cos}  {cos}       {JS(do_operation{2})}  \hss
887    \SomeKey {tan}  {tan}       {JS(do_operation{3})}  \hss
888    \SomeKey {max}  {max}       {JS(do_calculate{5})}  \hss
889    \SomeKey {exp}  {exp}       {JS(do_operation{4})}  \hss
890    \SomeKey {ceil} {ceil}      {JS(do_operation{5})}  \hss
891    \SomeKey {sqr}  {x\high{2}} {JS(do_operation{6})}  \hss
892    \SomeKey {fac}  {x!}        {JS(do_operation{7})}  \hss
893    \SomeKey {pow}  {x\high{y}} {JS(do_calculate{7})}  \hss
894    \SomeKey {rad}  {rad}       {JS(do_operation{16})}
895\egroup
896
897\setbox\scratchboxthree=\hbox to \wd\scratchboxone \bgroup
898    \ss\setstrut
899    \SomeKey {asin} {asin}   {JS(do_operation{8})}     \hss
900    \SomeKey {acos} {acos}   {JS(do_operation{9})}     \hss
901    \SomeKey {atan} {atan}   {JS(do_operation{10})}    \hss
902    \SomeKey {min}  {min}    {JS(do_calculate{6})}     \hss
903    \SomeKey {ln}   {ln}     {JS(do_operation{11})}    \hss
904    \SomeKey {floor}{floor}  {JS(do_operation{12})}    \hss
905    \SomeKey {sqrt} {sqrt}   {JS(do_operation{13})}    \hss
906    \SomeKey {round}{round}  {JS(do_operation{14})}    \hss
907    \SomeKey {inv}  {1/x}    {JS(do_operation{15})}    \hss
908    \SomeKey {deg}  {deg}    {JS(do_operation{17})}
909\egroup
910
911\setbox\scratchboxfour=\hbox to \wd\scratchboxone \bgroup
912   \ss\setstrut
913   \SomeKey {}     {}       {}                     \hss
914   \SomeKey {}     {}       {}                     \hss
915   \setupbuttons
916     [backgroundcolor=\MPcolor{keyboard}]%
917   \SomeKey {new}  {new}    {JS(reset)}            \hss
918   \SomeKey {}     {}       {}                     \hss
919   \SomeKey {}     {}       {}                     \hss
920   \SomeKey {}     {}       {}                     \hss
921   \SomeKey {}     {}       {}                     \hss
922   \SomeKey {newn} {new}    {JS(do_statistics{1})} \hss
923   \SomeKey {addn} {+n}     {JS(do_statistics{2})} \hss
924   \SomeKey {subn} {--n}    {JS(do_statistics{3})}
925\egroup
926
927\setbox\scratchboxfive=\hbox to \wd\scratchboxone \bgroup
928    \ss\setstrut
929    \SomeKey {neg}   {--x}    {JS(do_operation{18})} \hss
930    \SomeKey {random}{random} {JS(do_constant{3})}   \hss
931    \SomeKey {pi}    {pi}     {JS(do_constant{1})}   \hss
932    \SomeKey {e}     {e}      {JS(do_constant{2})}   \hss
933    \SomeKey {dup}   {dup}    {JS(do_constant{4})}   \hss
934    \SomeKey {}      {}       {}                     \hss
935    \SomeKey {}      {}       {}                     \hss
936    \setupbuttons
937      [backgroundcolor=\MPcolor{keyboard}]%
938    \SomeKey {}      {}       {}                     \hss
939    \SomeKey {exit}  {exit}   {CloseDocument}        \hss
940    \SomeKey {help}  {info}   {info:help}
941\egroup
942
943\setbox\scratchboxsix=\hbox to \wd\scratchboxone \bgroup
944    \ss\setstrut
945    \setupbuttons
946      [width=\measured{ButtonWidth},
947       height=.5\measured{ButtonWidth},
948       backgroundcolor=\MPcolor{keyboard}]%
949    \SomeKey   {newmem} {new}  {JS(do_memory{1})} \hss
950    \SomeKey   {addmem} {+m}   {JS(do_memory{2})} \hss
951    \SomeKey   {submem} {--m}  {JS(do_memory{3})} \hss
952    \StatField {mem}                              \hss
953    \setupbuttons
954      [backgroundcolor=\MPcolor{action}]%
955    \SomeKey   {copmem} {mem}  {JS(do_memory{4})} \hss
956    \SomeKey   {} {}    {}                        \hss
957    \setupbuttons
958      [backgroundcolor=\MPcolor{stack}]%
959    \SomeKey   {grow}   {grow} {JS(grow)}         \hss
960    \StatField {}
961\egroup
962
963\startstandardmakeup
964
965    \pagereference[calculator]
966
967    \vfill
968
969    \hbox to \hsize \bgroup
970        \hss
971        \vbox to \vsize \bgroup
972            \box\scratchboxtwo  \vss
973            \box\scratchboxthree\vss
974            \box\scratchboxone  \vss
975            \box\scratchboxfour \vss
976            \box\scratchboxfive \vss
977            \box\scratchboxsix
978        \egroup
979        \hss
980    \egroup
981
982    \vfill
983
984\stopstandardmakeup
985
986\starttexdefinition unexpanded BackgroundButton
987    \button [
988              background=screen,
989        backgroundscreen=.8,
990        backgroundoffset=5pt,
991                  height=\vsize,
992                   width=\hsize
993    ] {
994    } [
995        calculator
996    ]
997\stoptexdefinition
998
999\setuptexttexts
1000  [\BackgroundButton]
1001  []
1002
1003\starttexdefinition unexpanded Key #1#2
1004    \goto {
1005        \ss#1
1006    } [
1007        info:#2
1008    ]
1009\stoptexdefinition
1010
1011\startstandardmakeup[top=,bottom=]
1012
1013    \switchtobodyfont[8pt]
1014
1015    \start
1016
1017    \setupwhitespace[big]
1018
1019    \midaligned{\ssd The Calculator}
1020
1021    \blank[2*big]
1022
1023    \pagereference[info:help]
1024    This calculator is stack based, which means that one enters values and
1025    invokes an action that acts on the value(s) last entered. Subtracting 10 from
1026    20 using (\Key {--} {sub}) for instance comes down to clicking:
1027
1028    \startnarrower\ss
1029        10\quad in\quad 20\quad --
1030    \stopnarrower
1031
1032    while calculating a sinus (\Key {sin} {sin}) results from entering:
1033
1034    \startnarrower\ss
1035        .89\quad sin
1036    \stopnarrower
1037
1038    The left column of fields (numbers) shows the Stack. One uses \Key {push}
1039    {push} to push a value on the stack and \Key {pop} {pop} to remove a value.
1040    Clicking \Key {new} {new} removes them all and the \Key {del} {del} button
1041    can be used to undo the last entered digit. When a dyadic operation is
1042    applied, the top value is used as~y. The \Key {grow} {grow} key toggles
1043    between two different visualizations of the stack.
1044
1045    The stack is considerably larger than the screen representation suggests. In
1046    the rare occasion that one encounters the message {\ss exhausted}, the amount
1047    of stack entries already has totaled far beyond \MinLevel\ and one probably
1048    already has forgotten what the values first entered represent.
1049
1050    The right column of fields reports the statistic calculations. By clicking on
1051    the tag, one pushes the value on the Stack. The lower buttons are used to
1052    reset~(\Key {new} {newn}), enter~(\Key {+} {addn}) and remove~(\Key {--}
1053    {subn}) values to be taken into account when calculating those statistics.
1054
1055    This document is produced by \ConTeXt, a macro package written in \TeX. The
1056    graphics are METAPOST graphics. The graphics, the PDF objects and the form
1057    fields as well as JavaScript code were generated and inserted at run time.
1058    Originally we used PDF\TeX\ and \MKII\ to process this document but this one
1059    is done by \LUATEX\ and \MKIV. We kept the design and code original so that
1060    it reflects how things were done (for readability we updated some \TEX\
1061    definitions).
1062
1063    \stop
1064
1065    \vfilll
1066
1067    \startMPrun
1068        logo_type := 302 ; % force single logo type
1069        mpgraph := 302 ;   % and use this number
1070        input mp-prag ;    % calculate logo of type
1071    \stopMPrun
1072
1073    \startlinecorrection
1074        \midaligned{\externalfigure[mprun.302][height=1.5cm]}
1075    \stoplinecorrection
1076
1077    \midaligned{\strut Hans Hagen, PRAGMA ADE, \ConTeXt\ 18/2/1998--25/9/2018}
1078
1079    \blank
1080
1081    \midaligned{\strut\url[pragma-mail]}
1082
1083\stopstandardmakeup
1084
1085\starttexdefinition unexpanded BackgroundButton
1086    \button [
1087        background=screen,
1088        backgroundscreen=.8,
1089        backgroundoffset=5pt,
1090        height=\vsize,
1091        width=\hsize
1092    ] {
1093    } [
1094        firstpage
1095    ]
1096\stoptexdefinition
1097
1098\starttexdefinition unexpanded ShowInfo #1#2
1099    \startstandardmakeup
1100        \pagereference[info:#1]
1101        \vfill
1102        \hbox to \hsize \bgroup
1103            \hss
1104            \useMPgraphic{#1}
1105            \hss
1106        \egroup
1107        \blank[2*big]
1108        \midaligned{#2}
1109        \vfill
1110    \stopstandardmakeup
1111\stoptexdefinition
1112
1113\startMPinclusions
1114
1115    path ax, ay, p[] ;
1116    color c ; c := \MPcolor{action} ;
1117    pmax := 0 ;
1118
1119    let normalpow = pow ;
1120
1121    def draw_function (text fun) (expr xmin, xmax, xstep) =
1122        pmax := pmax+1 ;
1123        p[pmax] := for x=xmin step xstep until xmax:
1124            (x,fun(x)) ..
1125        endfor (xmax,fun(xmax)) ;
1126    enddef ;
1127
1128    def draw_axis = % should sort of snap, to-do
1129        pickup pencircle scaled 0 ;
1130        for i=1 upto pmax:
1131            draw p[i] ;
1132        endfor ;
1133        xmin := xpart llcorner currentpicture ;
1134        xmax := xpart urcorner currentpicture ;
1135        ymin := ypart llcorner currentpicture ;
1136        ymax := ypart urcorner currentpicture ;
1137        ax := (xmin,0)--(0,0)--(xmax,0) ;
1138        ay := (0,ymin)--(0,0)--(0,ymax) ;
1139        currentpicture := nullpicture ;
1140        sx := 400/(xmax-xmin) ;
1141        sy := 250/(ymax-ymin) ;
1142        pickup pencircle xscaled (10/sx) yscaled (10/sy) ;
1143        draw ax withcolor .4white ;
1144        draw ay withcolor .4white ;
1145        for i=1 upto pmax:
1146            draw p[i] withcolor c ;
1147        endfor ;
1148        currentpicture := currentpicture xscaled sx yscaled sy ;
1149        pmax := 0 ;
1150  enddef ;
1151
1152\stopMPinclusions
1153
1154\startuseMPgraphic{sin}
1155    draw_function(sind)(-360,360,60) ; draw_axis ;
1156\stopuseMPgraphic
1157
1158\ShowInfo{sin}{Calculate the sine of the topmost stack entry.}
1159
1160\startuseMPgraphic{cos}
1161    draw_function(cosd)(-360,360,60) ; draw_axis ;
1162\stopuseMPgraphic
1163
1164\ShowInfo{cos}{Calculate the cosine of the topmost stack entry.}
1165
1166\startuseMPgraphic{tan}
1167    draw_function(tand)(-240,-120,30) ;
1168    draw_function(tand)( -60,  60,30) ;
1169    draw_function(tand)( 120, 240,30) ;
1170    draw_axis ;
1171\stopuseMPgraphic
1172
1173\ShowInfo{tan}{Calculate the tangent of the topmost stack entry.}
1174
1175\startuseMPgraphic{asin}
1176    draw_function(asin)(-1,1,.2) ; draw_axis ;
1177\stopuseMPgraphic
1178
1179\ShowInfo{asin}{Calculate the arcsine of the topmost stack entry.}
1180
1181\startuseMPgraphic{acos}
1182    draw_function(acos)(-1,1,.2) ; draw_axis ;
1183\stopuseMPgraphic
1184
1185\ShowInfo{acos}{Calculate the arccosine of the topmost stack entry.}
1186
1187\startuseMPgraphic{atan}
1188    draw_function(atan)(-1,1,.2) ; draw_axis ;
1189\stopuseMPgraphic
1190
1191\ShowInfo{atan}{Calculate the arctangent of the topmost stack entry.}
1192
1193\startuseMPgraphic{sqr}
1194    draw_function(sqr)(-3,3,1) ; draw_axis ;
1195\stopuseMPgraphic
1196
1197\ShowInfo{sqr}{Calculate the square of the topmost stack entry.}
1198
1199\startuseMPgraphic{sqrt}
1200    draw_function(sqrt)(0,5,1) ; draw_axis ;
1201\stopuseMPgraphic
1202
1203\ShowInfo{sqrt}{Calculate the square root of the topmost stack entry.}
1204
1205\startuseMPgraphic{exp}
1206    draw_function(exp)(0,5,1) ; draw_axis ;
1207\stopuseMPgraphic
1208
1209\ShowInfo{exp}{Calculate the exponential function of the topmost stack entry.}
1210
1211\startuseMPgraphic{ln}
1212    draw_function(ln)(0,50,5) ; draw_axis ;
1213\stopuseMPgraphic
1214
1215\ShowInfo{ln}{Calculate the natural logaritm of the topmost stack entry.}
1216
1217\startuseMPgraphic{pow}
1218    vardef mypow(expr n) = 3**n enddef ;
1219    draw_function(mypow)(-3,3,.5) ; draw_axis ;
1220\stopuseMPgraphic
1221
1222\ShowInfo{pow}{Calculate x\high{y} where y is the topmost stack entry.}
1223
1224\startuseMPgraphic{inv}
1225    draw_function(inv)(-10,10,1) ; draw_axis ;
1226\stopuseMPgraphic
1227
1228\ShowInfo{inv}{Calculate 1/x using the topmost stack entry.}
1229
1230\startMPinclusions
1231
1232    def draw_statistics (expr ShowNew, ShowAdd, ShowSubtract, ShowN, ShowSum, ShowMin, ShowMax, ShowMean, ShowSdev) =
1233        color c ; c := \MPcolor{action} ;
1234        Delta := 20 ;
1235        Total := 100 ;
1236        Range := 24 ;
1237        Sum   := 0 ;
1238        Sqr   := 0 ;
1239        randomseed := .5 ;
1240        pickup pencircle scaled .5Delta ;
1241        for r := 0 upto Range:
1242            Value[r] := 0 ;
1243        endfor ;
1244        for i=1 upto Total:
1245            r := uniformdeviate 1 ;
1246            Sum := Sum + r ;
1247            Sqr := Sqr + r*r ;
1248            r := round(r*Range) ;
1249            Value[r] := Value[r]+1 ;
1250        endfor ;
1251        Mean := Sum/Total ;
1252        Sdev := sqrt((Sqr-2*Sum*Mean+Total*Mean*Mean)/Total) ;
1253        Mean := Mean*Range ;
1254        Sdev := Sdev*Range ;
1255        SdevMin := Mean-Sdev ;
1256        SdevMax := Mean+Sdev ;
1257        for r := 0 upto Range:
1258            draw (r*Delta,0)--(r*Delta,Value[r]*Delta)
1259                withcolor
1260                    if (ShowSdev and (r>SdevMin) and (r<SdevMax)) or ShowSum or
1261                        (ShowMin and (r=0)) or (ShowMax and (r=Range)) or
1262                        (ShowMean and (r=round(Mean)) or ShowSubtract) :
1263                        c
1264                    else :
1265                        .4white
1266                    fi ;
1267            if ShowN:
1268                draw (r*Delta,0) withcolor c
1269            fi ;
1270        endfor ;
1271        if ShowAdd or ShowNew:
1272            pushboundingbox currentpicture ;
1273            currentpicture := nullpicture ;
1274            for r := 0 upto Range:
1275                draw (r*Delta,0) withcolor .4white ;
1276            endfor ;
1277            if ShowAdd:
1278                draw (5*Delta,0) withcolor c ;
1279            fi ;
1280            popboundingbox currentpicture ;
1281        elseif ShowSubtract:
1282            draw (5*Delta,0) withcolor .4white ;
1283        fi ;
1284    enddef ;
1285
1286\stopMPinclusions
1287
1288\startuseMPgraphic{addn}
1289    draw_statistics (false, true, false, false, false, false, false, false, false) ;
1290\stopuseMPgraphic
1291
1292\ShowInfo{addn}{Add an observation to the statistics.}
1293
1294\startuseMPgraphic{subn}
1295    draw_statistics (false, false, true, false, false, false, false, false, false) ;
1296\stopuseMPgraphic
1297
1298\ShowInfo{subn}{Remove an observation from the statistics.}
1299
1300\startuseMPgraphic{newn}
1301    draw_statistics (true, false, false, false, false, false, false, false, false) ;
1302\stopuseMPgraphic
1303
1304\ShowInfo{newn}{Reset the statistics.}
1305
1306\startuseMPgraphic{sn}
1307    draw_statistics (false, false, false, true, false, false, false, false, false) ;
1308\stopuseMPgraphic
1309
1310\ShowInfo{sn}{Push the number of observations to the stack.}
1311
1312\startuseMPgraphic{stotal}
1313    draw_statistics (false, false, false, false, true, false, false, false, false) ;
1314\stopuseMPgraphic
1315
1316\ShowInfo{stotal}{Push the sum of encountered values to the stack.}
1317
1318\startuseMPgraphic{smin}
1319    draw_statistics (false, false, false, false, false, true, false, false, false) ;
1320\stopuseMPgraphic
1321
1322\ShowInfo{smin}{Push the lowest encountered value to the stack.}
1323
1324\startuseMPgraphic{smax}
1325    draw_statistics (false, false, false, false, false, false, true,  false, false) ;
1326\stopuseMPgraphic
1327
1328\ShowInfo{smax}{Push the highest encountered value to the stack.}
1329
1330\startuseMPgraphic{smean}
1331    draw_statistics (false, false, false, false, false, false, false, true,  false) ;
1332\stopuseMPgraphic
1333
1334\ShowInfo{smean}{Push the mean value to the stack.}
1335
1336\startuseMPgraphic{ssdev}
1337    draw_statistics (false, false, false, false, false, false, false, false, true) ;
1338\stopuseMPgraphic
1339
1340\ShowInfo{ssdev}{Push the standard deviation to the stack.}
1341
1342\startMPinclusions
1343
1344    def draw_ranges (expr ShowNegate, ShowCeiling, ShowFloor, ShowRound, ShowMin, ShowMax, ShowE) =
1345
1346        color c ; c := \MPcolor{action} ;
1347
1348        Tics   := 5 ;
1349        Gap    := 5Tics ;
1350        Height := .5Gap ;
1351        Place  := 3 ;
1352
1353        pickup pencircle scaled 10 ;
1354
1355        for i=-Tics upto Tics:
1356            draw (i*Gap,-Height)--(i*Gap,Height) withcolor .4white ;
1357        endfor ;
1358
1359        draw (-Tics*Gap,0)--(Tics*Gap,0) withcolor .4white ;
1360        draw (0,-2Height)--(0,2Height) withcolor .4white ;
1361
1362        z1 = (Place*Gap,0) ;
1363        z2 = ((Place+1)*Gap,0) ;
1364
1365        if ShowNegate:
1366            draw (x1,-Height)--(x1,Height) withcolor c ;
1367            draw (-x1,-0)--(-x1,0) withcolor c ;
1368        elseif ShowCeiling:
1369            draw (x2,-Height)--(x2,Height) withcolor c ;
1370            linecap := butt ;
1371            draw z1--z2 withcolor c ;
1372        elseif ShowFloor:
1373            draw (x1,-Height)--(x1,Height) withcolor c ;
1374            linecap := butt ;
1375            draw z1--z2 withcolor c ;
1376        elseif ShowRound:
1377            draw (x2,-Height)--(x2,Height) withcolor c ;
1378            linecap := butt ;
1379            draw .5[z1,z2]--z2 withcolor c ;
1380        elseif ShowMin:
1381            draw (x1,-Height)--(x1,Height) withcolor c ;
1382            draw (x2,0)--(x2,0) withcolor c ;
1383        elseif ShowMax:
1384            draw (x2,-Height)--(x2,Height) withcolor c ;
1385            draw (x1,0)--(x1,0) withcolor c ;
1386        elseif ShowE:
1387            e := Gap*mexp256 ;
1388            draw (e,-3Height)--(e,3Height) withcolor c ;
1389        fi ;
1390
1391enddef ;
1392
1393\stopMPinclusions
1394
1395\startuseMPgraphic{neg}
1396    draw_ranges (true, false, false, false, false, false, false) ;
1397\stopuseMPgraphic
1398
1399\ShowInfo{neg}{Negate the topmost stack entry.}
1400
1401\startuseMPgraphic{ceil}
1402    draw_ranges (false, true, false, false, false, false, false) ;
1403\stopuseMPgraphic
1404
1405\ShowInfo{ceil}{Set the topmost stack entry to the next integer.}
1406
1407\startuseMPgraphic{floor}
1408    draw_ranges (false, false, true, false, false, false, false) ;
1409\stopuseMPgraphic
1410
1411\ShowInfo{floor}{Set the topmost stack entry to the previous integer.}
1412
1413\startuseMPgraphic{round}
1414    draw_ranges (false, false, false, true, false, false, false) ;
1415\stopuseMPgraphic
1416
1417\ShowInfo{round}{Set the topmost stack entry to the nearest integer.}
1418
1419\startuseMPgraphic{min}
1420    draw_ranges (false, false, false, false, true, false, false) ;
1421\stopuseMPgraphic
1422
1423\ShowInfo{min}{Take the minumum of the two topmost stack entries.}
1424
1425\startuseMPgraphic{max}
1426    draw_ranges (false, false, false, false, false, true, false) ;
1427\stopuseMPgraphic
1428
1429\ShowInfo{max}{Take the maximum of the two topmost stack entries.}
1430
1431\startuseMPgraphic{e}
1432    draw_ranges (false, false, false, false, false, false, true) ;
1433\stopuseMPgraphic
1434
1435\ShowInfo{e}{Push 2.71828182845905 onto the stack.}
1436
1437\startuseMPgraphic{pi}
1438    pickup pencircle scaled 10 ;
1439    draw fullcircle scaled 150 withcolor .4white ;
1440    linecap := butt ;
1441    ahlength := 25 ;
1442    drawarrow halfcircle scaled 150 withcolor \MPcolor{action} ;
1443\stopuseMPgraphic
1444
1445\ShowInfo{pi}{Push 3.14159265358979 onto the stack.}
1446
1447\startMPinclusions
1448
1449    def draw_degrees(expr DrawInner, DrawOuter) =
1450        pickup pencircle scaled .02 ;
1451        path p ; p := fullcircle ;
1452        path q ; q := subpath(0,1) of fullcircle ;
1453        path r ; r := (0,0)--q--(0,0)--cycle ;
1454        filldraw p withcolor .4white ;
1455        filldraw r withcolor \MPcolor{action} ;
1456        ahlength := .04 ;
1457        if DrawInner:
1458            drawarrow q scaled .30 withcolor .4white ;
1459        elseif DrawOuter:
1460            drawarrow q scaled .90 withcolor .4white ;
1461        fi ;
1462        currentpicture := currentpicture scaled 200 ;
1463    enddef ;
1464
1465\stopMPinclusions
1466
1467\startuseMPgraphic{deg}
1468    draw_degrees (true, false)
1469\stopuseMPgraphic
1470
1471\ShowInfo{deg}{Convert radians into degrees.}
1472
1473\startuseMPgraphic{rad}
1474    draw_degrees (false, true)
1475\stopuseMPgraphic
1476
1477\ShowInfo{rad}{Convert degrees into radians.}
1478
1479\startuseMPgraphic{random}
1480
1481    pickup pencircle scaled 5 ;
1482    color c ; c := \MPcolor{action} ;
1483    draw unitsquare scaled 100 withcolor .4white ;
1484    for i=1 upto 250:
1485    draw (uniformdeviate 90, uniformdeviate 90)
1486        shifted (5,5) withcolor (.4+uniformdeviate .6)*c ;
1487    endfor ;
1488    currentpicture := currentpicture scaled 2 ;
1489
1490\stopuseMPgraphic
1491
1492\ShowInfo{random}{Generate a random number in the range 0--1.}
1493
1494\startMPinclusions
1495
1496    def do_draw_number (expr n, drift, s, c) =
1497        numeric Height, Delta, Drift, x_max, y_max, x_pos, y_pos ;
1498        Height := 11 ;
1499        Delta :=  5 ;
1500        Drift :=  if drift: 1.5 else: 0 fi ;
1501        x_max :=  8 ;
1502        def d = (uniformdeviate Drift) enddef ;
1503        if n=0:
1504            draw ((-d-4.5Delta,d)--(+d-0.5Delta,Height-d))
1505                withpen pencircle scaled 2
1506                withcolor c ;
1507        else:
1508            for i := 1 upto n :
1509                x_pos := ((i-1) mod (5*x_max))*Delta ;
1510                y_pos := ((i-1) div (5*x_max))*(Height+Delta) ;
1511                draw
1512                    if (i mod 5)=0 :
1513                        ((-d-4.5Delta,d)--(+d-0.5Delta,Height-d))
1514                    else :
1515                        ((-d,+d)--(+d,Height-d))
1516                    fi
1517                    shifted (x_pos,-y_pos)
1518                    withpen pencircle scaled 2
1519                    withcolor c ;
1520            endfor ;
1521        fi ;
1522        currentpicture := currentpicture scaled s ;
1523    enddef ;
1524
1525    def draw_number (expr n, s) =
1526        do_draw_number(n,false,s,\MPcolor{keyboard}) ;
1527        push_boundingbox currentpicture ;
1528        currentpicture := nullpicture ;
1529        do_draw_number(n,true,s,\MPcolor{keyboard}) ;
1530        pop_boundingbox currentpicture ;
1531    enddef ;
1532
1533\stopMPinclusions
1534
1535\dostepwiserecurse {0}{9}{1} {
1536    \startuseMPgraphic{\recurselevel}
1537        draw_number(\recurselevel,10)
1538    \stopuseMPgraphic
1539    \expanded {
1540        \ShowInfo
1541            {\recurselevel}
1542            {Add a digit \recurselevel\ to the current stack entry.}%
1543    }
1544}
1545
1546\startuseMPgraphic{fac}
1547
1548    def facultate (expr n) =
1549        if n=1: 1 else: n*facultate(n-1) fi
1550    enddef ;
1551    picture pic[] ;
1552    for m := 1 upto 5:
1553        do_draw_number(facultate(m),true,1,\MPcolor{action}) ;
1554        pic[m] := currentpicture ;
1555        currentpicture := nullpicture ;
1556    endfor ;
1557    xmax := xpart urcorner pic[5] - xpart llcorner pic[5] ;
1558    for m = 1 upto 5:
1559        xmin := xpart urcorner pic[m] - xpart llcorner pic[m] ;
1560        addto currentpicture also pic[m] shifted (.5(xmax-xmin),-m*25) ;
1561    endfor ;
1562    currentpicture := currentpicture scaled 2 ;
1563
1564\stopuseMPgraphic
1565
1566\ShowInfo{fac}{Calculate the recursive multiplication of n, n--1, n--2, etc.}
1567
1568\startMPinclusions
1569
1570    def draw_template (expr ShowSign, ShowPeriod, ShowExponent, ShowDel) =
1571        pickup pencircle scaled 10 ;
1572        color ca ; ca := if (ShowDel): .4white else: \MPcolor{stack} fi ;
1573        color cb ; cb := \MPcolor{keyboard} ;
1574        Delta := 20 ;
1575        Width := 10 ;
1576        Position :=  6 ;
1577        Max := 15 ;
1578        path p ; p := (0,0)--(Width,0) ;
1579        draw (-2Width,0)--(0,0) withcolor if ShowSign: cb else: ca fi ;
1580        for i=1 upto Position-1:
1581            draw p shifted (i*Delta,0) withcolor ca ;
1582        endfor ;
1583        draw (Position*Delta+.5Width,0)
1584            withcolor if ShowPeriod: cb else: ca fi ;
1585        for i=Position+1 upto Max:
1586            if i=Max-3:
1587                draw ((Width,0)--(0,0)--(0,2Width)--(Width,2Width))
1588                    shifted (i*Delta,-2.5)
1589                    withpen pencircle scaled 5
1590                    withcolor if ShowExponent: cb else: ca fi ;
1591                draw ((0,Width)--(Width,Width))
1592                    shifted (i*Delta,-2.5)
1593                    withpen pencircle scaled 5
1594                    withcolor if ShowExponent: cb else: ca fi ;
1595            else:
1596                draw p shifted (i*Delta,0) withcolor ca ;
1597            fi ;
1598        endfor ;
1599    enddef ;
1600
1601\stopMPinclusions
1602
1603\startuseMPgraphic{sign}
1604    draw_template(true, false, false, false) ;
1605\stopuseMPgraphic
1606
1607\ShowInfo{sign}{Add a sign to the current stack entry.}
1608
1609\startuseMPgraphic{period}
1610    draw_template(false, true, false, false) ;
1611\stopuseMPgraphic
1612
1613\ShowInfo{period}{Add a period to the current stack entry.}
1614
1615\startuseMPgraphic{E}
1616    draw_template(false, false, true, false) ;
1617\stopuseMPgraphic
1618
1619\ShowInfo{E}{Start setting the exponent part of the current stack entry.}
1620
1621\startuseMPgraphic{del}
1622    draw_template(false, false, false, true) ;
1623\stopuseMPgraphic
1624
1625\ShowInfo{del}{Delete the last entered digit of the current stack entry.}
1626
1627\startMPinclusions
1628
1629    u := 50 ;
1630    logo_type := 0 ;
1631    input mp-prag ;
1632    set_phead(u) ;
1633
1634    def draw_memory (expr DrawErase, DrawAdd, DrawSubtract, DrawCopy) =
1635        pickup pencircle scaled .1u ;
1636        color ca ; ca := \MPcolor{stack} ;
1637        color cb ; cb := \MPcolor{keyboard} ;
1638        draw phead withcolor .4white ;
1639        if DrawErase:
1640            stripe_path_n
1641                (withcolor .4white)
1642                (fill) pbrain scaled .8 shifted (.5u,.5u) withcolor .8cb ;
1643        else:
1644            fill pbrain scaled .8 shifted (.5u,.5u)
1645                if DrawCopy: withcolor .8ca else: withcolor .8cb fi ;
1646        fi ;
1647        draw pbrain scaled .8 shifted (.5u,.5u) withcolor cb ;
1648        push_boundingbox currentpicture ;
1649        ahlength:=.2u ;
1650        path drain ; drain := (4.5u,2u){dir 120}..(2.25u,2.75u) ;
1651        if DrawAdd:
1652            drawarrow drain withcolor ca ;
1653        elseif DrawSubtract or DrawCopy:
1654            drawarrow reverse drain withcolor ca ;
1655        fi ;
1656        pop_boundingbox currentpicture ;
1657    enddef ;
1658
1659\stopMPinclusions
1660
1661\startuseMPgraphic{newmem}
1662    draw_memory (true,false,false,false) ;
1663\stopuseMPgraphic
1664
1665\ShowInfo{newmem}{Erase the memory buffer.}
1666
1667\startuseMPgraphic{addmem}
1668    draw_memory (false,true,false,false) ;
1669\stopuseMPgraphic
1670
1671\ShowInfo{addmem}{Add to the memory buffer.}
1672
1673\startuseMPgraphic{submem}
1674    draw_memory (false,false,true,false) ;
1675\stopuseMPgraphic
1676
1677\ShowInfo{submem}{Substract from the memory buffer.}
1678
1679\startuseMPgraphic{copmem}
1680    draw_memory (false,false,false,true) ;
1681\stopuseMPgraphic
1682
1683\ShowInfo{copmem}{Copy the memory buffer to the stack.}
1684
1685\startMPinclusions
1686
1687    def erase_stack =
1688        stripe_path_n
1689            (withcolor .4white)
1690            (fill) p withcolor .8cb ;
1691    enddef ;
1692
1693    def draw_stack (expr ShowNew, ShowPush, ShowPop, ShowDup) =
1694        path p ;
1695        color ca ; ca := \MPcolor{stack} ;
1696        color cb ; cb := \MPcolor{keyboard} ;
1697        for i=8 downto 1:
1698            j := i-1 ;
1699            pickup pencircle scaled 1.5 ;
1700            p := unitsquare
1701                shifted(-.5,-.5)
1702                xscaled 100 yscaled 40
1703                shifted(20*j,j*15)
1704                scaled (1-j*.04) ;
1705            if i<3:
1706                fill p withcolor .4white ;
1707            elseif ShowPush:
1708                fill p withcolor if i=3: .8cb else : .8ca fi ;
1709            elseif ShowPop:
1710                if i=3: erase_stack else: fill p withcolor .8ca fi ;
1711            elseif ShowNew:
1712                erase_stack ;
1713            elseif ShowDup:
1714                fill p withcolor if i>4: .8ca else: .8cb fi ;
1715            else:
1716                fill p withcolor .4white ;
1717            fi ;
1718            draw p withcolor ca ;
1719        endfor ;
1720        currentpicture := currentpicture scaled 1.5 ;
1721    enddef ;
1722
1723\stopMPinclusions
1724
1725\startuseMPgraphic{push}
1726    draw_stack (false, true, false, false)
1727\stopuseMPgraphic
1728
1729\ShowInfo{push}{Push a new entry to the stack.}
1730
1731\startuseMPgraphic{pop}
1732    draw_stack (false, false, true, false)
1733\stopuseMPgraphic
1734
1735\ShowInfo{pop}{Remove the topmost entry from the stack.}
1736
1737\startuseMPgraphic{new}
1738    draw_stack (true, false, false, false)
1739\stopuseMPgraphic
1740
1741\ShowInfo{new}{Erase the whole stack.}
1742
1743\startuseMPgraphic{dup}
1744    draw_stack (false, false, false, true)
1745\stopuseMPgraphic
1746
1747\ShowInfo{dup}{Duplicate the topmost stack entry.}
1748
1749\startMPinclusions
1750
1751    def draw_funcalc (expr p, q, r, action) =
1752
1753        color b ; b := \MPcolor{keyboard} ;
1754        color c ; c := \MPcolor{stack} ;
1755
1756        draw ((-2.25max(p,q,r))-1,0)--(-1,0) withcolor .4white ;
1757
1758        pickup pencircle scaled 2 ;
1759        for i=1 upto p: draw (-i*2.25, 3.75) withcolor c ; endfor ;
1760        for i=1 upto q: draw (-i*2.25, 1.50) withcolor c ; endfor ;
1761        for i=1 upto r: draw (-i*2.25,-1.50) withcolor c ; endfor ;
1762        pickup pencircle scaled .5 ;
1763
1764        push_boundingbox currentpicture ;
1765
1766        pair w ;   w := (1.125,0) ;
1767        path ww ; ww := -w -- w ;
1768
1769        if action=1:
1770            draw ww shifted             w withcolor b ;
1771            draw ww rotated  90 shifted w withcolor b ;
1772        elseif action=2:
1773            draw ww shifted             w withcolor b ;
1774        elseif action=3:
1775            draw ww rotated  45 shifted w withcolor b ;
1776            draw ww rotated 135 shifted w withcolor b ;
1777        elseif action=4:
1778            draw ww rotated  45 shifted w withcolor b ;
1779        fi ;
1780
1781        pop_boundingbox currentpicture ;
1782
1783        currentpicture := currentpicture scaled 15 ;
1784
1785    enddef ;
1786
1787\stopMPinclusions
1788
1789\startuseMPgraphic{add}
1790    draw_funcalc (6, 6, 7, 1)
1791\stopuseMPgraphic
1792
1793\ShowInfo{add}{Add the two topmost stack entries.}
1794
1795\startuseMPgraphic{sub}
1796    draw_funcalc (5, 4, 5, 2)
1797\stopuseMPgraphic
1798
1799\ShowInfo{sub}{Subtract the topmost stack entry from the one below.}
1800
1801\startuseMPgraphic{mul}
1802    draw_funcalc (3, 4, 7, 3)
1803\stopuseMPgraphic
1804
1805\ShowInfo{mul}{Multiply the two topmost stack entries.}
1806
1807\startuseMPgraphic{div}
1808    draw_funcalc (5, 2, 4, 4)
1809\stopuseMPgraphic
1810
1811\ShowInfo{div}{Divide the pre-last stack entry by the topmost one.}
1812
1813\startuseMPgraphic{grow}
1814
1815    pickup pencircle scaled 5 ;
1816    ahlength := 10 ;
1817
1818    path p ; p := (0,0)--(60,0) ;
1819    path q ; q := (30,2*15)--(30,7*15) ;
1820    path r ; r := (30,0)--(30,7*15) ;
1821
1822    for i=0 upto 7:
1823        draw p shifted (0,i*15) withcolor
1824            if i<3: \MPcolor{stack} else: .4white fi ;
1825    endfor ;
1826
1827    addto currentpicture also currentpicture
1828    rotatedaround (center currentpicture, 180)
1829    shifted (90, 0) ;
1830
1831    drawarrow q withcolor \MPcolor{keyboard} ;
1832    drawarrow reverse r shifted (90, 0) withcolor \MPcolor{keyboard} ;
1833
1834    currentpicture := currentpicture scaled 2 ;
1835
1836\stopuseMPgraphic
1837
1838\ShowInfo{grow}{Toggle grow mode, another way of stacking.}
1839
1840\startuseMPgraphic{exit}
1841
1842    path p ; p := (100,30)--(100,0)--(0,0)--(0,100)--(100,100)--(100,70) ;
1843    pickup pencircle scaled 10 ;
1844    linecap := butt ;
1845    ahlength := 60 ;
1846    ahangle  := 75 ;
1847    filldraw
1848        p--cycle
1849        withcolor \MPcolor{action} ;
1850    draw
1851        p
1852        withcolor \MPcolor{stack} ;
1853    push_boundingbox currentpicture ;
1854    pickup pencircle scaled 30 ;
1855    draw
1856        center currentpicture --
1857        (xpart lrcorner currentpicture+.75ahlength, ypart center currentpicture)
1858        withcolor \MPcolor{keyboard} ;
1859    pickup pencircle scaled 5 ;
1860    drawarrow
1861        center currentpicture --
1862        (xpart lrcorner currentpicture, ypart center currentpicture)
1863        withcolor \MPcolor{keyboard} ;
1864    pop_boundingbox currentpicture ;
1865    currentpicture := currentpicture scaled 1.75 ;
1866
1867\stopuseMPgraphic
1868
1869\ShowInfo{exit}{Close this document.}
1870
1871\stoptext
1872