#-- # $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) 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 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. # @private def add_primitives(gc) return if !@text && @tspans.empty? gc.push x = cx + @dx y = 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 # class TextBase # Tspan and Tref shared methods - read/update @cx, @cy in parent Text object. # @private module TextLink 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 # @private class Tref < TextBase 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 # @private class Tspan < TextBase 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 # @private attr_accessor :cx, :cy # 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) raise ArgumentError, "wrong argument type #{obj.class} (expected Tspan)" unless obj.is_a?(Tspan) obj = obj.deep_copy obj.parent = self tref = Tref.new(obj, x, y, self) @tspans << tref 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 t end end # module TextConstructors end # class RVG end # module Magick