From 4003e00e2a5c78bb0ba98965dadee98200456a13 Mon Sep 17 00:00:00 2001 From: Andy Meneely Date: Mon, 5 Oct 2020 11:27:49 -0400 Subject: [PATCH] refactoring to get middle/center, possibly more --- docs/args/wh.rst | 2 +- docs/args/xywhbox.rst | 16 ++++++++++++ lib/squib/args/box.rb | 23 ++++++++++++------ lib/squib/args/unit_conversion.rb | 2 ++ lib/squib/args/xywh_shorthands.rb | 35 +++++++++++++++++++++++++++ lib/squib/dsl/units.rb | 5 ++++ lib/squib/layout_parser.rb | 12 +++++++++ samples/shorthands/_shorthands.rb | 30 +++++++++++++++++++++++ samples/shorthands/shorthands.yml | 7 ++++++ samples/units/_units.rb | 5 ++++ samples/units/using_units.yml | 7 ++++++ spec/args/box_spec.rb | 13 ++++++++++ spec/args/unit_conversion_spec.rb | 4 +++ spec/data/samples/units/_units.rb.txt | 22 +++++++++++++++++ 14 files changed, 175 insertions(+), 8 deletions(-) create mode 100644 docs/args/xywhbox.rst create mode 100644 lib/squib/args/xywh_shorthands.rb create mode 100644 samples/shorthands/_shorthands.rb create mode 100644 samples/shorthands/shorthands.yml diff --git a/docs/args/wh.rst b/docs/args/wh.rst index 65d3976..c35e1ba 100644 --- a/docs/args/wh.rst +++ b/docs/args/wh.rst @@ -9,4 +9,4 @@ width height default: ``:deck`` (the height of the deck) - the height of the box. Supports :doc:`/units`. + the height of the box. Supports :doc:`/units`. Also can be ``:center`` or ``:middle`` for half the height of the deck. Supports :doc:`/units`. diff --git a/docs/args/xywhbox.rst b/docs/args/xywhbox.rst new file mode 100644 index 0000000..787b7a9 --- /dev/null +++ b/docs/args/xywhbox.rst @@ -0,0 +1,16 @@ +.. :orphan: + +x + default: ``0`` + + the x-coordinate to place, relative to the upper-left corner of the card and moving right as it increases. Supports :doc:`/units`. + + Also can be ``:center`` or ``:middle`` for half the width of the deck. + + +y + default: ``0`` + + the y-coordinate to place, relative to the upper-left corner of the card and moving downward as it increases. Supports :doc:`/units`. + + Also can be ``:center`` or ``:middle`` for half the height of the deck. diff --git a/lib/squib/args/box.rb b/lib/squib/args/box.rb index 95e216f..1de15c3 100644 --- a/lib/squib/args/box.rb +++ b/lib/squib/args/box.rb @@ -1,17 +1,20 @@ require_relative 'arg_loader' +require_relative 'xywh_shorthands' module Squib::Args module_function def extract_box(opts, deck, dsl_method_defaults = {}) - Box.new(deck, dsl_method_defaults).extract!(opts, deck) + Box.new(deck, dsl_method_defaults, opts).extract!(opts, deck) end class Box include ArgLoader + include XYWHShorthands - def initialize(deck = nil, dsl_method_defaults = {}) + def initialize(deck = nil, dsl_method_defaults = {}, opts = {}) @deck = deck @dsl_method_defaults = dsl_method_defaults + @opts = opts # e.g. value of x can depend on the value of width end def self.parameters @@ -29,16 +32,22 @@ module Squib::Args parameters.keys # all of them end + def validate_x(arg, i) + apply_x_shorthands(arg, @deck.width) + end + + def validate_y(arg,_i) + apply_y_shorthands(arg, @deck.height) + end + def validate_width(arg, _i) return arg if @deck.nil? - return @deck.width if arg == :deck - arg + apply_x_shorthands(arg, @deck.width) end def validate_height(arg, _i) return arg if @deck.nil? - return @deck.height if arg == :deck - arg + apply_y_shorthands(arg, @deck.height) end def validate_x_radius(arg, i) @@ -49,7 +58,7 @@ module Squib::Args def validate_y_radius(arg, i) return radius[i] unless radius[i].nil? arg - end + end end diff --git a/lib/squib/args/unit_conversion.rb b/lib/squib/args/unit_conversion.rb index 84fe49c..b098ea3 100644 --- a/lib/squib/args/unit_conversion.rb +++ b/lib/squib/args/unit_conversion.rb @@ -13,6 +13,8 @@ module Squib arg.rstrip[0..-2].to_f * dpi * INCHES_IN_CM when /mm$/ # ends with "mm" arg.rstrip[0..-2].to_f * dpi * INCHES_IN_CM / 10.0 + when /deg$/ # ends with "deg" + arg.rstrip[0..-3].to_f * (Math::PI / 180.0) else arg end diff --git a/lib/squib/args/xywh_shorthands.rb b/lib/squib/args/xywh_shorthands.rb new file mode 100644 index 0000000..4d1a8bd --- /dev/null +++ b/lib/squib/args/xywh_shorthands.rb @@ -0,0 +1,35 @@ +module Squib + module Args + module XYWHShorthands + + def apply_x_shorthands(arg, deck_width) + arg_s = arg.to_s + case arg_s + when 'middle' + deck_width / 2.0 + when 'center' + deck_width / 2.0 + when 'deck' + deck_width + else + arg + end + end + + def apply_y_shorthands(arg, deck_height) + arg_s = arg.to_s + case arg_s + when 'middle' + deck_height / 2.0 + when 'center' + deck_height / 2.0 + when 'deck' + deck_height + else + arg + end + end + + end + end +end \ No newline at end of file diff --git a/lib/squib/dsl/units.rb b/lib/squib/dsl/units.rb index d665749..51e3dcb 100644 --- a/lib/squib/dsl/units.rb +++ b/lib/squib/dsl/units.rb @@ -23,5 +23,10 @@ module Squib @dpi * Squib::INCHES_IN_CM * n.to_f / 10.0 end + # DSL method. See http://squib.readthedocs.io + def deg(n) + n.to_f * (Math::PI / 180.0) + end + end end diff --git a/lib/squib/layout_parser.rb b/lib/squib/layout_parser.rb index f5ad58b..263c2a6 100644 --- a/lib/squib/layout_parser.rb +++ b/lib/squib/layout_parser.rb @@ -1,9 +1,11 @@ require 'yaml' +require_relative 'args/xywh_shorthands' module Squib # Internal class for handling layouts # @api private class LayoutParser + include Args::XYWHShorthands def initialize(dpi = 300) @dpi = dpi @@ -67,6 +69,9 @@ module Squib end def handle_relative_operators(parent_val, child_val) + unless has_digits?(parent_val) && has_digits?(child_val) + raise "Layout parse error: can't combine #{parent_val} and #{child_val}" + end if child_val.to_s.strip.start_with?('+=') add_parent_child(parent_val, child_val) elsif child_val.to_s.strip.start_with?('-=') @@ -104,6 +109,13 @@ module Squib parent_pixels / child_float end + # For relative operators, it's difficult for us to handle + # some of the shorthands - so let's just freak out if you're trying to use + # relative operators with words, e.g. "middle += 0.5in" + def has_digits?(str) + str.match? /.*\d.*/ + end + # Does this layout entry have an extends field? # i.e. is it a base-case or will it need recursion? # :nodoc: diff --git a/samples/shorthands/_shorthands.rb b/samples/shorthands/_shorthands.rb new file mode 100644 index 0000000..309d292 --- /dev/null +++ b/samples/shorthands/_shorthands.rb @@ -0,0 +1,30 @@ +require_relative '../../lib/squib' + +# Lots of DSL methods have shorthands that are accepted for +# x, y, width, and height parameters. +Squib::Deck.new(width: '0.5in', height: '0.25in') do + background color: :white + + text str: 'xymiddle', font: 'Sans Bold 3', hint: :red, + x: 'middle', y: :middle + + # 'center' also works + rect width: 30, height: 30, + x: :center, y: 'center' + + # Layouts apply this too. + use_layout file: 'shorthands.yml' + rect layout: :example + + # The x and y coordinates can also be "centered", assuming the + + # HOWEVER! Shorthands don't combine in an "extends" situation, + # e.g. this won't work: + # parent: + # x: middle + # child: + # extends: parent + # x: += 0.5in + + save_png prefix: 'shorthand_' +end diff --git a/samples/shorthands/shorthands.yml b/samples/shorthands/shorthands.yml new file mode 100644 index 0000000..e6462f5 --- /dev/null +++ b/samples/shorthands/shorthands.yml @@ -0,0 +1,7 @@ +example: + x: 0.15in + y: middle + stroke_color: blue + width: 30 + height: 30 + diff --git a/samples/units/_units.rb b/samples/units/_units.rb index 4fed555..6a17cec 100644 --- a/samples/units/_units.rb +++ b/samples/units/_units.rb @@ -23,10 +23,15 @@ Squib::Deck.new(width: '1.5in', height: '1.5in') do width: safe_width, height: safe_height, radius: '2 mm ' + # Angles are also automatically converted to radians if you use deg + svg file: '../spanner.svg', + x: 100, y: 100, width: 40, height: 40, angle: '30deg' + # We can also do stuff in layout. Check out the yml file... # (even cleaner in Yaml since we don't need quotes!) use_layout file: 'using_units.yml' text str: 'Hello.', layout: :example + svg file: '../spanner.svg', layout: :angled save prefix: 'units_', format: :png end diff --git a/samples/units/using_units.yml b/samples/units/using_units.yml index 99310a9..d2f0418 100644 --- a/samples/units/using_units.yml +++ b/samples/units/using_units.yml @@ -8,3 +8,10 @@ example: y: -= 5mm width: 1.25in height: 300 # pixels + +angled: + x: 220 + y: 300 + width: 30 + height: 30 + angle: 100deg \ No newline at end of file diff --git a/spec/args/box_spec.rb b/spec/args/box_spec.rb index 9a2428a..f6e80c8 100644 --- a/spec/args/box_spec.rb +++ b/spec/args/box_spec.rb @@ -122,6 +122,19 @@ describe Squib::Args::Box do expect(box).to have_attributes(x_radius: [3], y_radius: [3]) end + it 'listens to middle' do + args = { width: :middle, height: 'middle' } + box = Squib::Args::Box.new + box.extract! args, deck + expect(box).to have_attributes(width: [61.5], height: [228.0]) + end + it 'listens to center' do + args = { width: 'center', height: :center } + box = Squib::Args::Box.new + box.extract! args, deck + expect(box).to have_attributes(width: [61.5], height: [228.0]) + end + end diff --git a/spec/args/unit_conversion_spec.rb b/spec/args/unit_conversion_spec.rb index aba27bb..5cf1a52 100644 --- a/spec/args/unit_conversion_spec.rb +++ b/spec/args/unit_conversion_spec.rb @@ -30,5 +30,9 @@ describe Squib::Args::UnitConversion do expect(subject.parse('1mm ')).to eq(11.81102361) end + it 'does deg' do + expect(subject.parse('30deg')).to be_within(0.0001).of(0.523599) + end + end diff --git a/spec/data/samples/units/_units.rb.txt b/spec/data/samples/units/_units.rb.txt index 5297568..5760351 100644 --- a/spec/data/samples/units/_units.rb.txt +++ b/spec/data/samples/units/_units.rb.txt @@ -36,6 +36,17 @@ cairo: stroke([]) cairo: restore([]) cairo: save([]) cairo: new_path([]) +cairo: translate([100, 100]) +cairo: transform([Matrix]) +cairo: rotate([0.5235987755982988]) +cairo: scale([0.3125, 0.3125]) +cairo: rounded_rectangle([0, 0, 128.0, 128.0, 0, 0]) +cairo: clip([]) +cairo: translate([0, 0]) +cairo: render_rsvg_handle([Rsvg::Handlenil}]) +cairo: restore([]) +cairo: save([]) +cairo: new_path([]) cairo: set_source_color(["black"]) cairo: translate([134.05511805, 166.24488195]) cairo: rotate([0]) @@ -54,5 +65,16 @@ cairo: show_pango_layout([MockDouble]) pango: ellipsized?([]) pango: ellipsized?([]) cairo: restore([]) +cairo: save([]) +cairo: new_path([]) +cairo: translate([220, 300]) +cairo: transform([Matrix]) +cairo: rotate([1.7453292519943295]) +cairo: scale([0.234375, 0.234375]) +cairo: rounded_rectangle([0, 0, 128.0, 128.0, 0, 0]) +cairo: clip([]) +cairo: translate([0, 0]) +cairo: render_rsvg_handle([Rsvg::Handlenil}]) +cairo: restore([]) surface: write_to_png(["_output/units_00.png"]) surface: finish([])