class Mahoujin::Graphics::Layout
Public Instance Methods
layout(atom, style, format)
click to toggle source
# File lib/mahoujin/graphics/layout.rb, line 4 def layout(atom, style, format) case format when :PNG then layout_in_png_format(atom, style) when :SVG then layout_in_svg_format(atom, style) else raise end end
Private Instance Methods
expand_atom_bbox(atom, padding)
click to toggle source
# File lib/mahoujin/graphics/layout.rb, line 197 def expand_atom_bbox(atom, padding) bbox = atom.bbox x, y = bbox.left, bbox.top bbox.top -= padding.fetch(:top, 0) * graphics_unit bbox.bottom += padding.fetch(:bottom, 0) * graphics_unit bbox.left -= padding.fetch(:left, 0) * graphics_unit bbox.right += padding.fetch(:right, 0) * graphics_unit move_recursively(atom, :top, y) move_recursively(atom, :left, x) end
graphics_unit()
click to toggle source
# File lib/mahoujin/graphics/layout.rb, line 42 def graphics_unit @style.basic[:unit] end
graphics_value(atom, attribute)
click to toggle source
# File lib/mahoujin/graphics/layout.rb, line 46 def graphics_value(atom, attribute) @style.query(atom.class, attribute) end
initialize_graphics_environment()
click to toggle source
# File lib/mahoujin/graphics/layout.rb, line 32 def initialize_graphics_environment @ctx.set_source_color(:black) @ctx.set_line_width(@style.basic[:line][:width]) @ctx.select_font_face(@style.basic[:font][:family], Cairo::FONT_SLANT_NORMAL, Cairo::FONT_WEIGHT_NORMAL) @ctx.set_font_size(@style.basic[:font][:size]) @style.basic[:unit] ||= @ctx.text_extents([*('A'..'Z'), *('a'..'z'), *('0'..'9')].join).height end
initialize_text_atom(atom, bsize, font)
click to toggle source
# File lib/mahoujin/graphics/layout.rb, line 186 def initialize_text_atom(atom, bsize, font) bbox = atom.bbox text = atom.content bbox.top = 0 bbox.left = 0 bbox.width = bsize.fetch(:width, 0) * graphics_unit + measure_text_metrics(text, font).width bbox.height = bsize.fetch(:height, 0) * graphics_unit bbox.centerline = bbox.top + bbox.height.fdiv(2) end
layout_atom(atom)
click to toggle source
# File lib/mahoujin/graphics/layout.rb, line 60 def layout_atom(atom) send "layout_#{atom.class.underscore_name}", atom end
layout_choice(atom)
click to toggle source
# File lib/mahoujin/graphics/layout.rb, line 107 def layout_choice(atom) atom.atoms.each { |a| layout_atom(a) } reference = atom.atoms.max(&->(a1, a2) { a1.bbox.width <=> a2.bbox.width }) space = graphics_value(atom, :space) * graphics_unit top = 0 atom.atoms.each do |a| move_recursively(a, :top, top) top += a.bbox.height + space end bbox = Graphics::Utilities::Rectangle.new(0, 0, reference.bbox.width, top - space) bbox.centerline = reference.bbox.centerline atom.bbox.sync_with(bbox) expand_atom_bbox(atom, graphics_value(atom, :padding)) end
layout_concatenation(atom)
click to toggle source
# File lib/mahoujin/graphics/layout.rb, line 126 def layout_concatenation(atom) atom.atoms.each { |a| layout_atom(a) } reference = atom.atoms.max(&->(a1, a2) { a1.bbox.height <=> a2.bbox.height }) space = graphics_value(atom, :space) * graphics_unit left = 0 atom.atoms.each do |a| move_recursively(a, :top, reference.bbox.centerline + (a.bbox.top - a.bbox.centerline)) move_recursively(a, :left, left) left += a.bbox.width + space end bbox = Graphics::Utilities::Rectangle.new(0, 0, left - space, reference.bbox.height) bbox.centerline = reference.bbox.centerline atom.bbox.sync_with(bbox) end
layout_exception(atom)
click to toggle source
# File lib/mahoujin/graphics/layout.rb, line 174 def layout_exception(atom) initialize_text_atom(atom, graphics_value(atom, :bsize), graphics_value(atom, :font)) end
layout_grouping(atom)
click to toggle source
# File lib/mahoujin/graphics/layout.rb, line 165 def layout_grouping(atom) layout_atom(atom.atom) atom.bbox.sync_with(atom.atom.bbox) end
layout_in_png_format(atom, style)
click to toggle source
# File lib/mahoujin/graphics/layout.rb, line 14 def layout_in_png_format(atom, style) Cairo::ImageSurface.new(200, 200) do |surface| @ctx = Cairo::Context.new(surface) @style = style initialize_graphics_environment layout_atom(atom) end end
layout_in_svg_format(atom, style)
click to toggle source
# File lib/mahoujin/graphics/layout.rb, line 23 def layout_in_svg_format(atom, style) Cairo::SVGSurface.new(StringIO.new, 200, 200) do |surface| @ctx = Cairo::Context.new(surface) @style = style initialize_graphics_environment layout_atom(atom) end end
layout_non_terminal(atom)
click to toggle source
# File lib/mahoujin/graphics/layout.rb, line 178 def layout_non_terminal(atom) initialize_text_atom(atom, graphics_value(atom, :bsize), graphics_value(atom, :font)) end
layout_optional(atom)
click to toggle source
# File lib/mahoujin/graphics/layout.rb, line 151 def layout_optional(atom) layout_atom(atom.atom) atom.bbox.sync_with(atom.atom.bbox) expand_atom_bbox(atom, graphics_value(atom, :padding)) end
layout_prose(atom)
click to toggle source
# File lib/mahoujin/graphics/layout.rb, line 170 def layout_prose(atom) initialize_text_atom(atom, graphics_value(atom, :bsize), graphics_value(atom, :font)) end
layout_rule(atom)
click to toggle source
# File lib/mahoujin/graphics/layout.rb, line 82 def layout_rule(atom) layout_atom(atom.rule_name_atom) layout_atom(atom.atom) space = graphics_value(atom, :space) * graphics_unit top = 0 atoms = [atom.rule_name_atom, atom.atom] atoms.each do |a| move_recursively(a, :top, top) top += a.bbox.height + space end bbox = Graphics::Utilities::Rectangle.new(0, 0, atoms.map(&:bbox).map(&:width).max, top - space) bbox.centerline = atom.atom.bbox.centerline atom.bbox.sync_with(bbox) expand_atom_bbox(atom, graphics_value(atom, :padding)) move_recursively(atom.rule_name_atom, :left, 0) end
layout_rule_name(atom)
click to toggle source
# File lib/mahoujin/graphics/layout.rb, line 103 def layout_rule_name(atom) initialize_text_atom(atom, graphics_value(atom, :bsize), graphics_value(atom, :font)) end
layout_specific_repetition(atom)
click to toggle source
# File lib/mahoujin/graphics/layout.rb, line 144 def layout_specific_repetition(atom) layout_atom(atom.atom) atom.bbox.sync_with(atom.atom.bbox) expand_atom_bbox(atom, graphics_value(atom, :padding)) end
layout_syntax(atom)
click to toggle source
# File lib/mahoujin/graphics/layout.rb, line 64 def layout_syntax(atom) atom.atoms.each { |a| layout_atom(a) } space = graphics_value(atom, :space) * graphics_unit top = 0 atom.atoms.each do |a| move_recursively(a, :top, top) top += a.bbox.height + space end bbox = Graphics::Utilities::Rectangle.new(0, 0, atom.atoms.map(&:bbox).map(&:width).max, top - space) bbox.centerline = 0 atom.bbox.sync_with(bbox) expand_atom_bbox(atom, graphics_value(atom, :padding)) end
layout_terminal(atom)
click to toggle source
# File lib/mahoujin/graphics/layout.rb, line 182 def layout_terminal(atom) initialize_text_atom(atom, graphics_value(atom, :bsize), graphics_value(atom, :font)) end
layout_zero_or_more_repetition(atom)
click to toggle source
# File lib/mahoujin/graphics/layout.rb, line 158 def layout_zero_or_more_repetition(atom) layout_atom(atom.atom) atom.bbox.sync_with(atom.atom.bbox) expand_atom_bbox(atom, graphics_value(atom, :padding)) end
measure_text_metrics(text, font)
click to toggle source
# File lib/mahoujin/graphics/layout.rb, line 50 def measure_text_metrics(text, font) @ctx.save @ctx.select_font_face(@ctx.font_face.family, @ctx.font_face.slant, Cairo::FONT_WEIGHT_BOLD) if font[:bold] @ctx.select_font_face(@ctx.font_face.family, Cairo::FONT_SLANT_ITALIC, @ctx.font_face.weight) if font[:italic] @ctx.set_font_size(font[:size]) if font[:size] @ctx.text_extents(text) ensure @ctx.restore end
move_recursively(atom, bound, coordinate)
click to toggle source
# File lib/mahoujin/graphics/layout.rb, line 210 def move_recursively(atom, bound, coordinate) difference = coordinate - atom.bbox.send(bound) atom.bbox.send("move_#{bound}", coordinate) atom.atom.tap(&->(a) { move_recursively(a, bound, a.bbox.send(bound) + difference) }) if atom.respond_to?(:atom) atom.atoms.each(&->(a) { move_recursively(a, bound, a.bbox.send(bound) + difference) }) if atom.respond_to?(:atoms) atom.rule_name_atom.tap(&->(a) { move_recursively(a, bound, a.bbox.send(bound) + difference) }) if atom.is_a?(Atoms::Rule) end