syncsign 0.2.0 → 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2ec8ce97ef1f4882420617de3310d74e2d4a3783a4f1922847c706c3eb04b13c
4
- data.tar.gz: 0a867fa0debe259b37d347aff38800f9ae589a4e2afde253d69fbe2f2cab4bbe
3
+ metadata.gz: 4574f4a41e361efb3c930e259b9bd99ffba55989fb6d0a314fed51d8d93c5a56
4
+ data.tar.gz: 890c60254cd507474fc13de8a163c131385b9f38c5408b16e37f92e680668fd7
5
5
  SHA512:
6
- metadata.gz: fc9cc2483763d6a35cee7d3c9370b2abe6774b5870321ec219ed02c26b61a0d60378c8a38149507bcef9e4cecbb6b88f9a4888e888732d7d47516d6597ab4d3b
7
- data.tar.gz: 9bba6acf10f9b33d4a9d11065e12ae6c3d4270bc95e991e03651aace8dd0c52655fe07ea628f110572a0b58b6fce7ca51601dcf48d43cd30308b574b5b165de9
6
+ metadata.gz: 033cfd91cc3e501b61e8ef2e27028728b174c614b19a8ad2f2d60cc98489e261942773a2fba702a18a3725e6ac3caeb441c94da5eaa400d3a5a2f4ac745df5d1
7
+ data.tar.gz: 5daf0bead45f71423ca9d7b8b58549a26b2fb02ea6f1373ea235f5e83eb00cb53b1509b457553f64595a7855be25f19baec825ebc75d2a44cef0914d88a3424a
data/README.md CHANGED
@@ -5,14 +5,13 @@
5
5
  Ruby class/gem to access the [SyncSign](http://sync-sign.com) cloud service to display information on e-paper displays.
6
6
 
7
7
  ## Features
8
- * Display circles, lines, rectangles, QR codes, and text on the displays.
8
+ * Display circles, lines, rectangles, QR codes, symbols, text, and more on the displays.
9
9
  * Obtain information about associated hubs and displays.
10
10
 
11
11
  ## TODO
12
12
  * Support non-display nodes that connect to the SyncSign hub (like temperature or occupancy sensors)
13
13
  * Support display-resident images (item type IMAGE)
14
14
  * Support bitmap images from a URI (item type BITMAP\_URI)
15
- * Support icons in text boxes
16
15
 
17
16
  ## Use
18
17
 
@@ -29,10 +28,27 @@ Create a SyncSign Service instance using your API key (found in the SyncSign por
29
28
  template = SyncSign::Template.new(items: items)
30
29
  node.render(template: template)
31
30
 
31
+ ## Direct Rendering
32
+ The SyncSign hubs have a simplified API that can be used, bypassing the cloud service. This can result in significant time savings (15s vs 25s in one example) as well as less time between sending the request and the first visible change on the display. This is especially useful for the 4.2" model with buttons, as the time a user spends waiting after pressing a button can be significantly reduced.
33
+
34
+ To enable direct rendering, create a file named signhubs.cfg in either the same directory as your app, the current directory, or /etc/signhubs.cfg. This file should have the following format:
35
+ hub-serial-nbr hub-ip hub-apikey
36
+
37
+ As an example:
38
+ MCFEF5583A9DCA 192.168.0.50 8ab8125b-5d23-1b9a-e55e-a8b3d8c04614
39
+
40
+ Once this is created, you can test it using examples/hubs.rb which should now list your hub as direct rendering capable. To enable this in your app, pass "render\_direct: true" when instantiating a new SyncSign::Service object.
41
+
42
+
32
43
  ## Examples
33
44
 
34
45
  Check out the examples/ folder for:
35
46
  * account\_info.rb - Show information about the account associated with the provided API key.
36
47
  * nodes.rb - List all nodes on the system and information about them.
48
+ * hubs.rb - List all hubs on the system and whether we have enough info to support direct rendering.
37
49
  * render.rb - Render a sample screen to the given node.
50
+ * symbols.rb - Shows how to use the Symbolbox to utilize display-resident symbols.
51
+ * partial\_update.rb - Perform a screen render, then update that render with extra information.
38
52
 
53
+ ## Full Documentation
54
+ YARD docs included, also available on [RubyDoc.info](https://www.rubydoc.info/github/sarahemm/ruby-syncsign/master)
data/lib/syncsign/hub.rb CHANGED
@@ -6,13 +6,18 @@ module SyncSign
6
6
  attr_reader :sn
7
7
  # @return [String] the friendly name of the hub.
8
8
  attr_reader :name
9
-
9
+ # @return [String] the IP address or hostname of the hub.
10
+ attr_reader :addr
11
+ # @return [String] the API key of the hub.
12
+ attr_reader :apikey
13
+
10
14
  ##
11
15
  # Initialize a new hub object (normally only called from Service#hubs)
12
- def initialize(sn: null, name: null, service: null)
16
+ def initialize(service: nil, sn: nil, name: nil)
13
17
  @sn = sn
14
18
  @name = name
15
19
  @service = service
20
+ load_hub_info
16
21
  end
17
22
 
18
23
  ##
@@ -20,6 +25,38 @@ module SyncSign
20
25
  def nodes
21
26
  SyncSign::Node::parse_collection(service: @service, nodeinfo: @service.api_call(path: "/devices/#{@sn}/nodes"))
22
27
  end
28
+
29
+
30
+ def direct_rendering_capable?
31
+ return @addr && @apikey
32
+ end
33
+
34
+ private
35
+
36
+ ##
37
+ # Load info about a hub from the config file (IP address and API key)
38
+ def load_hub_info
39
+ cfg_locations = [
40
+ "./signhubs.cfg",
41
+ "#{File::dirname($0)}/signhubs.cfg",
42
+ "/etc/signhubs.cfg"
43
+ ]
44
+ cfgfile = cfg_locations.find { |file| File.exist?(file) }
45
+ return unless cfgfile
46
+
47
+ File.open(cfgfile) do |f|
48
+ f.each_line do |line|
49
+ next if line[0] == "#"
50
+
51
+ hubinfo = line.split(/\s+/)
52
+ if(@sn == hubinfo[0]) then
53
+ @addr = hubinfo[1]
54
+ @apikey = hubinfo[2]
55
+ return true
56
+ end
57
+ end
58
+ end
59
+ end
23
60
  end
24
61
  end
25
62
 
@@ -5,8 +5,10 @@ module SyncSign
5
5
  ##
6
6
  # Render a template to this display.
7
7
  # @param template [Template] Template to render to this display.
8
- def render(template: nil)
9
- @service.api_call(type: :post, path: "/nodes/#{@id}/renders", data: template.to_s)
8
+ # @param partial [Boolean] Specifies that this should be a partial update,
9
+ # leaving any information already on the screen in place.
10
+ def render(template: nil, partial: false)
11
+ @service.api_call(type: :post, path: "/nodes/#{@id}/renders", data: template.to_s(partial: partial), node: self, direct: @service.direct_rendering?)
10
12
  end
11
13
 
12
14
  ##
data/lib/syncsign/node.rb CHANGED
@@ -16,7 +16,7 @@ module SyncSign
16
16
 
17
17
  ##
18
18
  # Initialize a new Node object (normally only called from Hub#nodes or Service#nodes).
19
- def initialize(service: nil, id: nil, name: nil, online: nil, battery: nil, signal: nil, model: nil)
19
+ def initialize(service: nil, id: nil, name: nil, online: nil, battery: nil, signal: nil, model: nil, hubid: nil)
20
20
  @service = service
21
21
  @id = id
22
22
  @name = name
@@ -24,6 +24,7 @@ module SyncSign
24
24
  @battery = battery
25
25
  @signal = signal
26
26
  @model = model
27
+ @hubid = hubid
27
28
  end
28
29
 
29
30
  ##
@@ -32,6 +33,12 @@ module SyncSign
32
33
  @online
33
34
  end
34
35
 
36
+ ##
37
+ # Return the hub that this node is associated with
38
+ def hub
39
+ Hub.new(service: @service, sn: @hubid)
40
+ end
41
+
35
42
  ##
36
43
  # Parse a JSON description of a single node into a +Node+ object.
37
44
  # Normally only called from Hub#nodes or Service#nodes.
@@ -50,7 +57,8 @@ module SyncSign
50
57
  online: nodeinfo['onlined'],
51
58
  battery: nodeinfo['batteryLevel'],
52
59
  signal: nodeinfo['signalLevel'],
53
- model: nodeinfo['model']
60
+ model: nodeinfo['model'],
61
+ hubid: nodeinfo['thingName']
54
62
  )
55
63
  end
56
64
 
@@ -16,8 +16,11 @@ module SyncSign
16
16
  ##
17
17
  # Set up a new connection to the SyncSign cloud service.
18
18
  # @param apikey [String] the API key provided through the SyncSign portal.
19
- def initialize(apikey: null)
19
+ # @param render_direct [Boolean] try to send renders directly to the hub,
20
+ # bypassing the cloud service.
21
+ def initialize(apikey: nil, render_direct: false)
20
22
  @apikey = apikey
23
+ @directrender = render_direct
21
24
  @baseurl = "https://api.sync-sign.com/v2/key/#{apikey}"
22
25
  end
23
26
 
@@ -57,16 +60,28 @@ module SyncSign
57
60
  Node::parse(service: self, nodeinfo: api_call(path: "/nodes/#{id}"))
58
61
  end
59
62
 
63
+ ##
64
+ # Query whether we are rendering direct to the hub or via the cloud.
65
+ def direct_rendering?
66
+ @directrender
67
+ end
68
+
60
69
  ##
61
70
  # Make a call to the SyncSign cloud service.
62
71
  # @param type [Symbol] The HTTP method to use, either :get or :put.
63
72
  # @param path [String] The path to make the API call to, minus the base path.
64
73
  # @param data [String] The POST data to send with the API call.
74
+ # @param direct [Boolean] Whether to try to send the call directly to the hub,
75
+ # bypassing the cloud service.
76
+ # @param node [Node] The SyncSign node that this request is associated with.
77
+ # Optional unless using direct rendering, in which case it is required.
65
78
  # @api private
66
- def api_call(type: :get, path: "", data: "")
67
- apiurl = URI.parse("#{@baseurl}#{path}")
79
+ def api_call(type: :get, path: "", data: "", direct: false, node: nil)
80
+ baseurl = @baseurl
81
+ baseurl = "http://#{node.hub.addr}/key/#{node.hub.apikey}" if direct and node.hub.direct_rendering_capable?
82
+ apiurl = URI.parse("#{baseurl}#{path}")
68
83
  http_obj = Net::HTTP.new(apiurl.host, apiurl.port)
69
- http_obj.use_ssl = true
84
+ http_obj.use_ssl = baseurl.include?("https")
70
85
  response = nil
71
86
  http_obj.start() do |http|
72
87
  req = nil
@@ -14,9 +14,12 @@ module SyncSign
14
14
  # @param items [Array] List of Widgets to add to the template.
15
15
  # @param pollrate [Integer] How often (in ms) the node should poll the hub
16
16
  # for new information.
17
- def initialize(bgcolour: :white, items: [], pollrate: 10000)
17
+ # @param enable_buttons [Boolean] Whether to enable the button labels at
18
+ # the bottom of the screen.
19
+ def initialize(bgcolour: :white, items: [], pollrate: 10000, enable_buttons: false)
18
20
  @bgcolour = bgcolour
19
21
  @pollrate = pollrate
22
+ @enable_buttons = enable_buttons
20
23
 
21
24
  @items = []
22
25
  items.each do |item|
@@ -34,17 +37,24 @@ module SyncSign
34
37
 
35
38
  ##
36
39
  # Output this template as JSON in the format that the SyncSign service understands.
37
- def to_s
38
- background = {bgColor: @bgcolour.to_s.upcase}
40
+ # @param partial [Boolean] Whether to omit the background, which leaves
41
+ # any information already on-screen in place.
42
+ def to_s(partial: false)
43
+ background = {
44
+ bgColor: @bgcolour.to_s.upcase,
45
+ enableButtonZone: @enable_buttons
46
+ }
39
47
  items = @items.collect { |item| item.to_a }
40
48
  options = {'pollRate': @pollrate}
41
- {
49
+ tmpl = {
42
50
  layout: {
43
51
  background: background,
44
52
  items: items,
45
53
  options: options
46
54
  }
47
- }.to_json
55
+ }
56
+ tmpl[:layout].delete(:background) if partial
57
+ tmpl.to_json
48
58
  end
49
59
  end
50
60
  end
@@ -1,4 +1,4 @@
1
1
  module SyncSign
2
2
  # The version number of the SyncSign module.
3
- VERSION = '0.2.0'
3
+ VERSION = '0.4.2'
4
4
  end
@@ -0,0 +1,76 @@
1
+ module SyncSign
2
+ ##
3
+ # Raised when UI elements are not properly aligned.
4
+ # Several UI elements must be aligned to a multiple of 8 or corruption will
5
+ # occur on the display.
6
+ class AlignmentException < StandardError
7
+ end
8
+
9
+ ##
10
+ # Widgets are UI elements that are placed onto a +Template+ for rendering.
11
+ class Widget
12
+ ##
13
+ # An item that contains only x/y coordinates. This can't be used on its own, only its
14
+ # superclasses can be added to templates.
15
+ class Item
16
+ # @return [Integer] horizontal position of the item.
17
+ attr_accessor :x
18
+ # @return [Integer] vertical position of the item.
19
+ attr_accessor :y
20
+
21
+ ##
22
+ # Initialize a new Item widget.
23
+ # @param x [Integer] The horizontal position of the item.
24
+ # @param y [Integer] The vertical position of the item.
25
+ def initialize(x: nil, y: nil)
26
+ @x = x
27
+ @y = y
28
+ end
29
+ end
30
+
31
+ ##
32
+ # A box that contains x/y coordinates, width and height, and colour information.
33
+ # This can't be used on its own, only its superclasses can be added to templates.
34
+ # You may be looking for +Rectangle+ if you want to draw rectangles.
35
+ class Box < Item
36
+ # @return [Integer] the width of the box.
37
+ attr_accessor :width
38
+ # @return [Integer] the height of the box.
39
+ attr_accessor :height
40
+ # @return [Symbol] the stroke or foreground colour of the box.
41
+ attr_accessor :colour
42
+ # @return [Symbol] the background colour of the box.
43
+ attr_accessor :bgcolour
44
+
45
+ def initialize(x: nil, y: nil, width: nil, height: nil, colour: :black, bgcolour: :white)
46
+ Widget::check_colours [colour, bgcolour]
47
+ @colour = colour
48
+ @bgcolour = bgcolour
49
+ @width = width
50
+ @height = height
51
+ super(x: x, y: y)
52
+ end
53
+ end
54
+
55
+ ##
56
+ # Check a set of colours to make sure they're all valid.
57
+ # Will raise ArgumentError if any elements are not valid colours.
58
+ # @param colours [Array] An array of symbols to check.
59
+ def self.check_colours(colours)
60
+ colours.each do |colour|
61
+ next if [:white, :black, :red].include? colour
62
+ raise ArgumentError, "Colour must be :white, :black, or :red."
63
+ end
64
+ end
65
+
66
+ # Check a set of patterns to make sure they're all valid.
67
+ # Will raise ArgumentError if any elements are not valid patterns.
68
+ # @param patterns [Array] An array of symbols to check.
69
+ def self.check_patterns(patterns)
70
+ patterns.each do |pattern|
71
+ next if [:solid, :interleave, :dash_tiny, :dash_medium, :dash_wide, :none].include? pattern
72
+ raise ArgumentError, "Pattern must be :solid, :interleave, :dash_tiny, :dash_medium, :dash_wide, or :none."
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,46 @@
1
+ module SyncSign
2
+ class Widget
3
+ ##
4
+ # A widget that draws button labels for the 4.2" display.
5
+ class ButtonLabels
6
+ # @return [Array] Up to 4 strings of 17 characters each, to label the buttons with.
7
+ attr_accessor :labels
8
+ # @return [Array] Up to 4 boolean values showing whether each button should be reverse colours.
9
+ attr_accessor :reversed
10
+
11
+ ##
12
+ # Initialize a new Button Labels widget.
13
+ # @param labels [Array] Up to 4 strings of 17 characters each, to label the buttons with.
14
+ # @param reversed [Array] Up to 4 boolean values showing whether each button should be reverse colours (white on black). Default is black on white.
15
+ def initialize(labels: [], reversed: [])
16
+ # TODO: validate <= 17 characters in each label
17
+ @labels = labels
18
+ @reversed = reversed
19
+ end
20
+
21
+ ##
22
+ # Convert the widget into an array for sending to the SyncSign service.
23
+ def to_a
24
+ label_arr = []
25
+ (0..3).each do |idx|
26
+ label_arr[idx] = {
27
+ :title => @labels[idx] || "",
28
+ :style => @reversed[idx] || 'DISABLED'
29
+ }
30
+ end
31
+
32
+ {
33
+ 'type': 'BOTTOM_CUSTOM_BUTTONS',
34
+ 'data': {
35
+ 'list': label_arr
36
+ }
37
+ }
38
+ end
39
+
40
+ def ==(other)
41
+ @labels == other.labels &&
42
+ @reversed == other.reversed
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,63 @@
1
+ module SyncSign
2
+ class Widget
3
+ ##
4
+ # A widget that draws a circle.
5
+ class Circle < Item
6
+ attr_accessor :radius, :bgcolour, :colour, :fillpattern, :strokepattern
7
+
8
+ ##
9
+ # Initialize a new circle widget.
10
+ # @param x [Integer] horizontal position of the centre of the circle.
11
+ # @param y [Integer] vertical position of the centre of the circle
12
+ # @param radius [Integer] The radius of the circle in pixels.
13
+ # @param colour [Symbol] The stroke colour used for the circle
14
+ # (either black, white, or red).
15
+ # @param bgcolour [Symbol] The fill colour used for the circle
16
+ # (either black, white, or red).
17
+ # @param fillpattern [Symbol] The fill pattern to use when filling the circle.
18
+ # @param strokepattern [Symbol] The stroke pattern to use when drawing the circle.
19
+ # @param pen_width [Integer] The thickness in pixels of the stroke.
20
+ def initialize(x: nil, y: nil, radius: nil, bgcolour: :white, colour: :black, fillpattern: :none, strokepattern: :solid, pen_width: 1)
21
+ Widget::check_colours [colour, bgcolour]
22
+ Widget::check_patterns [fillpattern, strokepattern]
23
+ @radius = radius
24
+ @colour = colour
25
+ @bgcolour = bgcolour
26
+ @fillpattern = fillpattern
27
+ @strokepattern = strokepattern
28
+ @pen_width = pen_width
29
+ super(x: x, y:y)
30
+ end
31
+
32
+ ##
33
+ # Convert the widget into an array for sending to the SyncSign service.
34
+ def to_a
35
+ {
36
+ 'type': 'CIRCLE',
37
+ 'data': {
38
+ 'center': {x: @x, y: @y},
39
+ 'radius': @radius,
40
+ 'fillColor': @bgcolour.to_s.upcase,
41
+ 'fillPattern': @fillpattern.to_s.upcase,
42
+ 'strokeColor': @colour.to_s.upcase,
43
+ 'strokePattern': @strokepattern.to_s.upcase,
44
+ 'strokeThickness': @pen_width
45
+ }
46
+ }
47
+ end
48
+
49
+ def ==(other)
50
+ @x == other.x &&
51
+ @y == other.x &&
52
+ @width == other.width &&
53
+ @height == other.height &&
54
+ @radius == other.radius &&
55
+ @bgcolour == other.bgcolour &&
56
+ @colour == other.colour &&
57
+ @fillpattern == other.fillpattern &&
58
+ @strokepattern == other.strokepattern &&
59
+ @pen_width == other.pen_width
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,56 @@
1
+ module SyncSign
2
+ class Widget
3
+ ##
4
+ # A widget that draws a line.
5
+ class Line
6
+ attr_accessor :x0, :y0, :x1, :y1, :bgcolour, :colour, :pattern
7
+
8
+ ##
9
+ # Initialize a new line widget.
10
+ # @param x0 [Integer] horizontal position of the starting point of the line.
11
+ # @param y0 [Integer] vertical position of the starting point of the line.
12
+ # @param x1 [Integer] horizontal position of the ending point of the line.
13
+ # @param y1 [Integer] vertical position of the ending point of the line.
14
+ # @param colour [Symbol] The stroke colour used for the rectangle
15
+ # (either black, white, or red).
16
+ # @param bgcolour [Symbol] The fill colour used for the rectangle
17
+ # (either black, white, or red).
18
+ # @param pattern [Symbol] The linestyle to use when drawing the line, one of solid, interleave, dash_tiny, dash_mid, or dash_wide.
19
+ def initialize(x0: nil, y0: nil, x1: nil, y1: nil, bgcolour: :white, colour: :black, pattern: :solid)
20
+ Widget::check_colours [colour, bgcolour]
21
+ Widget::check_patterns [pattern]
22
+ @x0 = x0
23
+ @y0 = y0
24
+ @x1 = x1
25
+ @y1 = y1
26
+ @colour = colour
27
+ @bgcolour = bgcolour
28
+ @pattern = pattern
29
+ end
30
+
31
+ ##
32
+ # Convert the widget into an array for sending to the SyncSign service.
33
+ def to_a
34
+ {
35
+ 'type': 'LINE',
36
+ 'data': {
37
+ 'block': {x0: @x0, y0: @y0, x1: @x1, y1: @y1},
38
+ 'backgroundColor': @bgcolour.to_s.upcase,
39
+ 'lineColor': @colour.to_s.upcase,
40
+ 'linePattern': @pattern.to_s.upcase
41
+ }
42
+ }
43
+ end
44
+
45
+ def ==(other)
46
+ @x0 == other.x0 &&
47
+ @y0 == other.y0 &&
48
+ @x1 == other.x1 &&
49
+ @y1 == other.y1 &&
50
+ @bgcolour == other.bgcolour &&
51
+ @colour == other.colour &&
52
+ @pattern == other.pattern
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,62 @@
1
+ module SyncSign
2
+ class Widget
3
+ # A widget that draws a QR code.
4
+ class QRCode < Item
5
+ # @return [Integer] scale of the QR code (how many pixels to use to
6
+ # represent each base pixel).
7
+ attr_accessor :scale
8
+ # @return [Integer] the version (which is actually size, in QR-speak)
9
+ # of this QR code.
10
+ attr_accessor :version
11
+ # @return [Symbol] the level of error checking code for this QR code,
12
+ # either :low, :medium, :quartile, or :high.
13
+ attr_accessor :ecclevel
14
+ # @return [String] the text to encode in this QR code.
15
+ attr_accessor :text
16
+
17
+ ##
18
+ # Initialize a new QR code widget.
19
+ # @param x [Integer] horizontal position of the left side of the QR code.
20
+ # @param y [Integer] vertical position of the top of the QR code.
21
+ # @param scale [Integer] scale of the QR code (how many pixels to use to
22
+ # represent each base pixel).
23
+ # @param version [Integer] the version (which is actually size, in QR-speak)
24
+ # of this QR code.
25
+ # @param ecclevel [Symbol] the level of error checking code for this QR code,
26
+ # either :low, :medium, :quartile, or :high.
27
+ # @param text [String] the text to encode in this QR code.
28
+ def initialize(x: nil, y: nil, scale: 4, version: 2, ecclevel: :medium, text: nil)
29
+ @scale = scale
30
+ @version = version
31
+ @ecclevel = ecclevel
32
+ @text = text
33
+
34
+ super(x: x, y: y)
35
+ end
36
+
37
+ ##
38
+ # Convert the widget into an array for sending to the SyncSign service.
39
+ def to_a
40
+ {
41
+ 'type': 'QRCODE',
42
+ 'data': {
43
+ 'scale': @scale,
44
+ 'eccLevel': @ecclevel.to_s.upcase,
45
+ 'version': @version,
46
+ 'position': {x: @x, y: @y},
47
+ 'text': @text
48
+ }
49
+ }
50
+ end
51
+
52
+ def ==(other)
53
+ @x == other.x &&
54
+ @y == other.y &&
55
+ @scale == other.scale &&
56
+ @version == other.version &&
57
+ @ecclevel == other.ecclevel &&
58
+ @text == other.text
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,57 @@
1
+ module SyncSign
2
+ class Widget
3
+ ##
4
+ # A widget that draws a rectangle.
5
+ class Rectangle < Box
6
+ attr_accessor :pen_width
7
+
8
+ ##
9
+ # Initialize a new rectangle widget.
10
+ # @param x [Integer] horizontal position of the left side of the rectangle.
11
+ # @param y [Integer] vertical position of the top of the rectangle.
12
+ # @param width [Integer] how wide the rectangle should be.
13
+ # @param height [Integer] how tall the rectangle should be.
14
+ # @param colour [Symbol] The stroke colour used for the rectangle
15
+ # (either black, white, or red).
16
+ # @param bgcolour [Symbol] The fill colour used for the rectangle
17
+ # (either black, white, or red).
18
+ # @param pen_width [Integer] The width in pixels of the stroke.
19
+ def initialize(x: nil, y: nil, width: nil, height: nil, colour: :black, bgcolour: :white, pen_width: 1, fillpattern: :none, strokepattern: :solid)
20
+ Widget::check_patterns [fillpattern, strokepattern]
21
+ raise(AlignmentException, "Rect: x and width must both be a multiple of 8") if x % 8 != 0 or width % 8 != 0
22
+ @pen_width = pen_width
23
+ @fillpattern = fillpattern
24
+ @strokepattern = strokepattern
25
+ super(x: x, y: y, width: width, height: height, colour: colour, bgcolour: bgcolour)
26
+ end
27
+
28
+ ##
29
+ # Convert the widget into an array for sending to the SyncSign service.
30
+ def to_a
31
+ {
32
+ 'type': 'RECTANGLE',
33
+ 'data': {
34
+ 'block': {x: @x, y: @y, w: @width, h: @height},
35
+ 'fillColor': @bgcolour.to_s.upcase,
36
+ 'fillPattern': @fillpattern.to_s.upcase,
37
+ 'strokeColor': @colour.to_s.upcase,
38
+ 'strokePattern': @strokepattern.to_s.upcase,
39
+ 'strokeThickness': @pen_width
40
+ }
41
+ }
42
+ end
43
+
44
+ def ==(other)
45
+ @x == other.x &&
46
+ @y == other.y &&
47
+ @width == other.width &&
48
+ @height == other.height &&
49
+ @colour == other.colour &&
50
+ @bgcolour == other.bgcolour &&
51
+ @pen_width == other.pen_width &&
52
+ @fillpattern == other.fillpattern &&
53
+ @strokepattern == other.strokepattern
54
+ end
55
+ end
56
+ end
57
+ end