node/lib/metasm/metasm/gui/dasm_graph.rb
def layout_layers(groups)
		order = order_graph(groups)
		# already a tree
		layers = create_layers(groups, order)
		return if layers.empty?

		layers.each { |l| l.each { |g| group_remove_hz_margin(g) } }

		# widest layer width
		maxlw = layers.map { |l| l.inject(0) { |ll, g| ll + g.w } }.max

		# center the 1st layer boxes on a segment that large
		x0 = -maxlw/2.0
		curlw = layers[0].inject(0) { |ll, g| ll + g.w }
		dx0 = (maxlw - curlw) / (2.0*layers[0].length)
		layers[0].each { |g|
			x0 += dx0
			g.x = x0
			x0 += g.w + dx0
		}

		# at this point, the goal is to reorder the most populated layer the best we can, and
		# move other layers' boxes accordingly
		layers[1..-1].each { |l|
			# for each subsequent layer, reorder boxes based on their ties with the previous layer
			i = 0
			l.replace l.sort_by { |g|
				# we know g.from is not empty (g would be in @layer[0])
				medfrom = g.from.inject(0.0) { |mx, gg| mx + (gg.x + gg.w/2.0) } / g.from.length
				# on ties, keep original order
				[medfrom, i]
			}
			# now they are reordered, update their #x accordingly
			# evenly distribute them in the layer
			x0 = -maxlw/2.0
			curlw = l.inject(0) { |ll, g| ll + g.w }
			dx0 = (maxlw - curlw) / (2.0*l.length)
			l.each { |g|
				x0 += dx0
				g.x = x0
				x0 += g.w + dx0
			}
		}

		layers[0...-1].reverse_each { |l|
			# for each subsequent layer, reorder boxes based on their ties with the previous layer
			i = 0
			l.replace l.sort_by { |g|
				if g.to.empty?
					# TODO floating end
					medfrom = 0
				else
					medfrom = g.to.inject(0.0) { |mx, gg| mx + (gg.x + gg.w/2.0) } / g.to.length
				end
				# on ties, keep original order
				[medfrom, i]
			}
			# now they are reordered, update their #x accordingly
			x0 = -maxlw/2.0
			curlw = l.inject(0) { |ll, g| ll + g.w }
			dx0 = (maxlw - curlw) / (2.0*l.length)
			l.each { |g|
				x0 += dx0
				g.x = x0
				x0 += g.w + dx0
			}
		}

		# now the boxes are (hopefully) sorted correctly
		# position them according to their ties with prev/next layer
		# from the maxw layer (positionning = packed), propagate adjacent layers positions
		maxidx = (0..layers.length).find { |i| l = layers[i] ; l.inject(0) { |ll, g| ll + g.w } == maxlw }
		# list of layer indexes to walk
		ilist = [maxidx]
		ilist.concat((maxidx+1...layers.length).to_a) if maxidx < layers.length-1
		ilist.concat((0..maxidx-1).to_a.reverse) if maxidx > 0
		layerbox = []
		ilist.each { |i|
			l = layers[i]
			curlw = l.inject(0) { |ll, g| ll + g.w }
			# left/rightmost acceptable position for the current box w/o overflowing on the right side
			minx = -maxlw/2.0
			maxx = minx + (maxlw-curlw)

			# replace whole layer with a box
			newg = layerbox[i] = Box.new(nil, l.map { |g| g.content }.flatten)
			newg.w = maxlw
			newg.h = l.map { |g| g.h }.max
			newg.x = -newg.w/2
			newg.y = -newg.h/2
			# dont care for from/to, we'll return a single box anyway

			l.each { |g|
				ref = (i < maxidx) ? g.to : g.from
				# TODO elastic positionning around the ideal position
				# (g and g+1 may have the same med, then center both on it)
				if i == maxidx
					nx = minx
				elsif ref.empty?
					nx = (minx+maxx)/2
				else
					# center on the outline of rx
					# may want to center on rx center's center ?
					rx = ref.sort_by { |gg| gg.x }
					med = (rx.first.x + rx.last.x + rx.last.w - g.w) / 2.0
					nx = [[med, minx].max, maxx].min
				end
				dx = nx+g.w/2
				g.content.each { |b| b.x += dx }
				minx = nx+g.w
				maxx += g.w
			}
		}

		newg = Box.new(nil, layerbox.map { |g| g.content }.flatten)
		newg.w = layerbox.map { |g| g.w }.max
		newg.h = layerbox.inject(0) { |h, g| h + g.h }
		newg.x = -newg.w/2
		newg.y = -newg.h/2

		# vertical: just center each box on its layer
		y0 = newg.y
		layerbox.each { |lg|
			lg.content.each { |b|
				b.y += y0-lg.y
			}
			y0 += lg.h
		}

		groups.replace [newg]
	end
# take all groups, order them by order, layout as layers
# always return a single group holding everything
take all groups, order them by order, layout as layers
always return a single group holding everything
take all groups order them by order layout as layers always return a single group holding everything
def layout_layers(groups)
		order = order_graph(groups)
		layers = create_layers(groups, order)
		return if layers.empty?
		layers.each { |l| l.each { |g| group_remove_hz_margin(g) } }
		maxlw = layers.map { |l| l.inject(0) { |ll, g| ll + g.w } }.max
		x0 = -maxlw/2.0
		curlw = layers[0].inject(0) { |ll, g| ll + g.w }
		dx0 = (maxlw - curlw) / (2.0*layers[0].length)
		layers[0].each { |g|
			x0 += dx0
			g.x = x0
			x0 += g.w + dx0
		}
		layers[1..-1].each { |l|
			i = 0
			l.replace l.sort_by { |g|
				medfrom = g.from.inject(0.0) { |mx, gg| mx + (gg.x + gg.w/2.0) } / g.from.length
				[medfrom, i]
			}
			x0 = -maxlw/2.0
			curlw = l.inject(0) { |ll, g| ll + g.w }
			dx0 = (maxlw - curlw) / (2.0*l.length)
			l.each { |g|
				x0 += dx0
				g.x = x0
				x0 += g.w + dx0
			}
		}
		layers[0...-1].reverse_each { |l|
			i = 0
			l.replace l.sort_by { |g|
				if g.to.empty?
					medfrom = 0
				else
					medfrom = g.to.inject(0.0) { |mx, gg| mx + (gg.x + gg.w/2.0) } / g.to.length
				end
				[medfrom, i]
			}
			x0 = -maxlw/2.0
			curlw = l.inject(0) { |ll, g| ll + g.w }
			dx0 = (maxlw - curlw) / (2.0*l.length)
			l.each { |g|
				x0 += dx0
				g.x = x0
				x0 += g.w + dx0
			}
		}
		maxidx = (0..layers.length).find { |i| l = layers[i] ; l.inject(0) { |ll, g| ll + g.w } == maxlw }
		ilist = [maxidx]
		ilist.concat((maxidx+1...layers.length).to_a) if maxidx < layers.length-1
		ilist.concat((0..maxidx-1).to_a.reverse) if maxidx > 0
		layerbox = []
		ilist.each { |i|
			l = layers[i]
			curlw = l.inject(0) { |ll, g| ll + g.w }
			minx = -maxlw/2.0
			maxx = minx + (maxlw-curlw)
			newg = layerbox[i] = Box.new(nil, l.map { |g| g.content }.flatten)
			newg.w = maxlw
			newg.h = l.map { |g| g.h }.max
			newg.x = -newg.w/2
			newg.y = -newg.h/2
			l.each { |g|
				ref = (i < maxidx) ? g.to : g.from
				if i == maxidx
					nx = minx
				elsif ref.empty?
					nx = (minx+maxx)/2
				else
					rx = ref.sort_by { |gg| gg.x }
					med = (rx.first.x + rx.last.x + rx.last.w - g.w) / 2.0
					nx = [[med, minx].max, maxx].min
				end
				dx = nx+g.w/2
				g.content.each { |b| b.x += dx }
				minx = nx+g.w
				maxx += g.w
			}
		}
		newg = Box.new(nil, layerbox.map { |g| g.content }.flatten)
		newg.w = layerbox.map { |g| g.w }.max
		newg.h = layerbox.inject(0) { |h, g| h + g.h }
		newg.x = -newg.w/2
		newg.y = -newg.h/2
		y0 = newg.y
		layerbox.each { |lg|
			lg.content.each { |b|
				b.y += y0-lg.y
			}
			y0 += lg.h
		}
		groups.replace [newg]
	end
def layout_layers ( groups ) order = order_graph ( groups ) layers = create_layers ( groups , order ) return if layers . empty? layers . each { | l | l . each { | g | group_remove_hz_margin ( g ) } } maxlw = layers . map { | l | l . inject ( 0 ) { | ll , g | ll + g . w } } . max x0 = - maxlw / 2.0 curlw = layers [ 0 ] . inject ( 0 ) { | ll , g | ll + g . w } dx0 = ( maxlw - curlw ) / ( 2.0 * layers [ 0 ] . length ) layers [ 0 ] . each { | g | x0 += dx0 g . x = x0 x0 += g . w + dx0 } layers [ 1 .. - 1 ] . each { | l | i = 0 l . replace l . sort_by { | g | medfrom = g . from . inject ( 0.0 ) { | mx , gg | mx + ( gg . x + gg . w / 2.0 ) } / g . from . length [ medfrom , i ] } x0 = - maxlw / 2.0 curlw = l . inject ( 0 ) { | ll , g | ll + g . w } dx0 = ( maxlw - curlw ) / ( 2.0 * l . length ) l . each { | g | x0 += dx0 g . x = x0 x0 += g . w + dx0 } } layers [ 0 ... - 1 ] . reverse_each { | l | i = 0 l . replace l . sort_by { | g | if g . to . empty? medfrom = 0 else medfrom = g . to . inject ( 0.0 ) { | mx , gg | mx + ( gg . x + gg . w / 2.0 ) } / g . to . length end [ medfrom , i ] } x0 = - maxlw / 2.0 curlw = l . inject ( 0 ) { | ll , g | ll + g . w } dx0 = ( maxlw - curlw ) / ( 2.0 * l . length ) l . each { | g | x0 += dx0 g . x = x0 x0 += g . w + dx0 } } maxidx = ( 0 .. layers . length ) . find { | i | l = layers [ i ] ; l . inject ( 0 ) { | ll , g | ll + g . w } == maxlw } ilist = [ maxidx ] ilist . concat ( ( maxidx + 1 ... layers . length ) . to_a ) if maxidx < layers . length - 1 ilist . concat ( ( 0 .. maxidx - 1 ) . to_a . reverse ) if maxidx > 0 layerbox = [ ] ilist . each { | i | l = layers [ i ] curlw = l . inject ( 0 ) { | ll , g | ll + g . w } minx = - maxlw / 2.0 maxx = minx + ( maxlw - curlw ) newg = layerbox [ i ] = Box . new ( nil , l . map { | g | g . content } . flatten ) newg . w = maxlw newg . h = l . map { | g | g . h } . max newg . x = - newg . w / 2 newg . y = - newg . h / 2 l . each { | g | ref = ( i < maxidx ) ? g . to : g . from if i == maxidx nx = minx elsif ref . empty? nx = ( minx + maxx ) / 2 else rx = ref . sort_by { | gg | gg . x } med = ( rx . first . x + rx . last . x + rx . last . w - g . w ) / 2.0 nx = [ [ med , minx ] . max , maxx ] . min end dx = nx + g . w / 2 g . content . each { | b | b . x += dx } minx = nx + g . w maxx += g . w } } newg = Box . new ( nil , layerbox . map { | g | g . content } . flatten ) newg . w = layerbox . map { | g | g . w } . max newg . h = layerbox . inject ( 0 ) { | h , g | h + g . h } newg . x = - newg . w / 2 newg . y = - newg . h / 2 y0 = newg . y layerbox . each { | lg | lg . content . each { | b | b . y += y0 - lg . y } y0 += lg . h } groups . replace [ newg ] end
take all groups, order them by order, layout as layers
always return a single group holding everything
take all groups order them by order layout as layers always return a single group holding everything
# already a tree # widest layer width # center the 1st layer boxes on a segment that large # at this point, the goal is to reorder the most populated layer the best we can, and # move other layers' boxes accordingly # for each subsequent layer, reorder boxes based on their ties with the previous layer # we know g.from is not empty (g would be in @layer[0]) # on ties, keep original order # now they are reordered, update their #x accordingly # evenly distribute them in the layer # for each subsequent layer, reorder boxes based on their ties with the previous layer # TODO floating end # on ties, keep original order # now they are reordered, update their #x accordingly # now the boxes are (hopefully) sorted correctly # position them according to their ties with prev/next layer # from the maxw layer (positionning = packed), propagate adjacent layers positions # list of layer indexes to walk # left/rightmost acceptable position for the current box w/o overflowing on the right side # replace whole layer with a box # dont care for from/to, we'll return a single box anyway # TODO elastic positionning around the ideal position # (g and g+1 may have the same med, then center both on it) # center on the outline of rx # may want to center on rx center's center ? # vertical: just center each box on its layer
groups