squib 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +162 -133
- data/Gemfile +4 -4
- data/README.md +630 -550
- data/RELEASE TODO.md +18 -18
- data/Rakefile +99 -99
- data/lib/squib.rb +32 -32
- data/lib/squib/api/background.rb +20 -19
- data/lib/squib/api/data.rb +100 -99
- data/lib/squib/api/image.rb +90 -76
- data/lib/squib/api/save.rb +149 -103
- data/lib/squib/api/settings.rb +35 -37
- data/lib/squib/api/shapes.rb +230 -228
- data/lib/squib/api/text.rb +65 -66
- data/lib/squib/api/text_embed.rb +96 -66
- data/lib/squib/args/arg_loader.rb +138 -0
- data/lib/squib/args/box.rb +55 -0
- data/lib/squib/args/card_range.rb +32 -0
- data/lib/squib/args/color_validator.rb +12 -0
- data/lib/squib/args/coords.rb +33 -0
- data/lib/squib/args/dir_validator.rb +16 -0
- data/lib/squib/args/draw.rb +92 -0
- data/lib/squib/args/embed_adjust.rb +25 -0
- data/lib/squib/args/embed_key.rb +17 -0
- data/lib/squib/args/hand_special.rb +37 -0
- data/lib/squib/args/input_file.rb +37 -0
- data/lib/squib/args/paint.rb +44 -0
- data/lib/squib/args/paragraph.rb +115 -0
- data/lib/squib/args/save_batch.rb +60 -0
- data/lib/squib/args/scale_box.rb +53 -0
- data/lib/squib/args/sheet.rb +72 -0
- data/lib/squib/args/showcase_special.rb +38 -0
- data/lib/squib/args/svg_special.rb +37 -0
- data/lib/squib/args/transform.rb +25 -0
- data/lib/squib/args/typographer.rb +117 -117
- data/lib/squib/card.rb +67 -67
- data/lib/squib/conf.rb +117 -111
- data/lib/squib/constants.rb +178 -178
- data/lib/squib/deck.rb +113 -111
- data/lib/squib/graphics/cairo_context_wrapper.rb +99 -53
- data/lib/squib/graphics/gradient_regex.rb +46 -46
- data/lib/squib/graphics/hand.rb +42 -43
- data/lib/squib/graphics/image.rb +76 -73
- data/lib/squib/graphics/save_doc.rb +103 -137
- data/lib/squib/graphics/save_images.rb +33 -33
- data/lib/squib/graphics/shapes.rb +119 -152
- data/lib/squib/graphics/showcase.rb +85 -88
- data/lib/squib/graphics/text.rb +176 -216
- data/lib/squib/layout_parser.rb +91 -89
- data/lib/squib/layouts/economy.yml +85 -0
- data/lib/squib/layouts/fantasy.yml +101 -0
- data/lib/squib/layouts/hand.yml +62 -46
- data/lib/squib/layouts/playing-card.yml +35 -18
- data/lib/squib/project_template/config.yml +45 -40
- data/lib/squib/version.rb +10 -10
- data/samples/color_shortcuts.rb +6 -0
- data/samples/csv_import.rb +18 -18
- data/samples/custom-config.yml +5 -5
- data/samples/custom_config.rb +18 -18
- data/samples/draw_shapes.rb +45 -35
- data/samples/embed_text.rb +88 -90
- data/samples/hand.rb +24 -24
- data/samples/layouts.rb +62 -61
- data/samples/layouts_builtin.rb +51 -0
- data/samples/load_images.rb +78 -64
- data/samples/ranges.rb +64 -53
- data/samples/sample.csv +2 -2
- data/samples/text_options.rb +102 -94
- data/spec/api/api_data_spec.rb +57 -50
- data/spec/api/api_settings_spec.rb +37 -17
- data/spec/args/box_spec.rb +127 -0
- data/spec/args/draw_spec.rb +95 -0
- data/spec/args/embed_key_spec.rb +13 -0
- data/spec/args/input_file_spec.rb +21 -0
- data/spec/args/paint_spec.rb +22 -0
- data/spec/args/paragraph_spec.rb +153 -0
- data/spec/args/range_spec.rb +36 -0
- data/spec/args/save_batch_spec.rb +51 -0
- data/spec/args/scale_box_spec.rb +71 -0
- data/spec/args/sheet_spec.rb +58 -0
- data/spec/args/showcase_special_spec.rb +15 -0
- data/spec/data/samples/autoscale_font.rb.txt +84 -87
- data/spec/data/samples/basic.rb.txt +209 -203
- data/spec/data/samples/cairo_access.rb.txt +2 -2
- data/spec/data/samples/config_text_markup.rb.txt +72 -75
- data/spec/data/samples/csv_import.rb.txt +76 -80
- data/spec/data/samples/custom_config.rb.txt +48 -49
- data/spec/data/samples/draw_shapes.rb.txt +100 -42
- data/spec/data/samples/embed_text.rb.txt +283 -295
- data/spec/data/samples/excel.rb.txt +162 -171
- data/spec/data/samples/gradients.rb.txt +79 -67
- data/spec/data/samples/hand.rb.txt +538 -514
- data/spec/data/samples/hello_world.rb.txt +36 -38
- data/spec/data/samples/load_images.rb.txt +41 -5
- data/spec/data/samples/portrait-landscape.rb.txt +49 -51
- data/spec/data/samples/ranges.rb.txt +460 -429
- data/spec/data/samples/saves.rb.txt +801 -785
- data/spec/data/samples/showcase.rb.txt +5910 -5906
- data/spec/data/samples/text_options.rb.txt +1125 -981
- data/spec/data/samples/tgc_proofs.rb.txt +81 -79
- data/spec/data/samples/units.rb.txt +18 -12
- data/spec/data/xlsx/with_macros.xlsm +0 -0
- data/spec/graphics/cairo_context_wrapper_spec.rb +84 -75
- data/spec/graphics/graphics_images_spec.rb +94 -85
- data/spec/graphics/graphics_save_doc_spec.rb +67 -65
- data/spec/samples/expected/hand.png +0 -0
- data/spec/samples/expected/hand_pretty.png +0 -0
- data/spec/samples/expected/layout_00.png +0 -0
- data/spec/samples/expected/load_images_00.png +0 -0
- data/spec/samples/expected/ranges_00.png +0 -0
- data/spec/samples/expected/shape_00.png +0 -0
- data/spec/samples/expected/showcase.png +0 -0
- data/spec/samples/expected/showcase2.png +0 -0
- data/spec/samples/expected/showcase_individual_00.png +0 -0
- data/spec/samples/expected/showcase_individual_01.png +0 -0
- data/spec/samples/expected/showcase_individual_02.png +0 -0
- data/spec/samples/expected/showcase_individual_03.png +0 -0
- data/spec/samples/expected/text_00.png +0 -0
- data/spec/samples/expected/text_01.png +0 -0
- data/spec/samples/expected/text_02.png +0 -0
- data/spec/samples/samples_regression_spec.rb +82 -82
- data/spec/spec_helper.rb +3 -2
- data/squib.gemspec +48 -48
- data/squib.sublime-project +42 -36
- metadata +61 -33
- data/lib/squib/input_helpers.rb +0 -238
- data/spec/api/api_image_spec.rb +0 -38
- data/spec/api/api_text_spec.rb +0 -37
- data/spec/graphics/graphics_shapes_spec.rb +0 -85
- data/spec/graphics/graphics_text_spec.rb +0 -164
- data/spec/input_helpers_spec.rb +0 -238
- data/spec/samples/expected/embed_multi_00.png +0 -0
- data/spec/samples/expected/embed_multi_01.png +0 -0
- data/spec/samples/expected/embed_multi_02.png +0 -0
- data/spec/samples/expected/ranges_01.png +0 -0
- data/spec/samples/expected/ranges_02.png +0 -0
data/lib/squib/graphics/text.rb
CHANGED
|
@@ -1,216 +1,176 @@
|
|
|
1
|
-
require 'pango'
|
|
2
|
-
require 'squib/args/typographer'
|
|
3
|
-
|
|
4
|
-
module Squib
|
|
5
|
-
class Card
|
|
6
|
-
|
|
7
|
-
# :nodoc:
|
|
8
|
-
# @api private
|
|
9
|
-
def draw_text_hint(cc, x, y, layout, color)
|
|
10
|
-
color = @deck.text_hint if color.to_s.eql? 'off' and not @deck.text_hint.to_s.eql? 'off'
|
|
11
|
-
return if color.to_s.eql? 'off' or color.nil?
|
|
12
|
-
# when w,h < 0, it was never set. extents[1] are ink extents
|
|
13
|
-
w = layout.width / Pango::SCALE
|
|
14
|
-
w = layout.extents[1].width / Pango::SCALE if w < 0
|
|
15
|
-
h = layout.height / Pango::SCALE
|
|
16
|
-
h = layout.extents[1].height / Pango::SCALE if h < 0
|
|
17
|
-
cc.rounded_rectangle(0, 0, w, h, 0, 0)
|
|
18
|
-
cc.set_source_color(color)
|
|
19
|
-
cc.set_line_width(2.0)
|
|
20
|
-
cc.stroke
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
# :nodoc:
|
|
24
|
-
# @api private
|
|
25
|
-
def
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
when '
|
|
30
|
-
layout.
|
|
31
|
-
when '
|
|
32
|
-
layout.
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
end
|
|
36
|
-
end
|
|
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
|
-
# :nodoc:
|
|
120
|
-
# @api private
|
|
121
|
-
def
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
layout.
|
|
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
|
-
cc.
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
str = @deck.typographer.process(layout.text)
|
|
178
|
-
layout.markup = str
|
|
179
|
-
end
|
|
180
|
-
|
|
181
|
-
set_font_rendering_opts!(layout)
|
|
182
|
-
set_wh!(layout, width, height)
|
|
183
|
-
set_wrap!(layout, wrap)
|
|
184
|
-
set_ellipsize!(layout, ellipsize)
|
|
185
|
-
set_align!(layout, align)
|
|
186
|
-
|
|
187
|
-
layout.justify = justify unless justify.nil?
|
|
188
|
-
layout.spacing = spacing * Pango::SCALE unless spacing.nil?
|
|
189
|
-
cc.update_pango_layout(layout)
|
|
190
|
-
|
|
191
|
-
embed_draws = process_embeds(embed, str, layout)
|
|
192
|
-
|
|
193
|
-
vertical_start = compute_valign(layout, valign)
|
|
194
|
-
cc.move_to(0, vertical_start)
|
|
195
|
-
|
|
196
|
-
cc.update_pango_layout(layout)
|
|
197
|
-
cc.show_pango_layout(layout)
|
|
198
|
-
stroke_outline!(cc, layout, stroke_width, stroke_color)
|
|
199
|
-
begin
|
|
200
|
-
embed_draws.each { |ed| ed[:draw].call(self, ed[:x], ed[:y] + vertical_start) }
|
|
201
|
-
rescue Exception => e
|
|
202
|
-
puts "====EXCEPTION!===="
|
|
203
|
-
puts e
|
|
204
|
-
puts "If this was a non-invertible matrix error, this is a known issue with a potential workaround. Please report it at: https://github.com/andymeneely/squib/issues/55"
|
|
205
|
-
puts "=================="
|
|
206
|
-
raise e
|
|
207
|
-
end
|
|
208
|
-
draw_text_hint(cc, x, y, layout, hint)
|
|
209
|
-
extents = { width: layout.extents[1].width / Pango::SCALE,
|
|
210
|
-
height: layout.extents[1].height / Pango::SCALE }
|
|
211
|
-
end
|
|
212
|
-
return extents
|
|
213
|
-
end
|
|
214
|
-
|
|
215
|
-
end
|
|
216
|
-
end
|
|
1
|
+
require 'pango'
|
|
2
|
+
require 'squib/args/typographer'
|
|
3
|
+
|
|
4
|
+
module Squib
|
|
5
|
+
class Card
|
|
6
|
+
|
|
7
|
+
# :nodoc:
|
|
8
|
+
# @api private
|
|
9
|
+
def draw_text_hint(cc, x, y, layout, color)
|
|
10
|
+
color = @deck.text_hint if color.to_s.eql? 'off' and not @deck.text_hint.to_s.eql? 'off'
|
|
11
|
+
return if color.to_s.eql? 'off' or color.nil?
|
|
12
|
+
# when w,h < 0, it was never set. extents[1] are ink extents
|
|
13
|
+
w = layout.width / Pango::SCALE
|
|
14
|
+
w = layout.extents[1].width / Pango::SCALE if w < 0
|
|
15
|
+
h = layout.height / Pango::SCALE
|
|
16
|
+
h = layout.extents[1].height / Pango::SCALE if h < 0
|
|
17
|
+
cc.rounded_rectangle(0, 0, w, h, 0, 0)
|
|
18
|
+
cc.set_source_color(color)
|
|
19
|
+
cc.set_line_width(2.0)
|
|
20
|
+
cc.stroke
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# :nodoc:
|
|
24
|
+
# @api private
|
|
25
|
+
def compute_valign(layout, valign)
|
|
26
|
+
return 0 unless layout.height > 0
|
|
27
|
+
ink_extents = layout.extents[1]
|
|
28
|
+
case valign.to_s.downcase
|
|
29
|
+
when 'middle'
|
|
30
|
+
Pango.pixels( (layout.height - ink_extents.height) / 2)
|
|
31
|
+
when 'bottom'
|
|
32
|
+
Pango.pixels(layout.height - ink_extents.height)
|
|
33
|
+
else
|
|
34
|
+
0
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def set_font_rendering_opts!(layout)
|
|
39
|
+
font_options = Cairo::FontOptions.new
|
|
40
|
+
font_options.antialias = Conf::ANTIALIAS_OPTS[(@deck.antialias || 'gray').downcase]
|
|
41
|
+
font_options.hint_metrics = 'on' # TODO make this configurable
|
|
42
|
+
font_options.hint_style = 'full' # TODO make this configurable
|
|
43
|
+
layout.context.font_options = font_options
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# :nodoc:
|
|
47
|
+
# @api private
|
|
48
|
+
def set_wh!(layout, width, height)
|
|
49
|
+
layout.width = width * Pango::SCALE unless width.nil? || width == :auto
|
|
50
|
+
layout.height = height * Pango::SCALE unless height.nil? || height == :auto
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# :nodoc:
|
|
54
|
+
# @api private
|
|
55
|
+
def next_embed(keys, str)
|
|
56
|
+
ret = nil
|
|
57
|
+
ret_key = nil
|
|
58
|
+
keys.each do |key|
|
|
59
|
+
i = str.index(key)
|
|
60
|
+
ret ||= i
|
|
61
|
+
unless i.nil? || i > ret
|
|
62
|
+
ret = i
|
|
63
|
+
ret_key = key
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
ret_key
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# When we do embedded icons, we create a 3-character string that has a font
|
|
70
|
+
# size of zero and a letter-spacing that fits the icon we need. That gives
|
|
71
|
+
# us the wrapping behavior we need but no clutter beneath. On most
|
|
72
|
+
# platforms, this works fine. On Linux, this creates
|
|
73
|
+
# a Cairo transformation matrix that
|
|
74
|
+
ZERO_WIDTH_CHAR_SIZE = 0 # this works on most platforms
|
|
75
|
+
# some platforms make this Pango pixels (1/1024), others a 1 pt font
|
|
76
|
+
ZERO_WIDTH_CHAR_SIZE = 1 if RbConfig::CONFIG['host_os'] === 'linux-gnu'
|
|
77
|
+
|
|
78
|
+
# :nodoc:
|
|
79
|
+
# @api private
|
|
80
|
+
def process_embeds(embed, str, layout)
|
|
81
|
+
return [] unless embed.rules.any?
|
|
82
|
+
layout.markup = str
|
|
83
|
+
clean_str = layout.text
|
|
84
|
+
draw_calls = []
|
|
85
|
+
searches = []
|
|
86
|
+
while (key = next_embed(embed.rules.keys, clean_str)) != nil
|
|
87
|
+
rule = embed.rules[key]
|
|
88
|
+
spacing = rule[:box].width[@index] * Pango::SCALE
|
|
89
|
+
kindex = clean_str.index(key)
|
|
90
|
+
kindex = clean_str[0..kindex].bytesize #convert to byte index (bug #57)
|
|
91
|
+
str = str.sub(key, "<span size=\"#{ZERO_WIDTH_CHAR_SIZE}\">a<span letter_spacing=\"#{spacing.to_i}\">a</span>a</span>")
|
|
92
|
+
layout.markup = str
|
|
93
|
+
clean_str = layout.text
|
|
94
|
+
searches << { index: kindex, rule: rule }
|
|
95
|
+
end
|
|
96
|
+
searches.each do |search|
|
|
97
|
+
rect = layout.index_to_pos(search[:index])
|
|
98
|
+
x = Pango.pixels(rect.x) + search[:rule][:adjust].dx[@index]
|
|
99
|
+
y = Pango.pixels(rect.y) + search[:rule][:adjust].dy[@index]
|
|
100
|
+
draw_calls << {x: x, y: y, draw: search[:rule][:draw]} # defer drawing until we've valigned
|
|
101
|
+
end
|
|
102
|
+
return draw_calls
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def stroke_outline!(cc, layout, draw)
|
|
106
|
+
if draw.stroke_width > 0
|
|
107
|
+
cc.pango_layout_path(layout)
|
|
108
|
+
cc.fancy_stroke draw
|
|
109
|
+
cc.set_source_squibcolor(draw.color)
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def warn_if_ellipsized(layout)
|
|
114
|
+
if @deck.conf.warn_ellipsize? && layout.ellipsized?
|
|
115
|
+
Squib.logger.warn { "Ellipsized (too much text). Card \##{@index}. Text: \"#{layout.text}\". \n (To disable this warning, set warn_ellipsize: false in config.yml)" }
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# :nodoc:
|
|
120
|
+
# @api private
|
|
121
|
+
def text(embed, para, box, trans, draw)
|
|
122
|
+
Squib.logger.debug {"Rendering text with: \n#{para} \nat:\n #{box} \ndraw:\n #{draw} \ntransform: #{trans}"}
|
|
123
|
+
extents = nil
|
|
124
|
+
use_cairo do |cc|
|
|
125
|
+
cc.set_source_squibcolor(draw.color)
|
|
126
|
+
cc.translate(box.x, box.y)
|
|
127
|
+
cc.rotate(trans.angle)
|
|
128
|
+
cc.move_to(0, 0)
|
|
129
|
+
|
|
130
|
+
font_desc = Pango::FontDescription.new(para.font)
|
|
131
|
+
font_desc.size = para.font_size * Pango::SCALE unless para.font_size.nil?
|
|
132
|
+
layout = cc.create_pango_layout
|
|
133
|
+
layout.font_description = font_desc
|
|
134
|
+
layout.text = para.str
|
|
135
|
+
if para.markup
|
|
136
|
+
para.str = @deck.typographer.process(layout.text)
|
|
137
|
+
layout.markup = para.str
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
set_font_rendering_opts!(layout)
|
|
141
|
+
set_wh!(layout, box.width, box.height)
|
|
142
|
+
layout.wrap = para.wrap
|
|
143
|
+
layout.ellipsize = para.ellipsize
|
|
144
|
+
layout.alignment = para.align
|
|
145
|
+
|
|
146
|
+
layout.justify = para.justify unless para.justify.nil?
|
|
147
|
+
layout.spacing = para.spacing unless para.spacing.nil?
|
|
148
|
+
|
|
149
|
+
embed_draws = process_embeds(embed, para.str, layout)
|
|
150
|
+
|
|
151
|
+
vertical_start = compute_valign(layout, para.valign)
|
|
152
|
+
cc.move_to(0, vertical_start) #TODO clean this up a bit
|
|
153
|
+
|
|
154
|
+
stroke_outline!(cc, layout, draw) if draw.stroke_strategy == :stroke_first
|
|
155
|
+
cc.move_to(0, vertical_start)
|
|
156
|
+
cc.show_pango_layout(layout)
|
|
157
|
+
stroke_outline!(cc, layout, draw) if draw.stroke_strategy == :fill_first
|
|
158
|
+
begin
|
|
159
|
+
embed_draws.each { |ed| ed[:draw].call(self, ed[:x], ed[:y] + vertical_start) }
|
|
160
|
+
rescue Exception => e
|
|
161
|
+
puts "====EXCEPTION!===="
|
|
162
|
+
puts e
|
|
163
|
+
puts "If this was a non-invertible matrix error, this is a known issue with a potential workaround. Please report it at: https://github.com/andymeneely/squib/issues/55"
|
|
164
|
+
puts "=================="
|
|
165
|
+
raise e
|
|
166
|
+
end
|
|
167
|
+
draw_text_hint(cc, box.x, box.y, layout, para.hint)
|
|
168
|
+
extents = { width: layout.extents[1].width / Pango::SCALE,
|
|
169
|
+
height: layout.extents[1].height / Pango::SCALE }
|
|
170
|
+
warn_if_ellipsized layout
|
|
171
|
+
end
|
|
172
|
+
return extents
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
end
|
|
176
|
+
end
|
data/lib/squib/layout_parser.rb
CHANGED
|
@@ -1,89 +1,91 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
class
|
|
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
|
-
parent_keys
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
parent_val
|
|
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
|
-
|
|
1
|
+
require 'yaml'
|
|
2
|
+
|
|
3
|
+
module Squib
|
|
4
|
+
# Internal class for handling layouts
|
|
5
|
+
#@api private
|
|
6
|
+
class LayoutParser
|
|
7
|
+
|
|
8
|
+
# Load the layout file(s), if exists
|
|
9
|
+
# @api private
|
|
10
|
+
def self.load_layout(files)
|
|
11
|
+
layout = {}
|
|
12
|
+
Squib::logger.info { " using layout(s): #{files}" }
|
|
13
|
+
Array(files).each do |file|
|
|
14
|
+
thefile = file
|
|
15
|
+
thefile = builtin(file) unless File.exists?(file)
|
|
16
|
+
if File.exists? thefile
|
|
17
|
+
yml = layout.merge(YAML.load_file(thefile) || {}) #load_file returns false on empty file
|
|
18
|
+
yml.each do |key, value|
|
|
19
|
+
layout[key] = recurse_extends(yml, key, {})
|
|
20
|
+
end
|
|
21
|
+
else
|
|
22
|
+
Squib::logger.error { "Layout file not found: #{file}. Skipping..." }
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
return layout
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Determine the file path of the built-in layout file
|
|
29
|
+
def self.builtin(file)
|
|
30
|
+
"#{File.dirname(__FILE__)}/layouts/#{file}"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Process the extends recursively
|
|
34
|
+
# :nodoc:
|
|
35
|
+
# @api private
|
|
36
|
+
def self.recurse_extends(yml, key, visited )
|
|
37
|
+
assert_not_visited(key, visited)
|
|
38
|
+
return yml[key] unless has_extends?(yml, key)
|
|
39
|
+
return yml[key] unless parents_exist?(yml, key)
|
|
40
|
+
visited[key] = key
|
|
41
|
+
parent_keys = [yml[key]['extends']].flatten
|
|
42
|
+
h = {}
|
|
43
|
+
parent_keys.each do |parent_key|
|
|
44
|
+
from_extends = yml[key].merge(recurse_extends(yml, parent_key, visited)) do |key, child_val, parent_val|
|
|
45
|
+
if child_val.to_s.strip.start_with?('+=')
|
|
46
|
+
parent_val + child_val.sub('+=','').strip.to_f
|
|
47
|
+
elsif child_val.to_s.strip.start_with?('-=')
|
|
48
|
+
parent_val - child_val.sub('-=','').strip.to_f
|
|
49
|
+
else
|
|
50
|
+
child_val #child overrides parent when merging, no +=
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
h = h.merge(from_extends) do |key, older_sibling, younger_sibling|
|
|
54
|
+
younger_sibling #when two siblings have the same entry, the "younger" (lower one) overrides
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
return h
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Does this layout entry have an extends field?
|
|
61
|
+
# i.e. is it a base-case or will it need recursion?
|
|
62
|
+
# :nodoc:
|
|
63
|
+
# @api private
|
|
64
|
+
def self.has_extends?(yml, key)
|
|
65
|
+
!!yml[key] && yml[key].key?('extends')
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Checks if we have any absentee parents
|
|
69
|
+
# @api private
|
|
70
|
+
def self.parents_exist?(yml, key)
|
|
71
|
+
exists = true
|
|
72
|
+
Array(yml[key]['extends']).each do |parent|
|
|
73
|
+
unless yml.key?(parent)
|
|
74
|
+
exists = false unless
|
|
75
|
+
Squib.logger.error "Processing layout: '#{key}' attempts to extend a missing '#{yml[key]['extends']}'"
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
return exists
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Safeguard against malformed circular extends
|
|
82
|
+
# :nodoc:
|
|
83
|
+
# @api private
|
|
84
|
+
def self.assert_not_visited(key, visited)
|
|
85
|
+
if visited.key? key
|
|
86
|
+
raise "Invalid layout: circular extends with '#{key}'"
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
end
|
|
91
|
+
end
|