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.
@@ -12,71 +12,37 @@
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
- require 'elementlist'
15
+
16
+ require 'graph'
32
17
  require 'rmagick'
33
18
  include Magick
34
19
 
35
- class TreeGraph
20
+ class TreeGraph < Graph
36
21
 
37
- def initialize(e_list, metrics, symmetrize = true, color = true, terminal = "auto",
38
- font = "Helvetica", font_size = 10, simple = false, margin = 0)
22
+ def initialize(e_list, metrics, symmetrize, color, leafstyle, multibyte,
23
+ fontstyle, font, font_it, font_bd, font_itbd, font_cjk, font_size,
24
+ margin)
39
25
 
40
- # Store parameters (double font size and margin to make image retina ready)
41
- @e_list = e_list
42
- @m = metrics
43
- @font = font
44
- @terminal = terminal
45
- @symmetrize = symmetrize
46
- @simple = simple
26
+ # Store class-specific parameters
27
+ @fontstyle = fontstyle
28
+ @font = multibyte ? font_cjk : font
47
29
  @font_size = font_size
30
+ @font_it = font_it
31
+ @font_bd = font_bd
32
+ @font_itbd = font_itbd
33
+ @font_cjk = font_cjk
48
34
  @margin = margin
49
35
 
50
- # Calculate image dimensions
51
- @e_height = @font_size + metrics[:e_padd] * 2
52
- h = @e_list.get_level_height
53
- w = calc_level_width(0)
54
- w_px = w + metrics[:b_side] * 2
55
- h_px = h * @e_height + (h-1) * (metrics[:v_space] + @font_size) + metrics[:b_topbot] * 2
56
- @height = h_px
57
- @width = w_px
36
+ super(e_list, metrics, symmetrize, color, leafstyle, multibyte, @font, @font_size)
58
37
 
59
38
  # Initialize the image and colors
60
- @im = Image.new(w_px, h_px)
61
- @gc = Draw.new
62
- @gc.font = @font
39
+ @im = Image.new(@width, @height)
40
+ @im.interlace = PlaneInterlace
41
+ @gc = Draw.new
42
+ @gc.font = @font
63
43
  @gc.pointsize(@font_size)
64
-
65
- @col_bg = "none"
66
- @col_fg = "black"
67
- @col_line = "black"
68
-
69
- if color
70
- @col_node = "blue"
71
- @col_leaf = "green"
72
- @col_trace = "red"
73
- else
74
- @col_node = "black"
75
- @col_leaf = "black"
76
- @col_trace = "black"
77
- end
78
44
  end
79
-
45
+
80
46
  def destroy
81
47
  @im.destroy!
82
48
  end
@@ -97,17 +63,18 @@ class TreeGraph
97
63
  draw
98
64
  @im.border!(@margin, @margin, "white")
99
65
  return @im.to_blob do
100
- self.format = fileformat
66
+ self.format = fileformat
67
+ self.interlace = PlaneInterlace
101
68
  end
102
69
  end
103
-
70
+
104
71
  :private
105
-
72
+
106
73
  # Add the element into the tree (draw it)
107
74
  def draw_element(x, y, w, string, type)
108
75
  string = string.sub(/\^\z/){""}
109
76
  # Calculate element dimensions and position
110
- if (type == ETYPE_LEAF) and @terminal == "nothing"
77
+ if (type == ETYPE_LEAF) and @leafstyle == "nothing"
111
78
  top = row2px(y - 1) + (@font_size * 1.5)
112
79
  else
113
80
  top = row2px(y)
@@ -118,23 +85,90 @@ class TreeGraph
118
85
 
119
86
  # Split the string into the main part and the
120
87
  # subscript part of the element (if any)
121
- main = string
122
- sub = ""
123
-
124
- sub_size = (@font_size * 0.7 )
125
88
  parts = string.split("_", 2)
126
-
127
89
  if(parts.length > 1 )
128
- main = parts[0]
129
- sub = parts[1].gsub(/_/, " ")
90
+ main = parts[0].strip
91
+ sub = parts[1].gsub(/_/, " ").strip
92
+ else
93
+ main = parts[0].strip
94
+ sub = ""
95
+ end
96
+
97
+ if /\A\+(.+)\+\z/ =~ main
98
+ main = $1
99
+ main_decoration = OverlineDecoration
100
+ elsif /\A\-(.+)\-\z/ =~ main
101
+ main = $1
102
+ main_decoration = UnderlineDecoration
103
+ elsif /\A\=(.+)\=\z/ =~ main
104
+ main = $1
105
+ main_decoration = LineThroughDecoration
106
+ else
107
+ main_decoration = NoDecoration
108
+ end
109
+
110
+ if /\A\*\*\*(.+)\*\*\*\z/ =~ main
111
+ main = $1
112
+ if !@multibyte || !main.contains_cjk?
113
+ main_font = @font_itbd
114
+ end
115
+ elsif /\A\*\*(.+)\*\*\z/ =~ main
116
+ main = $1
117
+ if !@multibyte || !main.contains_cjk?
118
+ main_font = @font_bd
119
+ end
120
+ elsif /\A\*(.+)\*\z/ =~ main
121
+ main = $1
122
+ if !@multibyte || !main.contains_cjk?
123
+ main_font = @font_it
124
+ end
125
+ else
126
+ main_font = @font
130
127
  end
131
-
128
+
132
129
  # Calculate text size for the main and the
133
130
  # subscript part of the element
134
- main_width = img_get_txt_width(main, @font, @font_size)
131
+ # symbols for underline/overline removed temporarily
132
+
133
+ main_width = img_get_txt_width(main, main_font, @font_size)
134
+
135
+ if /\A\+(.+)\+\z/ =~ sub
136
+ sub = $1
137
+ sub_decoration = OverlineDecoration
138
+ elsif /\A\-(.+)\-\z/ =~ sub
139
+ sub = $1
140
+ @gc.decorate(UnderlineDecoration)
141
+ sub_decoration = UnderlineDecoration
142
+ elsif /\A\=(.+)\=\z/ =~ sub
143
+ sub = $1
144
+ sub_decoration = LineThroughDecoration
145
+ else
146
+ sub_decoration = NoDecoration
147
+ end
148
+
149
+ sub_font = @font
150
+
151
+ if /\A\*\*\*(.+)\*\*\*\z/ =~ sub
152
+ sub = $1
153
+ if !@multibyte || !sub.contains_cjk?
154
+ sub_font = @font_itbd
155
+ end
156
+ elsif /\A\*\*(.+)\*\*\z/ =~ sub
157
+ sub = $1
158
+ if !@multibyte || !sub.contains_cjk?
159
+ sub_font = @font_bd
160
+ end
161
+ elsif /\A\*(.+)\*\z/ =~ sub
162
+ sub = $1
163
+ if !@multibyte || !sub.contains_cjk?
164
+ sub_font = @font_it
165
+ end
166
+ else
167
+ sub_font = @font
168
+ end
135
169
 
136
170
  if sub != ""
137
- sub_width = img_get_txt_width(sub.to_s, @font, sub_size)
171
+ sub_width = img_get_txt_width(sub.to_s, sub_font, @sub_size)
138
172
  else
139
173
  sub_width = 0
140
174
  end
@@ -143,14 +177,14 @@ class TreeGraph
143
177
  txt_width = main_width + sub_width
144
178
 
145
179
  txt_pos = left + (right - left) / 2 - txt_width / 2
146
-
180
+
147
181
  # Select apropriate color
148
182
  if(type == ETYPE_LEAF)
149
183
  col = @col_leaf
150
184
  else
151
185
  col = @col_node
152
186
  end
153
-
187
+
154
188
  if(main[0].chr == "<" && main[-1].chr == ">")
155
189
  col = @col_trace
156
190
  end
@@ -162,16 +196,21 @@ class TreeGraph
162
196
  @gc.pointsize(@font_size)
163
197
  main_x = txt_pos
164
198
  main_y = top + @e_height - @m[:e_padd]
199
+
200
+ @gc.interline_spacing = -(@main_height / 3)
201
+ @gc.font(main_font)
202
+ @gc.decorate(main_decoration)
165
203
  @gc.text(main_x.ceil, main_y.ceil, main)
166
-
204
+
167
205
  # Draw subscript text
168
206
  if (sub.length > 0 )
169
- @gc.pointsize(sub_size)
170
- sub_x = txt_pos + main_width + (sub_size/8)
171
- sub_y = top + (@e_height - @m[:e_padd] + sub_size / 2)
207
+ @gc.pointsize(@sub_size)
208
+ sub_x = txt_pos + main_width + @sub_space_width
209
+ sub_y = top + (@e_height - @m[:e_padd] + @sub_size / 2)
210
+ @gc.font(sub_font)
211
+ @gc.decorate(sub_decoration)
172
212
  @gc.text(sub_x.ceil, sub_y.ceil, sub)
173
213
  end
174
-
175
214
  end
176
215
 
177
216
  # Draw a line between child/parent elements
@@ -180,7 +219,7 @@ class TreeGraph
180
219
  if (fromY == 0 )
181
220
  return
182
221
  end
183
-
222
+
184
223
  fromTop = row2px(fromY)
185
224
  fromLeft = (fromX + fromW / 2 + @m[:b_side])
186
225
  toBot = (row2px(fromY - 1 ) + @e_height)
@@ -193,14 +232,14 @@ class TreeGraph
193
232
  end
194
233
 
195
234
  # Draw a triangle between child/parent elements
196
- def triangle_to_parent(fromX, fromY, fromW, toX, textW, symmetrize = true)
235
+ def triangle_to_parent(fromX, fromY, fromW, textW, symmetrize = true)
197
236
  if (fromY == 0)
198
237
  return
199
238
  end
200
-
239
+
201
240
  toX = fromX
202
241
  fromCenter = (fromX + fromW / 2 + @m[:b_side])
203
-
242
+
204
243
  fromTop = row2px(fromY).ceil
205
244
  fromLeft1 = (fromCenter + textW / 2).ceil
206
245
  fromLeft2 = (fromCenter - textW / 2).ceil
@@ -210,7 +249,7 @@ class TreeGraph
210
249
  else
211
250
  toLeft = (toX + textW / 2 + @m[:b_side] * 3)
212
251
  end
213
-
252
+
214
253
  @gc.fill("none")
215
254
  @gc.stroke @col_line
216
255
  @gc.stroke_width 1
@@ -239,211 +278,17 @@ class TreeGraph
239
278
  end
240
279
  end
241
280
 
242
- # Calculate the width of the element. If the element is
243
- # a node, the calculation will be performed recursively
244
- # for all child elements.
245
- def calc_element_width(e)
246
- w = 0
247
-
248
- children = @e_list.get_children(e.id)
249
-
250
- if(children.length == 0)
251
- w = img_get_txt_width(e.content, @font, @font_size) + @font_size
252
- else
253
- children.each do |child|
254
- child_e = @e_list.get_id(child)
255
- w += calc_element_width(child_e)
256
- end
257
-
258
- tw = img_get_txt_width(e.content, @font, @font_size) + @font_size
259
- if(tw > w)
260
- fix_child_size(e.id, w, tw)
261
- w = tw
262
- end
263
- end
264
-
265
- @e_list.set_element_width(e.id, w)
266
- return w
267
- end
268
-
269
- # Calculate the width of all elements in a certain level
270
- def calc_level_width(l)
271
- w = 0
272
- e = @e_list.get_first
273
- while e
274
- if(e.level == l)
275
- w += calc_element_width(e)
276
- end
277
- e = @e_list.get_next
281
+ def img_get_txt_width(text, font, font_size, multiline = false)
282
+ parts = text.split("_", 2)
283
+ main_before = parts[0].strip
284
+ sub = parts[1]
285
+ main = get_txt_only(main_before)
286
+ main_metrics = img_get_txt_metrics(main, font, font_size, multiline)
287
+ width = main_metrics.width
288
+ if sub
289
+ sub_metrics = img_get_txt_metrics(sub.strip, font, font_size * SUBSCRIPT_CONST, multiline)
290
+ width += sub_metrics.width
278
291
  end
279
-
280
- return w
281
- end
282
-
283
- def calc_children_width(id)
284
- left = 0
285
- right = 0
286
- c_list = @e_list.get_children(id)
287
- return nil if c_list.empty?
288
-
289
- c_list.each do |c|
290
- left = c.indent if indent == 0 or left > c.indent
291
- end
292
- c_list.each do |c|
293
- right = c.indent + e.width if c.indent + c.width > right
294
- end
295
- return [left, right]
296
- end
297
-
298
- def get_children_indent(id)
299
- calc_children_width(id)[0]
300
- end
301
-
302
- def get_children_width(id)
303
- calc_children_width(id)[1] - get_children_indent(id)
304
- end
305
-
306
- # Parse the elements in the list top to bottom and
307
- # draw the elements into the image.
308
- # As we it iterate through the levels, the element
309
- # indentation is calculated.
310
- def parse_list
311
-
312
- # Calc element list recursively....
313
- e_arr = @e_list.get_elements
314
-
315
- h = @e_list.get_level_height
316
- h.times do |i|
317
- x = 0
318
- e_arr.each do |j|
319
-
320
- if (j.level == i)
321
- cw = @e_list.get_element_width(j.id)
322
- parent_indent = @e_list.get_indent(j.parent)
323
- if (x < parent_indent)
324
- x = parent_indent
325
- end
326
- @e_list.set_indent(j.id, x)
327
-
328
- if !@symmetrize
329
- draw_element(x, i, cw, j.content, j.type)
330
- if(j.parent != 0 )
331
- words = j.content.split(" ")
332
- unless @terminal == "nothing" && ETYPE_LEAF == j.type
333
- if (@terminal == "triangle" && ETYPE_LEAF == j.type && x == parent_indent && words.length > 0)
334
- txt_width = img_get_txt_width(j.content, @font, @font_size)
335
- triangle_to_parent(x, i, cw, @e_list.get_element_width(j.parent), txt_width)
336
- elsif (@terminal == "auto" && ETYPE_LEAF == j.type && x == parent_indent)
337
- if words.length > 1 || j.triangle
338
- txt_width = img_get_txt_width(j.content, @font, @font_size)
339
- triangle_to_parent(x, i, cw, @e_list.get_element_width(j.parent), txt_width, @symmetrize)
340
- else
341
- line_to_parent(x, i, cw, @e_list.get_indent(j.parent), @e_list.get_element_width(j.parent))
342
- end
343
- else
344
- line_to_parent(x, i, cw, @e_list.get_indent(j.parent), @e_list.get_element_width(j.parent))
345
- end
346
- end
347
- end
348
- end
349
-
350
- x += cw
351
- end
352
- end
353
- end
354
- return true if !@symmetrize
355
- h.times do |i|
356
- curlevel = h - i - 1
357
- indent = 0
358
- e_arr.each_with_index do |j, idx|
359
- if (j.level == curlevel)
360
- # Draw a line to the parent element
361
- children = @e_list.get_children(j.id)
362
-
363
- tw = img_get_txt_width(j.content, @font, @font_size)
364
- if children.length > 1
365
- left, right = -1, -1
366
- children.each do |child|
367
- k = @e_list.get_id(child)
368
- kw = img_get_txt_width(k.content, @font, @font_size)
369
- left = k.indent + kw / 2 if k.indent + kw / 2 < left or left == -1
370
- right = k.indent + kw / 2 if k.indent + kw / 2 > right
371
- end
372
- draw_element(left, curlevel, right - left, j.content, j.type)
373
- @e_list.set_indent(j.id, left + (right - left) / 2 - tw / 2)
374
-
375
- children.each do |child|
376
- k = @e_list.get_id(child)
377
- words = k.content.split(" ")
378
- dw = img_get_txt_width(k.content, @font, @font_size)
379
- unless @terminal == "nothing" && ETYPE_LEAF == k.type
380
- if (@terminal == "triangle" && ETYPE_LEAF == k.type && k.indent == j.indent && words.length > 0)
381
- txt_width = img_get_txt_width(k.content, @font, @font_size)
382
- triangle_to_parent(k.indent, curlevel + 1, dw, tw, txt_width)
383
- elsif (@terminal == "auto" && ETYPE_LEAF == k.type && k.indent == j.indent)
384
- if words.length > 1 || k.triangle
385
- txt_width = img_get_txt_width(k.content, @font, @font_size)
386
- triangle_to_parent(k.indent, curlevel + 1, dw, tw, txt_width)
387
- else
388
- line_to_parent(k.indent, curlevel + 1, dw, j.indent, tw)
389
- end
390
- else
391
- line_to_parent(k.indent, curlevel + 1, dw, j.indent, tw)
392
- end
393
- end
394
- end
395
-
396
- else
397
- unless children.empty?
398
- k = @e_list.get_id(children[0])
399
- kw = img_get_txt_width(k.content, @font, @font_size)
400
- left = k.indent
401
- right = k.indent + kw
402
- draw_element(left, curlevel, right - left, j.content, j.type)
403
- @e_list.set_indent(j.id, left + (right - left) / 2 - tw / 2)
404
- else
405
- parent = @e_list.get_id(j.parent)
406
- pw = img_get_txt_width(parent.content, @font, @font_size)
407
- pleft = parent.indent
408
- pright = pleft + pw
409
- left = j.indent
410
- right = left + tw
411
- if pw > tw
412
- left = pleft
413
- right = pright
414
- end
415
- draw_element(left, curlevel, right - left, j.content, j.type)
416
- @e_list.set_indent(j.id, left + (right - left) / 2 - tw / 2)
417
- end
418
-
419
- unless children.empty?
420
- k = @e_list.get_id(children[0])
421
- words = k.content.split(" ")
422
- dw = img_get_txt_width(k.content, @font, @font_size)
423
- unless @terminal == "nothing" && ETYPE_LEAF == k.type
424
- if (@terminal == "triangle" && ETYPE_LEAF == k.type && words.length > 0)
425
- txt_width = img_get_txt_width(k.content, @font, @font_size)
426
- triangle_to_parent(k.indent, curlevel + 1, dw,
427
- @e_list.get_element_width(k.parent), txt_width)
428
- elsif (@terminal == "auto" && ETYPE_LEAF == k.type)
429
- if words.length > 1 || k.triangle
430
- txt_width = img_get_txt_width(k.content, @font, @font_size)
431
- triangle_to_parent(k.indent, curlevel + 1, dw, @e_list.get_element_width(k.parent), txt_width)
432
- else
433
- line_to_parent(k.indent, curlevel + 1, dw, j.indent, tw)
434
- end
435
- else
436
- line_to_parent(k.indent, curlevel + 1, dw, j.indent, tw)
437
- end
438
- end
439
- end
440
- end
441
- end
442
- end
443
- end
444
- end
445
-
446
- def row2px(row)
447
- @m[:b_topbot] + @e_height * row + (@m[:v_space] + @font_size) * row
292
+ return width
448
293
  end
449
294
  end