rsyntaxtree 0.7.2 → 0.7.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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