rsyntaxtree 0.9.1 → 1.0.4

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,328 +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
- # add a separation of the width of "M"
193
- sub_width = img_get_txt_width(sub.to_s, sub_font, @sub_size)
194
- sub_height = img_get_txt_height(sub.to_s, sub_font, @sub_size)
195
- else
196
- sub_width = 0
197
- sub_height = 0
198
- end
199
-
200
- # Center text in the element
201
- txt_pos = left + (right - left) / 2
202
-
203
- # Select apropriate color
204
- if(type == ETYPE_LEAF)
205
- col = @col_leaf
206
- else
207
- col = @col_node
208
- end
209
-
210
- if(main[0].chr == "<" && main[-1].chr == ">")
211
- col = @col_trace
212
- end
213
-
214
- @gc.stroke("none")
215
- @gc.fill(col)
216
-
217
- # Draw main text
218
- @gc.pointsize(@font_size)
219
- @gc.kerning = 0
220
- @gc.interline_spacing = 0
221
- @gc.interword_spacing = 0
222
-
223
- main_x = txt_pos - sub_width / 2
224
- main_y = top + @e_height - @m[:e_padd]
225
-
226
- # @gc.interline_spacing = -(@main_height / 3)
227
- @gc.font(main_font)
228
- @gc.decorate(main_decoration)
229
- numlines = main.count("\\n")
230
- if numlines > 1
231
- @height = @height + @main_height * numlines
232
- end
233
- @gc.text_align(CenterAlign)
234
- @gc.text(main_x.ceil, main_y.ceil, main.gsub("\\n", "\n"))
235
-
236
- # Draw subscript text
237
- if (sub != "" )
238
- @gc.pointsize(@sub_size)
239
- sub_x = main_x + (main_width / 2) + (sub_width / 2)
240
- sub_y = top + main_height + sub_height / 4
241
- @height += sub_height / 4
242
- @gc.font(sub_font)
243
- @gc.decorate(sub_decoration)
244
- @gc.text_align(CenterAlign)
245
- @gc.text(sub_x.ceil, sub_y.ceil, " " + sub.gsub("\\n", "\n"))
246
- end
247
- end
248
-
249
- # Draw a line between child/parent elements
250
- def line_to_parent(fromX, fromY, fromW, toX, toW)
251
-
252
- if (fromY == 0 )
253
- return
254
- end
255
-
256
- fromTop = row2px(fromY)
257
- fromLeft = (fromX + fromW / 2 + @m[:b_side])
258
- toBot = (row2px(fromY - 1 ) + @e_height)
259
- toLeft = (toX + toW / 2 + @m[:b_side])
260
-
261
- @gc.fill("none")
262
- @gc.stroke @col_line
263
- @gc.stroke_width 1 * FONT_SCALING
264
- @gc.line(fromLeft.ceil, fromTop.ceil, toLeft.ceil, toBot.ceil)
265
- end
266
-
267
- # Draw a triangle between child/parent elements
268
- def triangle_to_parent(fromX, fromY, fromW, textW, symmetrize = true)
269
- if (fromY == 0)
270
- return
271
- end
272
-
273
- toX = fromX
274
- fromCenter = (fromX + fromW / 2 + @m[:b_side])
275
-
276
- fromTop = row2px(fromY).ceil
277
- fromLeft1 = (fromCenter + textW / 2).ceil
278
- fromLeft2 = (fromCenter - textW / 2).ceil
279
- toBot = (row2px(fromY - 1) + @e_height)
280
-
281
- if symmetrize
282
- toLeft = (toX + textW / 2 + @m[:b_side])
283
- else
284
- toLeft = (toX + textW / 2 + @m[:b_side] * 3)
285
- end
286
-
287
- @gc.fill("none")
288
- @gc.stroke @col_line
289
- @gc.stroke_width 1 * 2
290
- @gc.line(fromLeft1, fromTop, toLeft, toBot)
291
- @gc.line(fromLeft2, fromTop, toLeft, toBot)
292
- @gc.line(fromLeft1, fromTop, fromLeft2, fromTop)
293
- end
294
-
295
- # If a node element text is wider than the sum of it's
296
- # child elements, then the child elements need to
297
- # be resized to even out the space. This function
298
- # recurses down the a child tree and sizes the
299
- # children appropriately.
300
- def fix_child_size(id, current, target)
301
- children = @e_list.get_children(id)
302
- @e_list.set_element_width(id, target)
303
-
304
- if(children.length > 0 )
305
- delta = target - current
306
- target_delta = delta / children.length
307
-
308
- children.each do |child|
309
- child_width = @e_list.get_element_width(child)
310
- fix_child_size(child, child_width, child_width + target_delta)
311
- end
312
- end
313
- end
314
-
315
- def img_get_txt_width(text, font, font_size, multiline = true)
316
- parts = text.split("_", 2)
317
- main_before = parts[0].strip
318
- sub = parts[1]
319
- main = get_txt_only(main_before)
320
- main_metrics = img_get_txt_metrics(main, font, font_size, multiline)
321
- width = main_metrics.width
322
- if sub
323
- sub_metrics = img_get_txt_metrics(sub.strip, font, font_size * SUBSCRIPT_CONST, multiline)
324
- width += sub_metrics.width
325
- end
326
- return width
327
- end
328
- end