rsyntaxtree 0.7.2 → 0.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|