parent
ef43741eb1
commit
666dae393d
|
|
@ -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],
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -5,7 +5,6 @@ require 'squib/graphics/cairo_context_wrapper'
|
|||
module Squib
|
||||
# Back end graphics. Private.
|
||||
class Card
|
||||
include Squib::InputHelpers
|
||||
|
||||
# :nodoc:
|
||||
# @api private
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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…
Reference in New Issue