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,277 +1,277 @@
1
- require 'fileutils'
2
- require 'pathname'
3
- require 'highline'
4
- require 'bigdecimal'
5
- require 'yaml'
6
- require_relative 'data/template_option'
7
-
8
- module Squib
9
- # Squib's command-line option
10
- module Commands
11
- # Generate a template definition file that can be used for
12
- # +save_templated_sheet+
13
- #
14
- # @api public
15
- class MakeSprue
16
- # :nodoc:
17
- # @api private
18
- def process(args, input = $stdin, output = $stdout)
19
- # Get definitions from the user
20
- @option = prompt(input, output)
21
-
22
- @printable_edge_right = (
23
- @option.sheet_width - @option.sheet_margin.right)
24
- @printable_edge_bottom = (
25
- @option.sheet_height - @option.sheet_margin.bottom)
26
- @card_iter_x = @option.card_width + @option.card_gap.horizontal
27
- @card_iter_y = @option.card_height + @option.card_gap.vertical
28
-
29
- # Recalculate the sheet margin if the sheet alignment is in the center
30
- if @option.sheet_align == :center
31
- @option.sheet_margin = recalculate_center_align_sheet
32
- end
33
-
34
- # We would now have to output the file
35
- YAML.dump generate_template, File.new(@option.output_file, 'w')
36
- end
37
-
38
- private
39
-
40
- # Accept user input that defines the template.
41
- def prompt(input, output)
42
- option = TemplateOption.new
43
- cli = HighLine.new(input, output)
44
-
45
- option.unit = cli.choose do |menu|
46
- menu.prompt = 'What measure unit should we use? '
47
- menu.choice(:in)
48
- menu.choice(:cm)
49
- menu.choice(:mm)
50
- end
51
-
52
- cli.choose do |menu|
53
- menu.prompt = 'What paper size you are using? '
54
- menu.choice('A4, portrait') do
55
- option.sheet_width = convert_measurement_value(
56
- 210, :mm, option.unit
57
- )
58
- option.sheet_height = convert_measurement_value(
59
- 297, :mm, option.unit
60
- )
61
- end
62
- menu.choice('A4, landscape') do
63
- option.sheet_width = convert_measurement_value(
64
- 297, :mm, option.unit
65
- )
66
- option.sheet_height = convert_measurement_value(
67
- 210, :mm, option.unit
68
- )
69
- end
70
- menu.choice('US letter, portrait') do
71
- option.sheet_width = convert_measurement_value(
72
- 8.5, :in, option.unit
73
- )
74
- option.sheet_height = convert_measurement_value(
75
- 11, :in, option.unit
76
- )
77
- end
78
- menu.choice('US letter, landscape') do
79
- option.sheet_width = convert_measurement_value(
80
- 11, :in, option.unit
81
- )
82
- option.sheet_height = convert_measurement_value(
83
- 8.5, :in, option.unit
84
- )
85
- end
86
- menu.choice('Custom size') do
87
- option.sheet_width = cli.ask(
88
- "Custom paper width? (#{option.unit}) ", Float
89
- )
90
- option.sheet_height = cli.ask(
91
- "Custom paper height? (#{option.unit}) ", Float
92
- )
93
- end
94
- end
95
-
96
- option.sheet_margin = cli.ask(
97
- "Sheet margins? (#{option.unit}) "
98
- ) do |q|
99
- q.validate = /^((\d+\.\d+|\d+) ){0,3}(\d+\.\d+|\d+)/
100
- end
101
- option.sheet_align = cli.choose do |menu|
102
- menu.prompt = 'How to align cards on sheet? [left] '
103
- menu.choice(:left)
104
- menu.choice(:right)
105
- menu.choice(:center)
106
- menu.default = :left
107
- end
108
-
109
- option.card_width = cli.ask(
110
- "Card width? (#{option.unit}) ", Float
111
- ) { |q| q.above = 0 }
112
- option.card_height = cli.ask(
113
- "Card height? (#{option.unit}) ", Float
114
- ) { |q| q.above = 0 }
115
- option.card_gap = cli.ask(
116
- "Gap between cards? (#{option.unit}) "
117
- ) { |q| q.validate = /^((\d+\.\d+|\d+))(\s+(\d+\.\d+|\d+))?/ }
118
-
119
- option.card_ordering = cli.choose do |menu|
120
- menu.prompt = 'How to layout your cards? [rows]'
121
- menu.choice(:rows, text: 'In rows')
122
- menu.choice(:columns, text: 'In columns')
123
- menu.default = :rows
124
- end
125
-
126
- option.crop_lines = cli.choose do |menu|
127
- menu.prompt = 'Generate crop lines? [true]'
128
- menu.choice(:true)
129
- menu.choice(:false)
130
- menu.default = :true
131
- end
132
-
133
- option.output_file = cli.ask('Output to? ') do |q|
134
- q.validate = lambda do |path_str|
135
- path = Pathname.new path_str
136
- if path.exist?
137
- path.writable? && !path.directory?
138
- else
139
- path.dirname.writable?
140
- end
141
- end
142
-
143
- q.responses[:not_valid] = (
144
- 'The filename specified is not a writable file or is a directory.'
145
- )
146
- q.default = 'template.yml'
147
- end
148
-
149
- option
150
- end
151
-
152
- def convert_measurement_value(val, from_unit, to_unit)
153
- return val if from_unit == to_unit
154
-
155
- if from_unit == :in
156
- val_mm = val * 25.4
157
- elsif from_unit == :cm
158
- val_mm = val * 10.0
159
- else
160
- val_mm = val
161
- end
162
-
163
- if to_unit == :in
164
- val_mm / 25.4
165
- elsif to_unit == :cm
166
- val_mm / 10.0
167
- else
168
- val_mm
169
- end
170
- end
171
-
172
- def generate_template
173
- x = @option.sheet_margin.left
174
- y = @option.sheet_margin.top
175
- cards = []
176
- horizontal_crop_lines = Set.new
177
- vertical_crop_lines = Set.new
178
-
179
- while (
180
- x + @card_iter_x < @printable_edge_right &&
181
- y + @card_iter_y < @printable_edge_bottom)
182
- xpos = x + @option.card_gap.horizontal
183
- ypos = y + @option.card_gap.vertical
184
- cards.push(
185
- 'x' => "#{xpos}#{@option.unit}",
186
- 'y' => "#{ypos}#{@option.unit}"
187
- )
188
-
189
- # Append the crop lines
190
- vertical_crop_lines.add xpos
191
- vertical_crop_lines.add xpos + @option.card_width
192
- horizontal_crop_lines.add ypos
193
- horizontal_crop_lines.add ypos + @option.card_height
194
-
195
- # Calculate the next iterator
196
- if @option.card_ordering == :rows
197
- x, y = next_card_pos_row(x, y)
198
- elsif @option.card_ordering == :columns
199
- x, y = next_card_pos_col(x, y)
200
- else
201
- raise RunTimeException, 'Invalid card ordering value received'
202
- end
203
- end
204
-
205
- output = {
206
- 'sheet_width' => "#{@option.sheet_width}#{@option.unit}",
207
- 'sheet_height' => "#{@option.sheet_height}#{@option.unit}",
208
- 'card_width' => "#{@option.card_width}#{@option.unit}",
209
- 'card_height' => "#{@option.card_height}#{@option.unit}",
210
- 'cards' => cards
211
- }
212
-
213
- if @option.crop_lines == :true
214
- lines = []
215
- vertical_crop_lines.each do |val|
216
- lines.push(
217
- 'type' => :vertical, 'position' => "#{val}#{@option.unit}"
218
- )
219
- end
220
- horizontal_crop_lines.each do |val|
221
- lines.push(
222
- 'type' => :horizontal, 'position' => "#{val}#{@option.unit}"
223
- )
224
- end
225
- output['crop_line'] = { 'lines' => lines }
226
- end
227
-
228
- # Return the output data
229
- output
230
- end
231
-
232
- def recalculate_center_align_sheet
233
- # We will still respect the user specified margins
234
- printable_width = (
235
- @option.sheet_width - @option.sheet_margin.left -
236
- @option.sheet_margin.right)
237
- num_of_cols, remainder = printable_width.divmod(@card_iter_x)
238
- if (
239
- @option.card_gap.horizontal > 0 &&
240
- remainder < @option.card_gap.horizontal)
241
- num_of_cols -= 1
242
- end
243
-
244
- new_hor_margin = (
245
- (@option.sheet_width - num_of_cols * @card_iter_x -
246
- @option.card_gap.horizontal) / 2)
247
- Margin.new [
248
- @option.sheet_margin.top,
249
- new_hor_margin,
250
- @option.sheet_margin.bottom
251
- ]
252
- end
253
-
254
- def next_card_pos_row(x, y)
255
- x += @card_iter_x
256
-
257
- if (x + @card_iter_x) > @printable_edge_right
258
- x = @option.sheet_margin.left
259
- y += @card_iter_y
260
- end
261
-
262
- [x, y]
263
- end
264
-
265
- def next_card_pos_col(x, y)
266
- y += @card_iter_y
267
-
268
- if (y + @card_iter_y) > @printable_edge_bottom
269
- x += @card_iter_x
270
- y = @option.sheet_margin.top
271
- end
272
-
273
- [x, y]
274
- end
275
- end
276
- end
277
- end
1
+ require 'fileutils'
2
+ require 'pathname'
3
+ require 'highline'
4
+ require 'bigdecimal'
5
+ require 'yaml'
6
+ require_relative 'data/template_option'
7
+
8
+ module Squib
9
+ # Squib's command-line option
10
+ module Commands
11
+ # Generate a template definition file that can be used for
12
+ # +save_templated_sheet+
13
+ #
14
+ # @api public
15
+ class MakeSprue
16
+ # :nodoc:
17
+ # @api private
18
+ def process(args, input = $stdin, output = $stdout)
19
+ # Get definitions from the user
20
+ @option = prompt(input, output)
21
+
22
+ @printable_edge_right = (
23
+ @option.sheet_width - @option.sheet_margin.right)
24
+ @printable_edge_bottom = (
25
+ @option.sheet_height - @option.sheet_margin.bottom)
26
+ @card_iter_x = @option.card_width + @option.card_gap.horizontal
27
+ @card_iter_y = @option.card_height + @option.card_gap.vertical
28
+
29
+ # Recalculate the sheet margin if the sheet alignment is in the center
30
+ if @option.sheet_align == :center
31
+ @option.sheet_margin = recalculate_center_align_sheet
32
+ end
33
+
34
+ # We would now have to output the file
35
+ YAML.dump generate_template, File.new(@option.output_file, 'w')
36
+ end
37
+
38
+ private
39
+
40
+ # Accept user input that defines the template.
41
+ def prompt(input, output)
42
+ option = TemplateOption.new
43
+ cli = HighLine.new(input, output)
44
+
45
+ option.unit = cli.choose do |menu|
46
+ menu.prompt = 'What measure unit should we use? '
47
+ menu.choice(:in)
48
+ menu.choice(:cm)
49
+ menu.choice(:mm)
50
+ end
51
+
52
+ cli.choose do |menu|
53
+ menu.prompt = 'What paper size you are using? '
54
+ menu.choice('A4, portrait') do
55
+ option.sheet_width = convert_measurement_value(
56
+ 210, :mm, option.unit
57
+ )
58
+ option.sheet_height = convert_measurement_value(
59
+ 297, :mm, option.unit
60
+ )
61
+ end
62
+ menu.choice('A4, landscape') do
63
+ option.sheet_width = convert_measurement_value(
64
+ 297, :mm, option.unit
65
+ )
66
+ option.sheet_height = convert_measurement_value(
67
+ 210, :mm, option.unit
68
+ )
69
+ end
70
+ menu.choice('US letter, portrait') do
71
+ option.sheet_width = convert_measurement_value(
72
+ 8.5, :in, option.unit
73
+ )
74
+ option.sheet_height = convert_measurement_value(
75
+ 11, :in, option.unit
76
+ )
77
+ end
78
+ menu.choice('US letter, landscape') do
79
+ option.sheet_width = convert_measurement_value(
80
+ 11, :in, option.unit
81
+ )
82
+ option.sheet_height = convert_measurement_value(
83
+ 8.5, :in, option.unit
84
+ )
85
+ end
86
+ menu.choice('Custom size') do
87
+ option.sheet_width = cli.ask(
88
+ "Custom paper width? (#{option.unit}) ", Float
89
+ )
90
+ option.sheet_height = cli.ask(
91
+ "Custom paper height? (#{option.unit}) ", Float
92
+ )
93
+ end
94
+ end
95
+
96
+ option.sheet_margin = cli.ask(
97
+ "Sheet margins? (#{option.unit}) "
98
+ ) do |q|
99
+ q.validate = /^((\d+\.\d+|\d+) ){0,3}(\d+\.\d+|\d+)/
100
+ end
101
+ option.sheet_align = cli.choose do |menu|
102
+ menu.prompt = 'How to align cards on sheet? [left] '
103
+ menu.choice(:left)
104
+ menu.choice(:right)
105
+ menu.choice(:center)
106
+ menu.default = :left
107
+ end
108
+
109
+ option.card_width = cli.ask(
110
+ "Card width? (#{option.unit}) ", Float
111
+ ) { |q| q.above = 0 }
112
+ option.card_height = cli.ask(
113
+ "Card height? (#{option.unit}) ", Float
114
+ ) { |q| q.above = 0 }
115
+ option.card_gap = cli.ask(
116
+ "Gap between cards? (#{option.unit}) "
117
+ ) { |q| q.validate = /^((\d+\.\d+|\d+))(\s+(\d+\.\d+|\d+))?/ }
118
+
119
+ option.card_ordering = cli.choose do |menu|
120
+ menu.prompt = 'How to layout your cards? [rows]'
121
+ menu.choice(:rows, text: 'In rows')
122
+ menu.choice(:columns, text: 'In columns')
123
+ menu.default = :rows
124
+ end
125
+
126
+ option.crop_lines = cli.choose do |menu|
127
+ menu.prompt = 'Generate crop lines? [true]'
128
+ menu.choice(:true)
129
+ menu.choice(:false)
130
+ menu.default = :true
131
+ end
132
+
133
+ option.output_file = cli.ask('Output to? ') do |q|
134
+ q.validate = lambda do |path_str|
135
+ path = Pathname.new path_str
136
+ if path.exist?
137
+ path.writable? && !path.directory?
138
+ else
139
+ path.dirname.writable?
140
+ end
141
+ end
142
+
143
+ q.responses[:not_valid] = (
144
+ 'The filename specified is not a writable file or is a directory.'
145
+ )
146
+ q.default = 'template.yml'
147
+ end
148
+
149
+ option
150
+ end
151
+
152
+ def convert_measurement_value(val, from_unit, to_unit)
153
+ return val if from_unit == to_unit
154
+
155
+ if from_unit == :in
156
+ val_mm = val * 25.4
157
+ elsif from_unit == :cm
158
+ val_mm = val * 10.0
159
+ else
160
+ val_mm = val
161
+ end
162
+
163
+ if to_unit == :in
164
+ val_mm / 25.4
165
+ elsif to_unit == :cm
166
+ val_mm / 10.0
167
+ else
168
+ val_mm
169
+ end
170
+ end
171
+
172
+ def generate_template
173
+ x = @option.sheet_margin.left
174
+ y = @option.sheet_margin.top
175
+ cards = []
176
+ horizontal_crop_lines = Set.new
177
+ vertical_crop_lines = Set.new
178
+
179
+ while (
180
+ x + @card_iter_x < @printable_edge_right &&
181
+ y + @card_iter_y < @printable_edge_bottom)
182
+ xpos = x + @option.card_gap.horizontal
183
+ ypos = y + @option.card_gap.vertical
184
+ cards.push(
185
+ 'x' => "#{xpos}#{@option.unit}",
186
+ 'y' => "#{ypos}#{@option.unit}"
187
+ )
188
+
189
+ # Append the crop lines
190
+ vertical_crop_lines.add xpos
191
+ vertical_crop_lines.add xpos + @option.card_width
192
+ horizontal_crop_lines.add ypos
193
+ horizontal_crop_lines.add ypos + @option.card_height
194
+
195
+ # Calculate the next iterator
196
+ if @option.card_ordering == :rows
197
+ x, y = next_card_pos_row(x, y)
198
+ elsif @option.card_ordering == :columns
199
+ x, y = next_card_pos_col(x, y)
200
+ else
201
+ raise RunTimeException, 'Invalid card ordering value received'
202
+ end
203
+ end
204
+
205
+ output = {
206
+ 'sheet_width' => "#{@option.sheet_width}#{@option.unit}",
207
+ 'sheet_height' => "#{@option.sheet_height}#{@option.unit}",
208
+ 'card_width' => "#{@option.card_width}#{@option.unit}",
209
+ 'card_height' => "#{@option.card_height}#{@option.unit}",
210
+ 'cards' => cards
211
+ }
212
+
213
+ if @option.crop_lines == :true
214
+ lines = []
215
+ vertical_crop_lines.each do |val|
216
+ lines.push(
217
+ 'type' => :vertical, 'position' => "#{val}#{@option.unit}"
218
+ )
219
+ end
220
+ horizontal_crop_lines.each do |val|
221
+ lines.push(
222
+ 'type' => :horizontal, 'position' => "#{val}#{@option.unit}"
223
+ )
224
+ end
225
+ output['crop_line'] = { 'lines' => lines }
226
+ end
227
+
228
+ # Return the output data
229
+ output
230
+ end
231
+
232
+ def recalculate_center_align_sheet
233
+ # We will still respect the user specified margins
234
+ printable_width = (
235
+ @option.sheet_width - @option.sheet_margin.left -
236
+ @option.sheet_margin.right)
237
+ num_of_cols, remainder = printable_width.divmod(@card_iter_x)
238
+ if (
239
+ @option.card_gap.horizontal > 0 &&
240
+ remainder < @option.card_gap.horizontal)
241
+ num_of_cols -= 1
242
+ end
243
+
244
+ new_hor_margin = (
245
+ (@option.sheet_width - num_of_cols * @card_iter_x -
246
+ @option.card_gap.horizontal) / 2)
247
+ Margin.new [
248
+ @option.sheet_margin.top,
249
+ new_hor_margin,
250
+ @option.sheet_margin.bottom
251
+ ]
252
+ end
253
+
254
+ def next_card_pos_row(x, y)
255
+ x += @card_iter_x
256
+
257
+ if (x + @card_iter_x) > @printable_edge_right
258
+ x = @option.sheet_margin.left
259
+ y += @card_iter_y
260
+ end
261
+
262
+ [x, y]
263
+ end
264
+
265
+ def next_card_pos_col(x, y)
266
+ y += @card_iter_y
267
+
268
+ if (y + @card_iter_y) > @printable_edge_bottom
269
+ x += @card_iter_x
270
+ y = @option.sheet_margin.top
271
+ end
272
+
273
+ [x, y]
274
+ end
275
+ end
276
+ end
277
+ end