glimmer-dsl-swt 4.18.7.2 → 4.18.7.3

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: 91d53b49c974e0ce9b4f3d0a715ab59785d2b23fde0abe4bda5ad20de58e68a7
4
- data.tar.gz: db8c3d1030700bda5faed413c1719336e12e110fd65c154b5650d2b69e3d7eee
3
+ metadata.gz: 98ad3496a7f7eec9bebe867be21b6fefd3764baf67b8336a2177086826fc6e0c
4
+ data.tar.gz: 6093daa8c240d0e02f43078590f84eb77c9cdba070c2c8ba5c7e665fb4455338
5
5
  SHA512:
6
- metadata.gz: 9630530911bcd671a335cef7a1911db6150382532d03b85cd8e6629d02c6d10c44e7901fe40ee48f114c73465c56efff53d13b984cf53393999a449e83c394ca
7
- data.tar.gz: 0d07793e4f0a79b75a1eaf073a39dad0af872c19e6c325bd9d4632ce3b9cf53f0735d1bf7e9a2a1e7a46a7d95ebe202e38626400c128cff78d88a5c15d0154a3
6
+ metadata.gz: 43d3ffa17ae9ad9fae4f867d483439116d0e08055614f83c2ef59f87a38268472ace3821ee6b2521588d02fda8da6a6f009ff9ea93085dc60170835cb6aa4aff
7
+ data.tar.gz: 0f4bb8712916ddb9ee5cd25ded0bdce6b5fc008f2ab23a53ccac07f19eac556daf4eb3594944e91c3a47efd3df3794012abd572fb6ea17ed74357622a67a5253
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Change Log
2
2
 
3
+ ### 4.18.7.3
4
+
5
+ - Support the ability for nested shapes to override their parent `shape` common shared properties
6
+ - Refactor Tetris to use a custom shape (`bevel`) for its blocks given they are used in both the game and the icon, thus achieving code reuse
7
+ - Fix issue with moving filled polygon (moving drawn polygon works)
8
+
3
9
  ### 4.18.7.2
4
10
 
5
11
  - Enable defining custom shapes with direct args just like basic shapes (alternative to using keyword arg options)
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=85 />](https://github.com/AndyObtiva/glimmer) Glimmer DSL for SWT 4.18.7.2
1
+ # [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=85 />](https://github.com/AndyObtiva/glimmer) Glimmer DSL for SWT 4.18.7.3
2
2
  ## JRuby Desktop Development GUI Framework
3
3
  [![Gem Version](https://badge.fury.io/rb/glimmer-dsl-swt.svg)](http://badge.fury.io/rb/glimmer-dsl-swt)
4
4
  [![Travis CI](https://travis-ci.com/AndyObtiva/glimmer-dsl-swt.svg?branch=master)](https://travis-ci.com/github/AndyObtiva/glimmer-dsl-swt)
@@ -13,7 +13,7 @@
13
13
  [<img src="https://covers.oreillystatic.com/images/9780596519650/lrg.jpg" width=105 /><br />
14
14
  Featured in JRuby Cookbook](http://shop.oreilly.com/product/9780596519650.do) and [Chalmers/Gothenburg University Software Engineering Master's Lecture Material](http://www.cse.chalmers.se/~bergert/slides/guest_lecture_DSLs.pdf)
15
15
 
16
- [Glimmer DSL for SWT](https://rubygems.org/gems/glimmer-dsl-swt) 4.18.7.2 includes [SWT 4.18](https://download.eclipse.org/eclipse/downloads/drops4/R-4.18-202012021800/), which was released on December 2, 2020. Gem version numbers are in sync with the SWT library versions. The first two digits represent the SWT version number. The last two digits represent the minor and patch versions of Glimmer DSL for SWT.
16
+ [Glimmer DSL for SWT](https://rubygems.org/gems/glimmer-dsl-swt) 4.18.7.3 includes [SWT 4.18](https://download.eclipse.org/eclipse/downloads/drops4/R-4.18-202012021800/), which was released on December 2, 2020. Gem version numbers are in sync with the SWT library versions. The first two digits represent the SWT version number. The last two digits represent the minor and patch versions of Glimmer DSL for SWT.
17
17
 
18
18
  [Glimmer DSL for SWT receives two updates per month](https://rubygems.org/gems/glimmer-dsl-swt/versions). You can trust [Glimmer DSL for SWT](https://rubygems.org/gems/glimmer-dsl-swt) with your Ruby desktop GUI development needs! [Glimmer DSL for SWT](https://rubygems.org/gems/glimmer-dsl-swt) brings great ideas to the table, such as declarative programming via domain specific languages, currently under-utilized in the GUI domain. That said, it may not be feature complete enough for everybody's needs, so please help make [Glimmer DSL for SWT](https://rubygems.org/gems/glimmer-dsl-swt) even better by providing feedback and [contributing](#contributing) when possible. The project is very active, so any feature suggestions that are accepted could be implemented within weeks if not days. Also, you are welcome to [hire me](#hire-me) full-time if you want long-term development of [Glimmer DSL for SWT](https://rubygems.org/gems/glimmer-dsl-swt) for your project needs.
19
19
 
@@ -340,7 +340,7 @@ jgem install glimmer-dsl-swt
340
340
 
341
341
  Or this command if you want a specific version:
342
342
  ```
343
- jgem install glimmer-dsl-swt -v 4.18.7.2
343
+ jgem install glimmer-dsl-swt -v 4.18.7.3
344
344
  ```
345
345
 
346
346
  `jgem` is JRuby's version of `gem` command.
@@ -358,7 +358,7 @@ Note: if you're using activerecord or activesupport, keep in mind that Glimmer u
358
358
 
359
359
  Add the following to `Gemfile`:
360
360
  ```
361
- gem 'glimmer-dsl-swt', '~> 4.18.7.2'
361
+ gem 'glimmer-dsl-swt', '~> 4.18.7.3'
362
362
  ```
363
363
 
364
364
  And, then run:
data/VERSION CHANGED
@@ -1 +1 @@
1
- 4.18.7.2
1
+ 4.18.7.3
@@ -2,16 +2,16 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Juwelier::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: glimmer-dsl-swt 4.18.7.2 ruby lib
5
+ # stub: glimmer-dsl-swt 4.18.7.3 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "glimmer-dsl-swt".freeze
9
- s.version = "4.18.7.2"
9
+ s.version = "4.18.7.3"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib".freeze]
13
13
  s.authors = ["AndyMaleh".freeze]
14
- s.date = "2021-03-06"
14
+ s.date = "2021-03-09"
15
15
  s.description = "Glimmer DSL for SWT (JRuby Desktop Development GUI Framework) is a native-GUI cross-platform desktop development library written in JRuby, an OS-threaded faster JVM version of Ruby. Glimmer's main innovation is a declarative Ruby DSL that enables productive and efficient authoring of desktop application user-interfaces by relying on the robust Eclipse SWT library. Glimmer additionally innovates by having built-in data-binding support, which greatly facilitates synchronizing the GUI with domain models, thus achieving true decoupling of object oriented components and enabling developers to solve business problems (test-first) without worrying about GUI concerns, or alternatively drive development GUI-first, and then write clean business models (test-first) afterwards. Not only does Glimmer provide a large set of GUI widgets, but it also supports drawing Canvas Graphics like Shapes and Animations. To get started quickly, Glimmer offers scaffolding options for Apps, Gems, and Custom Widgets. Glimmer also includes native-executable packaging support, sorely lacking in other libraries, thus enabling the delivery of desktop apps written in Ruby as truly native DMG/PKG/APP files on the Mac + App Store, MSI/EXE files on Windows, and Gem Packaged Shell Scripts on Linux.".freeze
16
16
  s.email = "andy.am@gmail.com".freeze
17
17
  s.executables = ["glimmer".freeze, "girb".freeze]
@@ -176,6 +176,7 @@ Gem::Specification.new do |s|
176
176
  "samples/elaborate/tetris/model/game.rb",
177
177
  "samples/elaborate/tetris/model/past_game.rb",
178
178
  "samples/elaborate/tetris/model/tetromino.rb",
179
+ "samples/elaborate/tetris/view/bevel.rb",
179
180
  "samples/elaborate/tetris/view/block.rb",
180
181
  "samples/elaborate/tetris/view/high_score_dialog.rb",
181
182
  "samples/elaborate/tetris/view/playfield.rb",
@@ -171,7 +171,13 @@ module Glimmer
171
171
 
172
172
  # The bounding box top-left x, y, width, height in absolute positioning
173
173
  def bounds
174
- org.eclipse.swt.graphics.Rectangle.new(absolute_x, absolute_y, calculated_width, calculated_height)
174
+ bounds_dependencies = [absolute_x, absolute_y, calculated_width, calculated_height]
175
+ if bounds_dependencies != @bounds_dependencies
176
+ # avoid repeating calculations
177
+ absolute_x, absolute_y, calculated_width, calculated_height = @bounds_dependencies = bounds_dependencies
178
+ @bounds = org.eclipse.swt.graphics.Rectangle.new(absolute_x, absolute_y, calculated_width, calculated_height)
179
+ end
180
+ @bounds
175
181
  end
176
182
 
177
183
  # The bounding box top-left x and y
@@ -181,7 +187,13 @@ module Glimmer
181
187
 
182
188
  # The bounding box width and height (as a Point object with x being width and y being height)
183
189
  def size
184
- org.eclipse.swt.graphics.Point.new(calculated_width, calculated_height)
190
+ size_dependencies = [calculated_width, calculated_height]
191
+ if size_dependencies != @size_dependencies
192
+ # avoid repeating calculations
193
+ calculated_width, calculated_height = @size_dependencies = size_dependencies
194
+ @size = org.eclipse.swt.graphics.Point.new(calculated_width, calculated_height)
195
+ end
196
+ @size
185
197
  end
186
198
 
187
199
  def extent
@@ -308,10 +320,10 @@ module Glimmer
308
320
  end
309
321
  @pattern_args ||= {}
310
322
  pattern_type = method_name.to_s.match(/set(.+)Pattern/)[1]
311
- if args.first.is_a?(Pattern)
323
+ if args.first.is_a?(org.eclipse.swt.graphics.Pattern)
312
324
  new_args = @pattern_args[pattern_type]
313
325
  else
314
- new_args = args.first.is_a?(Display) ? args : ([DisplayProxy.instance.swt_display] + args)
326
+ new_args = args.first.is_a?(org.eclipse.swt.widgets.Display) ? args : ([DisplayProxy.instance.swt_display] + args)
315
327
  @pattern_args[pattern_type] = new_args.dup
316
328
  end
317
329
  args[0] = pattern(*new_args, type: pattern_type)
@@ -429,6 +441,10 @@ module Glimmer
429
441
  parameter_names.index(attribute_name.to_s.to_sym)
430
442
  end
431
443
 
444
+ def get_parameter_attribute(attribute_name)
445
+ @args[parameter_index(ruby_attribute_getter(attribute_name))]
446
+ end
447
+
432
448
  def set_parameter_attribute(attribute_name, *args)
433
449
  @args[parameter_index(ruby_attribute_getter(attribute_name))] = args.size == 1 ? args.first : args
434
450
  end
@@ -444,31 +460,43 @@ module Glimmer
444
460
  args.pop if !options.nil? && !options[:redraw].nil?
445
461
  perform_redraw = @perform_redraw
446
462
  perform_redraw = options[:redraw] if perform_redraw.nil? && !options.nil?
447
- perform_redraw = true if perform_redraw.nil?
463
+ perform_redraw ||= true
464
+ property_change = nil
465
+ ruby_attribute_getter_name = ruby_attribute_getter(attribute_name)
466
+ ruby_attribute_setter_name = ruby_attribute_setter(attribute_name)
448
467
  if parameter_name?(attribute_name)
449
- set_parameter_attribute(attribute_name, *args)
450
- elsif (respond_to?(attribute_name, super: true) and respond_to?(ruby_attribute_setter(attribute_name), super: true))
451
- self.send(ruby_attribute_setter(attribute_name), *args)
468
+ return if ruby_attribute_getter_name == (args.size == 1 ? args.first : args)
469
+ set_parameter_attribute(ruby_attribute_getter_name, *args)
470
+ elsif (respond_to?(attribute_name, super: true) and respond_to?(ruby_attribute_setter_name, super: true))
471
+ return if self.send(ruby_attribute_getter_name) == (args.size == 1 ? args.first : args)
472
+ self.send(ruby_attribute_setter_name, *args)
452
473
  else
453
- @properties[ruby_attribute_getter(attribute_name)] = args
474
+ # TODO consider this optimization of preconverting args (removing conversion from other methods) to reject equal args
475
+ args = apply_property_arg_conversions(ruby_attribute_getter_name, args)
476
+ return if @properties[ruby_attribute_getter_name] == args
477
+ @properties[ruby_attribute_getter_name] = args
478
+ property_change = true
454
479
  end
455
480
  if @content_added && perform_redraw && !drawable.is_disposed
456
- @calculated_paint_args = false
457
- if is_a?(PathSegment)
458
- root_path&.calculated_path_args = @calculated_path_args = false
459
- calculated_args_changed!
460
- root_path&.calculated_args_changed!
461
- end
462
- attribute_name = ruby_attribute_getter(attribute_name)
463
- if location_parameter_names.map(&:to_s).include?(attribute_name)
464
- @calculated_args = nil
465
- parent.calculated_args_changed_for_defaults! if parent.is_a?(Shape)
466
- end
467
- if ['width', 'height'].include?(attribute_name)
468
- calculated_args_changed_for_defaults!
481
+ redrawn = false
482
+ unless property_change
483
+ @calculated_paint_args = false
484
+ if is_a?(PathSegment)
485
+ root_path&.calculated_path_args = @calculated_path_args = false
486
+ calculated_args_changed!
487
+ root_path&.calculated_args_changed!
488
+ end
489
+ if location_parameter_names.map(&:to_s).include?(ruby_attribute_getter_name)
490
+ calculated_args_changed!(children: true)
491
+ redrawn = parent.calculated_args_changed_for_defaults! if parent.is_a?(Shape)
492
+ end
493
+ if ['width', 'height'].include?(ruby_attribute_getter_name)
494
+ redrawn = calculated_args_changed_for_defaults!
495
+ end
469
496
  end
470
497
  # TODO consider redrawing an image proxy's gc in the future
471
- drawable.redraw unless drawable.is_a?(ImageProxy)
498
+ # TODO consider ensuring only a single redraw happens for a hierarchy of nested shapes
499
+ drawable.redraw unless redrawn || drawable.is_a?(ImageProxy)
472
500
  end
473
501
  end
474
502
 
@@ -479,7 +507,7 @@ module Glimmer
479
507
  elsif (respond_to?(attribute_name, super: true) and respond_to?(ruby_attribute_setter(attribute_name), super: true))
480
508
  self.send(attribute_name)
481
509
  else
482
- @properties.symbolize_keys[attribute_name.to_s.to_sym]
510
+ @properties[attribute_name.to_s]
483
511
  end
484
512
  end
485
513
 
@@ -555,35 +583,73 @@ module Glimmer
555
583
  drawable.redraw if redraw && !drawable.is_a?(ImageProxy)
556
584
  end
557
585
 
558
- # Indicate if this is a shape composite (meaning a shape bag that just contains nested shapes, but doesn't render anything of its own)
559
- def shape_composite?
586
+ # Indicate if this is a container shape (meaning a shape bag that is just there to contain nested shapes, but doesn't render anything of its own)
587
+ def container?
560
588
  @name == 'shape'
561
589
  end
562
590
 
591
+ # Indicate if this is a composite shape (meaning a shape that contains nested shapes like a rectangle with ovals inside it)
592
+ def composite?
593
+ !shapes.empty?
594
+ end
595
+
563
596
  # ordered from closest to farthest parent
564
597
  def parent_shapes
565
- current_parent = parent
566
- the_parent_shapes = []
567
- until current_parent.is_a?(Drawable)
568
- the_parent_shapes << current_parent
569
- current_parent = current_parent.parent
598
+ if @parent_shapes.nil?
599
+ if parent.is_a?(Drawable)
600
+ @parent_shapes = []
601
+ else
602
+ @parent_shapes = parent.parent_shapes + [parent]
603
+ end
604
+ end
605
+ @parent_shapes
606
+ end
607
+
608
+ # ordered from closest to farthest parent
609
+ def parent_shape_containers
610
+ if @parent_shape_containers.nil?
611
+ if parent.is_a?(Drawable)
612
+ @parent_shape_containers = []
613
+ elsif !parent.container?
614
+ @parent_shape_containers = parent.parent_shape_containers
615
+ else
616
+ @parent_shape_containers = parent.parent_shape_containers + [parent]
617
+ end
570
618
  end
571
- the_parent_shapes
619
+ @parent_shape_containers
572
620
  end
573
621
 
574
622
  # ordered from closest to farthest parent
575
623
  def parent_shape_composites
576
- parent_shapes.select(&:shape_composite?)
624
+ if @parent_shape_composites.nil?
625
+ if parent.is_a?(Drawable)
626
+ @parent_shape_composites = []
627
+ elsif !parent.container?
628
+ @parent_shape_composites = parent.parent_shape_composites
629
+ else
630
+ @parent_shape_composites = parent.parent_shape_composites + [parent]
631
+ end
632
+ end
633
+ @parent_shape_composites
577
634
  end
578
635
 
579
- def all_parent_properties
580
- # TODO consider providing a converted property version of this ready for consumption
581
- @all_parent_properties ||= parent_shape_composites.reverse.reduce({}) do |all_properties, parent_shape|
582
- parent_properties = parent_shape.properties
583
- parent_properties.each do |property, args|
584
- parent_properties[property] = apply_property_arg_conversions(property, args)
636
+ def convert_properties!
637
+ if @properties != @converted_properties
638
+ @properties.each do |property, args|
639
+ @properties[property] = apply_property_arg_conversions(property, args)
585
640
  end
586
- all_properties.merge(parent_properties)
641
+ @converted_properties = @properties.dup
642
+ end
643
+ end
644
+
645
+ def converted_properties
646
+ convert_properties!
647
+ @properties
648
+ end
649
+
650
+ def all_parent_properties
651
+ @all_parent_properties ||= parent_shape_containers.reverse.reduce({}) do |all_properties, parent_shape|
652
+ all_properties.merge(parent_shape.converted_properties)
587
653
  end
588
654
  end
589
655
 
@@ -600,11 +666,10 @@ module Glimmer
600
666
 
601
667
  def paint_self(paint_event)
602
668
  @painting = true
603
- unless shape_composite?
669
+ unless container?
604
670
  calculate_paint_args!
605
671
  @original_gc_properties = {} # this stores GC properties before making calls to updates TODO avoid using in pixel graphics
606
- @original_properties = @properties # this stores original shape attributes like background/foreground/font
607
- @properties.merge(all_parent_properties).each do |property, args|
672
+ @properties.each do |property, args|
608
673
  method_name = attribute_setter(property)
609
674
  @original_gc_properties[method_name] = paint_event.gc.send(method_name.sub('set', 'get')) rescue nil
610
675
  paint_event.gc.send(method_name, *args)
@@ -614,10 +679,8 @@ module Glimmer
614
679
  end
615
680
  ensure_extent(paint_event)
616
681
  end
617
- if !@calculated_args || parent_shape_absolute_location_changed?
618
- @calculated_args = calculated_args
619
- end
620
- unless shape_composite?
682
+ @calculated_args ||= calculate_args!
683
+ unless container?
621
684
  # paint unless parent's calculated args are not calculated yet, meaning it is about to get painted and trigger a paint on this child anyways
622
685
  paint_event.gc.send(@method_name, *@calculated_args) unless (parent.is_a?(Shape) && !parent.calculated_args?)
623
686
  @original_gc_properties.each do |method_name, value|
@@ -663,26 +726,27 @@ module Glimmer
663
726
  end
664
727
  end
665
728
 
666
- def parent_shape_absolute_location_changed?
667
- (parent.is_a?(Shape) && (parent.absolute_x != @parent_absolute_x || parent.absolute_y != @parent_absolute_y))
668
- end
669
-
670
729
  def calculated_args_changed!(children: true)
671
730
  # TODO add a children: true option to enable setting to false to avoid recalculating children args
672
731
  @calculated_args = nil
673
732
  shapes.each(&:calculated_args_changed!) if children
674
733
  end
675
734
 
735
+ # Notifies object that calculated args changed for defaults. Returns true if redrawing and false otherwise.
676
736
  def calculated_args_changed_for_defaults!
677
737
  has_default_dimensions = default_width? || default_height?
678
738
  parent_calculated_args_changed_for_defaults = has_default_dimensions
679
- @calculated_args = nil if default_x? || default_y? || has_default_dimensions
739
+ calculated_args_changed!(children: false) if default_x? || default_y? || has_default_dimensions
680
740
  if has_default_dimensions && parent.is_a?(Shape)
681
741
  parent.calculated_args_changed_for_defaults!
682
742
  elsif @content_added && !drawable.is_disposed
683
743
  # TODO consider optimizing in the future if needed by ensuring one redraw for all parents in the hierarchy at the end instead of doing one per parent that needs it
684
- drawable.redraw if !@painting && !drawable.is_a?(ImageProxy)
744
+ if !@painting && !drawable.is_a?(ImageProxy)
745
+ drawable.redraw
746
+ return true
747
+ end
685
748
  end
749
+ false
686
750
  end
687
751
 
688
752
  def calculated_args?
@@ -690,76 +754,101 @@ module Glimmer
690
754
  end
691
755
 
692
756
  # args translated to absolute coordinates
693
- def calculated_args
694
- return @args if !default_x? && !default_y? && !default_width? && !default_height? && !max_width? && !max_height? && parent.is_a?(Drawable)
695
- # Note: Must set x and move_by because not all shapes have a real x and some must translate all their points with move_by
696
- # TODO change that by setting a bounding box for all shapes with a calculated top-left x, y and
697
- # a setter that does the moving inside them instead so that I could rely on absolute_x and absolute_y
698
- # here to get the job done of calculating absolute args
699
- @perform_redraw = false
700
- original_x = nil
701
- original_y = nil
702
- original_width = nil
703
- original_height = nil
704
- if parent.is_a?(Shape)
705
- @parent_absolute_x = parent.absolute_x
706
- @parent_absolute_y = parent.absolute_y
707
- end
708
- if default_width?
709
- original_width = width
710
- self.width = default_width + width_delta
711
- end
712
- if default_height?
713
- original_height = height
714
- self.height = default_height + height_delta
715
- end
716
- if max_width?
717
- original_width = width
718
- self.width = max_width + width_delta
719
- end
720
- if max_height?
721
- original_height = height
722
- self.height = max_height + height_delta
723
- end
724
- if default_x?
725
- original_x = x
726
- self.x = default_x + self.x_delta
727
- end
728
- if default_y?
729
- original_y = y
730
- self.y = default_y + self.y_delta
731
- end
732
- if parent.is_a?(Shape)
733
- move_by(@parent_absolute_x, @parent_absolute_y)
734
- result_args = @args.clone
735
- move_by(-1*@parent_absolute_x, -1*@parent_absolute_y)
736
- else
737
- result_args = @args.clone
738
- end
739
- if original_x
740
- self.x = original_x
741
- end
742
- if original_y
743
- self.y = original_y
744
- end
745
- if original_width
746
- self.width = original_width
747
- end
748
- if original_height
749
- self.height = original_height
757
+ def calculate_args!
758
+ # TODO add conditions for parent having default width/height too
759
+ return @args if parent.is_a?(Drawable) && !default_x? && !default_y? && !default_width? && !default_height? && !max_width? && !max_height?
760
+ calculated_args_dependencies = [
761
+ x,
762
+ y,
763
+ parent.is_a?(Shape) && parent.absolute_x,
764
+ parent.is_a?(Shape) && parent.absolute_y,
765
+ default_width? && default_width,
766
+ default_width? && width_delta,
767
+ default_height? && default_height,
768
+ default_height? && height_delta,
769
+ max_width? && max_width,
770
+ max_width? && width_delta,
771
+ max_height? && max_height,
772
+ max_height? && height_delta,
773
+ default_x? && default_x,
774
+ default_x? && x_delta,
775
+ default_y? && default_y,
776
+ default_y? && y_delta,
777
+ ]
778
+ if calculated_args_dependencies != @calculated_args_dependencies
779
+ # avoid recalculating values again
780
+ x, y, parent_absolute_x, parent_absolute_y, default_width, default_width_delta, default_height, default_height_delta, max_width, max_width_delta, max_height, max_height_delta, default_x, default_x_delta, default_y, default_y_delta = @calculated_args_dependencies = calculated_args_dependencies
781
+ # Note: Must set x and move_by because not all shapes have a real x and some must translate all their points with move_by
782
+ # TODO change that by setting a bounding box for all shapes with a calculated top-left x, y and
783
+ # a setter that does the moving inside them instead so that I could rely on absolute_x and absolute_y
784
+ # here to get the job done of calculating absolute args
785
+ @perform_redraw = false
786
+ original_x = nil
787
+ original_y = nil
788
+ original_width = nil
789
+ original_height = nil
790
+ if parent.is_a?(Shape)
791
+ @parent_absolute_x = parent_absolute_x
792
+ @parent_absolute_y = parent_absolute_y
793
+ end
794
+ if default_width?
795
+ original_width = width
796
+ self.width = default_width + default_width_delta
797
+ end
798
+ if default_height?
799
+ original_height = height
800
+ self.height = default_height + default_height_delta
801
+ end
802
+ if max_width?
803
+ original_width = width
804
+ self.width = max_width + max_width_delta
805
+ end
806
+ if max_height?
807
+ original_height = height
808
+ self.height = max_height + max_height_delta
809
+ end
810
+ if default_x?
811
+ original_x = x
812
+ self.x = default_x + default_x_delta
813
+ end
814
+ if default_y?
815
+ original_y = y
816
+ self.y = default_y + default_y_delta
817
+ end
818
+ if parent.is_a?(Shape)
819
+ move_by(@parent_absolute_x, @parent_absolute_y)
820
+ @result_calculated_args = @args.clone
821
+ move_by(-1*@parent_absolute_x, -1*@parent_absolute_y)
822
+ else
823
+ @result_calculated_args = @args.clone
824
+ end
825
+ if original_x
826
+ self.x = original_x
827
+ end
828
+ if original_y
829
+ self.y = original_y
830
+ end
831
+ if original_width
832
+ self.width = original_width
833
+ end
834
+ if original_height
835
+ self.height = original_height
836
+ end
837
+ @perform_redraw = true
750
838
  end
751
- @perform_redraw = true
752
- result_args
839
+ @result_calculated_args
753
840
  end
754
841
 
755
842
  def default_x?
756
- current_parameter_name?(:x) and
757
- (x.nil? || x.to_s == 'default' || (x.is_a?(Array) && x.first.to_s == 'default'))
843
+ return false unless current_parameter_name?(:x)
844
+ x = self.x
845
+ x.nil? || x.to_s == 'default' || (x.is_a?(Array) && x.first.to_s == 'default')
758
846
  end
759
847
 
760
848
  def default_y?
761
- current_parameter_name?(:y) and
762
- (y.nil? || y.to_s == 'default' || (y.is_a?(Array) && y.first.to_s == 'default'))
849
+ return false unless current_parameter_name?(:y)
850
+ y = self.y
851
+ y.nil? || y.to_s == 'default' || (y.is_a?(Array) && y.first.to_s == 'default')
763
852
  end
764
853
 
765
854
  def default_width?
@@ -775,108 +864,157 @@ module Glimmer
775
864
  end
776
865
 
777
866
  def max_width?
778
- current_parameter_name?(:width) and
779
- (width.nil? || width.to_s == 'max' || (width.is_a?(Array) && width.first.to_s == 'max'))
867
+ return false unless current_parameter_name?(:width)
868
+ width = self.width
869
+ (width.nil? || width.to_s == 'max' || (width.is_a?(Array) && width.first.to_s == 'max'))
780
870
  end
781
871
 
782
872
  def max_height?
783
- current_parameter_name?(:height) and
784
- (height.nil? || height.to_s == 'max' || (height.is_a?(Array) && height.first.to_s == 'max'))
873
+ return false unless current_parameter_name?(:height)
874
+ height = self.height
875
+ (height.nil? || height.to_s == 'max' || (height.is_a?(Array) && height.first.to_s == 'max'))
785
876
  end
786
877
 
787
878
  def default_x
788
- result = ((parent.size.x - size.x) / 2)
789
- result += parent.bounds.x - parent.absolute_x if parent.is_a?(Shape) && parent.irregular?
790
- result
879
+ default_x_dependencies = [parent.size.x, size.x, parent.is_a?(Shape) && parent.irregular? && parent.bounds.x, parent.is_a?(Shape) && parent.irregular? && parent.absolute_x]
880
+ if default_x_dependencies != @default_x_dependencies
881
+ @default_x_dependencies = default_x_dependencies
882
+ result = ((parent.size.x - size.x) / 2)
883
+ result += parent.bounds.x - parent.absolute_x if parent.is_a?(Shape) && parent.irregular?
884
+ @default_x = result
885
+ end
886
+ @default_x
791
887
  end
792
888
 
793
889
  def default_y
794
- result = ((parent.size.y - size.y) / 2)
795
- result += parent.bounds.y - parent.absolute_y if parent.is_a?(Shape) && parent.irregular?
796
- result
890
+ default_y_dependencies = [parent.size.y, size.y, parent.is_a?(Shape) && parent.irregular? && parent.bounds.y, parent.is_a?(Shape) && parent.irregular? && parent.absolute_y]
891
+ if default_y_dependencies != @default_y_dependencies
892
+ result = ((parent.size.y - size.y) / 2)
893
+ result += parent.bounds.y - parent.absolute_y if parent.is_a?(Shape) && parent.irregular?
894
+ @default_y = result
895
+ end
896
+ @default_y
897
+ end
898
+
899
+ # right-most x coordinate in this shape (adding up its width and location)
900
+ def x_end
901
+ x_end_dependencies = [calculated_width, default_x?, !default_x? && x]
902
+ if x_end_dependencies != @x_end_dependencies
903
+ # avoid recalculation of dependencies
904
+ calculated_width, is_default_x, x = @x_end_dependencies = x_end_dependencies
905
+ shape_width = calculated_width.to_f
906
+ shape_x = is_default_x ? 0 : x.to_f
907
+ @x_end = shape_x + shape_width
908
+ end
909
+ @x_end
910
+ end
911
+
912
+ # right-most y coordinate in this shape (adding up its height and location)
913
+ def y_end
914
+ y_end_dependencies = [calculated_height, default_y?, !default_y? && y]
915
+ if y_end_dependencies != @y_end_dependencies
916
+ # avoid recalculation of dependencies
917
+ calculated_height, is_default_y, y = @y_end_dependencies = y_end_dependencies
918
+ shape_height = calculated_height.to_f
919
+ shape_y = is_default_y ? 0 : y.to_f
920
+ @y_end = shape_y + shape_height
921
+ end
922
+ @y_end
797
923
  end
798
924
 
799
925
  def default_width
800
- # TODO consider caching
801
- x_ends = shapes.map do |shape|
802
- if shape.max_width?
803
- 0
926
+ default_width_dependencies = [shapes.empty? && max_width, shapes.size == 1 && shapes.first.max_width? && parent.size.x, shapes.size >= 1 && !shapes.first.max_width? && shapes.map {|s| s.max_width? ? 0 : s.x_end}]
927
+ if default_width_dependencies != @default_width_dependencies
928
+ # Do not repeat calculations
929
+ max_width, parent_size_x, x_ends = @default_width_dependencies = default_width_dependencies
930
+ @default_width = if shapes.empty?
931
+ max_width
932
+ elsif shapes.size == 1 && shapes.first.max_width?
933
+ parent_size_x
804
934
  else
805
- shape_width = shape.calculated_width.to_f
806
- shape_x = shape.default_x? ? 0 : shape.x.to_f
807
- shape_x + shape_width
935
+ x_ends.max.to_f
808
936
  end
809
937
  end
810
- if shapes.empty?
811
- max_width
812
- elsif shapes.size == 1 && shapes.first.max_width?
813
- self.parent.size.x
814
- else
815
- x_ends.max.to_f
816
- end
938
+ @default_width
817
939
  end
818
940
 
819
941
  def default_height
820
- # TODO consider caching
821
- y_ends = shapes.map do |shape|
822
- if shape.max_height?
823
- 0
942
+ default_height_dependencies = [shapes.empty? && max_height, shapes.size == 1 && shapes.first.max_height? && parent.size.y, shapes.size >= 1 && !shapes.first.max_height? && shapes.map {|s| s.max_height? ? 0 : s.y_end}]
943
+ if default_height_dependencies != @default_height_dependencies
944
+ # Do not repeat calculations
945
+ max_height, parent_size_y, y_ends = @default_height_dependencies = default_height_dependencies
946
+ @default_height = if shapes.empty?
947
+ max_height
948
+ elsif shapes.size == 1 && shapes.first.max_height?
949
+ parent_size_y
824
950
  else
825
- shape_height = shape.calculated_height.to_f
826
- shape_y = shape.default_y? ? 0 : shape.y.to_f
827
- shape_y + shape_height
951
+ y_ends.max.to_f
828
952
  end
829
953
  end
830
- if shapes.empty?
831
- max_height
832
- elsif shapes.size == 1 && shapes.first.max_height?
833
- self.parent.size.y
834
- else
835
- y_ends.max.to_f
836
- end
954
+ @default_height
837
955
  end
838
956
 
839
957
  def max_width
840
- # consider caching
841
- parent.is_a?(Drawable) ? parent.size.x : parent.calculated_width
958
+ max_width_dependencies = [parent.is_a?(Drawable) && parent.size.x, !parent.is_a?(Drawable) && parent.calculated_width]
959
+ if max_width_dependencies != @max_width_dependencies
960
+ # do not repeat calculations
961
+ parent_size_x, parent_calculated_width = @max_width_dependencies = max_width_dependencies
962
+ @max_width = parent.is_a?(Drawable) ? parent_size_x : parent_calculated_width
963
+ end
964
+ @max_width
842
965
  end
843
966
 
844
967
  def max_height
845
- # consider caching
846
- parent.is_a?(Drawable) ? parent.size.y : parent.calculated_height
968
+ max_height_dependencies = [parent.is_a?(Drawable) && parent.size.y, !parent.is_a?(Drawable) && parent.calculated_height]
969
+ if max_height_dependencies != @max_height_dependencies
970
+ # do not repeat calculations
971
+ parent_size_y, parent_calculated_height = @max_height_dependencies = max_height_dependencies
972
+ @max_height = parent.is_a?(Drawable) ? parent_size_y : parent_calculated_height
973
+ end
974
+ @max_height
847
975
  end
848
976
 
849
977
  def calculated_width
850
- result_width = width
851
- result_width = (default_width + width_delta) if default_width?
852
- result_width = (max_width + width_delta) if max_width?
853
- result_width
978
+ calculated_width_dependencies = [width, default_width? && (default_width + width_delta), max_width? && (max_width + width_delta)]
979
+ if calculated_width_dependencies != @calculated_width_dependencies
980
+ @calculated_width_dependencies = calculated_width_dependencies
981
+ result_width = width
982
+ result_width = (default_width + width_delta) if default_width?
983
+ result_width = (max_width + width_delta) if max_width?
984
+ @calculated_width = result_width
985
+ end
986
+ @calculated_width
854
987
  end
855
988
 
856
989
  def calculated_height
857
- result_height = height
858
- result_height = (default_height + height_delta) if default_height?
859
- result_height = (max_height + height_delta) if max_height?
860
- result_height
990
+ calculated_height_dependencies = [height, default_height? && (default_height + height_delta), max_height? && (max_height + height_delta)]
991
+ if calculated_height_dependencies != @calculated_height_dependencies
992
+ @calculated_height_dependencies = calculated_height_dependencies
993
+ result_height = height
994
+ result_height = (default_height + height_delta) if default_height?
995
+ result_height = (max_height + height_delta) if max_height?
996
+ @calculated_height = result_height
997
+ end
998
+ @calculated_height
861
999
  end
862
1000
 
863
1001
  def x_delta
864
- return 0 unless default_x? && x.is_a?(Array)
1002
+ return 0 unless x.is_a?(Array) && default_x?
865
1003
  x[1].to_f
866
1004
  end
867
1005
 
868
1006
  def y_delta
869
- return 0 unless default_y? && y.is_a?(Array)
1007
+ return 0 unless y.is_a?(Array) && default_y?
870
1008
  y[1].to_f
871
1009
  end
872
1010
 
873
1011
  def width_delta
874
- return 0 unless (default_width? || max_width?) && width.is_a?(Array)
1012
+ return 0 unless width.is_a?(Array) && (default_width? || max_width?)
875
1013
  width[1].to_f
876
1014
  end
877
1015
 
878
1016
  def height_delta
879
- return 0 unless (default_height? || max_height?) && height.is_a?(Array)
1017
+ return 0 unless height.is_a?(Array) && (default_height? || max_height?)
880
1018
  height[1].to_f
881
1019
  end
882
1020
 
@@ -905,39 +1043,68 @@ module Glimmer
905
1043
  end
906
1044
 
907
1045
  def calculated_x
908
- result = default_x? ? default_x : self.x
909
- result += self.x_delta
910
- result
1046
+ calculated_x_dependencies = [default_x? && default_x, !default_x? && self.x, self.x_delta]
1047
+ if calculated_x_dependencies != @calculated_x_dependencies
1048
+ default_x, x, x_delta = @calculated_x_dependencies = calculated_x_dependencies
1049
+ result = default_x? ? default_x : x
1050
+ result += x_delta
1051
+ @calculated_x = result
1052
+ end
1053
+ @calculated_x
911
1054
  end
912
1055
 
913
1056
  def calculated_y
914
- result = default_y? ? default_y : self.y
915
- result += self.y_delta
916
- result
1057
+ calculated_y_dependencies = [default_y? && default_y, !default_y? && self.y, self.y_delta]
1058
+ if calculated_y_dependencies != @calculated_y_dependencies
1059
+ default_y, y, y_delta = @calculated_y_dependencies = calculated_y_dependencies
1060
+ result = default_y? ? default_y : y
1061
+ result += y_delta
1062
+ @calculated_y = result
1063
+ end
1064
+ @calculated_y
917
1065
  end
918
1066
 
919
1067
  def absolute_x
920
- x = calculated_x
921
- if parent.is_a?(Shape)
922
- parent.absolute_x + x
923
- else
924
- x
1068
+ absolute_x_dependencies = [calculated_x, parent.is_a?(Shape) && parent.absolute_x]
1069
+ if absolute_x_dependencies != @absolute_x_dependencies
1070
+ # do not repeat calculations
1071
+ calculated_x, parent_absolute_x = @absolute_x_dependencies = absolute_x_dependencies
1072
+ x = calculated_x
1073
+ @absolute_x = if parent.is_a?(Shape)
1074
+ parent_absolute_x + x
1075
+ else
1076
+ x
1077
+ end
925
1078
  end
1079
+ @absolute_x
926
1080
  end
927
1081
 
928
1082
  def absolute_y
929
- y = calculated_y
930
- if parent.is_a?(Shape)
931
- parent.absolute_y + y
932
- else
933
- y
1083
+ absolute_y_dependencies = [calculated_y, parent.is_a?(Shape) && parent.absolute_y]
1084
+ if absolute_y_dependencies != @absolute_y_dependencies
1085
+ calculated_y, parent_absolute_y = @absolute_y_dependencies = absolute_y_dependencies
1086
+ y = calculated_y
1087
+ @absolute_y = if parent.is_a?(Shape)
1088
+ parent_absolute_y + y
1089
+ else
1090
+ y
1091
+ end
934
1092
  end
1093
+ @absolute_y
935
1094
  end
936
1095
 
937
- # Overriding inspect to avoid printing very long shape hierarchies
938
- def inspect
939
- "#<#{self.class.name}:0x#{self.hash.to_s(16)} args=#{@args.inspect}, properties=#{@properties.inspect}}>"
1096
+ # Overriding inspect to avoid printing very long nested shape hierarchies (recurses onces only)
1097
+ def inspect(recursive: 1, calculated: false, args: true, properties: true, calculated_args: false)
1098
+ recurse = recursive == true || recursive.is_a?(Integer) && recursive.to_i > 0
1099
+ recursive = [recursive -= 1, 0].max if recursive.is_a?(Integer)
1100
+ args_string = " args=#{@args.inspect}" if args
1101
+ properties_string = " properties=#{@properties.inspect}}" if properties
1102
+ calculated_args_string = " calculated_args=#{@calculated_args.inspect}" if calculated_args
1103
+ calculated_string = " absolute_x=#{absolute_x} absolute_y=#{absolute_y} calculated_width=#{calculated_width} calculated_height=#{calculated_height}" if calculated
1104
+ recursive_string = " shapes=#{@shapes.map {|s| s.inspect(recursive: recursive, calculated: calculated, args: args, properties: properties)}}" if recurse
1105
+ "#<#{self.class.name}:0x#{self.hash.to_s(16)}#{args_string}#{properties_string}#{calculated_args_string}#{calculated_string}#{recursive_string}>"
940
1106
  rescue => e
1107
+ Glimmer::Config.logger.error { e.full_message }
941
1108
  "#<#{self.class.name}:0x#{self.hash.to_s(16)}"
942
1109
  end
943
1110
 
@@ -958,17 +1125,14 @@ module Glimmer
958
1125
  end
959
1126
  end
960
1127
  else
1128
+ @properties = all_parent_properties.merge(@properties)
961
1129
  @properties['background'] = [@drawable.background] if fill? && !has_some_background?
962
1130
  @properties['foreground'] = [@drawable.foreground] if @drawable.respond_to?(:foreground) && draw? && !has_some_foreground?
963
1131
  # TODO regarding alpha, make sure to reset it to parent stored alpha once we allow setting shape properties on parents directly without shapes
964
- @properties['alpha'] ||= [255]
965
- @properties['font'] = [@drawable.font] if @drawable.respond_to?(:font) && draw? && !@properties.keys.map(&:to_s).include?('font')
1132
+ @properties['font'] = [@drawable.font] if @drawable.respond_to?(:font) && @name == 'text' && draw? && !@properties.keys.map(&:to_s).include?('font')
966
1133
  # TODO regarding transform, make sure to reset it to parent stored transform once we allow setting shape properties on parents directly without shapes
967
1134
  # Also do that with all future-added properties
968
- @properties['transform'] = [nil] if @drawable.respond_to?(:transform) && !@properties.keys.map(&:to_s).include?('transform')
969
- @properties.each do |property, args|
970
- @properties[property] = apply_property_arg_conversions(property, args)
971
- end
1135
+ convert_properties!
972
1136
  apply_shape_arg_conversions!
973
1137
  apply_shape_arg_defaults!
974
1138
  tolerate_shape_extra_args!
@@ -34,13 +34,9 @@ module Glimmer
34
34
  class Shape
35
35
  class Image < Shape
36
36
  def parameter_names
37
- if @args.to_a.size > 3
38
- image_part_parameter_names
39
- else
40
- image_whole_parameter_names
41
- end
37
+ @parameter_names || image_whole_parameter_names
42
38
  end
43
-
39
+
44
40
  def possible_parameter_names
45
41
  (image_part_parameter_names + image_whole_parameter_names).uniq
46
42
  end
@@ -53,13 +49,15 @@ module Glimmer
53
49
  [:image, :x, :y]
54
50
  end
55
51
 
56
- def parameter_index(attribute_name)
52
+ def set_parameter_attribute(attribute_name, *args)
53
+ return super if @parameter_names.to_a.map(&:to_s).include?(attribute_name.to_s)
57
54
  ####TODO refactor and improve this method through meta-programming (and share across other shapes)
58
55
  if image_part_parameter_names.map(&:to_s).include?(attribute_name.to_s)
59
- image_part_parameter_names.map(&:to_s).index(attribute_name.to_s)
56
+ @parameter_names = image_part_parameter_names
60
57
  elsif image_whole_parameter_names.map(&:to_s).include?(attribute_name.to_s)
61
- image_whole_parameter_names.map(&:to_s).index(attribute_name.to_s)
58
+ @parameter_names = image_whole_parameter_names
62
59
  end
60
+ super
63
61
  end
64
62
 
65
63
  def x
@@ -112,11 +112,7 @@ module Glimmer
112
112
  end
113
113
  end
114
114
 
115
- def calculated_args_changed!(children: true)
116
- super
117
- end
118
-
119
- def calculated_args
115
+ def calculate_args!
120
116
  new_swt_path = @swt_path.nil? || !@calculated_paint_args || !@calculated_path_args
121
117
  if new_swt_path
122
118
  Glimmer::SWT::DisplayProxy.instance.auto_exec do
@@ -119,16 +119,28 @@ module Glimmer
119
119
 
120
120
  # Logical x coordinate relative to parent
121
121
  def x
122
- x_value = bounds.x
123
- x_value -= parent.absolute_x if parent.is_a?(Shape)
124
- x_value
122
+ x_dependencies = [bounds.x, parent.is_a?(Shape) && parent.absolute_x]
123
+ if x_dependencies != @x_dependencies
124
+ # avoid recalculating values
125
+ bounds_x, parent_absolute_x = @x_dependencies = x_dependencies
126
+ x_value = bounds_x
127
+ x_value -= parent_absolute_x if parent.is_a?(Shape)
128
+ @x = x_value
129
+ end
130
+ @x
125
131
  end
126
132
 
127
133
  # Logical y coordinate relative to parent
128
134
  def y
129
- y_value = bounds.y
130
- y_value -= parent.absolute_y if parent.is_a?(Shape)
131
- y_value
135
+ y_dependencies = [bounds.y, parent.is_a?(Shape) && parent.absolute_y]
136
+ if y_dependencies != @y_dependencies
137
+ # avoid recalculating values
138
+ bounds_y, parent_absolute_y = @y_dependencies = y_dependencies
139
+ y_value = bounds_y
140
+ y_value -= parent_absolute_y if parent.is_a?(Shape)
141
+ @y = y_value
142
+ end
143
+ @y
132
144
  end
133
145
 
134
146
  def width
@@ -144,8 +156,12 @@ module Glimmer
144
156
  end
145
157
 
146
158
  def include?(x, y)
147
- comparison_lines = absolute_point_xy_array.zip(absolute_point_xy_array.rotate(1))
148
- comparison_lines.any? {|line| Line.include?(line.first.first, line.first.last, line.last.first, line.last.last, x, y)}
159
+ if filled?
160
+ contain?(x, y)
161
+ else
162
+ comparison_lines = absolute_point_xy_array.zip(absolute_point_xy_array.rotate(1))
163
+ comparison_lines.any? {|line| Line.include?(line.first.first, line.first.last, line.last.first, line.last.last, x, y)}
164
+ end
149
165
  end
150
166
 
151
167
  def move_by(x_delta, y_delta)
@@ -42,19 +42,23 @@ module Glimmer
42
42
  end
43
43
 
44
44
  def point_count
45
+ point_array = args.size > 1 ? args : self.point_array
45
46
  point_array.count / 2
46
47
  end
47
48
 
48
49
  def [](index)
50
+ point_array = args.size > 1 ? args : self.point_array
49
51
  index = 0 if index == point_count
50
52
  org.eclipse.swt.graphics.Point.new(point_array[index * 2], point_array[index * 2 + 1])
51
53
  end
52
54
 
53
55
  def x_array
56
+ point_array = args.size > 1 ? args : self.point_array
54
57
  point_array.each_with_index.select {|pair| pair.last.even?}.map(&:first)
55
58
  end
56
59
 
57
60
  def y_array
61
+ point_array = args.size > 1 ? args : self.point_array
58
62
  point_array.each_with_index.select {|pair| pair.last.odd?}.map(&:first)
59
63
  end
60
64
 
@@ -63,6 +67,7 @@ module Glimmer
63
67
  end
64
68
 
65
69
  def absolute_point_array
70
+ point_array = args.size > 1 ? args : self.point_array
66
71
  if parent.is_a?(Shape)
67
72
  point_array.each_with_index.map do |coordinate, i|
68
73
  if i.even?
@@ -23,7 +23,6 @@ require 'glimmer/swt/custom/shape'
23
23
  require 'glimmer/swt/swt_proxy'
24
24
  require 'glimmer/swt/display_proxy'
25
25
  require 'glimmer/swt/color_proxy'
26
- require 'glimmer/swt/font_proxy'
27
26
  require 'glimmer/swt/transform_proxy'
28
27
 
29
28
  module Glimmer
@@ -34,16 +33,7 @@ module Glimmer
34
33
  class Shape
35
34
  class Rectangle < Shape
36
35
  def parameter_names
37
- # TODO consider optimizing just like text where it is set upon updating attribute and here you just return a variable
38
- if @args.to_a.size >= 6
39
- rectangle_round_parameter_names
40
- elsif @args.to_a.size == 5
41
- rectangle_gradient_parameter_names
42
- elsif @args.to_a.size == 1
43
- rectangle_rectangle_parameter_names
44
- else
45
- rectangle_parameter_names
46
- end
36
+ @parameter_names || rectangle_parameter_names
47
37
  end
48
38
 
49
39
  def possible_parameter_names
@@ -68,17 +58,18 @@ module Glimmer
68
58
  [:rectangle]
69
59
  end
70
60
 
71
- def parameter_index(attribute_name)
72
- ####TODO refactor and improve this method through meta-programming (and share across other shapes)
73
- if rectangle_round_parameter_names.map(&:to_s).include?(attribute_name.to_s)
74
- rectangle_round_parameter_names.map(&:to_s).index(attribute_name.to_s)
61
+ def set_parameter_attribute(attribute_name, *args)
62
+ return super if @parameter_names.to_a.map(&:to_s).include?(attribute_name.to_s)
63
+ if rectangle_parameter_names.map(&:to_s).include?(attribute_name.to_s)
64
+ @parameter_names = rectangle_parameter_names
65
+ elsif rectangle_round_parameter_names.map(&:to_s).include?(attribute_name.to_s)
66
+ @parameter_names = rectangle_round_parameter_names
75
67
  elsif rectangle_gradient_parameter_names.map(&:to_s).include?(attribute_name.to_s)
76
- rectangle_gradient_parameter_names.map(&:to_s).index(attribute_name.to_s)
77
- elsif rectangle_parameter_names.map(&:to_s).include?(attribute_name.to_s)
78
- rectangle_parameter_names.map(&:to_s).index(attribute_name.to_s)
68
+ @parameter_names = rectangle_gradient_parameter_names
79
69
  elsif rectangle_rectangle_parameter_names.map(&:to_s).include?(attribute_name.to_s)
80
- rectangle_rectangle_parameter_names.map(&:to_s).index(attribute_name.to_s)
70
+ @parameter_names = rectangle_rectangle_parameter_names
81
71
  end
72
+ super
82
73
  end
83
74
 
84
75
  def point_xy_array
@@ -158,18 +158,7 @@ class Tetris
158
158
  y = row * icon_block_size
159
159
  rectangle(x, y, icon_block_size, icon_block_size) {
160
160
  background color
161
- }
162
- polygon(x, y, x + icon_block_size, y, x + icon_block_size - icon_bevel_pixel_size, y + icon_bevel_pixel_size, x + icon_bevel_pixel_size, y + icon_bevel_pixel_size) {
163
- background rgb(color.red + 4*BEVEL_CONSTANT, color.green + 4*BEVEL_CONSTANT, color.blue + 4*BEVEL_CONSTANT)
164
- }
165
- polygon(x + icon_block_size, y, x + icon_block_size - icon_bevel_pixel_size, y + icon_bevel_pixel_size, x + icon_block_size - icon_bevel_pixel_size, y + icon_block_size - icon_bevel_pixel_size, x + icon_block_size, y + icon_block_size) {
166
- background rgb(color.red - BEVEL_CONSTANT, color.green - BEVEL_CONSTANT, color.blue - BEVEL_CONSTANT)
167
- }
168
- polygon(x + icon_block_size, y + icon_block_size, x, y + icon_block_size, x + icon_bevel_pixel_size, y + icon_block_size - icon_bevel_pixel_size, x + icon_block_size - icon_bevel_pixel_size, y + icon_block_size - icon_bevel_pixel_size) {
169
- background rgb(color.red - 2*BEVEL_CONSTANT, color.green - 2*BEVEL_CONSTANT, color.blue - 2*BEVEL_CONSTANT)
170
- }
171
- polygon(x, y, x, y + icon_block_size, x + icon_bevel_pixel_size, y + icon_block_size - icon_bevel_pixel_size, x + icon_bevel_pixel_size, y + icon_bevel_pixel_size) {
172
- background rgb(color.red - BEVEL_CONSTANT, color.green - BEVEL_CONSTANT, color.blue - BEVEL_CONSTANT)
161
+ bevel(base_color: color, size: icon_block_size)
173
162
  }
174
163
  }
175
164
  }
@@ -33,6 +33,8 @@ class Tetris
33
33
  class Game
34
34
  PLAYFIELD_WIDTH = 10
35
35
  PLAYFIELD_HEIGHT = 20
36
+ # PLAYFIELD_WIDTH = 5
37
+ # PLAYFIELD_HEIGHT = 5
36
38
  PREVIEW_PLAYFIELD_WIDTH = 4
37
39
  PREVIEW_PLAYFIELD_HEIGHT = 2
38
40
  SCORE_MULTIPLIER = {1 => 40, 2 => 100, 3 => 300, 4 => 1200}
@@ -199,6 +201,7 @@ class Tetris
199
201
 
200
202
  def delay
201
203
  [1.1 - (level.to_i * 0.1), 0.001].max
204
+ # 99999
202
205
  end
203
206
 
204
207
  def beep
@@ -0,0 +1,78 @@
1
+ # Copyright (c) 2007-2021 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ # Creates a class-based custom shape representing the `bevel` keyword by convention
23
+ class Tetris
24
+ module View
25
+ class Bevel
26
+ include Glimmer::UI::CustomShape
27
+
28
+ options :base_color, :size, :bevel_pixel_size
29
+
30
+ before_body {
31
+ self.bevel_pixel_size = 0.16*size.to_f if bevel_pixel_size.nil?
32
+ }
33
+
34
+ body {
35
+ shape(0, 0, size, size) {
36
+ polygon(0, 0, size, 0, size - bevel_pixel_size, bevel_pixel_size, bevel_pixel_size, bevel_pixel_size) {
37
+ background bind(self, :base_color) { |color_value|
38
+ unless color_value.nil?
39
+ color = color(color_value)
40
+ rgb(color.red + 4*BEVEL_CONSTANT, color.green + 4*BEVEL_CONSTANT, color.blue + 4*BEVEL_CONSTANT)
41
+ end
42
+ }
43
+ }
44
+ polygon(size, 0, size - bevel_pixel_size, bevel_pixel_size, size - bevel_pixel_size, size - bevel_pixel_size, size, size) {
45
+ background bind(self, :base_color) { |color_value|
46
+ unless color_value.nil?
47
+ color = color(color_value)
48
+ rgb(color.red - BEVEL_CONSTANT, color.green - BEVEL_CONSTANT, color.blue - BEVEL_CONSTANT)
49
+ end
50
+ }
51
+ }
52
+ polygon(size, size, 0, size, bevel_pixel_size, size - bevel_pixel_size, size - bevel_pixel_size, size - bevel_pixel_size) {
53
+ background bind(self, :base_color) { |color_value|
54
+ unless color_value.nil?
55
+ color = color(color_value)
56
+ rgb(color.red - 2*BEVEL_CONSTANT, color.green - 2*BEVEL_CONSTANT, color.blue - 2*BEVEL_CONSTANT)
57
+ end
58
+ }
59
+ }
60
+ polygon(0, 0, 0, size, bevel_pixel_size, size - bevel_pixel_size, bevel_pixel_size, bevel_pixel_size) {
61
+ background bind(self, :base_color) { |color_value|
62
+ unless color_value.nil?
63
+ color = color(color_value)
64
+ rgb(color.red - BEVEL_CONSTANT, color.green - BEVEL_CONSTANT, color.blue - BEVEL_CONSTANT)
65
+ end
66
+ }
67
+ }
68
+ rectangle(0, 0, size, size) {
69
+ foreground bind(self, :base_color) { |color_value|
70
+ # use gray instead of white for the border
71
+ color_value == Model::Block::COLOR_CLEAR ? :gray : color_value
72
+ }
73
+ }
74
+ }
75
+ }
76
+ end
77
+ end
78
+ end
@@ -19,6 +19,8 @@
19
19
  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
20
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
+ require_relative 'bevel'
23
+
22
24
  class Tetris
23
25
  module View
24
26
  class Block
@@ -27,36 +29,11 @@ class Tetris
27
29
  options :game_playfield, :block_size, :row, :column
28
30
 
29
31
  body {
30
- canvas {
32
+ canvas { |canvas_proxy|
31
33
  background bind(game_playfield[row][column], :color)
32
- polygon(0, 0, block_size, 0, block_size - 4, 4, 4, 4) {
33
- background bind(game_playfield[row][column], :color) { |color_value|
34
- color = color(color_value)
35
- rgb(color.red + 4*BEVEL_CONSTANT, color.green + 4*BEVEL_CONSTANT, color.blue + 4*BEVEL_CONSTANT)
36
- }
37
- }
38
- polygon(block_size, 0, block_size - 4, 4, block_size - 4, block_size - 4, block_size, block_size) {
39
- background bind(game_playfield[row][column], :color) { |color_value|
40
- color = color(color_value)
41
- rgb(color.red - BEVEL_CONSTANT, color.green - BEVEL_CONSTANT, color.blue - BEVEL_CONSTANT)
42
- }
43
- }
44
- polygon(block_size, block_size, 0, block_size, 4, block_size - 4, block_size - 4, block_size - 4) {
45
- background bind(game_playfield[row][column], :color) { |color_value|
46
- color = color(color_value)
47
- rgb(color.red - 2*BEVEL_CONSTANT, color.green - 2*BEVEL_CONSTANT, color.blue - 2*BEVEL_CONSTANT)
48
- }
49
- }
50
- polygon(0, 0, 0, block_size, 4, block_size - 4, 4, 4) {
51
- background bind(game_playfield[row][column], :color) { |color_value|
52
- color = color(color_value)
53
- rgb(color.red - BEVEL_CONSTANT, color.green - BEVEL_CONSTANT, color.blue - BEVEL_CONSTANT)
54
- }
55
- }
56
- rectangle(0, 0, block_size, block_size) {
57
- foreground bind(game_playfield[row][column], :color) { |color_value|
58
- color_value == Model::Block::COLOR_CLEAR ? :gray : color_value
59
- }
34
+
35
+ bevel(base_color: game_playfield[row][column].color, size: block_size) {
36
+ base_color bind(game_playfield[row][column], :color)
60
37
  }
61
38
  }
62
39
  }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: glimmer-dsl-swt
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.18.7.2
4
+ version: 4.18.7.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - AndyMaleh
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-03-06 00:00:00.000000000 Z
11
+ date: 2021-03-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -495,6 +495,7 @@ files:
495
495
  - samples/elaborate/tetris/model/game.rb
496
496
  - samples/elaborate/tetris/model/past_game.rb
497
497
  - samples/elaborate/tetris/model/tetromino.rb
498
+ - samples/elaborate/tetris/view/bevel.rb
498
499
  - samples/elaborate/tetris/view/block.rb
499
500
  - samples/elaborate/tetris/view/high_score_dialog.rb
500
501
  - samples/elaborate/tetris/view/playfield.rb