class TreeGraph

Public Class Methods

new(e_list, metrics, symmetrize, color, leafstyle, multibyte, fontstyle, font, font_it, font_bd, font_itbd, font_cjk, font_size, margin) click to toggle source
Calls superclass method Graph::new
# File lib/rsyntaxtree/tree_graph.rb, line 22
def initialize(e_list, metrics, symmetrize, color, leafstyle, multibyte,
               fontstyle, font, font_it, font_bd, font_itbd, font_cjk, font_size,
               margin)

  # Store class-specific parameters
  @fontstyle  = fontstyle
  @font       = multibyte ? font_cjk : font
  @font_size  = font_size
  @font_it    = font_it
  @font_bd    = font_bd
  @font_itbd  = font_itbd
  @font_cjk   = font_cjk
  @margin     = margin

  super(e_list, metrics, symmetrize, color, leafstyle, multibyte, @font, @font_size)

  # Initialize the image and colors
  @im           = Image.new(@width, @height)
  @im.interlace = PlaneInterlace
  @gc           = Draw.new
  @gc.font      = @font
  @gc.pointsize(@font_size)
end

Public Instance Methods

destroy() click to toggle source
# File lib/rsyntaxtree/tree_graph.rb, line 46
def destroy
  @im.destroy!
end
draw() click to toggle source
# File lib/rsyntaxtree/tree_graph.rb, line 50
def draw
  parse_list
  @gc.draw(@im)
end
draw_element(x, y, w, string, type) click to toggle source

Add the element into the tree (draw it)

# File lib/rsyntaxtree/tree_graph.rb, line 74
def draw_element(x, y, w, string, type)
  string = string.sub(/\^\z/){""}
  # Calculate element dimensions and position
  if (type == ETYPE_LEAF) and @leafstyle == "nothing"
    top = row2px(y - 1) + (@font_size * 1.5)
  else
    top   = row2px(y)
  end
  left   = x + @m[:b_side]
  bottom = top  + @e_height
  right  = left + w

  # Split the string into the main part and the
  # subscript part of the element (if any)
  parts = string.split("_", 2)
  if(parts.length > 1 )
    main = parts[0].strip
    sub  = parts[1].gsub(/_/, " ").strip
  else
    main = parts[0].strip
    sub  = ""
  end

  if /\A\+(.+)\+\z/ =~ main
    main = $1
    main_decoration = OverlineDecoration
  elsif /\A\-(.+)\-\z/ =~ main
    main = $1
    main_decoration = UnderlineDecoration
  elsif /\A\=(.+)\=\z/ =~ main
    main = $1
    main_decoration = LineThroughDecoration
  else
    main_decoration = NoDecoration
  end

  if /\A\*\*\*(.+)\*\*\*\z/ =~ main
    main = $1
    if !@multibyte
      main_font = @font_itbd
    end
  elsif /\A\*\*(.+)\*\*\z/ =~ main
    main = $1
    if !@multibyte
      main_font = @font_bd
    end
  elsif /\A\*(.+)\*\z/ =~ main
    main = $1
    if !@multibyte
      main_font = @font_it
    end
  else
    main_font = @font
  end

  # Calculate text size for the main and the
  # subscript part of the element
  # symbols for underline/overline removed temporarily

  main_width = img_get_txt_width(main, main_font, @font_size)

  if /\A\+(.+)\+\z/ =~ sub
    sub = $1
    sub_decoration = OverlineDecoration
  elsif /\A\-(.+)\-\z/ =~ sub
    sub = $1
    @gc.decorate(UnderlineDecoration)
    sub_decoration = UnderlineDecoration
  elsif /\A\=(.+)\=\z/ =~ sub
    sub = $1
    sub_decoration = LineThroughDecoration
  else
    sub_decoration = NoDecoration
  end

  sub_font = @font

  if /\A\*\*\*(.+)\*\*\*\z/ =~ sub
    sub = $1
    if !@multibyte
      sub_font = @font_itbd
    end
  elsif /\A\*\*(.+)\*\*\z/ =~ sub
    sub = $1
    if !@multibyte
      sub_font = @font_bd
    end
  elsif /\A\*(.+)\*\z/ =~ sub
    sub = $1
    if !@multibyte
      sub_font = @font_it
    end
  else
    sub_font = @font
  end

  if sub != ""
    sub_width  = img_get_txt_width(sub.to_s, sub_font, @sub_size)
  else
    sub_width = 0
  end

  # Center text in the element
  txt_width = main_width + sub_width

  txt_pos   = left + (right - left) / 2 - txt_width / 2

  # Select apropriate color
  if(type == ETYPE_LEAF)
    col = @col_leaf
  else
    col = @col_node
  end

  if(main[0].chr == "<" && main[-1].chr == ">")
    col = @col_trace
  end

  @gc.stroke("none")
  @gc.fill(col)

  # Draw main text
  @gc.pointsize(@font_size)
  main_x = txt_pos
  main_y = top + @e_height - @m[:e_padd]

  @gc.interline_spacing = -(@main_height / 3)
  @gc.font(main_font)
  @gc.decorate(main_decoration)
  @gc.text(main_x.ceil, main_y.ceil, main)

  # Draw subscript text
  if (sub.length > 0 )
    @gc.pointsize(@sub_size)
    sub_x = txt_pos + main_width + @sub_space_width
    sub_y = top + (@e_height - @m[:e_padd] + @sub_size / 2)
    @gc.font(sub_font)
    @gc.decorate(sub_decoration)
    @gc.text(sub_x.ceil, sub_y.ceil, sub)
  end
end
fix_child_size(id, current, target) click to toggle source

If a node element text is wider than the sum of it's

child elements, then the child elements need to
be resized to even out the space. This function
recurses down the a child tree and sizes the
children appropriately.
# File lib/rsyntaxtree/tree_graph.rb, line 266
def fix_child_size(id, current, target)
  children = @e_list.get_children(id)
  @e_list.set_element_width(id, target)

  if(children.length > 0 )
    delta = target - current
    target_delta = delta / children.length

    children.each do |child|
      child_width = @e_list.get_element_width(child)
      fix_child_size(child, child_width, child_width + target_delta)
    end
  end
end
img_get_txt_width(text, font, font_size, multiline = false) click to toggle source
# File lib/rsyntaxtree/tree_graph.rb, line 281
def img_get_txt_width(text, font, font_size, multiline = false)
  parts = text.split("_", 2)
  main_before = parts[0].strip
  sub = parts[1]
  main = get_txt_only(main_before)
  main_metrics = img_get_txt_metrics(main, font, font_size, multiline)
  width = main_metrics.width
  if sub
    sub_metrics = img_get_txt_metrics(sub.strip, font, font_size * SUBSCRIPT_CONST, multiline)
    width += sub_metrics.width
  end
  return width
end
line_to_parent(fromX, fromY, fromW, toX, toW) click to toggle source

Draw a line between child/parent elements

# File lib/rsyntaxtree/tree_graph.rb, line 217
def line_to_parent(fromX, fromY, fromW, toX, toW)

  if (fromY == 0 )
    return
  end

  fromTop  = row2px(fromY)
  fromLeft = (fromX + fromW / 2 + @m[:b_side])
  toBot    = (row2px(fromY - 1 ) + @e_height)
  toLeft  = (toX + toW / 2 + @m[:b_side])

  @gc.fill("none")
  @gc.stroke @col_line
  @gc.stroke_width 1
  @gc.line(fromLeft.ceil, fromTop.ceil, toLeft.ceil, toBot.ceil)
end
save(filename) click to toggle source
# File lib/rsyntaxtree/tree_graph.rb, line 55
def save(filename)
  draw
  @im.write(filename)
end
to_blob(fileformat='PNG') click to toggle source

inspired by the implementation of Gruff by Geoffrey Grosenbach

# File lib/rsyntaxtree/tree_graph.rb, line 62
def to_blob(fileformat='PNG')
  draw
  @im.border!(@margin, @margin, "white")
  return @im.to_blob do
    self.format = fileformat
    self.interlace = PlaneInterlace
  end
end
triangle_to_parent(fromX, fromY, fromW, textW, symmetrize = true) click to toggle source

Draw a triangle between child/parent elements

# File lib/rsyntaxtree/tree_graph.rb, line 235
def triangle_to_parent(fromX, fromY, fromW, textW, symmetrize = true)
  if (fromY == 0)
    return
  end

  toX = fromX
  fromCenter = (fromX + fromW / 2 + @m[:b_side])

  fromTop  = row2px(fromY).ceil
  fromLeft1 = (fromCenter + textW / 2).ceil
  fromLeft2 = (fromCenter - textW / 2).ceil
  toBot    = (row2px(fromY - 1) + @e_height)
  if symmetrize
    toLeft   = (toX + textW / 2 + @m[:b_side])
  else
    toLeft   = (toX + textW / 2 + @m[:b_side] * 3)
  end

  @gc.fill("none")
  @gc.stroke @col_line
  @gc.stroke_width 1
  @gc.line(fromLeft1, fromTop, toLeft, toBot)
  @gc.line(fromLeft2, fromTop, toLeft, toBot)
  @gc.line(fromLeft1, fromTop, fromLeft2, fromTop)
end