rsyntaxtree 0.7.2 → 0.7.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4579e09d625fbfed3bf8415818f1d3e1faae5f1c
4
- data.tar.gz: b8541960fc98bc992340960990bf53a36a73730d
3
+ metadata.gz: '0586aec9488760401c729ef70db38c730883341e'
4
+ data.tar.gz: f9f95b8713cbcef850c3be737e5cd2cd2c3babe5
5
5
  SHA512:
6
- metadata.gz: fa4628dc3690b7532d80ca4d093d12fef301a8054ab034d9ea8b45302e802c65ac96d3cc2ce12edba514d439d75f6851e8d4297c50e042c9a2b1e2a56f7c9735
7
- data.tar.gz: a11e485de6a1cdc3f11be9d75e0177b6b7f46ec6fbc1b6a23ba827227e593610a99206c26271f6dd4b2cc194316cb41bbefdab7eb872c7b44c4f97bab96bfdc0
6
+ metadata.gz: cbbe7a1e063d5098f40b0f67b1fe832b92ff58b3bb7d9b3823ccafae6979dd1930c7b7ac5f787b0cdf17eeda267c15faf5c2305b843576cff15b83f062bd6be3
7
+ data.tar.gz: dfa583dbcf971ccaab04ce2db7f3dd633e0110e575063ab82cf80b740e73348397d41afa6922595d2a12c0a709b717f48ac7949f626d0235a907eb14223f1e76
data/README.md CHANGED
@@ -15,7 +15,7 @@ Working web interface of is available at <https://yohasebe.com/rsyntaxtree>.
15
15
  For the web interface, see Usage section of <https://yohasebe.com/rsyntaxtree>.
16
16
 
17
17
  For the command-line interface, type `$rsyntaxtree -h` after installation. Here's what you get:
18
-
18
+
19
19
  ```text
20
20
  RSyntaxTree, (linguistic) syntax tree generator written in Ruby.
21
21
 
@@ -25,14 +25,14 @@ where [options] are:
25
25
  -o, --outdir=<s> Output directory (default: ./)
26
26
  -f, --format=<s> Output format: png, pdf, or svg (default: png)
27
27
  -l, --leafstyle=<s> visual style of tree leaves: auto, triangle, bar, or nothing (default: auto)
28
- -n, --fontstyle=<s> Font style (available when ttf font is specified): sans, serif, mono, cjk (default: sans)
28
+ -n, --fontstyle=<s> Font style: sans, serif, cjk (default: sans)
29
29
  -t, --font=<s> Path to a ttf font used to generate tree (optional)
30
30
  -s, --fontsize=<i> Size: 8-26 (default: 16)
31
31
  -c, --color=<s> Color text and bars: on or off (default: on)
32
32
  -y, --symmetrize=<s> Generate symmetrical, balanced tree: on or off (default: on)
33
33
  -a, --autosub=<s> Put subscript numbers to nodes: on or off (default: off)
34
34
  -m, --margin=<i> Margin: 0-120 (default: 0)
35
- -v, --vheight=<f> Connector Height: 0.5-2.0 (default: 0.5)
35
+ -v, --vheight=<f> Connector Height: 0.5-2.0 (default: 1.0)
36
36
  -e, --version Print version and exit
37
37
  -h, --help Show this message
38
38
  ```
@@ -22,7 +22,7 @@ EOS
22
22
  :default => "png"
23
23
  opt :leafstyle, "visual style of tree leaves: auto, triangle, bar, or nothing",
24
24
  :default => "auto"
25
- opt :fontstyle, "Font style (available when ttf font is specified): sans, serif, mono, cjk",
25
+ opt :fontstyle, "Font style (available when ttf font is specified): sans, serif, cjk",
26
26
  :default => "sans"
27
27
  opt :font, "Path to a ttf font used to generate tree (optional)", :type => String
28
28
  opt :fontsize, "Size: 8-26",
@@ -42,7 +42,7 @@ end
42
42
  Trollop::die :outdir, "must be an exsting directory path" unless FileTest::directory?(opts[:outdir])
43
43
  Trollop::die :format, "must be png, jpg, gif, or svg" unless /\A(png|jpg|gif|pdf|svg)\z/ =~ opts[:format]
44
44
  Trollop::die :leafstyle, "must be auto, triangle, bar, or nothing" unless /\A(auto|triangle|bar|nothing)\z/ =~ opts[:leafstyle]
45
- Trollop::die :fontstyle, "must be sans, serif, mono, cjk" unless /\A(sans|serif|mono|cjk)\z/ =~ opts[:fontstyle]
45
+ Trollop::die :fontstyle, "must be sans, serif, cjk" unless /\A(sans|serif|cjk)\z/ =~ opts[:fontstyle]
46
46
  Trollop::die :font, "must be path to an existing ttf font" if opts[:font] && !File::exists?(opts[:font])
47
47
  Trollop::die :fontsize, "must be in the range of 8-26" unless opts[:fontsize] >= 8 && opts[:fontsize] <= 26
48
48
  Trollop::die :color, "must be either on or off" unless /\A(on|off)\z/ =~ opts[:color]
Binary file
Binary file
Binary file
@@ -12,25 +12,11 @@
12
12
  # excellent program phpSyntaxTree.
13
13
  # Copyright (c) 2007-2018 Yoichiro Hasebe <yohasebe@gmail.com>
14
14
  # Copyright (c) 2003-2004 Andre Eisenbach <andre@ironcreek.net>
15
- #
16
- # This program is free software; you can redistribute it and/or modify
17
- # it under the terms of the GNU General Public License as published by
18
- # the Free Software Foundation; either version 2 of the License, or
19
- # (at your option) any later version.
20
- #
21
- # This program is distributed in the hope that it will be useful,
22
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
23
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24
- # GNU General Public License for more details.
25
- #
26
- # You should have received a copy of the GNU General Public License
27
- # along with this program; if not, write to the Free Software
28
- # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29
15
 
30
16
  $LOAD_PATH << File.join( File.dirname(__FILE__), 'rsyntaxtree')
31
17
 
32
18
  require 'uri'
33
- require 'imgutils'
19
+ require 'utils'
34
20
  require 'element'
35
21
  require 'elementlist'
36
22
  require 'string_parser'
@@ -38,13 +24,13 @@ require 'tree_graph'
38
24
  require 'svg_graph'
39
25
  require 'error_message'
40
26
  require 'version'
41
- require 'pp'
42
27
 
43
28
  FONT_DIR = File.expand_path(File.dirname(__FILE__) + "/../fonts")
44
29
 
45
30
  ETYPE_UNDEFINED = 0
46
31
  ETYPE_NODE = 1
47
32
  ETYPE_LEAF = 2
33
+ SUBSCRIPT_CONST = 0.7
48
34
 
49
35
  class RSGenerator
50
36
  def initialize(params = {})
@@ -61,6 +47,7 @@ class RSGenerator
61
47
  .gsub('-OABRACKET-', '<')
62
48
  .gsub('-CABRACKET-', '>')
63
49
  new_params[key] = data
50
+ new_params[:multibyte] = data.contains_cjk?
64
51
  when :symmetrize, :color, :autosub
65
52
  new_params[key] = value && value != "off" ? true : false
66
53
  when :fontsize
@@ -71,23 +58,32 @@ class RSGenerator
71
58
  new_params[key] = value.to_f
72
59
  when :fontstyle
73
60
  if value == "noto-sans" || value == "sans"
74
- new_params[:font] = FONT_DIR + "/NotoSansCJKjp-Regular.otf"
61
+ new_params[:font] = FONT_DIR + "/NotoSans-Regular.ttf"
62
+ new_params[:font_it] = FONT_DIR + "/NotoSans-Italic.ttf"
63
+ new_params[:font_bd] = FONT_DIR + "/NotoSans-Bold.ttf"
64
+ new_params[:font_bdit] = FONT_DIR + "/NotoSans-BoldItalic.ttf"
65
+ new_params[:font_cjk] = FONT_DIR + "/NotoSansCJKjp-Regular.otf"
66
+ new_params[:fontstyle] = "sans"
75
67
  elsif value == "noto-serif" || value == "serif"
76
- new_params[:font] = FONT_DIR + "/NotoSerifCJKjp-Regular.otf"
77
- elsif value == "noto-mono" || value == "mono"
78
- new_params[:font] = FONT_DIR + "/NotoSansMonoCJKjp-Regular.otf"
79
- elsif value == "western-sans"
80
- new_params[:font] = FONT_DIR + "/DroidSans.ttf"
81
- elsif value == "western-serif"
82
- new_params[:font] = FONT_DIR + "/DroidSerif-Regular.ttf"
68
+ new_params[:font] = FONT_DIR + "/NotoSerif-Regular.ttf"
69
+ new_params[:font_it] = FONT_DIR + "/NotoSerif-Italic.ttf"
70
+ new_params[:font_bd] = FONT_DIR + "/NotoSerif-Bold.ttf"
71
+ new_params[:font_bdit] = FONT_DIR + "/NotoSerif-BoldItalic.ttf"
72
+ new_params[:font_cjk] = FONT_DIR + "/NotoSerifCJKjp-Regular.otf"
73
+ new_params[:fontstyle] = "serif"
83
74
  elsif value == "cjk zenhei" || value == "cjk"
84
75
  new_params[:font] = FONT_DIR + "/wqy-zenhei.ttf"
76
+ new_params[:font_it] = FONT_DIR + "/NotoSans-Italic.ttf"
77
+ new_params[:font_bd] = FONT_DIR + "/NotoSans-Bold.ttf"
78
+ new_params[:font_bdit] = FONT_DIR + "/NotoSans-BoldItalic.ttf"
79
+ new_params[:font_cjk] = FONT_DIR + "/wqy-zenhei.ttf"
80
+ new_params[:fontstyle] = "sans"
85
81
  end
86
82
  else
87
83
  new_params[key] = value
88
84
  end
89
85
  end
90
-
86
+
91
87
  @params = {
92
88
  :symmetrize => true,
93
89
  :color => true,
@@ -95,11 +91,15 @@ class RSGenerator
95
91
  :fontsize => 18,
96
92
  :format => "png",
97
93
  :leafstyle => "auto",
98
- :font => FONT_DIR + "/NotoSansCKjp-Regular.otf",
99
94
  :filename => "syntree",
100
95
  :data => "",
101
96
  :margin => 0,
102
- :vheight => 1.0
97
+ :vheight => 1.0,
98
+ :fontstyle => "sans",
99
+ :font => "/NotoSansCJKjp-Regular.otf",
100
+ :font_it => "/NotoSans-Italic.ttf",
101
+ :font_bd => "/NotoSans-Bold.ttf",
102
+ :font_bdit => "/NotoSans-BoldItalic.ttf",
103
103
  }
104
104
  @metrics = {
105
105
  :e_width => 120,
@@ -109,7 +109,7 @@ class RSGenerator
109
109
  :b_side => 10,
110
110
  :b_topbot => 10
111
111
  }
112
-
112
+
113
113
  @params.merge! new_params
114
114
  @params[:fontsize] = @params[:fontsize] * 2
115
115
  @params[:margin] = @params[:margin] * 2
@@ -120,7 +120,7 @@ class RSGenerator
120
120
  sp = StringParser.new(text)
121
121
  sp.valid?
122
122
  end
123
-
123
+
124
124
  def draw_png
125
125
  @params[:format] = "png"
126
126
  draw_tree
@@ -140,17 +140,7 @@ class RSGenerator
140
140
  @params[:format] = "pdf"
141
141
  draw_tree
142
142
  end
143
-
144
- def draw_tree
145
- sp = StringParser.new(@params[:data])
146
- sp.parse
147
- sp.auto_subscript if @params[:autosub]
148
- elist = sp.get_elementlist
149
- graph = TreeGraph.new(elist, @metrics,
150
- @params[:symmetrize], @params[:color], @params[:leafstyle], @params[:font], @params[:fontsize], @params[:format], @params[:margin])
151
- graph.to_blob(@params[:format])
152
- end
153
-
143
+
154
144
  def draw_svg
155
145
  @params[:format] = "svg"
156
146
  sp = StringParser.new(@params[:data].gsub('&', '&amp;').gsub('%', '&#37;'))
@@ -158,8 +148,23 @@ class RSGenerator
158
148
  sp.auto_subscript if @params[:autosub]
159
149
  elist = sp.get_elementlist
160
150
  graph = SVGGraph.new(elist, @metrics,
161
- @params[:symmetrize], @params[:color], @params[:leafstyle], @params[:font], @params[:fontsize])
151
+ @params[:symmetrize], @params[:color], @params[:leafstyle], @params[:multibyte],
152
+ @params[:fontstyle], @params[:fontsize],
153
+ )
162
154
  graph.svg_data
163
155
  end
156
+
157
+ def draw_tree
158
+ sp = StringParser.new(@params[:data])
159
+ sp.parse
160
+ sp.auto_subscript if @params[:autosub]
161
+ elist = sp.get_elementlist
162
+ graph = TreeGraph.new(elist, @metrics,
163
+ @params[:symmetrize], @params[:color], @params[:leafstyle], @params[:multibyte],
164
+ @params[:fontstyle], @params[:font], @params[:font_it], @params[:font_bd], @params[:font_bdit],
165
+ @params[:font_cjk], @params[:fontsize], @params[:margin],
166
+ )
167
+ graph.to_blob(@params[:format])
168
+ end
164
169
  end
165
170
 
@@ -12,20 +12,6 @@
12
12
  #
13
13
  # Copyright (c) 2007-2018 Yoichiro Hasebe <yohasebe@gmail.com>
14
14
  # Copyright (c) 2003-2004 Andre Eisenbach <andre@ironcreek.net>
15
- #
16
- # This program is free software; you can redistribute it and/or modify
17
- # it under the terms of the GNU General Public License as published by
18
- # the Free Software Foundation; either version 2 of the License, or
19
- # (at your option) any later version.
20
- #
21
- # This program is distributed in the hope that it will be useful,
22
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
23
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24
- # GNU General Public License for more details.
25
- #
26
- # You should have received a copy of the GNU General Public License
27
- # along with this program; if not, write to the Free Software
28
- # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29
15
 
30
16
  class Element
31
17
 
@@ -46,7 +32,7 @@ class Element
46
32
  @triangle = false # draw triangle instead of stright bar when in auto mode
47
33
  end
48
34
  end
49
-
35
+
50
36
  # Debug helper function
51
37
  def dump
52
38
  printf( "ID : %d\n", @id );
@@ -12,20 +12,6 @@
12
12
  #
13
13
  # Copyright (c) 2007-2018 Yoichiro Hasebe <yohasebe@gmail.com>
14
14
  # Copyright (c) 2003-2004 Andre Eisenbach <andre@ironcreek.net>
15
- #
16
- # This program is free software; you can redistribute it and/or modify
17
- # it under the terms of the GNU General Public License as published by
18
- # the Free Software Foundation; either version 2 of the License, or
19
- # (at your option) any later version.
20
- #
21
- # This program is distributed in the hope that it will be useful,
22
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
23
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24
- # GNU General Public License for more details.
25
- #
26
- # You should have received a copy of the GNU General Public License
27
- # along with this program; if not, write to the Free Software
28
- # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29
15
 
30
16
  require 'element'
31
17
 
@@ -36,7 +22,7 @@ class ElementList
36
22
  @elements = Array.new # The element array
37
23
  @iterator = -1 # Iterator index (used for get_first / get_next)
38
24
  end
39
-
25
+
40
26
  def add(element)
41
27
  @elements << element
42
28
  if(element.parent != 0)
@@ -132,6 +118,4 @@ class ElementList
132
118
  end
133
119
  return maxlevel + 1;
134
120
  end
135
-
136
121
  end
137
-
@@ -12,22 +12,6 @@
12
12
  #
13
13
  # Copyright (c) 2007-2018 Yoichiro Hasebe <yohasebe@gmail.com>
14
14
  # Copyright (c) 2003-2004 Andre Eisenbach <andre@ironcreek.net>
15
- #
16
- # This program is free software; you can redistribute it and/or modify
17
- # it under the terms of the GNU General Public License as published by
18
- # the Free Software Foundation; either version 2 of the License, or
19
- # (at your option) any later version.
20
- #
21
- # This program is distributed in the hope that it will be useful,
22
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
23
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24
- # GNU General Public License for more details.
25
- #
26
- # You should have received a copy of the GNU General Public License
27
- # along with this program; if not, write to the Free Software
28
- # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29
-
30
- require 'imgutils'
31
15
 
32
16
  class ErrorMessage
33
17
 
@@ -38,7 +22,7 @@ class ErrorMessage
38
22
  @font_size = font_size
39
23
  @filename = filename
40
24
  @format = format
41
-
25
+
42
26
  metrics = img_get_txt_metrics(text, font, font_size, true)
43
27
 
44
28
  @im = Image.new(metrics.width, metrics.height)
@@ -51,6 +35,27 @@ class ErrorMessage
51
35
  @gc.text(0, 0, text)
52
36
  end
53
37
 
38
+ def img_get_txt_metrics(text, font, font_size, multiline)
39
+
40
+ background = Image.new(500, 250)
41
+
42
+ gc = Draw.new
43
+ gc.annotate(background, 0, 0, 0, 0, text) do |gc|
44
+ gc.font = font
45
+ gc.pointsize = font_size
46
+ gc.gravity = CenterGravity
47
+ gc.stroke = 'none'
48
+ end
49
+
50
+ if multiline
51
+ metrics = gc.get_multiline_type_metrics(background, text)
52
+ else
53
+ metrics = gc.get_type_metrics(background, text)
54
+ end
55
+
56
+ return metrics
57
+ end
58
+
54
59
  def draw
55
60
  @gc.draw(@im)
56
61
  end
@@ -0,0 +1,305 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+
4
+ #==========================
5
+ # graph.rb
6
+ #==========================
7
+ #
8
+ # Image utility functions to inspect text font metrics
9
+ #
10
+ # This file is part of RSyntaxTree, which is a ruby port of Andre Eisenbach's
11
+ # excellent program phpSyntaxTree.
12
+ #
13
+ # Copyright (c) 2007-2018 Yoichiro Hasebe <yohasebe@gmail.com>
14
+ # Copyright (c) 2003-2004 Andre Eisenbach <andre@ironcreek.net>
15
+
16
+ require 'rmagick'
17
+ include Magick
18
+
19
+ class Graph
20
+
21
+ def initialize(e_list, metrics, symmetrize, color, leafstyle, multibyte, font, font_size)
22
+
23
+ # Set class-specific parameters beforehand in subclass
24
+
25
+ # Store parameters
26
+ @e_list = e_list
27
+ @m = metrics
28
+ @multibyte = multibyte
29
+ @leafstyle = leafstyle
30
+ @symmetrize = symmetrize
31
+
32
+ # Calculate image dimensions
33
+ @e_height = font_size + @m[:e_padd] * 2
34
+ h = @e_list.get_level_height
35
+ w = calc_level_width(0)
36
+ @width = w + @m[:b_side] * 2
37
+ @height = h * @e_height + (h-1) * (@m[:v_space] + font_size) + @m[:b_topbot] * 2
38
+
39
+ # Initialize the image and colors
40
+ @col_bg = "none"
41
+ @col_fg = "black"
42
+ @col_line = "black"
43
+
44
+ if color
45
+ @col_node = "blue"
46
+ @col_leaf = "green"
47
+ @col_trace = "red"
48
+ else
49
+ @col_node = "black"
50
+ @col_leaf = "black"
51
+ @col_trace = "black"
52
+ end
53
+
54
+ @main_height = img_get_txt_height("l", font, font_size)
55
+ @sub_size = (font_size * SUBSCRIPT_CONST)
56
+ @sub_space_width = img_get_txt_width("l", font, @sub_size)
57
+ end
58
+
59
+ def img_get_txt_metrics(text, font, font_size, multiline)
60
+
61
+ background = Image.new(500, 250)
62
+
63
+ gc = Draw.new
64
+ gc.annotate(background, 0, 0, 0, 0, text) do |gc|
65
+ gc.font = font
66
+ gc.pointsize = font_size
67
+ gc.gravity = CenterGravity
68
+ gc.stroke = 'none'
69
+ end
70
+
71
+ if multiline
72
+ metrics = gc.get_multiline_type_metrics(background, text)
73
+ else
74
+ metrics = gc.get_type_metrics(background, text)
75
+ end
76
+
77
+ return metrics
78
+ end
79
+
80
+ # Calculate the width of the element. If the element is
81
+ # a node, the calculation will be performed recursively
82
+ # for all child elements.
83
+ def calc_element_width(e)
84
+ w = 0
85
+
86
+ children = @e_list.get_children(e.id)
87
+
88
+ if(children.length == 0)
89
+ w = img_get_txt_width(e.content, @font, @font_size) + @font_size
90
+ else
91
+ children.each do |child|
92
+ child_e = @e_list.get_id(child)
93
+ w += calc_element_width(child_e)
94
+ end
95
+
96
+ tw = img_get_txt_width(e.content, @font, @font_size) + @font_size
97
+ if(tw > w)
98
+ fix_child_size(e.id, w, tw)
99
+ w = tw
100
+ end
101
+ end
102
+
103
+ @e_list.set_element_width(e.id, w)
104
+ return w
105
+ end
106
+
107
+ # Calculate the width of all elements in a certain level
108
+ def calc_level_width(level)
109
+ w = 0
110
+ e = @e_list.get_first
111
+ while e
112
+ if(e.level == level)
113
+ w += calc_element_width(e)
114
+ end
115
+ e = @e_list.get_next
116
+ end
117
+ return w
118
+ end
119
+
120
+ def calc_children_width(id)
121
+ left = 0
122
+ right = 0
123
+ c_list = @e_list.get_children(id)
124
+ return nil if c_list.empty?
125
+
126
+ c_list.each do |c|
127
+ left = c.indent if indent == 0 or left > c.indent
128
+ end
129
+ c_list.each do |c|
130
+ right = c.indent + e.width if c.indent + c.width > right
131
+ end
132
+ return [left, right]
133
+ end
134
+
135
+ def get_children_indent(id)
136
+ calc_children_width(id)[0]
137
+ end
138
+
139
+ def get_children_width(id)
140
+ calc_children_width(id)[1] - get_children_indent(id)
141
+ end
142
+
143
+ # Parse the elements in the list top to bottom and
144
+ # draw the elements into the image.
145
+ # As we it iterate through the levels, the element
146
+ # indentation is calculated.
147
+ def parse_list
148
+
149
+ # Calc element list recursively....
150
+ e_arr = @e_list.get_elements
151
+
152
+ h = @e_list.get_level_height
153
+ h.times do |i|
154
+ x = 0
155
+ e_arr.each do |j|
156
+
157
+ if (j.level == i)
158
+ cw = @e_list.get_element_width(j.id)
159
+ parent_indent = @e_list.get_indent(j.parent)
160
+ if (x < parent_indent)
161
+ x = parent_indent
162
+ end
163
+ @e_list.set_indent(j.id, x)
164
+
165
+ if !@symmetrize
166
+ draw_element(x, i, cw, j.content, j.type)
167
+ if(j.parent != 0 )
168
+ words = j.content.split(" ")
169
+ unless @leafstyle == "nothing" && ETYPE_LEAF == j.type
170
+ if (@leafstyle == "triangle" && ETYPE_LEAF == j.type && x == parent_indent && words.length > 0)
171
+ txt_width = img_get_txt_width(j.content, @font, @font_size)
172
+ triangle_to_parent(x, i, cw, txt_width, @symmetrize)
173
+ elsif (@leafstyle == "auto" && ETYPE_LEAF == j.type && x == parent_indent)
174
+ if words.length > 1 || j.triangle
175
+ txt_width = img_get_txt_width(j.content, @font, @font_size)
176
+ triangle_to_parent(x, i, cw, txt_width, @symmetrize)
177
+ else
178
+ line_to_parent(x, i, cw, @e_list.get_indent(j.parent), @e_list.get_element_width(j.parent))
179
+ end
180
+ else
181
+ line_to_parent(x, i, cw, @e_list.get_indent(j.parent), @e_list.get_element_width(j.parent))
182
+ end
183
+ end
184
+ end
185
+ end
186
+
187
+ x += cw
188
+ end
189
+ end
190
+ end
191
+ return true if !@symmetrize
192
+ h.times do |i|
193
+ curlevel = h - i - 1
194
+ indent = 0
195
+ e_arr.each_with_index do |j, idx|
196
+ if (j.level == curlevel)
197
+ # Draw a line to the parent element
198
+ children = @e_list.get_children(j.id)
199
+
200
+ tw = img_get_txt_width(j.content, @font, @font_size)
201
+ if children.length > 1
202
+ left, right = -1, -1
203
+ children.each do |child|
204
+ k = @e_list.get_id(child)
205
+ kw = img_get_txt_width(k.content, @font, @font_size)
206
+ left = k.indent + kw / 2 if k.indent + kw / 2 < left or left == -1
207
+ right = k.indent + kw / 2 if k.indent + kw / 2 > right
208
+ end
209
+ draw_element(left, curlevel, right - left, j.content, j.type)
210
+ @e_list.set_indent(j.id, left + (right - left) / 2 - tw / 2)
211
+
212
+ children.each do |child|
213
+ k = @e_list.get_id(child)
214
+ words = k.content.split(" ")
215
+ dw = img_get_txt_width(k.content, @font, @font_size)
216
+ unless @leafstyle == "nothing" && ETYPE_LEAF == k.type
217
+ if (@leafstyle == "triangle" && ETYPE_LEAF == k.type && k.indent == j.indent && words.length > 0)
218
+ txt_width = img_get_txt_width(k.content, @font, @font_size)
219
+ triangle_to_parent(k.indent, curlevel + 1, dw, txt_width)
220
+ elsif (@leafstyle == "auto" && ETYPE_LEAF == k.type && k.indent == j.indent)
221
+ if words.length > 1 || k.triangle
222
+ txt_width = img_get_txt_width(k.content, @font, @font_size)
223
+ triangle_to_parent(k.indent, curlevel + 1, dw, txt_width)
224
+ else
225
+ line_to_parent(k.indent, curlevel + 1, dw, j.indent, tw)
226
+ end
227
+ else
228
+ line_to_parent(k.indent, curlevel + 1, dw, j.indent, tw)
229
+ end
230
+ end
231
+ end
232
+
233
+ else
234
+ unless children.empty?
235
+ k = @e_list.get_id(children[0])
236
+ kw = img_get_txt_width(k.content, @font, @font_size)
237
+ left = k.indent
238
+ right = k.indent + kw
239
+ draw_element(left, curlevel, right - left, j.content, j.type)
240
+ @e_list.set_indent(j.id, left + (right - left) / 2 - tw / 2)
241
+ else
242
+ parent = @e_list.get_id(j.parent)
243
+ pw = img_get_txt_width(parent.content, @font, @font_size)
244
+ pleft = parent.indent
245
+ pright = pleft + pw
246
+ left = j.indent
247
+ right = left + tw
248
+ if pw > tw
249
+ left = pleft
250
+ right = pright
251
+ end
252
+ draw_element(left, curlevel, right - left, j.content, j.type)
253
+ @e_list.set_indent(j.id, left + (right - left) / 2 - tw / 2)
254
+ end
255
+
256
+ unless children.empty?
257
+ k = @e_list.get_id(children[0])
258
+ words = k.content.split(" ")
259
+ dw = img_get_txt_width(k.content, @font, @font_size)
260
+ unless @leafstyle == "nothing" && ETYPE_LEAF == k.type
261
+ if (@leafstyle == "triangle" && ETYPE_LEAF == k.type && words.length > 0)
262
+ txt_width = img_get_txt_width(k.content, @font, @font_size)
263
+ triangle_to_parent(k.indent, curlevel + 1, dw, txt_width)
264
+ elsif (@leafstyle == "auto" && ETYPE_LEAF == k.type)
265
+ if words.length > 1 || k.triangle
266
+ txt_width = img_get_txt_width(k.content, @font, @font_size)
267
+ triangle_to_parent(k.indent, curlevel + 1, dw, txt_width)
268
+ else
269
+ line_to_parent(k.indent, curlevel + 1, dw, j.indent, tw)
270
+ end
271
+ else
272
+ line_to_parent(k.indent, curlevel + 1, dw, j.indent, tw)
273
+ end
274
+ end
275
+ end
276
+ end
277
+ end
278
+ end
279
+ end
280
+ end
281
+
282
+ # Calculate top position from row (level)
283
+ def row2px(row)
284
+ @m[:b_topbot] + @e_height * row + (@m[:v_space] + @font_size) * row
285
+ end
286
+
287
+ def get_txt_only(text)
288
+ text = text.strip
289
+ if /\A([\+\-\=\*]+).+/ =~ text
290
+ prefix = $1
291
+ prefix_l = Regexp.escape(prefix)
292
+ prefix_r = Regexp.escape(prefix.reverse)
293
+ if /\A#{prefix_l}(.+)#{prefix_r}\z/ =~ text
294
+ return $1
295
+ end
296
+ end
297
+ return text
298
+ end
299
+
300
+ def img_get_txt_height(text, font, font_size, multiline = false)
301
+ metrics = img_get_txt_metrics(text, font, font_size, multiline)
302
+ y = metrics.height
303
+ return y
304
+ end
305
+ end