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 +4 -4
- data/README.md +3 -3
- data/bin/rsyntaxtree +2 -2
- data/fonts/NotoSans-Bold.ttf +0 -0
- data/fonts/NotoSans-BoldItalic.ttf +0 -0
- data/fonts/NotoSans-Italic.ttf +0 -0
- data/fonts/NotoSans-Regular.ttf +0 -0
- data/fonts/NotoSerif-Bold.ttf +0 -0
- data/fonts/NotoSerif-BoldItalic.ttf +0 -0
- data/fonts/NotoSerif-Italic.ttf +0 -0
- data/fonts/NotoSerif-Regular.ttf +0 -0
- data/lib/rsyntaxtree.rb +46 -41
- data/lib/rsyntaxtree/element.rb +1 -15
- data/lib/rsyntaxtree/elementlist.rb +1 -17
- data/lib/rsyntaxtree/error_message.rb +22 -17
- data/lib/rsyntaxtree/graph.rb +305 -0
- data/lib/rsyntaxtree/string_parser.rb +19 -34
- data/lib/rsyntaxtree/svg_graph.rb +126 -301
- data/lib/rsyntaxtree/tree_graph.rb +129 -284
- data/lib/rsyntaxtree/utils.rb +20 -0
- data/lib/rsyntaxtree/version.rb +1 -1
- metadata +12 -6
- data/fonts/DroidSans.ttf +0 -0
- data/fonts/DroidSerif-Regular.ttf +0 -0
- data/fonts/NotoSansMonoCJKjp-Regular.otf +0 -0
- data/lib/rsyntaxtree/imgutils.rb +0 -70
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '0586aec9488760401c729ef70db38c730883341e'
|
4
|
+
data.tar.gz: f9f95b8713cbcef850c3be737e5cd2cd2c3babe5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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
|
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
|
```
|
data/bin/rsyntaxtree
CHANGED
@@ -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,
|
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,
|
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
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/lib/rsyntaxtree.rb
CHANGED
@@ -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 '
|
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 + "/
|
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 + "/
|
77
|
-
|
78
|
-
new_params[:
|
79
|
-
|
80
|
-
new_params[:
|
81
|
-
|
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
|
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('&', '&').gsub('%', '%'))
|
@@ -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[:
|
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
|
|
data/lib/rsyntaxtree/element.rb
CHANGED
@@ -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
|