little tool for building Wardley maps
compute_layout = function(node, x,y, nodes_to_render, preserve_screen_top_of_cursor_node)
	-- append to nodes_to_render flattened instructions to render a hierarchy of nodes
	-- return x,y rendered until (surface coordinates)
	if node.type == 'text' then
		-- leaf node containing raw text
		node.x = x
		node.y = y
		-- render a bar to grab for moving the node
		local move_bar = {type='rectangle', r=0.8,g=0.8,b=0.8, x=node.x-10, y=node.y-10-5-10, h=10, id=node.id}
		table.insert(nodes_to_render, move_bar)
		-- render bounding box
		local bounding_box = {type='rectangle', drawmode='line', r=0.5, g=0.5, b=0.5, x=node.x-10, y=node.y-10, rx=5, id=node.id}
		table.insert(nodes_to_render, bounding_box)
		-- render contents
		if node.width then
			node.w = node.width
		else
			node.w = 0
			for i,s in ipairs(node.data) do
				local width = love.graphics.getFont():getWidth(s)/Viewport.zoom
				if node.w < width then node.w = width end
			end
		end
		if node.editor == nil then
			initialize_editor(node)
		else
			update_editor_box(node, preserve_screen_top_of_cursor_node)
		end
		node.h = box_height(node)
		table.insert(nodes_to_render, node)
		move_bar.w = node.w/2
		bounding_box.w = node.w+20
		local buffer_height = node_height(node)
		bounding_box.h = buffer_height+20
		-- resize affordance
		table.insert(nodes_to_render, {type='line', r=0.7,g=0.7,b=0.7, data={node.x+node.w+20,node.y, node.x+node.w+20,node.y+buffer_height}, id=node.id})
		table.insert(nodes_to_render, {type='line', r=0.7,g=0.7,b=0.7, data={node.x+node.w+20+4,node.y, node.x+node.w+20+4,node.y+buffer_height}, id=node.id})
	elseif node.type == 'rows' then
		node.x = x
		node.y = y
		local node_to_render
		if node.bg then
			node_to_render = {type='rectangle', r=node.bg.r, g=node.bg.g, b=node.bg.b, x=node.x, y=node.y}
			table.insert(nodes_to_render, node_to_render)
		end
		-- lay out children top to bottom
		local subx,suby = x,y
		local w,h = 0,0
		local subnodes
		for _,child in ipairs(node.data) do
			if child.margin then
				suby = suby+child.margin
				h = h+child.margin
			end
			if not child.width then
				child.width = node.width  -- HACK: should we set child.w or child.width? Neither is quite satisfactory.
			end
			subx,suby = compute_layout(child, x,suby, nodes_to_render)
			if w < child.w then
				w = child.w
			end
			h = h+child.h
		end
		node.w = w
		node.h = h
		if node_to_render then
			node_to_render.w = w
			node_to_render.h = h
		end
	elseif node.type == 'cols' then
		node.x = x
		node.y = y
		-- lay out children left to right
		local node_to_render
		if node.bg then
			node_to_render = {type='rectangle', r=node.bg.r, g=node.bg.g, b=node.bg.b, x=node.x, y=node.y}
			table.insert(nodes_to_render, node_to_render)
		end
		local subx,suby = x,y
		local w,h = 0,0
		for _,child in ipairs(node.data) do
			if child.margin then
				subx = subx+child.margin
				w = w+child.margin
			end
			subx,suby = compute_layout(child, subx,y, nodes_to_render)
			w = w + child.w
			if h < child.h then
				h = child.h
			end
		end
		node.w = w
		node.h = h
		if node_to_render then
			node_to_render.w = w
			node_to_render.h = h
		end
	end
	return x+node.w,y+node.h
end