rsyntaxtree 1.0.7 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,262 +1,260 @@
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
- # Copyright (c) 2007-2021 Yoichiro Hasebe <yohasebe@gmail.com>
10
-
11
- require 'utils'
12
-
13
- module RSyntaxTree
14
- class BaseGraph
15
-
16
- def initialize(element_list, params)
17
-
18
- @element_list = element_list
19
- @symmetrize = params[:symmetrize]
20
-
21
- if params[:color]
22
- @col_node = "blue"
23
- @col_leaf = "green"
24
- @col_path = "purple"
25
- else
26
- @col_node = "black"
27
- @col_leaf = "black"
28
- @col_path = "black"
29
- end
30
-
31
- @col_bg = "none"
32
- @col_fg = "black"
33
- @col_line = "black"
34
-
35
- @leafstyle = params[:leafstyle]
36
- @fontset = params[:fontset]
37
- @fontsize = params[:fontsize]
38
- end
39
-
40
- def calculate_level
41
- @element_list.get_elements.select{|e| e.type == 2}.each do |e|
42
- e.level = @element_list.get_id(e.parent).level + 1
43
- end
44
- end
45
-
46
- def calculate_width(id = 1)
47
- target = @element_list.get_id(id)
48
- if target.children.empty?
49
- target.width = target.content_width + $h_gap_between_nodes * 4
50
-
51
- parent = @element_list.get_id(target.parent)
52
- while parent && parent.children.size == 1
53
- w = parent.content_width
54
- target.width = w + $h_gap_between_nodes * 4 if w > target.content_width
55
- parent = @element_list.get_id(parent.parent)
56
- end
57
- return target.width
58
- else
59
- if target.width != 0
60
- return target.width
61
- else
62
- accum_array = []
63
- target.children.each do |c|
64
- accum_array << calculate_width(c)
65
- end
66
- if @symmetrize
67
- accum_width = accum_array.max * target.children.size
68
- else
69
- accum_width = accum_array.sum
70
- end
71
-
72
- target.width = [accum_width, target.content_width].max
73
- end
74
-
75
- return target.width
76
- end
77
- end
78
-
79
- def calculate_height(id = 1)
80
- target = @element_list.get_id(id)
81
- if id == 1
82
- target.vertical_indent = 0
83
- else
84
- parent = @element_list.get_id(target.parent)
85
-
86
- if !target.triangle && @leafstyle == "nothing" && ETYPE_LEAF == target.type && parent.children.size == 1
87
- vertical_indent = parent.vertical_indent + parent.content_height
88
- else
89
- vertical_indent = parent.vertical_indent + parent.content_height + $height_connector
90
- end
91
-
92
- target.vertical_indent = vertical_indent
93
- end
94
-
95
- if target.children.empty?
96
- target.height = target.content_height
97
- vertical_end = target.vertical_indent + target.content_height
98
- else
99
- accum_array = []
100
- target.children.each do |c|
101
- accum_array << calculate_height(c)
102
- end
103
- target.height = accum_array.max - target.vertical_indent
104
- vertical_end = accum_array.max
105
- end
106
- return vertical_end
107
- end
108
-
109
- def make_balance(id = 1)
110
- target = @element_list.get_id(id)
111
- if target.children.empty?
112
- parent = @element_list.get_id(target.parent)
113
- accum_array = []
114
- parent.children.each do |c|
115
- accum_array << @element_list.get_id(c).width
116
- end
117
- max = accum_array.max
118
- parent.children.each do |c|
119
- @element_list.get_id(c).width = max
120
- end
121
- return max
122
- else
123
- accum_array = []
124
- target.children.each do |c|
125
- accum_array << make_balance(c)
126
- end
127
- accum_width = accum_array.max
128
- max = [accum_width, target.content_width].max
129
- target.children.each do |c|
130
- @element_list.get_id(c).width = max
131
- end
132
- return target.width
133
- end
134
- end
135
-
136
- def calculate_indent
137
- node_groups = @element_list.get_elements.group_by {|e| e.parent}
138
- node_groups.each do |k, v|
139
- next if k == 0
140
- parent = @element_list.get_id(k)
141
- if @symmetrize
142
- num_leaves = v.size
143
- partition_width = parent.width / num_leaves
144
- left_offset = parent.horizontal_indent + parent.content_width / 2.0 - parent.width / 2.0
145
- v.each do |e|
146
- indent = left_offset + (partition_width - e.content_width) / 2.0
147
- e.horizontal_indent = indent
148
- left_offset += partition_width
149
- end
150
- else
151
- left_offset = parent.horizontal_indent + parent.content_width / 2.0 - parent.width / 2.0
152
- v.each do |e|
153
- indent = left_offset + (e.width - e.content_width) / 2.0
154
- e.horizontal_indent = indent
155
- left_offset += e.width
156
- end
157
- end
158
- end
159
- end
160
-
161
- def draw_elements
162
- @element_list.get_elements.each do |element|
163
- draw_element(element)
164
- end
165
- end
166
-
167
- def draw_connector(id = 1)
168
- parent = @element_list.get_id(id)
169
- children = parent.children.map{|c| @element_list.get_id(c)}
170
-
171
- if children.empty?
172
- ;
173
- elsif children.size == 1
174
- child = children[0]
175
- if (@leafstyle == "auto")
176
- if child.contains_phrase || child.triangle
177
- triangle_to_parent(parent, child)
178
- else
179
- line_to_parent(parent, child)
180
- end
181
- elsif(@leafstyle == "bar")
182
- if child.triangle
183
- triangle_to_parent(parent, child)
184
- else
185
- line_to_parent(parent, child)
186
- end
187
- elsif(@leafstyle == "nothing")
188
- if child.triangle
189
- triangle_to_parent(parent, child)
190
- elsif ETYPE_LEAF == child.type
191
- child.vertical_indent = parent.vertical_indent + parent.content_height + $height_connector / 2
192
- end
193
- end
194
- else
195
- children.each do |child|
196
- line_to_parent(parent, child)
197
- end
198
- end
199
-
200
- parent.children.each do |c|
201
- draw_connector(c)
202
- end
203
- end
204
-
205
- def get_leftmost(id = 1)
206
- target = @element_list.get_id(id)
207
- target_indent = target.horizontal_indent
208
- children_indent = target.children.map{|c| get_leftmost(c)}
209
- (children_indent << target_indent).min
210
- end
211
-
212
- def get_rightmost(id = 1)
213
- target = @element_list.get_id(id)
214
- target_right_end = target.horizontal_indent + target.content_width
215
- children_right_end = target.children.map{|c| get_rightmost(c)}
216
- (children_right_end << target_right_end).max
217
- end
218
-
219
- def node_centering
220
- node_groups = @element_list.get_elements.group_by {|e| e.parent}
221
- node_groups.sort_by{|k, v| -k}.each do |k, v|
222
- next if k == 0
223
- parent = @element_list.get_id(k)
224
- child_positions =v.map {|child| child.horizontal_indent + child.content_width / 2 }
225
- parent.horizontal_indent = child_positions.min + (child_positions.max - child_positions.min - parent.content_width) / 2
226
- end
227
- end
228
-
229
- def parse_list
230
- calculate_level
231
- calculate_width
232
- make_balance if @symmetrize
233
- calculate_indent
234
- node_centering
235
-
236
- top = @element_list.get_id(1)
237
- diff = top.horizontal_indent
238
- @element_list.get_elements.each do |e|
239
- e.horizontal_indent -= diff
240
- end
241
-
242
- offset_l = (top.horizontal_indent - get_leftmost) + $h_gap_between_nodes
243
- offset_r = top.width / 2 - offset_l - $h_gap_between_nodes
244
-
245
- @element_list.get_elements.each do |e|
246
- e.horizontal_indent += offset_l
247
- end
248
-
249
- calculate_height
250
- draw_elements
251
- draw_connector
252
- num_paths = draw_paths
253
-
254
- # width = get_rightmost - get_leftmost + $h_gap_between_nodes * 2
255
- width = get_rightmost - get_leftmost + $h_gap_between_nodes
256
- height = @element_list.get_id(1).height
257
- height = @height if @height > height
258
-
259
- return {height: height, width: width}
260
- end
261
- end
262
- end
1
+ # frozen_string_literal: true
2
+
3
+ #==========================
4
+ # graph.rb
5
+ #==========================
6
+ #
7
+ # Image utility functions to inspect text font metrics
8
+ # Copyright (c) 2007-2023 Yoichiro Hasebe <yohasebe@gmail.com>
9
+
10
+ require_relative 'utils'
11
+
12
+ module RSyntaxTree
13
+ class BaseGraph
14
+ def initialize(element_list, params, global)
15
+ @global = global
16
+ @element_list = element_list
17
+ @symmetrize = params[:symmetrize]
18
+
19
+ if params[:color]
20
+ @col_node = "blue"
21
+ @col_leaf = "green"
22
+ @col_path = "purple"
23
+ else
24
+ @col_node = "black"
25
+ @col_leaf = "black"
26
+ @col_path = "black"
27
+ end
28
+
29
+ @col_bg = "none"
30
+ @col_fg = "black"
31
+ @col_line = "black"
32
+
33
+ @leafstyle = params[:leafstyle]
34
+ @fontset = params[:fontset]
35
+ @fontsize = params[:fontsize]
36
+ end
37
+
38
+ def calculate_level
39
+ @element_list.get_elements.select { |e| e.type == 2 }.each do |e|
40
+ e.level = @element_list.get_id(e.parent).level + 1
41
+ end
42
+ end
43
+
44
+ def calculate_width(id = 1)
45
+ target = @element_list.get_id(id)
46
+ if target.children.empty?
47
+ target.width = target.content_width + @global[:h_gap_between_nodes] * 4
48
+
49
+ parent = @element_list.get_id(target.parent)
50
+ while parent && parent.children.size == 1
51
+ w = parent.content_width
52
+ target.width = w + @global[:h_gap_between_nodes] * 4 if w > target.content_width
53
+ parent = @element_list.get_id(parent.parent)
54
+ end
55
+ target.width
56
+ else
57
+ return target.width if target.width != 0
58
+
59
+ accum_array = []
60
+ target.children.each do |c|
61
+ accum_array << calculate_width(c)
62
+ end
63
+ accum_width = if @symmetrize
64
+ accum_array.max * target.children.size
65
+ else
66
+ accum_array.sum
67
+ end
68
+
69
+ target.width = [accum_width, target.content_width].max
70
+ end
71
+ end
72
+
73
+ def calculate_height(id = 1)
74
+ target = @element_list.get_id(id)
75
+ if id == 1
76
+ target.vertical_indent = 0
77
+ else
78
+ parent = @element_list.get_id(target.parent)
79
+
80
+ vertical_indent = if !target.triangle &&
81
+ @leafstyle == "nothing" &&
82
+ ETYPE_LEAF == target.type &&
83
+ parent.children.size == 1
84
+ parent.vertical_indent + parent.content_height
85
+ else
86
+ parent.vertical_indent + parent.content_height + @global[:height_connector]
87
+ end
88
+
89
+ target.vertical_indent = vertical_indent
90
+ end
91
+
92
+ if target.children.empty?
93
+ target.height = target.content_height
94
+ target.vertical_indent + target.content_height
95
+ else
96
+ accum_array = []
97
+ target.children.each do |c|
98
+ accum_array << calculate_height(c)
99
+ end
100
+ target.height = accum_array.max - target.vertical_indent
101
+ accum_array.max
102
+ end
103
+ end
104
+
105
+ def make_balance(id = 1)
106
+ target = @element_list.get_id(id)
107
+ if target.children.empty?
108
+ parent = @element_list.get_id(target.parent)
109
+ accum_array = []
110
+ parent.children.each do |c|
111
+ accum_array << @element_list.get_id(c).width
112
+ end
113
+ max = accum_array.max
114
+ parent.children.each do |c|
115
+ @element_list.get_id(c).width = max
116
+ end
117
+ max
118
+ else
119
+ accum_array = []
120
+ target.children.each do |c|
121
+ accum_array << make_balance(c)
122
+ end
123
+ accum_width = accum_array.max
124
+ max = [accum_width, target.content_width].max
125
+ target.children.each do |c|
126
+ @element_list.get_id(c).width = max
127
+ end
128
+ target.width
129
+ end
130
+ end
131
+
132
+ def calculate_indent
133
+ node_groups = @element_list.get_elements.group_by(&:parent)
134
+ node_groups.each do |k, v|
135
+ next if k.zero?
136
+
137
+ parent = @element_list.get_id(k)
138
+ if @symmetrize
139
+ num_leaves = v.size
140
+ partition_width = parent.width / num_leaves
141
+ left_offset = parent.horizontal_indent + parent.content_width / 2.0 - parent.width / 2.0
142
+ v.each do |e|
143
+ indent = left_offset + (partition_width - e.content_width) / 2.0
144
+ e.horizontal_indent = indent
145
+ left_offset += partition_width
146
+ end
147
+ else
148
+ left_offset = parent.horizontal_indent + parent.content_width / 2.0 - parent.width / 2.0
149
+ v.each do |e|
150
+ indent = left_offset + (e.width - e.content_width) / 2.0
151
+ e.horizontal_indent = indent
152
+ left_offset += e.width
153
+ end
154
+ end
155
+ end
156
+ end
157
+
158
+ def draw_elements
159
+ @element_list.get_elements.each do |element|
160
+ draw_element(element)
161
+ end
162
+ end
163
+
164
+ def draw_connector(id = 1)
165
+ parent = @element_list.get_id(id)
166
+ children = parent.children.map { |c| @element_list.get_id(c) }
167
+
168
+ if children.size == 1
169
+ child = children[0]
170
+ case @leafstyle
171
+ when "auto"
172
+ if child.contains_phrase || child.triangle
173
+ triangle_to_parent(parent, child)
174
+ else
175
+ line_to_parent(parent, child)
176
+ end
177
+ when "bar"
178
+ if child.triangle
179
+ triangle_to_parent(parent, child)
180
+ else
181
+ line_to_parent(parent, child)
182
+ end
183
+ when "nothing"
184
+ if child.triangle
185
+ triangle_to_parent(parent, child)
186
+ elsif ETYPE_LEAF != child.type
187
+ line_to_parent(parent, child)
188
+ elsif ETYPE_LEAF == child.type
189
+ child.vertical_indent = parent.vertical_indent + parent.content_height + @global[:height_connector] / 2
190
+ end
191
+ end
192
+ else
193
+ children.each do |child|
194
+ line_to_parent(parent, child)
195
+ end
196
+ end
197
+
198
+ parent.children.each do |c|
199
+ draw_connector(c)
200
+ end
201
+ end
202
+
203
+ def get_leftmost(id = 1)
204
+ target = @element_list.get_id(id)
205
+ target_indent = target.horizontal_indent
206
+ children_indent = target.children.map { |c| get_leftmost(c) }
207
+ (children_indent << target_indent).min
208
+ end
209
+
210
+ def get_rightmost(id = 1)
211
+ target = @element_list.get_id(id)
212
+ target_right_end = target.horizontal_indent + target.content_width
213
+ children_right_end = target.children.map { |c| get_rightmost(c) }
214
+ (children_right_end << target_right_end).max
215
+ end
216
+
217
+ def node_centering
218
+ node_groups = @element_list.get_elements.group_by(&:parent)
219
+ node_groups.sort_by { |k, _v| -k }.each do |k, v|
220
+ next if k.zero?
221
+
222
+ parent = @element_list.get_id(k)
223
+ child_positions = v.map { |child| child.horizontal_indent + child.content_width / 2 }
224
+ parent.horizontal_indent = child_positions.min + (child_positions.max - child_positions.min - parent.content_width) / 2
225
+ end
226
+ end
227
+
228
+ def parse_list
229
+ calculate_level
230
+ calculate_width
231
+ make_balance if @symmetrize
232
+ calculate_indent
233
+ node_centering
234
+
235
+ top = @element_list.get_id(1)
236
+ diff = top.horizontal_indent
237
+ @element_list.get_elements.each do |e|
238
+ e.horizontal_indent -= diff
239
+ end
240
+
241
+ offset_l = (top.horizontal_indent - get_leftmost) + @global[:h_gap_between_nodes]
242
+ # offset_r = top.width / 2 - offset_l - @global[:h_gap_between_nodes:
243
+
244
+ @element_list.get_elements.each do |e|
245
+ e.horizontal_indent += offset_l
246
+ end
247
+
248
+ calculate_height
249
+ draw_elements
250
+ draw_connector
251
+ draw_paths
252
+
253
+ width = get_rightmost - get_leftmost + @global[:h_gap_between_nodes]
254
+ height = @element_list.get_id(1).height
255
+ height = @height if @height > height
256
+
257
+ { height: height, width: width }
258
+ end
259
+ end
260
+ end