squib 0.18.0 → 0.19.0a

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.
Files changed (202) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +39 -39
  3. data/.github/ISSUE_TEMPLATE/feature_request.md +22 -22
  4. data/.github/ISSUE_TEMPLATE/help-wanted.md +13 -13
  5. data/.github/ISSUE_TEMPLATE/release-todo.md +45 -33
  6. data/.github/PULL_REQUEST_TEMPLATE.md +13 -13
  7. data/.github/workflows/tests.yml +22 -22
  8. data/.gitignore +41 -41
  9. data/.vscode/settings.json +4 -3
  10. data/CHANGELOG.md +460 -460
  11. data/CONTRIBUTING.md +40 -40
  12. data/Dockerfile +27 -27
  13. data/Gemfile +2 -2
  14. data/Guardfile +8 -8
  15. data/LICENSE.txt +22 -22
  16. data/README.md +139 -139
  17. data/Rakefile +51 -51
  18. data/bin/squib +5 -5
  19. data/lib/squib/api/settings.rb +21 -21
  20. data/lib/squib/args/arg_loader.rb +138 -138
  21. data/lib/squib/args/box.rb +59 -59
  22. data/lib/squib/args/card_range.rb +34 -34
  23. data/lib/squib/args/color_validator.rb +7 -7
  24. data/lib/squib/args/coords.rb +49 -49
  25. data/lib/squib/args/csv_opts.rb +22 -22
  26. data/lib/squib/args/dir_validator.rb +11 -11
  27. data/lib/squib/args/draw.rb +93 -93
  28. data/lib/squib/args/drop_shadow.rb +39 -39
  29. data/lib/squib/args/embed_adjust.rb +22 -22
  30. data/lib/squib/args/embed_key.rb +12 -12
  31. data/lib/squib/args/hand_special.rb +37 -37
  32. data/lib/squib/args/import.rb +67 -67
  33. data/lib/squib/args/input_file.rb +55 -55
  34. data/lib/squib/args/paint.rb +43 -43
  35. data/lib/squib/args/paragraph.rb +118 -118
  36. data/lib/squib/args/save_batch.rb +65 -65
  37. data/lib/squib/args/scale_box.rb +57 -57
  38. data/lib/squib/args/sheet.rb +165 -165
  39. data/lib/squib/args/showcase_special.rb +41 -41
  40. data/lib/squib/args/sprue_file.rb +44 -44
  41. data/lib/squib/args/svg_special.rb +37 -37
  42. data/lib/squib/args/transform.rb +55 -55
  43. data/lib/squib/args/typographer.rb +115 -115
  44. data/lib/squib/args/unit_conversion.rb +27 -27
  45. data/lib/squib/args/xywh_shorthands.rb +50 -50
  46. data/lib/squib/builtin/layouts/economy.yml +85 -85
  47. data/lib/squib/builtin/layouts/fantasy.yml +101 -101
  48. data/lib/squib/builtin/layouts/hand.yml +62 -62
  49. data/lib/squib/builtin/layouts/party.yml +94 -94
  50. data/lib/squib/builtin/layouts/playing-card.yml +35 -35
  51. data/lib/squib/builtin/layouts/tuck_box.yml +46 -46
  52. data/lib/squib/builtin/projects/advanced/.gitignore +4 -4
  53. data/lib/squib/builtin/projects/advanced/ABOUT.md +19 -19
  54. data/lib/squib/builtin/projects/advanced/Gemfile +11 -11
  55. data/lib/squib/builtin/projects/advanced/Guardfile +21 -21
  56. data/lib/squib/builtin/projects/advanced/IDEAS.md +22 -22
  57. data/lib/squib/builtin/projects/advanced/PLAYTESTING.md +26 -26
  58. data/lib/squib/builtin/projects/advanced/Rakefile +27 -27
  59. data/lib/squib/builtin/projects/advanced/config.yml +49 -49
  60. data/lib/squib/builtin/projects/advanced/docs/PNP NOTES.md +3 -3
  61. data/lib/squib/builtin/projects/advanced/docs/RULES.md +21 -21
  62. data/lib/squib/builtin/projects/advanced/img/example.svg +60 -60
  63. data/lib/squib/builtin/projects/advanced/layouts/deck.yml +27 -27
  64. data/lib/squib/builtin/projects/advanced/src/deck.rb +34 -34
  65. data/lib/squib/builtin/projects/advanced/src/version.rb +3 -3
  66. data/lib/squib/builtin/projects/basic/.gitignore +4 -4
  67. data/lib/squib/builtin/projects/basic/ABOUT.md +19 -19
  68. data/lib/squib/builtin/projects/basic/Gemfile +3 -3
  69. data/lib/squib/builtin/projects/basic/IDEAS.md +22 -22
  70. data/lib/squib/builtin/projects/basic/PLAYTESTING.md +26 -26
  71. data/lib/squib/builtin/projects/basic/PNP NOTES.md +3 -3
  72. data/lib/squib/builtin/projects/basic/RULES.md +21 -21
  73. data/lib/squib/builtin/projects/basic/Rakefile +7 -7
  74. data/lib/squib/builtin/projects/basic/config.yml +50 -50
  75. data/lib/squib/builtin/projects/basic/deck.rb +6 -6
  76. data/lib/squib/builtin/sprues/a4_euro_card.yml +42 -42
  77. data/lib/squib/builtin/sprues/a4_poker_card_8up.yml +40 -40
  78. data/lib/squib/builtin/sprues/a4_poker_card_9up.yml +42 -42
  79. data/lib/squib/builtin/sprues/a4_usa_card.yml +42 -42
  80. data/lib/squib/builtin/sprues/drivethrucards_1up.yml +10 -10
  81. data/lib/squib/builtin/sprues/letter_poker_card_9up.yml +25 -25
  82. data/lib/squib/builtin/sprues/letter_poker_foldable_8up.yml +52 -52
  83. data/lib/squib/builtin/sprues/printplaygames_18up.yml +68 -68
  84. data/lib/squib/card.rb +75 -75
  85. data/lib/squib/commands/cli.rb +39 -39
  86. data/lib/squib/commands/data/template_option.rb +109 -109
  87. data/lib/squib/commands/make_sprue.rb +277 -277
  88. data/lib/squib/commands/new.rb +77 -77
  89. data/lib/squib/conf.rb +149 -149
  90. data/lib/squib/constants.rb +17 -17
  91. data/lib/squib/deck.rb +138 -138
  92. data/lib/squib/dsl/background.rb +35 -35
  93. data/lib/squib/dsl/circle.rb +39 -39
  94. data/lib/squib/dsl/csv.rb +42 -42
  95. data/lib/squib/dsl/curve.rb +35 -35
  96. data/lib/squib/dsl/cut_zone.rb +47 -47
  97. data/lib/squib/dsl/ellipse.rb +37 -37
  98. data/lib/squib/dsl/grid.rb +35 -35
  99. data/lib/squib/dsl/groups.rb +54 -54
  100. data/lib/squib/dsl/hand.rb +42 -42
  101. data/lib/squib/dsl/line.rb +35 -35
  102. data/lib/squib/dsl/png.rb +57 -57
  103. data/lib/squib/dsl/polygon.rb +36 -36
  104. data/lib/squib/dsl/rect.rb +37 -37
  105. data/lib/squib/dsl/safe_zone.rb +48 -48
  106. data/lib/squib/dsl/save.rb +21 -21
  107. data/lib/squib/dsl/save_pdf.rb +50 -50
  108. data/lib/squib/dsl/save_png.rb +48 -48
  109. data/lib/squib/dsl/save_sheet.rb +53 -53
  110. data/lib/squib/dsl/showcase.rb +43 -43
  111. data/lib/squib/dsl/star.rb +37 -37
  112. data/lib/squib/dsl/svg.rb +63 -63
  113. data/lib/squib/dsl/text.rb +54 -54
  114. data/lib/squib/dsl/text_embed.rb +79 -79
  115. data/lib/squib/dsl/triangle.rb +35 -35
  116. data/lib/squib/dsl/units.rb +37 -37
  117. data/lib/squib/dsl/xlsx.rb +40 -40
  118. data/lib/squib/dsl/yaml.rb +40 -40
  119. data/lib/squib/errors_warnings/warn_unexpected_params.rb +14 -14
  120. data/lib/squib/graphics/background.rb +14 -14
  121. data/lib/squib/graphics/cairo_context_wrapper.rb +115 -115
  122. data/lib/squib/graphics/embedding_utils.rb +28 -28
  123. data/lib/squib/graphics/gradient_regex.rb +47 -47
  124. data/lib/squib/graphics/hand.rb +42 -42
  125. data/lib/squib/graphics/image.rb +123 -123
  126. data/lib/squib/graphics/save_doc.rb +77 -77
  127. data/lib/squib/graphics/save_images.rb +91 -91
  128. data/lib/squib/graphics/save_pdf.rb +90 -90
  129. data/lib/squib/graphics/save_sprue.rb +231 -231
  130. data/lib/squib/graphics/shapes.rb +143 -143
  131. data/lib/squib/graphics/showcase.rb +85 -85
  132. data/lib/squib/graphics/text.rb +202 -202
  133. data/lib/squib/import/csv_importer.rb +45 -45
  134. data/lib/squib/import/data_frame.rb +108 -108
  135. data/lib/squib/import/quantity_exploder.rb +17 -17
  136. data/lib/squib/import/xlsx_importer.rb +28 -28
  137. data/lib/squib/import/yaml_importer.rb +30 -30
  138. data/lib/squib/layout_parser.rb +155 -155
  139. data/lib/squib/progress.rb +38 -38
  140. data/lib/squib/sample_helpers.rb +34 -34
  141. data/lib/squib/sprues/crop_line.rb +28 -28
  142. data/lib/squib/sprues/crop_line_dash.rb +35 -35
  143. data/lib/squib/sprues/invalid_sprue_definition.rb +9 -9
  144. data/lib/squib/sprues/sprue.rb +208 -208
  145. data/lib/squib/sprues/sprue_schema.rb +51 -51
  146. data/lib/squib/system_fonts.rb +16 -16
  147. data/lib/squib/version.rb +11 -11
  148. data/lib/squib.rb +35 -35
  149. data/samples/autoscale_font/_autoscale_font.rb +98 -98
  150. data/samples/backend/_backend.rb +26 -26
  151. data/samples/basic.rb +19 -19
  152. data/samples/build_groups/build_groups.rb +36 -36
  153. data/samples/colors/_colors.rb +44 -44
  154. data/samples/colors/_gradients.rb +34 -34
  155. data/samples/colors/_switch_color.rb +33 -33
  156. data/samples/config/config_text_markup.rb +20 -20
  157. data/samples/config/custom_config.rb +18 -18
  158. data/samples/data/_csv.rb +33 -33
  159. data/samples/data/_excel.rb +55 -55
  160. data/samples/data/_yaml.rb +12 -12
  161. data/samples/hello_world.rb +6 -6
  162. data/samples/images/_cairo_access.rb +39 -39
  163. data/samples/images/_images.rb +104 -104
  164. data/samples/images/_more_load_images.rb +102 -102
  165. data/samples/images/_placeholders.rb +48 -48
  166. data/samples/intro/01_hello.rb +8 -8
  167. data/samples/intro/02_options.rb +14 -14
  168. data/samples/intro/03_layout.rb +11 -11
  169. data/samples/intro/04_arrays.rb +15 -15
  170. data/samples/intro/05_excel.rb +14 -14
  171. data/samples/layouts/builtin_layouts.rb +97 -97
  172. data/samples/layouts/layouts.rb +71 -71
  173. data/samples/project/src/characters.rb +8 -8
  174. data/samples/project/src/skills.rb +7 -7
  175. data/samples/proofs/_tgc_proofs.rb +16 -16
  176. data/samples/ranges/_ranges.rb +64 -64
  177. data/samples/saves/_hand.rb +23 -23
  178. data/samples/saves/_portrait_landscape.rb +23 -23
  179. data/samples/saves/_save_filenames.rb +28 -28
  180. data/samples/saves/_save_pdf.rb +29 -29
  181. data/samples/saves/_saves.rb +75 -75
  182. data/samples/saves/_showcase.rb +25 -25
  183. data/samples/shadows/_shadow.rb +71 -71
  184. data/samples/shapes/_draw_shapes.rb +60 -60
  185. data/samples/shapes/_proofs.rb +22 -22
  186. data/samples/sprues/_advanced_sprues.rb +25 -25
  187. data/samples/sprues/_builtin_sprues.rb +22 -22
  188. data/samples/sprues/_fold_sheet.rb +30 -30
  189. data/samples/sprues/_hex_tiles.rb +15 -15
  190. data/samples/sprues/_mints.rb +11 -11
  191. data/samples/sprues/_negative_coords.rb +6 -6
  192. data/samples/sprues/_sprue_example.rb +11 -11
  193. data/samples/system_font_debug/_list_fonts.rb +14 -14
  194. data/samples/text/_embed_text.rb +128 -128
  195. data/samples/text/_text.rb +52 -52
  196. data/samples/text/_text_options.rb +103 -103
  197. data/samples/text/bug134.rb +14 -14
  198. data/samples/units/_cells.rb +50 -50
  199. data/samples/units/_shorthands.rb +48 -48
  200. data/samples/units/_units.rb +39 -39
  201. data/squib.gemspec +58 -58
  202. metadata +21 -21
@@ -1,202 +1,202 @@
1
- require 'pango'
2
- require_relative '../args/typographer'
3
- require_relative 'embedding_utils'
4
-
5
- module Squib
6
- class Card
7
-
8
- # :nodoc:
9
- # @api private
10
- def draw_text_hint(cc, x, y, layout, color)
11
- color = @deck.text_hint if color.to_s.eql? 'off' and not @deck.text_hint.to_s.eql? 'off'
12
- return if color.to_s.eql? 'off' or color.nil?
13
- # when w,h < 0, it was never set. extents[1] are ink extents
14
- w = layout.width / Pango::SCALE
15
- w = layout.extents[1].width / Pango::SCALE if w < 0
16
- h = layout.height / Pango::SCALE
17
- h = layout.extents[1].height / Pango::SCALE if h < 0
18
- cc.rounded_rectangle(0, 0, w, h, 0, 0)
19
- cc.set_source_color(color)
20
- cc.set_line_width(2.0)
21
- cc.stroke
22
- end
23
-
24
- # :nodoc:
25
- # @api private
26
- def compute_valign(layout, valign, embed_h)
27
- return 0 unless layout.height > 0
28
- ink_extents = layout.extents[1]
29
- ink_extents.height = embed_h * Pango::SCALE if ink_extents.height == 0 # JUST embed, bug #134
30
- case valign.to_s.downcase
31
- when 'middle'
32
- Pango.pixels((layout.height - ink_extents.height) / 2)
33
- when 'bottom'
34
- Pango.pixels(layout.height - ink_extents.height)
35
- else
36
- 0
37
- end
38
- end
39
-
40
- def set_font_rendering_opts!(layout)
41
- font_options = Cairo::FontOptions.new
42
- font_options.antialias = Conf::ANTIALIAS_OPTS[(@deck.antialias || 'gray').downcase]
43
- font_options.hint_metrics = 'on' # TODO make this configurable
44
- font_options.hint_style = 'full' # TODO make this configurable
45
- layout.context.font_options = font_options
46
- end
47
-
48
- # :nodoc:
49
- # @api private
50
- def set_wh!(layout, width, height)
51
- layout.width = width * Pango::SCALE unless width.nil? || width == :auto
52
- layout.height = height * Pango::SCALE unless height.nil? || height == :auto
53
- end
54
-
55
- # Compute the width of the carve that we need
56
- def compute_carve(rule, range)
57
- w = rule[:box].width[@index]
58
- if w == :native
59
- file = rule[:file][@index].file
60
- case rule[:type]
61
- when :png
62
- Squib.cache_load_image(file).width.to_f / (range.size - 1)
63
- when :svg
64
- svg_data = rule[:svg_args].data[@index]
65
- unless file.to_s.empty? || svg_data.to_s.empty?
66
- Squib.logger.warn 'Both an SVG file and SVG data were specified'
67
- end
68
- return 0 if (file.nil? or file.eql? '') and svg_data.nil?
69
- svg_data = File.read(file) if svg_data.to_s.empty?
70
- RSVG::Handle.new_from_data(svg_data).width
71
- end
72
- else
73
- rule[:box].width[@index] * Pango::SCALE / (range.size - 1)
74
- end
75
- end
76
-
77
- # # :nodoc:
78
- # # @api private
79
- def embed_images!(embed, str, layout, valign, scale)
80
- return [] unless embed.rules.any?
81
- layout.markup = str
82
- clean_str = layout.text
83
- attrs = layout.attributes || Pango::AttrList.new
84
- EmbeddingUtils.indices(clean_str, embed.rules.keys).each do |key, ranges|
85
- rule = embed.rules[key]
86
- ranges.each do |range|
87
- carve = Pango::Rectangle.new(0, 0, compute_carve(rule, range) * scale, 0)
88
- att = Pango::AttrShape.new(carve, carve, rule)
89
- att.start_index = range.first
90
- att.end_index = range.last
91
- attrs.insert(att)
92
- end
93
- end
94
- layout.attributes = attrs
95
- layout.context.set_shape_renderer do |cxt, att, do_path|
96
- unless do_path # when stroking the text
97
- rule = att.data
98
- x = Pango.pixels(layout.index_to_pos(att.start_index).x) +
99
- rule[:adjust].dx[@index]
100
- y = Pango.pixels(layout.index_to_pos(att.start_index).y) +
101
- rule[:adjust].dy[@index] +
102
- compute_valign(layout, valign, rule[:box].height[@index])
103
- rule[:draw].call(self, x, y, scale)
104
- cxt.reset_clip
105
- [cxt, att, do_path]
106
- end
107
- end
108
- end
109
-
110
- def stroke_outline!(cc, layout, draw)
111
- if draw.stroke_width > 0
112
- cc.pango_layout_path(layout)
113
- cc.fancy_stroke draw
114
- cc.set_source_squibcolor(draw.color)
115
- end
116
- end
117
-
118
- def warn_if_ellipsized(layout)
119
- if @deck.conf.warn_ellipsize? && layout.ellipsized?
120
- Squib.logger.warn { "Ellipsized (too much text). Card \##{@index}. Text: \"#{layout.text}\". \n (To disable this warning, set warn_ellipsize: false in config.yml)" }
121
- end
122
- end
123
-
124
- # @api private
125
- def text(embed, para, box, trans, draw, dpi)
126
- font_desc = Pango::FontDescription.new(para.font)
127
- font_desc.size = para.font_size * Pango::SCALE if para.font_size.is_a? Numeric
128
- orig_font_size = font_desc.size
129
-
130
- # If text autoscaling is enabled, find the largest text size (smaller or equal to the set text size) that fits
131
- if para.ellipsize == :autoscale
132
- para.ellipsize = Pango::EllipsizeMode::END
133
- sizes = sizes = (1 .. font_desc.size).to_a.reverse
134
-
135
- # Dummy render to an area outside the card with decreasing font sizes until text no longer ellipsizes
136
- max_fitting_size = sizes.bsearch{ |sz|
137
- font_desc.size = sz
138
- extents = render_text(embed, para, box, trans, draw, dpi, font_desc, orig_font_size, true)
139
- !extents[:ellipsized]
140
- }
141
-
142
- if max_fitting_size.nil?
143
- max_fitting_size = sizes.last
144
- Squib.logger.warn{"Could not autosize for Card \##{@index} as minimum specified size #{max_fitting_size} still ellipsizes."}
145
- end
146
- font_desc.size = max_fitting_size
147
- end
148
-
149
- render_text(embed, para, box, trans, draw, dpi, font_desc, orig_font_size, false)
150
- end
151
-
152
- # :nodoc:
153
- # @api private
154
- def render_text(embed, para, box, trans, draw, dpi, font_desc, orig_font_size, dummy_draw)
155
- Squib.logger.debug {"Rendering text with: \n#{para} \nat:\n #{box} \ndraw:\n #{draw} \ntransform: #{trans}"}
156
- extents = nil
157
- use_cairo do |cc|
158
- cc.set_source_squibcolor(draw.color)
159
- cc.translate(box.x, box.y)
160
- cc.translate(-10000, -10000) if dummy_draw
161
- cc.rotate(trans.angle)
162
- cc.move_to(0, 0)
163
-
164
- layout = cc.create_pango_layout
165
- layout.font_description = font_desc
166
- layout.text = para.str.to_s
167
- layout.context.resolution = dpi
168
- if para.markup
169
- para.str = @deck.typographer.process(layout.text)
170
- layout.markup = para.str.to_s
171
- end
172
-
173
- set_font_rendering_opts!(layout)
174
- set_wh!(layout, box.width, box.height)
175
- layout.wrap = para.wrap
176
- layout.ellipsize = para.ellipsize
177
- layout.alignment = para.align
178
-
179
- layout.justify = para.justify unless para.justify.nil?
180
- layout.spacing = para.spacing unless para.spacing.nil?
181
-
182
- embed_images!(embed, para.str, layout, para.valign, font_desc.size / orig_font_size.to_f)
183
-
184
- vertical_start = compute_valign(layout, para.valign, 0)
185
- cc.move_to(0, vertical_start)
186
-
187
- stroke_outline!(cc, layout, draw) if draw.stroke_strategy == :stroke_first
188
- cc.move_to(0, vertical_start)
189
-
190
- cc.show_pango_layout(layout)
191
- stroke_outline!(cc, layout, draw) if draw.stroke_strategy == :fill_first
192
- draw_text_hint(cc, box.x, box.y, layout, para.hint)
193
- extents = { width: layout.extents[1].width / Pango::SCALE,
194
- height: layout.extents[1].height / Pango::SCALE,
195
- ellipsized: layout.ellipsized?}
196
- warn_if_ellipsized layout unless dummy_draw
197
- end
198
- return extents
199
- end
200
-
201
- end
202
- end
1
+ require 'pango'
2
+ require_relative '../args/typographer'
3
+ require_relative 'embedding_utils'
4
+
5
+ module Squib
6
+ class Card
7
+
8
+ # :nodoc:
9
+ # @api private
10
+ def draw_text_hint(cc, x, y, layout, color)
11
+ color = @deck.text_hint if color.to_s.eql? 'off' and not @deck.text_hint.to_s.eql? 'off'
12
+ return if color.to_s.eql? 'off' or color.nil?
13
+ # when w,h < 0, it was never set. extents[1] are ink extents
14
+ w = layout.width / Pango::SCALE
15
+ w = layout.extents[1].width / Pango::SCALE if w < 0
16
+ h = layout.height / Pango::SCALE
17
+ h = layout.extents[1].height / Pango::SCALE if h < 0
18
+ cc.rounded_rectangle(0, 0, w, h, 0, 0)
19
+ cc.set_source_color(color)
20
+ cc.set_line_width(2.0)
21
+ cc.stroke
22
+ end
23
+
24
+ # :nodoc:
25
+ # @api private
26
+ def compute_valign(layout, valign, embed_h)
27
+ return 0 unless layout.height > 0
28
+ ink_extents = layout.extents[1]
29
+ ink_extents.height = embed_h * Pango::SCALE if ink_extents.height == 0 # JUST embed, bug #134
30
+ case valign.to_s.downcase
31
+ when 'middle'
32
+ Pango.pixels((layout.height - ink_extents.height) / 2)
33
+ when 'bottom'
34
+ Pango.pixels(layout.height - ink_extents.height)
35
+ else
36
+ 0
37
+ end
38
+ end
39
+
40
+ def set_font_rendering_opts!(layout)
41
+ font_options = Cairo::FontOptions.new
42
+ font_options.antialias = Conf::ANTIALIAS_OPTS[(@deck.antialias || 'gray').downcase]
43
+ font_options.hint_metrics = 'on' # TODO make this configurable
44
+ font_options.hint_style = 'full' # TODO make this configurable
45
+ layout.context.font_options = font_options
46
+ end
47
+
48
+ # :nodoc:
49
+ # @api private
50
+ def set_wh!(layout, width, height)
51
+ layout.width = width * Pango::SCALE unless width.nil? || width == :auto
52
+ layout.height = height * Pango::SCALE unless height.nil? || height == :auto
53
+ end
54
+
55
+ # Compute the width of the carve that we need
56
+ def compute_carve(rule, range)
57
+ w = rule[:box].width[@index]
58
+ if w == :native
59
+ file = rule[:file][@index].file
60
+ case rule[:type]
61
+ when :png
62
+ Squib.cache_load_image(file).width.to_f / (range.size - 1)
63
+ when :svg
64
+ svg_data = rule[:svg_args].data[@index]
65
+ unless file.to_s.empty? || svg_data.to_s.empty?
66
+ Squib.logger.warn 'Both an SVG file and SVG data were specified'
67
+ end
68
+ return 0 if (file.nil? or file.eql? '') and svg_data.nil?
69
+ svg_data = File.read(file) if svg_data.to_s.empty?
70
+ RSVG::Handle.new_from_data(svg_data).width
71
+ end
72
+ else
73
+ rule[:box].width[@index] * Pango::SCALE / (range.size - 1)
74
+ end
75
+ end
76
+
77
+ # # :nodoc:
78
+ # # @api private
79
+ def embed_images!(embed, str, layout, valign, scale)
80
+ return [] unless embed.rules.any?
81
+ layout.markup = str
82
+ clean_str = layout.text
83
+ attrs = layout.attributes || Pango::AttrList.new
84
+ EmbeddingUtils.indices(clean_str, embed.rules.keys).each do |key, ranges|
85
+ rule = embed.rules[key]
86
+ ranges.each do |range|
87
+ carve = Pango::Rectangle.new(0, 0, compute_carve(rule, range) * scale, 0)
88
+ att = Pango::AttrShape.new(carve, carve, rule)
89
+ att.start_index = range.first
90
+ att.end_index = range.last
91
+ attrs.insert(att)
92
+ end
93
+ end
94
+ layout.attributes = attrs
95
+ layout.context.set_shape_renderer do |cxt, att, do_path|
96
+ unless do_path # when stroking the text
97
+ rule = att.data
98
+ x = Pango.pixels(layout.index_to_pos(att.start_index).x) +
99
+ rule[:adjust].dx[@index]
100
+ y = Pango.pixels(layout.index_to_pos(att.start_index).y) +
101
+ rule[:adjust].dy[@index] +
102
+ compute_valign(layout, valign, rule[:box].height[@index])
103
+ rule[:draw].call(self, x, y, scale)
104
+ cxt.reset_clip
105
+ [cxt, att, do_path]
106
+ end
107
+ end
108
+ end
109
+
110
+ def stroke_outline!(cc, layout, draw)
111
+ if draw.stroke_width > 0
112
+ cc.pango_layout_path(layout)
113
+ cc.fancy_stroke draw
114
+ cc.set_source_squibcolor(draw.color)
115
+ end
116
+ end
117
+
118
+ def warn_if_ellipsized(layout)
119
+ if @deck.conf.warn_ellipsize? && layout.ellipsized?
120
+ Squib.logger.warn { "Ellipsized (too much text). Card \##{@index}. Text: \"#{layout.text}\". \n (To disable this warning, set warn_ellipsize: false in config.yml)" }
121
+ end
122
+ end
123
+
124
+ # @api private
125
+ def text(embed, para, box, trans, draw, dpi)
126
+ font_desc = Pango::FontDescription.new(para.font)
127
+ font_desc.size = para.font_size * Pango::SCALE if para.font_size.is_a? Numeric
128
+ orig_font_size = font_desc.size
129
+
130
+ # If text autoscaling is enabled, find the largest text size (smaller or equal to the set text size) that fits
131
+ if para.ellipsize == :autoscale
132
+ para.ellipsize = Pango::EllipsizeMode::END
133
+ sizes = sizes = (1 .. font_desc.size).to_a.reverse
134
+
135
+ # Dummy render to an area outside the card with decreasing font sizes until text no longer ellipsizes
136
+ max_fitting_size = sizes.bsearch{ |sz|
137
+ font_desc.size = sz
138
+ extents = render_text(embed, para, box, trans, draw, dpi, font_desc, orig_font_size, true)
139
+ !extents[:ellipsized]
140
+ }
141
+
142
+ if max_fitting_size.nil?
143
+ max_fitting_size = sizes.last
144
+ Squib.logger.warn{"Could not autosize for Card \##{@index} as minimum specified size #{max_fitting_size} still ellipsizes."}
145
+ end
146
+ font_desc.size = max_fitting_size
147
+ end
148
+
149
+ render_text(embed, para, box, trans, draw, dpi, font_desc, orig_font_size, false)
150
+ end
151
+
152
+ # :nodoc:
153
+ # @api private
154
+ def render_text(embed, para, box, trans, draw, dpi, font_desc, orig_font_size, dummy_draw)
155
+ Squib.logger.debug {"Rendering text with: \n#{para} \nat:\n #{box} \ndraw:\n #{draw} \ntransform: #{trans}"}
156
+ extents = nil
157
+ use_cairo do |cc|
158
+ cc.set_source_squibcolor(draw.color)
159
+ cc.translate(box.x, box.y)
160
+ cc.translate(-10000, -10000) if dummy_draw
161
+ cc.rotate(trans.angle)
162
+ cc.move_to(0, 0)
163
+
164
+ layout = cc.create_pango_layout
165
+ layout.font_description = font_desc
166
+ layout.text = para.str.to_s
167
+ layout.context.resolution = dpi
168
+ if para.markup
169
+ para.str = @deck.typographer.process(layout.text)
170
+ layout.markup = para.str.to_s
171
+ end
172
+
173
+ set_font_rendering_opts!(layout)
174
+ set_wh!(layout, box.width, box.height)
175
+ layout.wrap = para.wrap
176
+ layout.ellipsize = para.ellipsize
177
+ layout.alignment = para.align
178
+
179
+ layout.justify = para.justify unless para.justify.nil?
180
+ layout.spacing = para.spacing unless para.spacing.nil?
181
+
182
+ embed_images!(embed, para.str, layout, para.valign, font_desc.size / orig_font_size.to_f)
183
+
184
+ vertical_start = compute_valign(layout, para.valign, 0)
185
+ cc.move_to(0, vertical_start)
186
+
187
+ stroke_outline!(cc, layout, draw) if draw.stroke_strategy == :stroke_first
188
+ cc.move_to(0, vertical_start)
189
+
190
+ cc.show_pango_layout(layout)
191
+ stroke_outline!(cc, layout, draw) if draw.stroke_strategy == :fill_first
192
+ draw_text_hint(cc, box.x, box.y, layout, para.hint)
193
+ extents = { width: layout.extents[1].width / Pango::SCALE,
194
+ height: layout.extents[1].height / Pango::SCALE,
195
+ ellipsized: layout.ellipsized?}
196
+ warn_if_ellipsized layout unless dummy_draw
197
+ end
198
+ return extents
199
+ end
200
+
201
+ end
202
+ end
@@ -1,45 +1,45 @@
1
- require 'csv'
2
- require_relative 'quantity_exploder'
3
-
4
- module Squib::Import
5
- class CsvImporter
6
- include Squib::Import::QuantityExploder
7
- def import_to_dataframe(import, csv_opts, &block)
8
- data = import.data.nil? ? File.read(import.file) : import.data
9
- table = CSV.parse(data, **csv_opts.to_hash)
10
- check_duplicate_csv_headers(table)
11
- hash = Squib::DataFrame.new
12
- table.headers.each do |header|
13
- new_header = header.to_s
14
- new_header = new_header.strip if import.strip?
15
- hash[new_header] ||= table[header]
16
- end
17
- if import.strip?
18
- new_hash = Squib::DataFrame.new
19
- hash.each do |header, col|
20
- new_hash[header] = col.map do |str|
21
- str = str.strip if str.respond_to?(:strip)
22
- str
23
- end
24
- end
25
- hash = new_hash
26
- end
27
- unless block.nil?
28
- hash.each do |header, col|
29
- col.map! do |val|
30
- yield(header, val)
31
- end
32
- end
33
- end
34
- return explode_quantities(hash, import.explode)
35
- end
36
-
37
- def check_duplicate_csv_headers(table)
38
- if table.headers.size != table.headers.uniq.size
39
- dups = table.headers.select{|e| table.headers.count(e) > 1 }
40
- Squib.logger.warn "CSV duplicated the following column keys: #{dups.join(',')}"
41
- end
42
- end
43
- end
44
- end
45
-
1
+ require 'csv'
2
+ require_relative 'quantity_exploder'
3
+
4
+ module Squib::Import
5
+ class CsvImporter
6
+ include Squib::Import::QuantityExploder
7
+ def import_to_dataframe(import, csv_opts, &block)
8
+ data = import.data.nil? ? File.read(import.file) : import.data
9
+ table = CSV.parse(data, **csv_opts.to_hash)
10
+ check_duplicate_csv_headers(table)
11
+ hash = Squib::DataFrame.new
12
+ table.headers.each do |header|
13
+ new_header = header.to_s
14
+ new_header = new_header.strip if import.strip?
15
+ hash[new_header] ||= table[header]
16
+ end
17
+ if import.strip?
18
+ new_hash = Squib::DataFrame.new
19
+ hash.each do |header, col|
20
+ new_hash[header] = col.map do |str|
21
+ str = str.strip if str.respond_to?(:strip)
22
+ str
23
+ end
24
+ end
25
+ hash = new_hash
26
+ end
27
+ unless block.nil?
28
+ hash.each do |header, col|
29
+ col.map! do |val|
30
+ yield(header, val)
31
+ end
32
+ end
33
+ end
34
+ return explode_quantities(hash, import.explode)
35
+ end
36
+
37
+ def check_duplicate_csv_headers(table)
38
+ if table.headers.size != table.headers.uniq.size
39
+ dups = table.headers.select{|e| table.headers.count(e) > 1 }
40
+ Squib.logger.warn "CSV duplicated the following column keys: #{dups.join(',')}"
41
+ end
42
+ end
43
+ end
44
+ end
45
+