/
text.rb
187 lines (151 loc) · 5.64 KB
/
text.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
#--
# $Id: text.rb,v 1.7 2009/02/28 23:52:28 rmagick Exp $
# Copyright (C) 2009 Timothy P. Hunter
#++
# Text-related classes
module Magick
class RVG
# Base class for Tspan, Tref and Text.
class TextBase
include Stylable
include Duplicatable
private
def initialize(text, &block) #:nodoc:
super()
@text = text.to_s if text
@dx = @dy = 0
@rotation = 0
@tspans = Content.new
yield(self) if block_given?
end
public
# Create a new text chunk. Each chunk can have its own initial position and styles.
# If <tt>x</tt> and <tt>y</tt> are omitted the text starts at the current text
# position.
def tspan(text, x=nil, y=nil)
tspan = Tspan.new(text, x, y)
tspan.parent = self
@tspans << tspan
return tspan
end
# Add <tt>x</tt> and <tt>y</tt> to the current text position.
def d(x, y=0)
@dx, @dy = Magick::RVG.convert_to_float(x, y)
yield(self) if block_given?
self
end
# Rotate the text about the current text position.
def rotate(degrees)
@rotation = Magick::RVG.convert_to_float(degrees)[0]
yield(self) if block_given?
self
end
# We do our own transformations.
def add_primitives(gc) #:nodoc:
if @text || @tspans.length > 0
gc.push
x = self.cx + @dx
y = self.cy + @dy
if @rotation != 0
gc.translate(x, y)
gc.rotate(@rotation)
gc.translate(-x, -y)
end
add_style_primitives(gc)
if @text
x2, y2 = gc.text(x, y, @text)
self.cx = x + x2
self.cy = y + y2
end
@tspans.each do |tspan|
tspan.add_primitives(gc)
end
gc.pop
end
end
end # class TextBase
# Tspan and Tref shared methods - read/update @cx, @cy in parent Text object.
module TextLink #:nodoc:
def add_primitives(gc)
@parent.cx = @x if @x
@parent.cy = @y if @y
super
end
def cx()
@parent.cx
end
def cy()
@parent.cy
end
def cx=(x)
@parent.cx = x
end
def cy=(y)
@parent.cy = y
end
end # module TextLink
class Tref < TextBase #:nodoc:
include TextLink
def initialize(obj, x, y, parent)
@x, @y = Magick::RVG.convert_to_float(x, y, :allow_nil)
super(nil)
@tspans << obj
@parent = parent
end
end # class Tref
class Tspan < TextBase #:nodoc:
include TextLink
attr_accessor :parent
# Define a text segment starting at (<tt>x</tt>, <tt>y</tt>).
# If <tt>x</tt> and <tt>y</tt> are omitted the segment starts
# at the current text position.
#
# Tspan objects can contain Tspan objects.
def initialize(text=nil, x=nil, y=nil, &block)
@x, @y = Magick::RVG.convert_to_float(x, y, :allow_nil)
super(text, &block)
end
end # class Tspan
class Text < TextBase
attr_accessor :cx, :cy #:nodoc:
# Define a text string starting at [<tt>x</tt>, <tt>y</tt>].
# Use the RVG::TextConstructors#text method to create Text objects in a container.
#
# container.text(100, 100, "Simple text").styles(:font=>'Arial')
#
# Text objects can contain Tspan objects.
#
# container.text(100, 100).styles(:font=>'Arial') do |t|
# t.tspan("Red text").styles(:fill=>'red')
# t.tspan("Blue text").styles(:fill=>'blue')
# end
def initialize(x=0, y=0, text=nil, &block)
@cx, @cy = Magick::RVG.convert_to_float(x, y)
super(text, &block)
end
# Reference a Tspan object. <tt>x</tt> and <tt>y</tt> are just
# like <tt>x</tt> and <tt>y</tt> in RVG::TextBase#tspan
def tref(obj, x=nil, y=nil)
if ! obj.kind_of?(Tspan)
raise ArgumentError, "wrong argument type #{obj.class} (expected Tspan)"
end
obj = obj.deep_copy
obj.parent = self
tref = Tref.new(obj, x, y, self)
@tspans << tref
return tref
end
end # class Text
# Methods that construct text objects within a container
module TextConstructors
# Draw a text string at (<tt>x</tt>,<tt>y</tt>). The string can
# be omitted. Optionally, define text chunks within the associated
# block.
def text(x=0, y=0, text=nil, &block)
t = Text.new(x, y, text, &block)
@content << t
return t
end
end # module TextConstructors
end # class RVG
end # module Magick