Browse Source

Base functionality of icon embedding working

Contributes to #30
dev
Andy Meneely 11 years ago
parent
commit
666dae393d
  1. 7
      lib/squib/api/text.rb
  2. 26
      lib/squib/api/text_embed.rb
  3. 1
      lib/squib/card.rb
  4. 91
      lib/squib/graphics/text.rb
  5. 17
      samples/embed_text.rb
  6. 19
      samples/text_options.rb

7
lib/squib/api/text.rb

@ -1,3 +1,5 @@
require 'squib/api/text_embed'
module Squib
class Deck
@ -41,9 +43,12 @@ module Squib
def text(opts = {})
opts = needs(opts, [:range, :str, :font, :font_size, :x, :y, :width, :height, :color, :wrap,
:align, :justify, :spacing, :valign, :markup, :ellipsize, :hint, :layout, :angle])
embed = TextEmbed.new
yield(embed) if block_given? #store the opts for later use
extents = Array.new(@cards.size)
opts[:range].each do |i|
extents[i] = @cards[i].text(opts[:str][i], opts[:font][i], opts[:font_size][i], opts[:color][i],
extents[i] = @cards[i].text(embed,
opts[:str][i], opts[:font][i], opts[:font_size][i], opts[:color][i],
opts[:x][i], opts[:y][i], opts[:width][i], opts[:height][i],
opts[:markup][i], opts[:justify][i], opts[:wrap][i],
opts[:ellipsize][i], opts[:spacing][i], opts[:align][i],

26
lib/squib/api/text_embed.rb

@ -0,0 +1,26 @@
module Squib
class TextEmbed
attr_reader :rules
def initialize
@rules = {} # store an array of options for later usage
end
# Context object for embedding text within a string
#
# @option opts file [String] ('') file(s) to read in. If it's a single file, then it's use for every card in range. If the parameter is an Array of files, then each file is looked up for each card. If any of them are nil or '', nothing is done. See {file:README.md#Specifying_Files Specifying Files}. Supports Arrays, see {file:README.md#Arrays_and_Singleton_Expansion Arrays and Singleon Expansion}
# @option opts id [String] (nil) if set, then only render the SVG element with the given id. Prefix '#' is optional. Note: the x-y coordinates are still relative to the SVG document's page. Supports Arrays, see {file:README.md#Arrays_and_Singleton_Expansion Arrays and Singleon Expansion}
# @option opts force_id [Boolean] (false) if set, then this svg will not be rendered at all if the id is empty or nil. If not set, the entire SVG is rendered. Supports Arrays, see {file:README.md#Arrays_and_Singleton_Expansion Arrays and Singleon Expansion}
# @option opts layout [String, Symbol] (nil) entry in the layout to use as defaults for this command. See {file:README.md#Custom_Layouts Custom Layouts}. Supports Arrays, see {file:README.md#Arrays_and_Singleton_Expansion Arrays and Singleon Expansion}
# @option opts width [Integer, :native] (:native) the width of the image rendered
# @option opts height [Integer, :native] the height the height of the image rendered
# @option opts alpha [Decimal] (1.0) the alpha-transparency percentage used to blend this image. Supports Arrays, see {file:README.md#Arrays_and_Singleton_Expansion Arrays and Singleon Expansion}
# @option opts blend [:none, :multiply, :screen, :overlay, :darken, :lighten, :color_dodge, :color_burn, :hard_light, :soft_light, :difference, :exclusion, :hsl_hue, :hsl_saturation, :hsl_color, :hsl_luminosity] (:none) the composite blend operator used when applying this image. See Blend Modes at http://cairographics.org/operators. Supports Arrays, see {file:README.md#Arrays_and_Singleton_Expansion Arrays and Singleon Expansion}
# @option opts angle [FixNum] (0) Rotation of the in radians. Note that this rotates around the upper-left corner, making the placement of x-y coordinates slightly tricky. Supports Arrays, see {file:README.md#Arrays_and_Singleton_Expansion Arrays and Singleon Expansion}
def svg(opts)
opts = Squib::SYSTEM_DEFAULTS.merge(opts)
# TODO: add input validation here. We need the key for example.
@rules[opts[:key]] = {type: :svg}.merge(opts)
end
end
end

1
lib/squib/card.rb

@ -5,7 +5,6 @@ require 'squib/graphics/cairo_context_wrapper'
module Squib
# Back end graphics. Private.
class Card
include Squib::InputHelpers
# :nodoc:
# @api private

91
lib/squib/graphics/text.rb

@ -6,14 +6,14 @@ module Squib
# :nodoc:
# @api private
def draw_text_hint(cc,x,y,layout, color,angle)
color = @deck.text_hint if color.to_s.eql? 'off' and not @deck.text_hint.to_s.eql? 'off'
color = @deck.text_hint if color.eql? 'off' and not @deck.text_hint.to_s.eql? 'off'
return if color.to_s.eql? 'off' or color.nil?
# when w,h < 0, it was never set. extents[1] are ink extents
w = layout.width / Pango::SCALE
w = layout.extents[1].width / Pango::SCALE if w < 0
h = layout.height / Pango::SCALE
h = layout.extents[1].height / Pango::SCALE if h < 0
cc.rounded_rectangle(x,y,w,h,0,0)
cc.rounded_rectangle(0, 0, w, h, 0, 0)
cc.set_source_color(color)
cc.set_line_width(2.0)
cc.stroke
@ -62,14 +62,14 @@ module Squib
# :nodoc:
# @api private
def valign!(cc, layout, x, y, valign)
def valign!(cc, layout, valign)
if layout.height > 0
ink_extents = layout.extents[1]
case valign.to_s
case valign.to_s.downcase
when 'middle'
cc.move_to(x, y + (layout.height - ink_extents.height) / (2 * Pango::SCALE))
cc.move_to(0, (layout.height - ink_extents.height) / (2 * Pango::SCALE))
when 'bottom'
cc.move_to(x, y + (layout.height - ink_extents.height) / Pango::SCALE)
cc.move_to(0, (layout.height - ink_extents.height) / Pango::SCALE)
end
end
end
@ -82,36 +82,97 @@ module Squib
layout
end
def next_embed(keys, str)
ret = nil
ret_key = nil
keys.each do |key|
i = str.index(key)
ret ||= i
unless i.nil? || i > ret
ret = i
ret_key = key
end
end
ret_key
end
def process_embeds(embed, str, layout, cc)
return unless embed.rules.any?
while (key = next_embed(embed.rules.keys, str)) != nil
rule = embed.rules[key]
spacing = rule[:width] * Pango::SCALE
index = str.gsub(/<span letter_spacing="\d+"> <\/span>/,' ').index(key)
str = str.sub(key, "<span letter_spacing=\"#{spacing.to_i}\"> </span>")
layout.markup = str
cc.update_pango_layout(layout)
iter = layout.iter
while iter.next_char! && iter.index < index; end
rect = layout.index_to_pos(index)
letter_width = iter.char_extents.width - spacing # the spacing of our actual letter
x = (rect.x + letter_width / 2) / Pango::SCALE
# x = rect.x / Pango::SCALE
y = rect.y / Pango::SCALE
circle(x, y + 2, 2, :red, :red, 0)
# circle(x,y + 2, 2, :red, :red, 0)
puts <<-EOS
Embedding #{key}
at index: #{index}
xy #{x},#{y}
spacing at #{spacing} or #{spacing / Pango::SCALE}px
space character width #{letter_width} or #{letter_width / Pango::SCALE}px
and string is:
#{str}
EOS
svg(rule[:file], rule[:id], x, y, rule[:width], rule[:height],
rule[:alpha], rule[:blend], rule[:angle], SYSTEM_DEFAULTS[:mask])
end
# embed.rules.each do |rule|
# cc.update_pango_layout(layout)
# index = str.index(rule[:key])
# unless index.nil?
# puts "embed #{rule[:type]} #{rule[:file]} into #{rule[:key]} at #{x},#{y}, index #{index}"
# end
# end
end
# :nodoc:
# @api private
def text(str, font, font_size, color,
def text(embed,str, font, font_size, color,
x, y, width, height,
markup, justify, wrap, ellipsize,
spacing, align, valign, hint, angle)
Squib.logger.debug {"Placing '#{str}'' with font '#{font}' @ #{x}, #{y}, color: #{color}, angle: #{angle} etc."}
extents = nil
str = str.to_s
use_cairo do |cc|
cc.set_source_squibcolor(color)
cc.translate(x,y)
cc.rotate(angle)
cc.translate(-1*x,-1*y)
cc.move_to(x,y)
cc.move_to(0, 0)
layout = cc.create_pango_layout
font_desc = Pango::FontDescription.new(font)
font_desc = Pango::FontDescription.new(font)
font_desc.size = font_size * Pango::SCALE unless font_size.nil?
layout = cc.create_pango_layout
layout.font_description = font_desc
layout.text = str.to_s
layout.markup = str.to_s if markup
layout.text = str
layout.markup = str if markup
set_wh!(layout, width, height)
set_wrap!(layout, wrap)
set_ellipsize!(layout, ellipsize)
set_align!(layout, align)
layout.justify = justify unless justify.nil?
layout.spacing = spacing * Pango::SCALE unless spacing.nil?
cc.update_pango_layout(layout)
valign!(cc, layout, x, y, valign)
cc.update_pango_layout(layout) ; cc.show_pango_layout(layout)
valign!(cc, layout, valign)
cc.update_pango_layout(layout)
process_embeds(embed, str, layout, cc)
cc.update_pango_layout(layout)
cc.show_pango_layout(layout)
draw_text_hint(cc,x,y,layout,hint,angle)
extents = { width: layout.extents[1].width / Pango::SCALE,
height: layout.extents[1].height / Pango::SCALE }

17
samples/embed_text.rb

@ -0,0 +1,17 @@
require 'squib'
Squib::Deck.new do
rect x: 0, y: 0, width: 825, height: 1125
rect x: 0, y: 0, width: 180, height: 180, stroke_color: :red
# embed_text = 'Take 1:tool:and gain 2 :health:. Take 2 :tool: if level 2'
embed_text = '1 :tool: 2 :health:'
text(str: embed_text, font: 'Sans 18',
x: 0, y: 0, width: 180,
align: :center, ellipsize: false, justify: false) do |embed|
embed.svg key: ':tool:', width: 28, height: 28, file: 'spanner.svg'
embed.svg key: ':health:', width: 28, height: 28, file: 'glass-heart.svg'
end
save_png prefix: 'embed_'
end

19
samples/text_options.rb

@ -3,9 +3,9 @@ require 'squib'
data = {'name' => ['Thief', 'Grifter', 'Mastermind'],
'level' => [1,2,3]}
longtext = "This is left-justified text.\nWhat do you know about tweetle beetles? well... \nWhen tweetle beetles fight, it's called a tweetle beetle battle. And when they battle in a puddle, it's a tweetle beetle puddle battle. AND when tweetle beetles battle with paddles in a puddle, they call it a tweetle beetle puddle paddle battle. AND... When beetles battle beetles in a puddle paddle battle and the beetle battle puddle is a puddle in a bottle... ..they call this a tweetle beetle bottle puddle paddle battle muddle. AND... When beetles fight these battles in a bottle with their paddles and the bottle's on a poodle and the poodle's eating noodles... ...they call this a muddle puddle tweetle poodle beetle noodle bottle paddle battle."
longtext = "This is left-justified text, with newlines.\nWhat do you know about tweetle beetles? well... When tweetle beetles fight, it's called a tweetle beetle battle. And when they battle in a puddle, it's a tweetle beetle puddle battle. AND when tweetle beetles battle with paddles in a puddle, they call it a tweetle beetle puddle paddle battle. AND... When beetles battle beetles in a puddle paddle battle and the beetle battle puddle is a puddle in a bottle... ..they call this a tweetle beetle bottle puddle paddle battle muddle."
Squib::Deck.new(width: 825, height: 1125, cards: 3) do
Squib::Deck.new(width: 825, height: 1125, cards: 1) do
background color: :white
rect x: 15, y: 15, width: 795, height: 1095, x_radius: 50, y_radius: 50
rect x: 30, y: 30, width: 128, height: 128, x_radius: 25, y_radius: 25
@ -62,9 +62,19 @@ Squib::Deck.new(width: 825, height: 1125, cards: 3) do
text str: longtext, font: 'Arial 16',
x: 65, y: 700,
width: inches(2.25), height: inches(1),
width: '1.5in', height: inches(1),
justify: true
# Here's how you embed images into text.
embed_text = 'Embedded icons! Take one 1 :tool: and gain 2 :health:. If Level 2, take 2 :tool:'
# embed_text = '1 :tool: 2 :health: 2 :tool:'
text(str: embed_text, font: 'Sans 18',
x: '1.8in', y: '2.5in', width: '0.85in',
align: :center, ellipsize: false) do |embed|
embed.svg key: ':tool:', width: 28, height: 28, file: 'spanner.svg'
embed.svg key: ':health:', width: 28, height: 28, file: 'glass-heart.svg'
end
text str: '<b>Markup</b> is also <i>quite</i> <s>easy</s> awesome',
markup: true,
x: 50, y: 1000,
@ -72,5 +82,6 @@ Squib::Deck.new(width: 825, height: 1125, cards: 3) do
valign: :bottom,
font: 'Arial 32', hint: :cyan
save prefix: 'text_', format: :png
save range: 0, prefix: 'text_', format: :png
end

Loading…
Cancel
Save