if not modules then modules = { } end modules ['x-flow'] = { version = 1.001, comment = "companion to m-flow.mkvi", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", copyright = "PRAGMA ADE / ConTeXt Development Team", license = "see context related readme files" } -- when we can resolve mpcolor at the lua end we will -- use metapost.graphic(....) directly -- todo: labels -- todo: named colors local type, tonumber, rawget, next = type, tonumber, rawget, next local gsub, find, lower = string.gsub, string.find, string.lower local P, S, C, Cc, lpegmatch = lpeg.P, lpeg.S, lpeg.C, lpeg.Cc, lpeg.match local context = context local ctx_startgraphic = metapost.startgraphic local ctx_stopgraphic = metapost.stopgraphic local ctx_tographic = metapost.tographic local formatters = string.formatters local setmetatableindex = table.setmetatableindex local settings_to_hash = utilities.parsers.settings_to_hash moduledata.charts = moduledata.charts or { } local report_chart = logs.reporter("chart") local variables = interfaces.variables local implement = interfaces.implement local v_yes = variables.yes local v_no = variables.no local v_none = variables.none local v_standard = variables.standard local v_overlay = variables.overlay local v_round = variables.round local v_test = variables.test local defaults = { chart = { name = "", option = "", backgroundcolor = "", width = 100*65536, height = 50*65536, dx = 30*65536, dy = 30*65536, offset = 0, bodyfont = "", dot = "", hcompact = variables_no, vcompact = variables_no, autofocus = "", focus = "", labeloffset = 5*65536, commentoffset = 5*65536, exitoffset = 0, }, shape = { -- FLOS rulethickness = 65536, default = "", framecolor = "darkblue", backgroundcolor = "lightgray", }, focus = { -- FLOF rulethickness = 65536, framecolor = "darkred", backgroundcolor = "gray", }, line = { -- FLOL rulethickness = 65536, radius = 10*65536, color = "darkgreen", corner = "", dash = "", arrow = "", offset = "", }, set = { -- FLOX }, split = { nx = 3, ny = 3, command = "", marking = "", before = "", after = "", } } local validshapes = { ["node"] = { kind = "shape", number = 0 }, ["action"] = { kind = "shape", number = 24 }, ["procedure"] = { kind = "shape", number = 5 }, ["product"] = { kind = "shape", number = 12 }, ["decision"] = { kind = "shape", number = 14 }, ["archive"] = { kind = "shape", number = 19 }, ["loop"] = { kind = "shape", number = 35 }, ["wait"] = { kind = "shape", number = 6 }, ["subprocedure"] = { kind = "shape", number = 20 }, ["singledocument"] = { kind = "shape", number = 32 }, ["multidocument"] = { kind = "shape", number = 33 }, ["right"] = { kind = "line", number = 66 }, ["left"] = { kind = "line", number = 67 }, ["up"] = { kind = "line", number = 68 }, ["down"] = { kind = "line", number = 69 }, } local validlabellocations = { l = "l", left = "l", r = "r", right = "r", t = "t", top = "t", b = "b", bottom = "b", lt = "lt", rt = "rt", lb = "lb", rb = "rb", tl = "tl", tr = "tr", bl = "bl", br = "br", } local validcommentlocations = { l = "l", left = "l", r = "r", right = "r", t = "t", top = "t", b = "b", bottom = "b", lt = "lt", rt = "rt", lb = "lb", rb = "rb", tl = "tl", tr = "tr", bl = "bl", br = "br", } local validtextlocations = { l = "l", left = "l", r = "r", right = "r", t = "t", top = "t", b = "b", bottom = "b", c = "c", center = "c", m = "c", middle = "m", lt = "lt", rt = "rt", lb = "lb", rb = "rb", tl = "lt", tr = "rt", bl = "lb", br = "rb", } setmetatableindex(validshapes,function(t,k) local l = gsub(lower(k)," ","") local v = rawget(t,l) if not v then local n = tonumber(k) if n then v = { kind = "shape", number = n } else v = rawget(t,"action") end end t[k] = v return v end) local charts = { } local data, hash, temp, last_x, last_y, name implement { name = "flow_start_chart", arguments = "string", actions = function(chartname) data = { } hash = { } last_x, last_y = 0, 0 name = chartname end } implement { name = "flow_stop_chart", actions = function() charts[name] = { data = data, hash = hash, last_x = last_x, last_y = last_y, } data, hash, temp = nil, nil, nil end } -- function commands.flow_set(chartname,chartdata) -- local hash = { } -- local data = { } -- charts[name] = { -- data = data, -- hash = hash, -- } -- for i=1,#chartdata do -- local di = data[i] -- local name = di.name or "" -- if name then -- data[#data+1] = { -- name = name, -- labels = di.labels or { }, -- comments = di.comments or { }, -- exits = di.exits or { }, -- connections = di.connections or { }, -- settings = di.settings or { }, -- x = di.x or 1, -- y = di.y or 1, -- } -- hash[name] = i -- end -- end -- end implement { name = "flow_reset", actions = function() charts[name] = nil end } implement { name = "flow_set_current_cell", arguments = "integer", actions = function(n) temp = data[n] or { } end } implement { name = "flow_start_cell", arguments = { { { "shape", { { "rulethickness", "dimension" }, { "default" }, { "framecolor" }, { "backgroundcolor" }, }, }, { "focus", { { "rulethickness", "dimension" }, { "framecolor" }, { "backgroundcolor" }, }, }, { "line", { { "rulethickness", "dimension" }, { "radius", "dimension" }, { "color" }, { "corner" }, { "dash" }, { "arrow" }, { "offset", "dimension" }, }, }, }, }, actions = function(settings) temp = { texts = { }, labels = { }, exits = { }, connections = { }, settings = settings, x = 1, y = 1, realx = 1, realy = 1, name = "", } end } implement { name = "flow_stop_cell", actions = function() data[#data+1] = temp hash[temp.name or #data] = temp end } implement { name = "flow_set_name", arguments = "string", actions = function(str) temp.name = str end } implement { name = "flow_set_shape", arguments = "string", actions = function(str) temp.shape = str end } implement { name = "flow_set_destination", arguments = "string", actions = function(str) temp.destination = str end } implement { name = "flow_set_text", arguments = "2 strings", actions = function(align,str) temp.texts[#temp.texts+1] = { align = align, text = str, } end } implement { name = "flow_set_overlay", arguments = "string", actions = function(str) temp.overlay = str end } implement { name = "flow_set_focus", arguments = "string", actions = function(str) temp.focus = str end } implement { name = "flow_set_figure", arguments = "string", actions = function(str) temp.figure = str end } implement { name = "flow_set_label", arguments = "2 strings", actions = function(location,text) temp.labels[#temp.labels+1] = { location = location, text = text, } end } implement { name = "flow_set_comment", arguments = "2 strings", actions = function(location,text) local connections = temp.connections if connections then local connection = connections[#connections] if connection then local comments = connection.comments if comments then comments[#comments+1] = { location = location, text = text, } end end end end } implement { name = "flow_set_exit", arguments = "2 strings", actions = function(location,text) temp.exits[#temp.exits+1] = { location = location, text = text, } end } implement { name = "flow_set_include", arguments = { "string", "integer", "integer", "string" }, actions = function(name,x,y,settings) data[#data+1] = { include = name, x = x, y = y, -- settings = settings, } end } local function inject(includedata,data,hash) local subchart = charts[includedata.include] if not subchart then return end local subdata = subchart.data if not subdata then return end local xoffset = (includedata.x or 1) - 1 local yoffset = (includedata.y or 1) - 1 local settings = includedata.settings for i=1,#subdata do local si = subdata[i] if si.include then inject(si,data,hash) else local x = si.x + xoffset local y = si.y + yoffset local t = { x = x, y = y, realx = x, realy = y, settings = settings, } setmetatableindex(t,si) data[#data+1] = t hash[si.name or #data] = t end end end local function pack(data,field) local list, max = { }, 0 for e=1,#data do local d = data[e] local f = d[field] list[f] = true if f > max then max = f end end for i=1,max do if not list[i] then for e=1,#data do local d = data[e] local f = d[field] if f > i then d[field] = f - 1 end end end end end local function expanded(chart,chartsettings) local expandeddata = { } local expandedhash = { } local expandedchart = { data = expandeddata, hash = expandedhash, } setmetatableindex(expandedchart,chart) local data = chart.data local hash = chart.hash for i=1,#data do local di = data[i] if di.include then inject(di,expandeddata,expandedhash) else expandeddata[#expandeddata+1] = di expandedhash[di.name or #expandeddata] = di end end -- expandedchart.settings = chartsettings or { } -- make locals chartsettings.shape = chartsettings.shape or { } chartsettings.focus = chartsettings.focus or { } chartsettings.line = chartsettings.line or { } chartsettings.set = chartsettings.set or { } chartsettings.split = chartsettings.split or { } chartsettings.chart = chartsettings.chart or { } setmetatableindex(chartsettings.shape,defaults.shape) setmetatableindex(chartsettings.focus,defaults.focus) setmetatableindex(chartsettings.line ,defaults.line ) setmetatableindex(chartsettings.set ,defaults.set ) setmetatableindex(chartsettings.split,defaults.split) setmetatableindex(chartsettings.chart,defaults.chart) -- if chartsettings.chart.vcompact == v_yes then pack(expandeddata,"y") end if chartsettings.chart.hcompact == v_yes then pack(expandeddata,"x") end -- for i=1,#expandeddata do local cell = expandeddata[i] local settings = cell.settings if not settings then cell.settings = chartsettings else settings.shape = settings.shape or { } settings.focus = settings.focus or { } settings.line = settings.line or { } setmetatableindex(settings.shape,chartsettings.shape) setmetatableindex(settings.focus,chartsettings.focus) setmetatableindex(settings.line ,chartsettings.line) end end return expandedchart end local splitter = lpeg.splitat(",") implement { name = "flow_set_location", arguments = "string", actions = function(x,y) if type(x) == "string" and not y then x, y = lpegmatch(splitter,x) end local oldx, oldy = x, y if not x or x == "" then x = last_x elseif type(x) == "number" then -- ok elseif x == "+" then x = last_x + 1 elseif x == "-" then x = last_x - 1 elseif find(x,"^[%+%-]") then x = last_x + (tonumber(x) or 0) else x = tonumber(x) end if not y or y == "" then y = last_y elseif type(y) == "number" then -- ok elseif y == "+" then y = last_y + 1 elseif x == "-" then y = last_y - 1 elseif find(y,"^[%+%-]") then y = last_y + (tonumber(y) or 0) else y = tonumber(y) end if x < 1 or y < 1 then report_chart("the cell (%s,%s) ends up at (%s,%s) and gets relocated to (1,1)",oldx or"?", oldy or "?", x,y) if x < 1 then x = 1 end if y < 1 then y = 1 end end temp.x = x or 1 temp.y = y or 1 temp.realx = x or 1 temp.realy = y or 1 last_x = x or last_x last_y = y or last_y end } implement { name = "flow_set_connection", arguments = "3 strings", actions = function(location,displacement,name) local dx, dy = lpegmatch(splitter,displacement) dx = tonumber(dx) dy = tonumber(dy) temp.connections[#temp.connections+1] = { location = location, dx = dx or 0, dy = dy or 0, name = name, comments = { }, } end } local function visible(chart,cell) local x, y = cell.x, cell.y return x >= chart.from_x and x <= chart.to_x and y >= chart.from_y and y <= chart.to_y and cell end local function process_cells(g,chart,xoffset,yoffset) local data = chart.data if not data then return end local focus = settings_to_hash(chart.settings.chart.focus or "") for i=1,#data do local cell = visible(chart,data[i]) if cell then local settings = cell.settings local shapesettings = settings.shape local shape = cell.shape if not shape or shape == "" then shape = shapesettings.default or "none" end if shape ~= v_none then local shapedata = validshapes[shape] ctx_tographic(g,"flow_begin_sub_chart ;") -- when is this needed if shapedata.kind == "line" then local linesettings = settings.line ctx_tographic(g,"flow_shape_line_color := %q ;", linesettings.color) ctx_tographic(g,"flow_shape_fill_color := %q ;","black") ctx_tographic(g,"flow_shape_line_width := %p ; ",linesettings.rulethickness) elseif focus[cell.focus] or focus[cell.name] then local focussettings = settings.focus ctx_tographic(g,"flow_shape_line_color := %q ;", focussettings.framecolor) ctx_tographic(g,"flow_shape_fill_color := %q ;", focussettings.backgroundcolor) ctx_tographic(g,"flow_shape_line_width := %p ; ",focussettings.rulethickness) else local shapesettings = settings.shape ctx_tographic(g,"flow_shape_line_color := %q ;", shapesettings.framecolor) ctx_tographic(g,"flow_shape_fill_color := %q ;", shapesettings.backgroundcolor) ctx_tographic(g,"flow_shape_line_width := %p ; ",shapesettings.rulethickness) end ctx_tographic(g,"flow_peepshape := false ;") -- todo ctx_tographic(g,"flow_new_shape(%s,%s,%s) ;",cell.x+xoffset,cell.y+yoffset,shapedata.number) ctx_tographic(g,"flow_end_sub_chart ;") end end end end -- todo : make lpeg for splitter local sign = S("+p") / "1" + S("-mn") / "-1" local full = C(P("left")) + C(P("right")) + C(P("top")) + C(P("bottom")) local char = P("l") / "left" + P("r") / "right" + P("t") / "top" + P("b") / "bottom" local space = P(" ")^0 local what = space * (sign + Cc("0")) * space * (full + char) * space * (sign + Cc("0")) * space * (full + char) * space * P(-1) -- print(lpegmatch(what,"lr")) -- print(lpegmatch(what,"+l+r")) -- print(lpegmatch(what,"+l")) -- print(lpegmatch(what,"+ left+r ")) local function process_connections(g,chart,xoffset,yoffset) local data = chart.data local hash = chart.hash if not data then return end local settings = chart.settings for i=1,#data do local cell = visible(chart,data[i]) if cell then local connections = cell.connections for j=1,#connections do local connection = connections[j] local othername = connection.name local othercell = hash[othername] if othercell then -- and visible(chart,data[i]) then local cellx, celly = cell.x, cell.y local otherx, othery, location = othercell.x, othercell.y, connection.location if otherx > 0 and othery > 0 and cellx > 0 and celly > 0 and location then local what_cell, where_cell, what_other, where_other = lpegmatch(what,location) if what_cell and where_cell and what_other and where_other then local linesettings = settings.line ctx_tographic(g,"flow_smooth := %s ;", linesettings.corner == v_round and "true" or "false") ctx_tographic(g,"flow_dashline := %s ;", linesettings.dash == v_yes and "true" or "false") ctx_tographic(g,"flow_arrowtip := %s ;", linesettings.arrow == v_yes and "true" or "false") ctx_tographic(g,"flow_touchshape := %s ;", linesettings.offset == v_none and "true" or "false") ctx_tographic(g,"flow_dsp_x := %s ; flow_dsp_y := %s ;",connection.dx or 0, connection.dy or 0) ctx_tographic(g,"flow_connection_line_color := %q ;",linesettings.color) ctx_tographic(g,"flow_connection_line_width := %p ;",linesettings.rulethickness) 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) ctx_tographic(g,"flow_dsp_x := 0 ; flow_dsp_y := 0 ;") end end end end end end end local 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]"] local f_texttemplate_l = formatters["\\doFLOWlabel{%i}{%i}{%i}{%i}{%i}"] local splitter = lpeg.splitat(":") local charttexts = { } -- permits " etc in mp implement { name = "flow_get_text", arguments = "integer", actions = function(n) if n > 0 then context(charttexts[n]) end end } local function process_texts(g,chart,xoffset,yoffset) local data = chart.data local hash = chart.hash if not data then return end charttexts = { } for i=1,#data do local cell = visible(chart,data[i]) if cell then local x = cell.x or 1 local y = cell.y or 1 local figure = cell.figure or "" local overlay = cell.overlay or "" local destination = cell.destination or "" local texts = cell.texts local noftexts = #texts local realx = cell.realx or x local realy = cell.realy or y if noftexts > 0 then for i=1,noftexts do local text = texts[i] local data = text.text local align = text.align or "" local align = validlabellocations[align] or align charttexts[#charttexts+1] = data 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)) if i == 1 then figure = "" overlay = "" destination = "" end end elseif figure ~= "" or overlay ~= "" or destination ~= "" then ctx_tographic(g,'flow_chart_draw_text(%s,%s,textext("%s")) ;',x,y,f_texttemplate_t(x,y,0,"",figure,overlay,destination,realx,realy)) end local labels = cell.labels for i=1,#labels do local label = labels[i] local text = label.text local location = label.location or "" local location = validlabellocations[location] or location if text and text ~= "" then charttexts[#charttexts+1] = text ctx_tographic(g,'flow_chart_draw_label(%s,%s,"%s",textext("%s")) ;',x,y,location,f_texttemplate_l(x,y,#charttexts,realx,realy)) end end local exits = cell.exits for i=1,#exits do local exit = exits[i] local text = exit.text local location = exit.location or "" local location = validlabellocations[location] or location if text ~= "" then -- maybe make autoexit an option if location == "l" and x == chart.from_x + 1 or location == "r" and x == chart.to_x - 1 or location == "t" and y == chart.to_y - 1 or location == "b" and y == chart.from_y + 1 then charttexts[#charttexts+1] = text ctx_tographic(g,'flow_chart_draw_exit(%s,%s,"%s",textext("%s")) ;',x,y,location,f_texttemplate_l(x,y,#charttexts,realx,realy)) end end end local connections = cell.connections for i=1,#connections do local comments = connections[i].comments for j=1,#comments do local comment = comments[j] local text = comment.text local location = comment.location or "" local length = 0 -- "tl" "tl:*" "tl:0.5" local loc, len = lpegmatch(splitter,location) -- do the following in lpeg if len == "*" then location = validcommentlocations[loc] or "" if location == "" then location = "*" else location = location .. ":*" end elseif loc then location = validcommentlocations[loc] or "*" length = tonumber(len) or 0 else location = validcommentlocations[location] or "" end if text and text ~= "" then charttexts[#charttexts+1] = text 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)) end end end end end end local function getchart(settings,forced_x,forced_y,forced_nx,forced_ny) if not settings then print("no settings given") return end local chartname = settings.chart.name if not chartname then print("no name given") return end local chart = charts[chartname] if not chart then print("no such chart",chartname) return end chart = expanded(chart,settings) local chartsettings = chart.settings.chart local autofocus = chart.settings.chart.autofocus if autofocus then autofocus = settings_to_hash(autofocus) if not next(autofocus) then autofocus = false end end -- check natural window local x = forced_x or tonumber(chartsettings.x) local y = forced_y or tonumber(chartsettings.y) local nx = forced_nx or tonumber(chartsettings.nx) local ny = forced_ny or tonumber(chartsettings.ny) -- local minx, miny, maxx, maxy = 0, 0, 0, 0 local data = chart.data for i=1,#data do local cell = data[i] if not autofocus or autofocus[cell.name] then -- offsets probably interfere with autofocus local x = cell.realx -- was bug: .x local y = cell.realy -- was bug: .y if minx == 0 or x < minx then minx = x end if miny == 0 or y < miny then miny = y end if minx == 0 or x > maxx then maxx = x end if miny == 0 or y > maxy then maxy = y end end end -- optional: if x + nx > maxx then nx = maxx - x + 1 end if y + ny > maxy then ny = maxy - y + 1 end -- -- check if window should be larger (maybe autofocus + nx/ny?) if autofocus then -- x and y are ignored if nx and nx > 0 then maxx = minx + nx - 1 end if ny and ny > 0 then maxy = miny + ny - 1 end else if x and x > 0 then minx = x end if y and y > 0 then miny = y end if nx and nx > 0 then maxx = minx + nx - 1 end if ny and ny > 0 then maxy = miny + ny - 1 end end -- print("3>",minx, miny, maxx, maxy) -- local nx = maxx - minx + 1 local ny = maxy - miny + 1 -- relocate cells for i=1,#data do local cell = data[i] cell.x = cell.realx - minx + 1 cell.y = cell.realy - miny + 1 end chart.from_x = 1 chart.from_y = 1 chart.to_x = nx chart.to_y = ny chart.nx = nx chart.ny = ny -- chart.shift_x = minx + 1 chart.shift_y = miny + 1 -- return chart end local function makechart_indeed(chart) local settings = chart.settings local chartsettings = settings.chart -- local g = ctx_startgraphic { instance = "metafun", format = "metafun", method = "scaled", definitions = "", wrapped = true, } -- ctx_tographic(g,"if unknown context_flow : input mp-char.mpiv ; fi ;") ctx_tographic(g,"flow_begin_chart(0,%s,%s);",chart.nx,chart.ny) -- if chartsettings.option == v_test or chartsettings.dot == v_yes then ctx_tographic(g,"flow_show_con_points := true ;") ctx_tographic(g,"flow_show_mid_points := true ;") ctx_tographic(g,"flow_show_all_points := true ;") elseif chartsettings.dot ~= "" then -- no checking done, private option ctx_tographic(g,"flow_show_%s_points := true ;",chartsettings.dot) end -- local backgroundcolor = chartsettings.backgroundcolor if backgroundcolor and backgroundcolor ~= "" then ctx_tographic(g,"flow_chart_background_color := %q ;",backgroundcolor) end -- local shapewidth = chartsettings.width local gridwidth = shapewidth + 2*chartsettings.dx local shapeheight = chartsettings.height local gridheight = shapeheight + 2*chartsettings.dy local chartoffset = chartsettings.offset local labeloffset = chartsettings.labeloffset local exitoffset = chartsettings.exitoffset local commentoffset = chartsettings.commentoffset local clipoffset = chartsettings.clipoffset ctx_tographic(g,"flow_grid_width := %p ;", gridwidth) ctx_tographic(g,"flow_grid_height := %p ;", gridheight) ctx_tographic(g,"flow_shape_width := %p ;", shapewidth) ctx_tographic(g,"flow_shape_height := %p ;", shapeheight) ctx_tographic(g,"flow_chart_offset := %p ;", chartoffset) ctx_tographic(g,"flow_label_offset := %p ;", labeloffset) ctx_tographic(g,"flow_exit_offset := %p ;", exitoffset) ctx_tographic(g,"flow_comment_offset := %p ;", commentoffset) -- local radius = settings.line.radius local rulethickness = settings.line.rulethickness local dx = chartsettings.dx local dy = chartsettings.dy if radius < rulethickness then radius = 2.5*rulethickness if radius > dx then radius = dx end if radius > dy then radius = dy end end ctx_tographic(g,"flow_connection_line_width := %p ;", rulethickness) ctx_tographic(g,"flow_connection_smooth_size := %p ;", radius) ctx_tographic(g,"flow_connection_arrow_size := %p ;", radius) ctx_tographic(g,"flow_connection_dash_size := %p ;", radius) -- local offset = chartsettings.offset -- todo: pass string if offset == v_none or offset == v_overlay or offset == "" then offset = -2.5 * radius -- or rulethickness? elseif offset == v_standard then offset = radius -- or rulethickness? end ctx_tographic(g,"flow_chart_offset := %p ;",offset) ctx_tographic(g,"flow_chart_clip_offset := %p ;",clipoffset) -- ctx_tographic(g,"flow_reverse_y := true ;") if chartsettings.option == v_test then ctx_tographic(g,"flow_draw_test_shapes ;") end -- process_cells(g,chart,0,0) process_connections(g,chart,0,0) process_texts(g,chart,0,0) -- -- ctx_tographic(g,"clip_chart(%s,%s,%s,%s) ;",x,y,nx,ny) -- todo: draw lines but not shapes ctx_tographic(g,"flow_end_chart ;") ctx_stopgraphic(g) -- end -- We need to wrap because of tex.runlocal! local function makechart(chart) context.hbox() context.bgroup() context.forgetall() context(function() makechart_indeed(chart) end) context.egroup() end local function splitchart(chart) local settings = chart.settings local splitsettings = settings.split local chartsettings = settings.chart -- local name = chartsettings.name -- local from_x = chart.from_x local from_y = chart.from_y local to_x = chart.to_x local to_y = chart.to_y -- local step_x = splitsettings.nx or to_x local step_y = splitsettings.ny or to_y local delta_x = splitsettings.dx or 0 local delta_y = splitsettings.dy or 0 -- report_chart("spliting %a from (%s,%s) upto (%s,%s) with steps (%s,%s) and overlap (%s,%s)", name,from_x,from_y,to_x,to_y,step_x,step_y,delta_x,delta_y) -- local part_x = 0 local first_x = from_x while true do part_x = part_x + 1 local last_x = first_x + step_x - 1 local done = last_x >= to_x if done then last_x = to_x end -- if first_x >= to_x then -- break -- end local part_y = 0 local first_y = from_y while true do part_y = part_y + 1 local last_y = first_y + step_y - 1 local done = last_y >= to_y if done then last_y = to_y end -- if first_y >= to_y then -- break -- end -- local data = chart.data for i=1,#data do local cell = data[i] -- inspect(cell) local cx, cy = cell.x, cell.y if cx >= first_x and cx <= last_x then if cy >= first_y and cy <= last_y then 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) local x = first_x local y = first_y local nx = last_x - first_x + 1 local ny = last_y - first_y + 1 context.beforeFLOWsplit() context.handleFLOWsplit(function() makechart(getchart(settings,x,y,nx,ny)) -- we need to pass frozen settings ! end) context.afterFLOWsplit() break end end end -- if done then break else first_y = last_y + 1 - delta_y end end if done then break else first_x = last_x + 1 - delta_x end end end implement { name = "flow_make_chart", arguments = { { { "chart", { { "name" }, { "option" }, { "backgroundcolor" }, { "width", "dimension" }, { "height", "dimension" }, { "dx", "dimension" }, { "dy", "dimension" }, { "offset", "dimension" }, -- { "bodyfont" }, { "dot" }, { "hcompact" }, { "vcompact" }, { "focus" }, { "autofocus" }, { "nx", "integer" }, { "ny", "integer" }, { "x", "integer" }, { "y", "integer" }, { "clipoffset", "dimension" }, { "labeloffset", "dimension" }, { "commentoffset", "dimension" }, { "exitoffset", "dimension" }, { "split" }, }, }, { "shape", { { "rulethickness", "dimension" }, { "default" }, { "framecolor" }, { "backgroundcolor" }, }, }, { "focus", { { "rulethickness", "dimension" }, { "framecolor" }, { "backgroundcolor" }, }, }, { "line", { { "rulethickness", "dimension" }, { "radius", "dimension" }, { "color" }, { "corner" }, { "dash" }, { "arrow" }, { "offset" }, }, }, { "split", { { "nx", "integer" }, { "ny", "integer" }, { "dx", "integer" }, { "dy", "integer" }, { "command" }, { "marking" }, { "before" }, { "after" }, }, }, -- { "set" }, } }, actions = function(settings) local chart = getchart(settings) if chart then local settings = chart.settings if settings then local chartsettings = settings.chart if chartsettings and chartsettings.split == v_yes then splitchart(chart) else makechart(chart) end else makechart(chart) end end end }