1if not modules then modules = { } end modules [ ' x-flow ' ] = {
2 version = 1 . 001 ,
3 comment = " companion to m-flow.mkvi " ,
4 author = " Hans Hagen, PRAGMA-ADE, Hasselt NL " ,
5 copyright = " PRAGMA ADE / ConTeXt Development Team " ,
6 license = " see context related readme files "
7}
8
9
10
11
12
13
14
15local type , tonumber , rawget , next = type , tonumber , rawget , next
16local gsub , find , lower = string . gsub , string . find , string . lower
17local P , S , C , Cc , lpegmatch = lpeg . P , lpeg . S , lpeg . C , lpeg . Cc , lpeg . match
18
19local context = context
20
21local ctx_startgraphic = metapost . startgraphic
22local ctx_stopgraphic = metapost . stopgraphic
23local ctx_tographic = metapost . tographic
24
25local formatters = string . formatters
26local setmetatableindex = table . setmetatableindex
27local settings_to_hash = utilities . parsers . settings_to_hash
28
29moduledata . charts = moduledata . charts or { }
30
31local report_chart = logs . reporter ( " chart " )
32
33local variables = interfaces . variables
34local implement = interfaces . implement
35
36local v_yes = variables . yes
37local v_no = variables . no
38local v_none = variables . none
39local v_standard = variables . standard
40local v_overlay = variables . overlay
41local v_round = variables . round
42local v_test = variables . test
43
44local defaults = {
45 chart = {
46 name = " " ,
47 option = " " ,
48 backgroundcolor = " " ,
49 width = 100 * 65536 ,
50 height = 50 * 65536 ,
51 dx = 30 * 65536 ,
52 dy = 30 * 65536 ,
53 offset = 0 ,
54 bodyfont = " " ,
55 dot = " " ,
56 hcompact = variables_no ,
57 vcompact = variables_no ,
58 autofocus = " " ,
59 focus = " " ,
60 labeloffset = 5 * 65536 ,
61 commentoffset = 5 * 65536 ,
62 exitoffset = 0 ,
63
64 } ,
65 shape = {
66 rulethickness = 65536 ,
67 default = " " ,
68 framecolor = " darkblue " ,
69 backgroundcolor = " lightgray " ,
70 } ,
71 focus = {
72 rulethickness = 65536 ,
73 framecolor = " darkred " ,
74 backgroundcolor = " gray " ,
75 } ,
76 line = {
77 rulethickness = 65536 ,
78 radius = 10 * 65536 ,
79 color = " darkgreen " ,
80 corner = " " ,
81 dash = " " ,
82 arrow = " " ,
83 offset = " " ,
84 } ,
85 set = {
86 } ,
87 split = {
88 nx = 3 ,
89 ny = 3 ,
90 command = " " ,
91 marking = " " ,
92 before = " " ,
93 after = " " ,
94 }
95}
96
97local validshapes = {
98 [ " node " ] = { kind = " shape " , number = 0 } ,
99 [ " action " ] = { kind = " shape " , number = 24 } ,
100 [ " procedure " ] = { kind = " shape " , number = 5 } ,
101 [ " product " ] = { kind = " shape " , number = 12 } ,
102 [ " decision " ] = { kind = " shape " , number = 14 } ,
103 [ " archive " ] = { kind = " shape " , number = 19 } ,
104 [ " loop " ] = { kind = " shape " , number = 35 } ,
105 [ " wait " ] = { kind = " shape " , number = 6 } ,
106 [ " subprocedure " ] = { kind = " shape " , number = 20 } ,
107 [ " singledocument " ] = { kind = " shape " , number = 32 } ,
108 [ " multidocument " ] = { kind = " shape " , number = 33 } ,
109
110 [ " right " ] = { kind = " line " , number = 66 } ,
111 [ " left " ] = { kind = " line " , number = 67 } ,
112 [ " up " ] = { kind = " line " , number = 68 } ,
113 [ " down " ] = { kind = " line " , number = 69 } ,
114}
115
116local validlabellocations = {
117 l = " l " , left = " l " ,
118 r = " r " , right = " r " ,
119 t = " t " , top = " t " ,
120 b = " b " , bottom = " b " ,
121 lt = " lt " ,
122 rt = " rt " ,
123 lb = " lb " ,
124 rb = " rb " ,
125 tl = " tl " ,
126 tr = " tr " ,
127 bl = " bl " ,
128 br = " br " ,
129}
130
131local validcommentlocations = {
132 l = " l " , left = " l " ,
133 r = " r " , right = " r " ,
134 t = " t " , top = " t " ,
135 b = " b " , bottom = " b " ,
136 lt = " lt " ,
137 rt = " rt " ,
138 lb = " lb " ,
139 rb = " rb " ,
140 tl = " tl " ,
141 tr = " tr " ,
142 bl = " bl " ,
143 br = " br " ,
144}
145
146local validtextlocations = {
147 l = " l " , left = " l " ,
148 r = " r " , right = " r " ,
149 t = " t " , top = " t " ,
150 b = " b " , bottom = " b " ,
151 c = " c " , center = " c " ,
152 m = " c " , middle = " m " ,
153 lt = " lt " ,
154 rt = " rt " ,
155 lb = " lb " ,
156 rb = " rb " ,
157 tl = " lt " ,
158 tr = " rt " ,
159 bl = " lb " ,
160 br = " rb " ,
161}
162
163setmetatableindex ( validshapes , function ( t , k )
164 local l = gsub ( lower ( k ) , " " , " " )
165 local v = rawget ( t , l )
166 if not v then
167 local n = tonumber ( k )
168 if n then
169 v = { kind = " shape " , number = n }
170 else
171 v = rawget ( t , " action " )
172 end
173 end
174 t [ k ] = v
175 return v
176end )
177
178local charts = { }
179
180local data , hash , temp , last_x , last_y , name
181
182implement {
183 name = " flow_start_chart " ,
184 arguments = " string " ,
185 actions = function ( chartname )
186 data = { }
187 hash = { }
188 last_x , last_y = 0 , 0
189 name = chartname
190 end
191}
192
193implement {
194 name = " flow_stop_chart " ,
195 actions = function ( )
196 charts [ name ] = {
197 data = data ,
198 hash = hash ,
199 last_x = last_x ,
200 last_y = last_y ,
201 }
202 data , hash , temp = nil , nil , nil
203 end
204}
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232implement {
233 name = " flow_reset " ,
234 actions = function ( )
235 charts [ name ] = nil
236 end
237}
238
239implement {
240 name = " flow_set_current_cell " ,
241 arguments = " integer " ,
242 actions = function ( n )
243 temp = data [ n ] or { }
244 end
245}
246
247implement {
248 name = " flow_start_cell " ,
249 arguments = {
250 {
251 { " shape " , {
252 { " rulethickness " , " dimension " } ,
253 { " default " } ,
254 { " framecolor " } ,
255 { " backgroundcolor " } ,
256 } ,
257 } ,
258 { " focus " , {
259 { " rulethickness " , " dimension " } ,
260 { " framecolor " } ,
261 { " backgroundcolor " } ,
262 } ,
263 } ,
264 { " line " , {
265 { " rulethickness " , " dimension " } ,
266 { " radius " , " dimension " } ,
267 { " color " } ,
268 { " corner " } ,
269 { " dash " } ,
270 { " arrow " } ,
271 { " offset " , " dimension " } ,
272 } ,
273 } ,
274 } ,
275 } ,
276 actions = function ( settings )
277 temp = {
278 texts = { } ,
279 labels = { } ,
280 exits = { } ,
281 connections = { } ,
282 settings = settings ,
283 x = 1 ,
284 y = 1 ,
285 realx = 1 ,
286 realy = 1 ,
287 name = " " ,
288 }
289 end
290}
291
292implement {
293 name = " flow_stop_cell " ,
294 actions = function ( )
295 data [ # data + 1 ] = temp
296 hash [ temp . name or # data ] = temp
297 end
298}
299
300implement {
301 name = " flow_set_name " ,
302 arguments = " string " ,
303 actions = function ( str )
304 temp . name = str
305 end
306}
307
308implement {
309 name = " flow_set_shape " ,
310 arguments = " string " ,
311 actions = function ( str )
312 temp . shape = str
313 end
314}
315
316implement {
317 name = " flow_set_destination " ,
318 arguments = " string " ,
319 actions = function ( str )
320 temp . destination = str
321 end
322}
323
324implement {
325 name = " flow_set_text " ,
326 arguments = " 2 strings " ,
327 actions = function ( align , str )
328 temp . texts [ # temp . texts + 1 ] = {
329 align = align ,
330 text = str ,
331 }
332 end
333}
334
335implement {
336 name = " flow_set_overlay " ,
337 arguments = " string " ,
338 actions = function ( str )
339 temp . overlay = str
340 end
341}
342
343implement {
344 name = " flow_set_focus " ,
345 arguments = " string " ,
346 actions = function ( str )
347 temp . focus = str
348 end
349}
350
351implement {
352 name = " flow_set_figure " ,
353 arguments = " string " ,
354 actions = function ( str )
355 temp . figure = str
356 end
357}
358
359implement {
360 name = " flow_set_label " ,
361 arguments = " 2 strings " ,
362 actions = function ( location , text )
363 temp . labels [ # temp . labels + 1 ] = {
364 location = location ,
365 text = text ,
366 }
367 end
368}
369
370implement {
371 name = " flow_set_comment " ,
372 arguments = " 2 strings " ,
373 actions = function ( location , text )
374 local connections = temp . connections
375 if connections then
376 local connection = connections [ # connections ]
377 if connection then
378 local comments = connection . comments
379 if comments then
380 comments [ # comments + 1 ] = {
381 location = location ,
382 text = text ,
383 }
384 end
385 end
386 end
387 end
388}
389
390implement {
391 name = " flow_set_exit " ,
392 arguments = " 2 strings " ,
393 actions = function ( location , text )
394 temp . exits [ # temp . exits + 1 ] = {
395 location = location ,
396 text = text ,
397 }
398 end
399}
400
401implement {
402 name = " flow_set_include " ,
403 arguments = { " string " , " integer " , " integer " , " string " } ,
404 actions = function ( name , x , y , settings )
405 data [ # data + 1 ] = {
406 include = name ,
407 x = x ,
408 y = y ,
409
410 }
411 end
412}
413
414local function inject ( includedata , data , hash )
415 local subchart = charts [ includedata . include ]
416 if not subchart then
417 return
418 end
419 local subdata = subchart . data
420 if not subdata then
421 return
422 end
423 local xoffset = ( includedata . x or 1 ) - 1
424 local yoffset = ( includedata . y or 1 ) - 1
425 local settings = includedata . settings
426 for i = 1 , # subdata do
427 local si = subdata [ i ]
428 if si . include then
429 inject ( si , data , hash )
430 else
431 local x = si . x + xoffset
432 local y = si . y + yoffset
433 local t = {
434 x = x ,
435 y = y ,
436 realx = x ,
437 realy = y ,
438 settings = settings ,
439 }
440 setmetatableindex ( t , si )
441 data [ # data + 1 ] = t
442 hash [ si . name or # data ] = t
443 end
444 end
445end
446
447local function pack ( data , field )
448 local list , max = { } , 0
449 for e = 1 , # data do
450 local d = data [ e ]
451 local f = d [ field ]
452 list [ f ] = true
453 if f > max then
454 max = f
455 end
456 end
457 for i = 1 , max do
458 if not list [ i ] then
459 for e = 1 , # data do
460 local d = data [ e ]
461 local f = d [ field ]
462 if f > i then
463 d [ field ] = f - 1
464 end
465 end
466 end
467 end
468end
469
470local function expanded ( chart , chartsettings )
471 local expandeddata = { }
472 local expandedhash = { }
473 local expandedchart = {
474 data = expandeddata ,
475 hash = expandedhash ,
476 }
477 setmetatableindex ( expandedchart , chart )
478 local data = chart . data
479 local hash = chart . hash
480 for i = 1 , # data do
481 local di = data [ i ]
482 if di . include then
483 inject ( di , expandeddata , expandedhash )
484 else
485 expandeddata [ # expandeddata + 1 ] = di
486 expandedhash [ di . name or # expandeddata ] = di
487 end
488 end
489
490 expandedchart . settings = chartsettings or { }
491
492 chartsettings . shape = chartsettings . shape or { }
493 chartsettings . focus = chartsettings . focus or { }
494 chartsettings . line = chartsettings . line or { }
495 chartsettings . set = chartsettings . set or { }
496 chartsettings . split = chartsettings . split or { }
497 chartsettings . chart = chartsettings . chart or { }
498 setmetatableindex ( chartsettings . shape , defaults . shape )
499 setmetatableindex ( chartsettings . focus , defaults . focus )
500 setmetatableindex ( chartsettings . line , defaults . line )
501 setmetatableindex ( chartsettings . set , defaults . set )
502 setmetatableindex ( chartsettings . split , defaults . split )
503 setmetatableindex ( chartsettings . chart , defaults . chart )
504
505 if chartsettings . chart . vcompact = = v_yes then
506 pack ( expandeddata , " y " )
507 end
508 if chartsettings . chart . hcompact = = v_yes then
509 pack ( expandeddata , " x " )
510 end
511
512 for i = 1 , # expandeddata do
513 local cell = expandeddata [ i ]
514 local settings = cell . settings
515 if not settings then
516 cell . settings = chartsettings
517 else
518 settings . shape = settings . shape or { }
519 settings . focus = settings . focus or { }
520 settings . line = settings . line or { }
521 setmetatableindex ( settings . shape , chartsettings . shape )
522 setmetatableindex ( settings . focus , chartsettings . focus )
523 setmetatableindex ( settings . line , chartsettings . line )
524 end
525 end
526 return expandedchart
527end
528
529local splitter = lpeg . splitat ( " , " )
530
531implement {
532 name = " flow_set_location " ,
533 arguments = " string " ,
534 actions = function ( x , y )
535 if type ( x ) = = " string " and not y then
536 x , y = lpegmatch ( splitter , x )
537 end
538 local oldx , oldy = x , y
539 if not x or x = = " " then
540 x = last_x
541 elseif type ( x ) = = " number " then
542
543 elseif x = = " + " then
544 x = last_x + 1
545 elseif x = = " - " then
546 x = last_x - 1
547 elseif find ( x , " ^[%+%-] " ) then
548 x = last_x + ( tonumber ( x ) or 0 )
549 else
550 x = tonumber ( x )
551 end
552 if not y or y = = " " then
553 y = last_y
554 elseif type ( y ) = = " number " then
555
556 elseif y = = " + " then
557 y = last_y + 1
558 elseif x = = " - " then
559 y = last_y - 1
560 elseif find ( y , " ^[%+%-] " ) then
561 y = last_y + ( tonumber ( y ) or 0 )
562 else
563 y = tonumber ( y )
564 end
565 if x < 1 or y < 1 then
566 report_chart ( " the cell (%s,%s) ends up at (%s,%s) and gets relocated to (1,1) " , oldx or " ? " , oldy or " ? " , x , y )
567 if x < 1 then
568 x = 1
569 end
570 if y < 1 then
571 y = 1
572 end
573 end
574 temp . x = x or 1
575 temp . y = y or 1
576 temp . realx = x or 1
577 temp . realy = y or 1
578 last_x = x or last_x
579 last_y = y or last_y
580 end
581}
582
583implement {
584 name = " flow_set_connection " ,
585 arguments = " 3 strings " ,
586 actions = function ( location , displacement , name )
587 local dx , dy = lpegmatch ( splitter , displacement )
588 dx = tonumber ( dx )
589 dy = tonumber ( dy )
590 temp . connections [ # temp . connections + 1 ] = {
591 location = location ,
592 dx = dx or 0 ,
593 dy = dy or 0 ,
594 name = name ,
595 comments = { } ,
596 }
597 end
598}
599
600local function visible ( chart , cell )
601 local x , y = cell . x , cell . y
602 return
603 x > = chart . from_x and x < = chart . to_x and
604 y > = chart . from_y and y < = chart . to_y and cell
605end
606
607local function process_cells ( g , chart , xoffset , yoffset )
608 local data = chart . data
609 if not data then
610 return
611 end
612 local focus = settings_to_hash ( chart . settings . chart . focus or " " )
613 for i = 1 , # data do
614 local cell = visible ( chart , data [ i ] )
615 if cell then
616 local settings = cell . settings
617 local shapesettings = settings . shape
618 local shape = cell . shape
619 if not shape or shape = = " " then
620 shape = shapesettings . default or " none "
621 end
622 if shape ~ = v_none then
623 local shapedata = validshapes [ shape ]
624 ctx_tographic ( g , " flow_begin_sub_chart ; " )
625 if shapedata . kind = = " line " then
626 local linesettings = settings . line
627 ctx_tographic ( g , " flow_shape_line_color := %q ; " , linesettings . color )
628 ctx_tographic ( g , " flow_shape_fill_color := %q ; " , " black " )
629 ctx_tographic ( g , " flow_shape_line_width := %p ; " , linesettings . rulethickness )
630 elseif focus [ cell . focus ] or focus [ cell . name ] then
631 local focussettings = settings . focus
632 ctx_tographic ( g , " flow_shape_line_color := %q ; " , focussettings . framecolor )
633 ctx_tographic ( g , " flow_shape_fill_color := %q ; " , focussettings . backgroundcolor )
634 ctx_tographic ( g , " flow_shape_line_width := %p ; " , focussettings . rulethickness )
635 else
636 local shapesettings = settings . shape
637 ctx_tographic ( g , " flow_shape_line_color := %q ; " , shapesettings . framecolor )
638 ctx_tographic ( g , " flow_shape_fill_color := %q ; " , shapesettings . backgroundcolor )
639 ctx_tographic ( g , " flow_shape_line_width := %p ; " , shapesettings . rulethickness )
640 end
641 ctx_tographic ( g , " flow_peepshape := false ; " )
642 ctx_tographic ( g , " flow_new_shape(%s,%s,%s) ; " , cell . x + xoffset , cell . y + yoffset , shapedata . number )
643 ctx_tographic ( g , " flow_end_sub_chart ; " )
644 end
645 end
646 end
647end
648
649
650
651local sign = S ( " +p " ) / " 1 "
652 + S ( " -mn " ) / " -1 "
653
654local full = C ( P ( " left " ) )
655 + C ( P ( " right " ) )
656 + C ( P ( " top " ) )
657 + C ( P ( " bottom " ) )
658
659local char = P ( " l " ) / " left "
660 + P ( " r " ) / " right "
661 + P ( " t " ) / " top "
662 + P ( " b " ) / " bottom "
663
664local space = P ( " " ) ^ 0
665
666local what = space
667 * ( sign + Cc ( " 0 " ) )
668 * space
669 * ( full + char )
670 * space
671 * ( sign + Cc ( " 0 " ) )
672 * space
673 * ( full + char )
674 * space
675 * P ( -1 )
676
677
678
679
680
681
682local function process_connections ( g , chart , xoffset , yoffset )
683 local data = chart . data
684 local hash = chart . hash
685 if not data then
686 return
687 end
688 local settings = chart . settings
689 for i = 1 , # data do
690 local cell = visible ( chart , data [ i ] )
691 if cell then
692 local connections = cell . connections
693 for j = 1 , # connections do
694 local connection = connections [ j ]
695 local othername = connection . name
696 local othercell = hash [ othername ]
697 if othercell then
698 local cellx , celly = cell . x , cell . y
699 local otherx , othery , location = othercell . x , othercell . y , connection . location
700 if otherx > 0 and othery > 0 and cellx > 0 and celly > 0 and location then
701 local what_cell , where_cell , what_other , where_other = lpegmatch ( what , location )
702 if what_cell and where_cell and what_other and where_other then
703 local linesettings = settings . line
704 ctx_tographic ( g , " flow_smooth := %s ; " , linesettings . corner = = v_round and " true " or " false " )
705 ctx_tographic ( g , " flow_dashline := %s ; " , linesettings . dash = = v_yes and " true " or " false " )
706 ctx_tographic ( g , " flow_arrowtip := %s ; " , linesettings . arrow = = v_yes and " true " or " false " )
707 ctx_tographic ( g , " flow_touchshape := %s ; " , linesettings . offset = = v_none and " true " or " false " )
708 ctx_tographic ( g , " flow_dsp_x := %s ; flow_dsp_y := %s ; " , connection . dx or 0 , connection . dy or 0 )
709 ctx_tographic ( g , " flow_connection_line_color := %q ; " , linesettings . color )
710 ctx_tographic ( g , " flow_connection_line_width := %p ; " , linesettings . rulethickness )
711 ctx_tographic ( g , " flow_connect_%s_%s (%s) (%s,%s,%s) (%s,%s,%s) ; " , where_cell , where_other , j , cellx , celly , what_cell , otherx , othery , what_other )
712 ctx_tographic ( g , " flow_dsp_x := 0 ; flow_dsp_y := 0 ; " )
713 end
714 end
715 end
716 end
717 end
718 end
719end
720
721local f_texttemplate_t = formatters [ " \\setvariables[flowcell:text][x=%s,y=%s,n=%i,align={%s},figure={%s},overlay={%s},destination={%s},realx=%s,realy=%s] " ]
722local f_texttemplate_l = formatters [ " \\doFLOWlabel{%i}{%i}{%i}{%i}{%i} " ]
723
724local splitter = lpeg . splitat ( " : " )
725local charttexts = { }
726
727implement {
728 name = " flow_get_text " ,
729 arguments = " integer " ,
730 actions = function ( n )
731 if n > 0 then
732 context ( charttexts [ n ] )
733 end
734 end
735}
736
737local function process_texts ( g , chart , xoffset , yoffset )
738 local data = chart . data
739 local hash = chart . hash
740 if not data then
741 return
742 end
743 charttexts = { }
744 for i = 1 , # data do
745 local cell = visible ( chart , data [ i ] )
746 if cell then
747 local x = cell . x or 1
748 local y = cell . y or 1
749 local figure = cell . figure or " "
750 local overlay = cell . overlay or " "
751 local destination = cell . destination or " "
752 local texts = cell . texts
753 local noftexts = # texts
754 local realx = cell . realx or x
755 local realy = cell . realy or y
756 if noftexts > 0 then
757 for i = 1 , noftexts do
758 local text = texts [ i ]
759 local data = text . text
760 local align = text . align or " "
761 local align = validlabellocations [ align ] or align
762 charttexts [ # charttexts + 1 ] = data
763 ctx_tographic ( g , ' flow_chart_draw_text(%s,%s,textext("%s")) ; ' , x , y , f_texttemplate_t ( x , y , # charttexts , align , figure , overlay , destination , realx , realy ) )
764 if i = = 1 then
765 figure = " "
766 overlay = " "
767 destination = " "
768 end
769 end
770 elseif figure ~ = " " or overlay ~ = " " or destination ~ = " " then
771 ctx_tographic ( g , ' flow_chart_draw_text(%s,%s,textext("%s")) ; ' , x , y , f_texttemplate_t ( x , y , 0 , " " , figure , overlay , destination , realx , realy ) )
772 end
773 local labels = cell . labels
774 for i = 1 , # labels do
775 local label = labels [ i ]
776 local text = label . text
777 local location = label . location or " "
778 local location = validlabellocations [ location ] or location
779 if text and text ~ = " " then
780 charttexts [ # charttexts + 1 ] = text
781 ctx_tographic ( g , ' flow_chart_draw_label(%s,%s,"%s",textext("%s")) ; ' , x , y , location , f_texttemplate_l ( x , y , # charttexts , realx , realy ) )
782 end
783 end
784 local exits = cell . exits
785 for i = 1 , # exits do
786 local exit = exits [ i ]
787 local text = exit . text
788 local location = exit . location or " "
789 local location = validlabellocations [ location ] or location
790 if text ~ = " " then
791
792 if location = = " l " and x = = chart . from_x + 1 or
793 location = = " r " and x = = chart . to_x - 1 or
794 location = = " t " and y = = chart . to_y - 1 or
795 location = = " b " and y = = chart . from_y + 1 then
796 charttexts [ # charttexts + 1 ] = text
797 ctx_tographic ( g , ' flow_chart_draw_exit(%s,%s,"%s",textext("%s")) ; ' , x , y , location , f_texttemplate_l ( x , y , # charttexts , realx , realy ) )
798 end
799 end
800 end
801 local connections = cell . connections
802 for i = 1 , # connections do
803 local comments = connections [ i ] . comments
804 for j = 1 , # comments do
805 local comment = comments [ j ]
806 local text = comment . text
807 local location = comment . location or " "
808 local length = 0
809
810 local loc , len = lpegmatch ( splitter , location )
811 if len = = " * " then
812 location = validcommentlocations [ loc ] or " "
813 if location = = " " then
814 location = " * "
815 else
816 location = location . . " :* "
817 end
818 elseif loc then
819 location = validcommentlocations [ loc ] or " * "
820 length = tonumber ( len ) or 0
821 else
822 location = validcommentlocations [ location ] or " "
823 end
824 if text and text ~ = " " then
825 charttexts [ # charttexts + 1 ] = text
826 ctx_tographic ( g , ' flow_chart_draw_comment(%s,%s,%s,"%s",%s,textext("%s")) ; ' , x , y , i , location , length , f_texttemplate_l ( x , y , # charttexts , realx , realy ) )
827 end
828 end
829 end
830 end
831 end
832end
833
834local function getchart ( settings , forced_x , forced_y , forced_nx , forced_ny )
835 if not settings then
836 print ( " no settings given " )
837 return
838 end
839 local chartname = settings . chart . name
840 if not chartname then
841 print ( " no name given " )
842 return
843 end
844 local chart = charts [ chartname ]
845 if not chart then
846 print ( " no such chart " , chartname )
847 return
848 end
849 chart = expanded ( chart , settings )
850 local chartsettings = chart . settings . chart
851 local autofocus = chart . settings . chart . autofocus
852 if autofocus then
853 autofocus = settings_to_hash ( autofocus )
854 if not next ( autofocus ) then
855 autofocus = false
856 end
857 end
858
859 local x = forced_x or tonumber ( chartsettings . x )
860 local y = forced_y or tonumber ( chartsettings . y )
861 local nx = forced_nx or tonumber ( chartsettings . nx )
862 local ny = forced_ny or tonumber ( chartsettings . ny )
863
864 local minx , miny , maxx , maxy = 0 , 0 , 0 , 0
865 local data = chart . data
866 for i = 1 , # data do
867 local cell = data [ i ]
868 if not autofocus or autofocus [ cell . name ] then
869 local x = cell . realx
870 local y = cell . realy
871 if minx = = 0 or x < minx then minx = x end
872 if miny = = 0 or y < miny then miny = y end
873 if minx = = 0 or x > maxx then maxx = x end
874 if miny = = 0 or y > maxy then maxy = y end
875 end
876 end
877
878 if x + nx > maxx then
879 nx = maxx - x + 1
880 end
881 if y + ny > maxy then
882 ny = maxy - y + 1
883 end
884
885
886 if autofocus then
887
888 if nx and nx > 0 then
889 maxx = minx + nx - 1
890 end
891 if ny and ny > 0 then
892 maxy = miny + ny - 1
893 end
894 else
895 if x and x > 0 then
896 minx = x
897 end
898 if y and y > 0 then
899 miny = y
900 end
901 if nx and nx > 0 then
902 maxx = minx + nx - 1
903 end
904 if ny and ny > 0 then
905 maxy = miny + ny - 1
906 end
907 end
908
909
910 local nx = maxx - minx + 1
911 local ny = maxy - miny + 1
912
913 for i = 1 , # data do
914 local cell = data [ i ]
915 cell . x = cell . realx - minx + 1
916 cell . y = cell . realy - miny + 1
917 end
918 chart . from_x = 1
919 chart . from_y = 1
920 chart . to_x = nx
921 chart . to_y = ny
922 chart . nx = nx
923 chart . ny = ny
924
925 chart . shift_x = minx + 1
926 chart . shift_y = miny + 1
927
928 return chart
929end
930
931local function makechart_indeed ( chart )
932 local settings = chart . settings
933 local chartsettings = settings . chart
934
935 local g = ctx_startgraphic {
936 instance = " metafun " ,
937 format = " metafun " ,
938 method = " scaled " ,
939 definitions = " " ,
940 wrapped = true ,
941 }
942
943 ctx_tographic ( g , " if unknown context_flow : input mp-char.mpiv ; fi ; " )
944 ctx_tographic ( g , " flow_begin_chart(0,%s,%s); " , chart . nx , chart . ny )
945
946 if chartsettings . option = = v_test or chartsettings . dot = = v_yes then
947 ctx_tographic ( g , " flow_show_con_points := true ; " )
948 ctx_tographic ( g , " flow_show_mid_points := true ; " )
949 ctx_tographic ( g , " flow_show_all_points := true ; " )
950 elseif chartsettings . dot ~ = " " then
951 ctx_tographic ( g , " flow_show_%s_points := true ; " , chartsettings . dot )
952 end
953
954 local backgroundcolor = chartsettings . backgroundcolor
955 if backgroundcolor and backgroundcolor ~ = " " then
956 ctx_tographic ( g , " flow_chart_background_color := %q ; " , backgroundcolor )
957 end
958
959 local shapewidth = chartsettings . width
960 local gridwidth = shapewidth + 2 * chartsettings . dx
961 local shapeheight = chartsettings . height
962 local gridheight = shapeheight + 2 * chartsettings . dy
963 local chartoffset = chartsettings . offset
964 local labeloffset = chartsettings . labeloffset
965 local exitoffset = chartsettings . exitoffset
966 local commentoffset = chartsettings . commentoffset
967 local clipoffset = chartsettings . clipoffset
968 ctx_tographic ( g , " flow_grid_width := %p ; " , gridwidth )
969 ctx_tographic ( g , " flow_grid_height := %p ; " , gridheight )
970 ctx_tographic ( g , " flow_shape_width := %p ; " , shapewidth )
971 ctx_tographic ( g , " flow_shape_height := %p ; " , shapeheight )
972 ctx_tographic ( g , " flow_chart_offset := %p ; " , chartoffset )
973 ctx_tographic ( g , " flow_label_offset := %p ; " , labeloffset )
974 ctx_tographic ( g , " flow_exit_offset := %p ; " , exitoffset )
975 ctx_tographic ( g , " flow_comment_offset := %p ; " , commentoffset )
976
977 local radius = settings . line . radius
978 local rulethickness = settings . line . rulethickness
979 local dx = chartsettings . dx
980 local dy = chartsettings . dy
981 if radius < rulethickness then
982 radius = 2 . 5 * rulethickness
983 if radius > dx then
984 radius = dx
985 end
986 if radius > dy then
987 radius = dy
988 end
989 end
990 ctx_tographic ( g , " flow_connection_line_width := %p ; " , rulethickness )
991 ctx_tographic ( g , " flow_connection_smooth_size := %p ; " , radius )
992 ctx_tographic ( g , " flow_connection_arrow_size := %p ; " , radius )
993 ctx_tographic ( g , " flow_connection_dash_size := %p ; " , radius )
994
995 local offset = chartsettings . offset
996 if offset = = v_none or offset = = v_overlay or offset = = " " then
997 offset = -2 . 5 * radius
998 elseif offset = = v_standard then
999 offset = radius
1000 end
1001 ctx_tographic ( g , " flow_chart_offset := %p ; " , offset )
1002 ctx_tographic ( g , " flow_chart_clip_offset := %p ; " , clipoffset )
1003
1004 ctx_tographic ( g , " flow_reverse_y := true ; " )
1005 if chartsettings . option = = v_test then
1006 ctx_tographic ( g , " flow_draw_test_shapes ; " )
1007 end
1008
1009 process_cells ( g , chart , 0 , 0 )
1010 process_connections ( g , chart , 0 , 0 )
1011 process_texts ( g , chart , 0 , 0 )
1012
1013
1014 ctx_tographic ( g , " flow_end_chart ; " )
1015 ctx_stopgraphic ( g )
1016
1017end
1018
1019
1020
1021local function makechart ( chart )
1022 context . hbox ( )
1023 context . bgroup ( )
1024 context . forgetall ( )
1025 context ( function ( ) makechart_indeed ( chart ) end )
1026 context . egroup ( )
1027end
1028
1029local function splitchart ( chart )
1030 local settings = chart . settings
1031 local splitsettings = settings . split
1032 local chartsettings = settings . chart
1033
1034 local name = chartsettings . name
1035
1036 local from_x = chart . from_x
1037 local from_y = chart . from_y
1038 local to_x = chart . to_x
1039 local to_y = chart . to_y
1040
1041 local step_x = splitsettings . nx or to_x
1042 local step_y = splitsettings . ny or to_y
1043 local delta_x = splitsettings . dx or 0
1044 local delta_y = splitsettings . dy or 0
1045
1046 report_chart ( " spliting %a from (%s,%s) upto (%s,%s) with steps (%s,%s) and overlap (%s,%s) " ,
1047 name , from_x , from_y , to_x , to_y , step_x , step_y , delta_x , delta_y )
1048
1049 local part_x = 0
1050 local first_x = from_x
1051 while true do
1052 part_x = part_x + 1
1053 local last_x = first_x + step_x - 1
1054 local done = last_x > = to_x
1055 if done then
1056 last_x = to_x
1057 end
1058
1059
1060
1061 local part_y = 0
1062 local first_y = from_y
1063 while true do
1064 part_y = part_y + 1
1065 local last_y = first_y + step_y - 1
1066 local done = last_y > = to_y
1067 if done then
1068 last_y = to_y
1069 end
1070
1071
1072
1073
1074 local data = chart . data
1075 for i = 1 , # data do
1076 local cell = data [ i ]
1077
1078 local cx , cy = cell . x , cell . y
1079 if cx > = first_x and cx < = last_x then
1080 if cy > = first_y and cy < = last_y then
1081 report_chart ( " part (%s,%s) of %a is split from (%s,%s) -> (%s,%s) " , part_x , part_y , name , first_x , first_y , last_x , last_y )
1082 local x = first_x
1083 local y = first_y
1084 local nx = last_x - first_x + 1
1085 local ny = last_y - first_y + 1
1086 context . beforeFLOWsplit ( )
1087 context . handleFLOWsplit ( function ( )
1088 makechart ( getchart ( settings , x , y , nx , ny ) )
1089 end )
1090 context . afterFLOWsplit ( )
1091 break
1092 end
1093 end
1094 end
1095
1096 if done then
1097 break
1098 else
1099 first_y = last_y + 1 - delta_y
1100 end
1101 end
1102 if done then
1103 break
1104 else
1105 first_x = last_x + 1 - delta_x
1106 end
1107 end
1108end
1109
1110implement {
1111 name = " flow_make_chart " ,
1112 arguments = {
1113 {
1114 { " chart " , {
1115 { " name " } ,
1116 { " option " } ,
1117 { " backgroundcolor " } ,
1118 { " width " , " dimension " } ,
1119 { " height " , " dimension " } ,
1120 { " dx " , " dimension " } ,
1121 { " dy " , " dimension " } ,
1122 { " offset " , " dimension " } ,
1123
1124 { " dot " } ,
1125 { " hcompact " } ,
1126 { " vcompact " } ,
1127 { " focus " } ,
1128 { " autofocus " } ,
1129 { " nx " , " integer " } ,
1130 { " ny " , " integer " } ,
1131 { " x " , " integer " } ,
1132 { " y " , " integer " } ,
1133 { " clipoffset " , " dimension " } ,
1134 { " labeloffset " , " dimension " } ,
1135 { " commentoffset " , " dimension " } ,
1136 { " exitoffset " , " dimension " } ,
1137 { " split " } ,
1138 } ,
1139 } ,
1140 { " shape " , {
1141 { " rulethickness " , " dimension " } ,
1142 { " default " } ,
1143 { " framecolor " } ,
1144 { " backgroundcolor " } ,
1145 } ,
1146 } ,
1147 { " focus " , {
1148 { " rulethickness " , " dimension " } ,
1149 { " framecolor " } ,
1150 { " backgroundcolor " } ,
1151 } ,
1152 } ,
1153 { " line " , {
1154 { " rulethickness " , " dimension " } ,
1155 { " radius " , " dimension " } ,
1156 { " color " } ,
1157 { " corner " } ,
1158 { " dash " } ,
1159 { " arrow " } ,
1160 { " offset " } ,
1161 } ,
1162 } ,
1163 { " split " , {
1164 { " nx " , " integer " } ,
1165 { " ny " , " integer " } ,
1166 { " dx " , " integer " } ,
1167 { " dy " , " integer " } ,
1168 { " command " } ,
1169 { " marking " } ,
1170 { " before " } ,
1171 { " after " } ,
1172 } ,
1173 } ,
1174
1175 }
1176 } ,
1177 actions = function ( settings )
1178 local chart = getchart ( settings )
1179 if chart then
1180 local settings = chart . settings
1181 if settings then
1182 local chartsettings = settings . chart
1183 if chartsettings and chartsettings . split = = v_yes then
1184 splitchart ( chart )
1185 else
1186 makechart ( chart )
1187 end
1188 else
1189 makechart ( chart )
1190 end
1191 end
1192 end
1193}
1194 |