rsyntaxtree 0.9.3 → 1.0.1

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.
@@ -1,327 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # -*- coding: utf-8 -*-
3
-
4
- #==========================
5
- # tree_graph.rb
6
- #==========================
7
- #
8
- # Parses an element list into a (non-SVG) graphical tree.
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-2021 Yoichiro Hasebe <yohasebe@gmail.com>
14
- # Copyright (c) 2003-2004 Andre Eisenbach <andre@ironcreek.net>
15
-
16
- require 'graph'
17
- require 'rmagick'
18
- include Magick
19
-
20
- class TreeGraph < Graph
21
-
22
- def initialize(e_list, metrics, symmetrize, color, leafstyle, multibyte,
23
- fontstyle, font, font_it, font_bd, font_itbd, font_math, font_cjk, font_size,
24
- margin, transparent)
25
-
26
- # Store class-specific parameters
27
- @fontstyle = fontstyle
28
- @font = multibyte ? font_cjk : font
29
- @font_size = font_size
30
- @font_it = font_it
31
- @font_bd = font_bd
32
- @font_itbd = font_itbd
33
- @font_math = font_math
34
- @font_cjk = font_cjk
35
- @margin = margin
36
- @transparent = transparent
37
-
38
- super(e_list, metrics, symmetrize, color, leafstyle, multibyte, @font, @font_size)
39
-
40
- # Initialize the image and colors
41
- @gc = Draw.new
42
- @gc.font = @font
43
- @gc.pointsize(@font_size)
44
- end
45
-
46
- def destroy
47
- @im.destroy!
48
- end
49
-
50
- def draw
51
- parse_list
52
- @im = Image.new(@width, @height)
53
- if @transparent
54
- @im.matte_reset!
55
- end
56
- # @im.interlace = PlaneInterlace
57
- @im.interlace = LineInterlace
58
- @gc.draw(@im)
59
- end
60
-
61
- def save(filename)
62
- draw
63
- @im.write(filename)
64
- end
65
-
66
- # inspired by the implementation of Gruff
67
- # by Geoffrey Grosenbach
68
- def to_blob(fileformat='PNG')
69
- draw
70
- @im.trim!
71
- if @transparent
72
- @im.border!(@margin, @margin, "transparent")
73
- else
74
- @im.border!(@margin, @margin, "white")
75
- end
76
- @im.format = fileformat
77
- @im.interlace = PlaneInterlace
78
- return @im.to_blob
79
- end
80
-
81
- :private
82
-
83
- # Add the element into the tree (draw it)
84
- def draw_element(x, y, w, string, type)
85
- string = string.sub(/\^\z/){""}
86
- # Calculate element dimensions and position
87
- if (type == ETYPE_LEAF) and @leafstyle == "nothing"
88
- top = row2px(y - 1) + (@font_size * 1.5)
89
- else
90
- top = row2px(y)
91
- end
92
- left = x + @m[:b_side]
93
- right = left + w
94
-
95
- # Split the string into the main part and the
96
- # subscript part of the element (if any)
97
- parts = string.split("_", 2)
98
- if(parts.length > 1 )
99
- main = parts[0].strip
100
- sub = parts[1].gsub(/_/, " ").strip
101
- else
102
- main = parts[0].strip
103
- sub = ""
104
- end
105
-
106
- if /\A\=(.+)\=\z/ =~ main
107
- main = $1
108
- main_decoration = OverlineDecoration
109
- elsif /\A\-(.+)\-\z/ =~ main
110
- main = $1
111
- main_decoration = UnderlineDecoration
112
- elsif /\A\~(.+)\~\z/ =~ main
113
- main = $1
114
- main_decoration = LineThroughDecoration
115
- else
116
- main_decoration = NoDecoration
117
- end
118
-
119
- main_font = @font
120
-
121
- if /\A\*\*\*(.+)\*\*\*\z/ =~ main
122
- main = $1
123
- if !@multibyte
124
- main_font = @font_itbd
125
- end
126
- elsif /\A\*\*(.+)\*\*\z/ =~ main
127
- main = $1
128
- if !@multibyte
129
- main_font = @font_bd
130
- end
131
- elsif /\A\*(.+)\*\z/ =~ main
132
- main = $1
133
- if !@multibyte
134
- main_font = @font_it
135
- end
136
- end
137
-
138
- if /\A#(.+)#\z/ =~ main
139
- main = $1
140
- main_font = @font_math
141
- end
142
-
143
- # Calculate text size for the main and the
144
- # subscript part of the element
145
-
146
-
147
- main_width = 0
148
- main_height = 0
149
- main.split(/\\n/).each do |l|
150
- l_width = img_get_txt_width(l, main_font, @font_size)
151
- main_width = l_width if main_width < l_width
152
- main_height += img_get_txt_height(l, @font, @font_size)
153
- end
154
-
155
- if /\A\=(.+)\=\z/ =~ sub
156
- sub = $1
157
- sub_decoration = OverlineDecoration
158
- elsif /\A\-(.+)\-\z/ =~ sub
159
- sub = $1
160
- sub_decoration = UnderlineDecoration
161
- elsif /\A\~(.+)\~z/ =~ sub
162
- sub = $1
163
- sub_decoration = LineThroughDecoration
164
- else
165
- sub_decoration = NoDecoration
166
- end
167
-
168
- sub_font = @font
169
- if /\A\*\*\*(.+)\*\*\*\z/ =~ sub
170
- sub = $1
171
- if !@multibyte
172
- sub_font = @font_itbd
173
- end
174
- elsif /\A\*\*(.+)\*\*\z/ =~ sub
175
- sub = $1
176
- if !@multibyte
177
- sub_font = @font_bd
178
- end
179
- elsif /\A\*(.+)\*\z/ =~ sub
180
- sub = $1
181
- if !@multibyte
182
- sub_font = @font_it
183
- end
184
- end
185
-
186
- if /\A#(.+)#\z/ =~ sub
187
- sub = $1
188
- sub_font = @font_math
189
- end
190
-
191
- if sub != ""
192
- sub_width = img_get_txt_width(sub.to_s, sub_font, @sub_size)
193
- sub_height = img_get_txt_height(sub.to_s, sub_font, @sub_size)
194
- else
195
- sub_width = 0
196
- sub_height = 0
197
- end
198
-
199
- # Center text in the element
200
- txt_pos = left + (right - left) / 2
201
-
202
- # Select apropriate color
203
- if(type == ETYPE_LEAF)
204
- col = @col_leaf
205
- else
206
- col = @col_node
207
- end
208
-
209
- if(main[0].chr == "<" && main[-1].chr == ">")
210
- col = @col_trace
211
- end
212
-
213
- @gc.stroke("none")
214
- @gc.fill(col)
215
-
216
- # Draw main text
217
- @gc.pointsize(@font_size)
218
- @gc.kerning = 0
219
- @gc.interline_spacing = 0
220
- @gc.interword_spacing = 0
221
-
222
- main_x = txt_pos - sub_width / 2
223
- main_y = top + @e_height - @m[:e_padd]
224
-
225
- # @gc.interline_spacing = -(@main_height / 3)
226
- @gc.font(main_font)
227
- @gc.decorate(main_decoration)
228
- numlines = main.count("\\n")
229
- if numlines > 1
230
- @height = @height + @main_height * numlines
231
- end
232
- @gc.text_align(CenterAlign)
233
- @gc.text(main_x.ceil, main_y.ceil, main.gsub("\\n", "\n"))
234
-
235
- # Draw subscript text
236
- if (sub != "" )
237
- @gc.pointsize(@sub_size)
238
- sub_x = main_x + (main_width / 2) + (sub_width / 2)
239
- sub_y = top + main_height + sub_height / 4
240
- @height += sub_height / 4
241
- @gc.font(sub_font)
242
- @gc.decorate(sub_decoration)
243
- @gc.text_align(CenterAlign)
244
- @gc.text(sub_x.ceil, sub_y.ceil, " " + sub.gsub("\\n", "\n"))
245
- end
246
- end
247
-
248
- # Draw a line between child/parent elements
249
- def line_to_parent(fromX, fromY, fromW, toX, toW)
250
-
251
- if (fromY == 0 )
252
- return
253
- end
254
-
255
- fromTop = row2px(fromY)
256
- fromLeft = (fromX + fromW / 2 + @m[:b_side])
257
- toBot = (row2px(fromY - 1 ) + @e_height)
258
- toLeft = (toX + toW / 2 + @m[:b_side])
259
-
260
- @gc.fill("none")
261
- @gc.stroke @col_line
262
- @gc.stroke_width 1 * FONT_SCALING
263
- @gc.line(fromLeft.ceil, fromTop.ceil, toLeft.ceil, toBot.ceil)
264
- end
265
-
266
- # Draw a triangle between child/parent elements
267
- def triangle_to_parent(fromX, fromY, fromW, textW, symmetrize = true)
268
- if (fromY == 0)
269
- return
270
- end
271
-
272
- toX = fromX
273
- fromCenter = (fromX + fromW / 2 + @m[:b_side])
274
-
275
- fromTop = row2px(fromY).ceil
276
- fromLeft1 = (fromCenter + textW / 2).ceil
277
- fromLeft2 = (fromCenter - textW / 2).ceil
278
- toBot = (row2px(fromY - 1) + @e_height)
279
-
280
- if symmetrize
281
- toLeft = (toX + textW / 2 + @m[:b_side])
282
- else
283
- toLeft = (toX + textW / 2 + @m[:b_side] * 3)
284
- end
285
-
286
- @gc.fill("none")
287
- @gc.stroke @col_line
288
- @gc.stroke_width 1 * 2
289
- @gc.line(fromLeft1, fromTop, toLeft, toBot)
290
- @gc.line(fromLeft2, fromTop, toLeft, toBot)
291
- @gc.line(fromLeft1, fromTop, fromLeft2, fromTop)
292
- end
293
-
294
- # If a node element text is wider than the sum of it's
295
- # child elements, then the child elements need to
296
- # be resized to even out the space. This function
297
- # recurses down the a child tree and sizes the
298
- # children appropriately.
299
- def fix_child_size(id, current, target)
300
- children = @e_list.get_children(id)
301
- @e_list.set_element_width(id, target)
302
-
303
- if(children.length > 0 )
304
- delta = target - current
305
- target_delta = delta / children.length
306
-
307
- children.each do |child|
308
- child_width = @e_list.get_element_width(child)
309
- fix_child_size(child, child_width, child_width + target_delta)
310
- end
311
- end
312
- end
313
-
314
- def img_get_txt_width(text, font, font_size, multiline = true)
315
- parts = text.split("_", 2)
316
- main_before = parts[0].strip
317
- sub = parts[1]
318
- main = get_txt_only(main_before)
319
- main_metrics = img_get_txt_metrics(main, font, font_size, multiline)
320
- width = main_metrics.width
321
- if sub
322
- sub_metrics = img_get_txt_metrics(sub.strip, font, font_size * SUBSCRIPT_CONST, multiline)
323
- width += sub_metrics.width
324
- end
325
- return width
326
- end
327
- end