glimmer-dsl-swt 4.21.2.4 → 4.22.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +208 -167
  3. data/README.md +18 -11
  4. data/VERSION +1 -1
  5. data/docs/reference/GLIMMER_COMMAND.md +2 -2
  6. data/docs/reference/GLIMMER_CONFIGURATION.md +14 -3
  7. data/docs/reference/GLIMMER_GUI_DSL_SYNTAX.md +277 -112
  8. data/docs/reference/GLIMMER_SAMPLES.md +26 -0
  9. data/glimmer-dsl-swt.gemspec +0 -0
  10. data/lib/ext/glimmer/config.rb +41 -24
  11. data/lib/glimmer/data_binding/observable_widget.rb +6 -6
  12. data/lib/glimmer/data_binding/widget_binding.rb +4 -3
  13. data/lib/glimmer/dsl/swt/observe_expression.rb +2 -1
  14. data/lib/glimmer/dsl/swt/sync_call_expression.rb +38 -0
  15. data/lib/glimmer/dsl/swt/transform_expression.rb +1 -1
  16. data/lib/glimmer/launcher.rb +15 -14
  17. data/lib/glimmer/rake_task/package.rb +5 -3
  18. data/lib/glimmer/rake_task/scaffold.rb +2 -14
  19. data/lib/glimmer/swt/color_proxy.rb +5 -5
  20. data/lib/glimmer/swt/custom/drawable.rb +8 -2
  21. data/lib/glimmer/swt/custom/shape/line.rb +0 -1
  22. data/lib/glimmer/swt/custom/shape/path.rb +2 -2
  23. data/lib/glimmer/swt/custom/shape/path_segment.rb +2 -2
  24. data/lib/glimmer/swt/custom/shape/point.rb +8 -1
  25. data/lib/glimmer/swt/custom/shape.rb +170 -69
  26. data/lib/glimmer/swt/display_proxy.rb +15 -10
  27. data/lib/glimmer/swt/image_proxy.rb +5 -5
  28. data/lib/glimmer/swt/message_box_proxy.rb +5 -5
  29. data/lib/glimmer/swt/shape_listener_proxy.rb +55 -0
  30. data/lib/glimmer/swt/shell_proxy.rb +1 -1
  31. data/lib/glimmer/swt/transform_proxy.rb +3 -3
  32. data/lib/glimmer/swt/tray_proxy.rb +4 -4
  33. data/lib/glimmer/swt/widget_proxy.rb +14 -10
  34. data/lib/glimmer/ui/custom_shape.rb +34 -10
  35. data/lib/glimmer/ui/custom_widget.rb +7 -10
  36. data/lib/glimmer-dsl-swt.rb +6 -2
  37. data/samples/elaborate/battleship/view/cell.rb +10 -2
  38. data/samples/elaborate/klondike_solitaire/model/column_pile.rb +0 -1
  39. data/samples/elaborate/klondike_solitaire/view/column_pile.rb +3 -16
  40. data/samples/elaborate/klondike_solitaire/view/dealing_pile.rb +1 -1
  41. data/samples/elaborate/klondike_solitaire/view/dealt_pile.rb +12 -5
  42. data/samples/elaborate/klondike_solitaire/view/empty_playing_card.rb +2 -1
  43. data/samples/elaborate/klondike_solitaire/view/foundation_pile.rb +2 -2
  44. data/samples/elaborate/klondike_solitaire/view/hidden_playing_card.rb +2 -2
  45. data/samples/elaborate/klondike_solitaire/view/klondike_solitaire_menu_bar.rb +60 -0
  46. data/samples/elaborate/klondike_solitaire/view/playing_card.rb +3 -2
  47. data/samples/elaborate/klondike_solitaire.rb +13 -55
  48. data/samples/elaborate/mandelbrot_fractal.rb +3 -1
  49. data/samples/elaborate/quarto/model/game.rb +124 -0
  50. data/samples/elaborate/quarto/model/piece/cube.rb +31 -0
  51. data/samples/elaborate/quarto/model/piece/cylinder.rb +31 -0
  52. data/samples/elaborate/quarto/model/piece.rb +70 -0
  53. data/samples/elaborate/quarto/view/available_pieces_area.rb +72 -0
  54. data/samples/elaborate/quarto/view/board.rb +65 -0
  55. data/samples/elaborate/quarto/view/cell.rb +85 -0
  56. data/samples/elaborate/quarto/view/cube.rb +73 -0
  57. data/samples/elaborate/quarto/view/cylinder.rb +72 -0
  58. data/samples/elaborate/quarto/view/message_box_panel.rb +114 -0
  59. data/samples/elaborate/quarto/view/piece.rb +56 -0
  60. data/samples/elaborate/quarto/view/selected_piece_area.rb +69 -0
  61. data/samples/elaborate/quarto.rb +190 -0
  62. data/samples/hello/hello_custom_widget.rb +23 -5
  63. data/samples/hello/hello_scrolled_composite.rb +95 -0
  64. data/samples/hello/hello_world.rb +1 -0
  65. data/vendor/swt/linux/swt.jar +0 -0
  66. data/vendor/swt/linux_aarch64/swt.jar +0 -0
  67. data/vendor/swt/mac/swt.jar +0 -0
  68. data/vendor/swt/mac_aarch64/swt.jar +0 -0
  69. data/vendor/swt/windows/swt.jar +0 -0
  70. metadata +21 -25
  71. data/bin/glimmer_runner.rb +0 -4
@@ -25,6 +25,7 @@ require 'glimmer/swt/display_proxy'
25
25
  require 'glimmer/swt/color_proxy'
26
26
  require 'glimmer/swt/font_proxy'
27
27
  require 'glimmer/swt/transform_proxy'
28
+ require 'glimmer/swt/shape_listener_proxy'
28
29
 
29
30
  class Java::OrgEclipseSwtGraphics::GC
30
31
  def setLineDashOffset(value)
@@ -65,7 +66,7 @@ module Glimmer
65
66
  DropEvent = Struct.new(:doit, :x, :y, :dragged_shape, :dragged_shape_original_x, :dragged_shape_original_y, :dragging_x, :dragging_y, :drop_shapes, keyword_init: true)
66
67
 
67
68
  class << self
68
- attr_accessor :dragging, :dragging_x, :dragging_y, :dragged_shape, :dragged_shape_original_x, :dragged_shape_original_y
69
+ attr_accessor :dragging, :dragging_x, :dragging_y, :dragged_shape, :dragged_shape_original_x, :dragged_shape_original_y, :drop_shape_handling_count
69
70
  alias dragging? dragging
70
71
 
71
72
  def create(parent, keyword, *args, &property_block)
@@ -132,15 +133,13 @@ module Glimmer
132
133
  def flyweight_patterns
133
134
  @flyweight_patterns ||= {}
134
135
  end
135
-
136
- # shapes that have defined on_drop expecting to received a dragged shape
137
- def drop_shapes
138
- @drop_shapes ||= []
139
- end
140
136
  end
141
137
 
142
- attr_reader :drawable, :parent, :name, :args, :options, :shapes, :properties
138
+ attr_reader :drawable, :parent, :name, :args, :options, :shapes, :properties, :disposed, :widget_listener_proxies
143
139
  attr_accessor :extent
140
+ alias disposed? disposed
141
+ alias is_disposed disposed # for SWT widget compatibility
142
+ # TODO consider making shapes return a dup, always, in case consumers want to dispose
144
143
 
145
144
  def initialize(parent, keyword, *args, &property_block)
146
145
  @parent = parent
@@ -229,19 +228,45 @@ module Glimmer
229
228
  contain?(x, y)
230
229
  end
231
230
 
232
- def include_with_children?(x, y, except_child: nil)
233
- included = include?(x, y)
234
- included ||= expanded_shapes.reject {|shape| shape == except_child}.detect { |shape| shape.include?(x, y) }
231
+ def include_with_children?(x, y, except_shape: nil)
232
+ included_in_self = (!self.equal?(except_shape) && include?(x, y))
233
+ # TODO note that expanded shapes does not filter when reject below happens, keeping nested shapes
234
+ included_in_self || expanded_shapes(except_shape: except_shape).any? { |shape| shape.include?(x, y) }
235
+ end
236
+
237
+ def bounds_contain?(x, y)
238
+ x, y = inverse_transform_point(x, y)
239
+ bounds.contains(x, y)
240
+ end
241
+
242
+ # Recursively checks if other shape is included in this shape, beginning by comparing to self
243
+ # and then recursing into children shapes.
244
+ def include_shape?(other)
245
+ self == other || shapes.any? { |shape| shape.include_shape?(other) }
235
246
  end
236
247
 
248
+ # if there is a transform, apply on x, y point coordinates
249
+ def transform_point(x, y)
250
+ # keep in mind that transform is an array of a single element that is the transform object
251
+ current_transform = (transform || parent_shape_containers.map(&:transform).first)&.first
252
+ if current_transform
253
+ transform_array = [x, y].to_java(:float) # just placeholder data that gets overwritten with getElements
254
+ current_transform.transform(transform_array)
255
+ x = transform_array[0]
256
+ y = transform_array[1]
257
+ end
258
+ [x, y]
259
+ end
260
+
237
261
  # if there is a transform, invert it and apply on x, y point coordinates
238
262
  def inverse_transform_point(x, y)
239
- current_transform = (transform || parent_shape_containers.map(&:transform).first)&.first
263
+ # keep in mind that transform is an array of a single element that is the transform object
264
+ current_transform = (transform || parent_shape_containers.map(&:transform).compact.first)&.first
240
265
  if current_transform
241
- transform_array = [1,2,3,4,5,6].to_java(:float)
266
+ transform_array = [1,2,3,4,5,6].to_java(:float) # just placeholder data that gets overwritten with getElements
242
267
  current_transform.getElements(transform_array)
243
268
  inverse_transform = TransformProxy.new(DisplayProxy.instance.swt_display, *transform_array.to_a)
244
- inverse_transform_array = [1,2,3,4,5,6].to_java(:float)
269
+ inverse_transform_array = [1,2,3,4,5,6].to_java(:float) # just placeholder data that gets overwritten with getElements
245
270
  inverse_transform.getElements(inverse_transform_array)
246
271
  matrix = Matrix[[inverse_transform_array[0], inverse_transform_array[1]], [inverse_transform_array[2], inverse_transform_array[3]]]
247
272
  result = matrix * Matrix.column_vector([x, y])
@@ -315,6 +340,7 @@ module Glimmer
315
340
  end
316
341
 
317
342
  def content(&block)
343
+ # TODO consider supporting adding content without redraw (redraw: false)
318
344
  Glimmer::SWT::DisplayProxy.instance.auto_exec do
319
345
  Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::SWT::ShapeExpression.new, @name, &block)
320
346
  calculated_args_changed!(children: false)
@@ -601,17 +627,27 @@ module Glimmer
601
627
  end
602
628
 
603
629
  def can_handle_observation_request?(observation_request)
604
- drawable.can_handle_observation_request?(observation_request)
605
- end
606
-
607
- def handle_observation_request(observation_request, &block)
608
- shape_block = lambda do |event|
609
- block.call(event) if include_with_children?(event.x, event.y)
630
+ observation_request = observation_request.to_s
631
+ observation_request.start_with?('on_') &&
632
+ (
633
+ observation_request == 'on_shape_disposed' ||
634
+ (
635
+ drawable.respond_to?(:can_handle_observation_request?) &&
636
+ drawable.can_handle_observation_request?(observation_request)
637
+ )
638
+ )
639
+ end
640
+
641
+ def handle_observation_request(observation_request, source_observation_request: nil, &block)
642
+ if observation_request.to_s == 'on_shape_disposed'
643
+ @on_shape_disposed_handlers ||= []
644
+ @on_shape_disposed_handlers << block
645
+ return ShapeListenerProxy.new(shape: self, drawable: drawable, shape_listener_block: block, observation_request: 'on_shape_disposed')
610
646
  end
611
647
  if observation_request == 'on_drop'
612
- Shape.drop_shapes << self
613
- handle_observation_request('on_mouse_up') do |event|
614
- if Shape.dragging && include_with_children?(event.x, event.y, except_child: Shape.dragged_shape)
648
+ drawable.drop_shapes << self
649
+ handle_observation_request('on_mouse_up', source_observation_request: 'on_drop') do |event|
650
+ if Shape.dragging && include_with_children?(event.x, event.y, except_shape: Shape.dragged_shape)
615
651
  drop_event = DropEvent.new(
616
652
  doit: true,
617
653
  dragged_shape: Shape.dragged_shape,
@@ -619,29 +655,56 @@ module Glimmer
619
655
  dragged_shape_original_y: Shape.dragged_shape_original_y,
620
656
  dragging_x: Shape.dragging_x,
621
657
  dragging_y: Shape.dragging_y,
622
- drop_shapes: Shape.drop_shapes,
658
+ drop_shapes: drawable.drop_shapes,
623
659
  x: event.x,
624
660
  y: event.y
625
661
  )
626
662
  begin
627
663
  block.call(drop_event)
628
664
  rescue => e
629
- Glimmer::Config.logger.error e.full_message
665
+ Glimmer::Config.logger.error {e.full_message}
630
666
  ensure
631
- Shape.dragging = false
632
- if !drop_event.doit && Shape.dragged_shape
633
- Shape.dragged_shape.x = Shape.dragged_shape_original_x
634
- Shape.dragged_shape.y = Shape.dragged_shape_original_y
667
+ if drop_event.doit
668
+ Shape.dragging = false
669
+ Shape.dragged_shape = nil
670
+ elsif Shape.drop_shape_handling_count.to_i >= drawable.drop_shapes.count && Shape.dragged_shape
671
+ cancel_dragging!
635
672
  end
636
- Shape.dragged_shape = nil
673
+ end
674
+ else
675
+ if Shape.drop_shape_handling_count.to_i >= drawable.drop_shapes.count
676
+ cancel_dragging!
637
677
  end
638
678
  end
639
679
  end
640
680
  else
641
- drawable.handle_observation_request(observation_request, &shape_block)
681
+ widget_listener_proxy = nil
682
+ shape_block = lambda do |event|
683
+ if @disposed
684
+ widget_listener_proxy.deregister
685
+ @widget_listener_proxies.delete(widget_listener_proxy)
686
+ else
687
+ Shape.drop_shape_handling_count += 1 if source_observation_request == 'on_drop' && event.x == Shape.dragging_x && event.y == Shape.dragging_y
688
+ if !event.respond_to?(:x) || !event.respond_to?(:y) || include_with_children?(event.x, event.y)
689
+ block.call(event)
690
+ elsif source_observation_request == 'on_drop' && Shape.drop_shape_handling_count.to_i >= drawable.drop_shapes.count
691
+ cancel_dragging!
692
+ end
693
+ end
694
+ end
695
+ widget_listener_proxy = drawable.respond_to?(:handle_observation_request) && drawable.handle_observation_request(observation_request, &shape_block)
696
+ @widget_listener_proxies ||= []
697
+ if widget_listener_proxy
698
+ @widget_listener_proxies << widget_listener_proxy
699
+ ShapeListenerProxy.new(shape: self, drawable: drawable, shape_listener_block: shape_block, observation_request: source_observation_request || observation_request, widget_listener_proxy: widget_listener_proxy)
700
+ end
642
701
  end
643
702
  end
644
703
 
704
+ def remove_shape_disposed_listener(listener_block)
705
+ @on_shape_disposed_handlers.delete(listener_block)
706
+ end
707
+
645
708
  # Sets data just like SWT widgets
646
709
  def set_data(key=nil, value)
647
710
  @data ||= {}
@@ -656,55 +719,75 @@ module Glimmer
656
719
  end
657
720
  alias getData get_data # for compatibility with SWT APIs
658
721
  alias data get_data # for compatibility with SWT APIs
722
+
723
+ def shell_proxy
724
+ drawable.shell_proxy
725
+ end
659
726
 
727
+ def respond_to?(method_name, *args, &block)
728
+ options = args.last if args.last.is_a?(Hash)
729
+ super_invocation = options && options[:super]
730
+ if !super_invocation && has_attribute?(method_name)
731
+ true
732
+ else
733
+ result = super
734
+ return true if result
735
+ can_handle_observation_request?(method_name)
736
+ end
737
+ end
738
+
660
739
  def method_missing(method_name, *args, &block)
661
740
  if method_name.to_s.end_with?('=')
662
741
  set_attribute(method_name, *args)
663
742
  elsif has_attribute?(method_name)
664
743
  get_attribute(method_name)
665
- else # TODO support proxying calls to handle_observation_request for listeners just like WidgetProxy
744
+ elsif block && can_handle_observation_request?(method_name)
745
+ handle_observation_request(method_name, &block)
746
+ else
666
747
  super
667
748
  end
668
749
  end
669
750
 
670
- def respond_to?(method_name, *args, &block)
671
- options = args.last if args.last.is_a?(Hash)
672
- super_invocation = options && options[:super]
673
- if !super_invocation && has_attribute?(method_name)
674
- true
675
- else
676
- super
677
- end
751
+ def deregister_drag_listeners
752
+ @on_drag_detected&.deregister
753
+ @on_drag_detected = nil
754
+ @drawable_on_mouse_move&.deregister
755
+ @drawable_on_mouse_move = nil
756
+ @drawable_on_mouse_up&.deregister
757
+ @drawable_on_mouse_up = nil
678
758
  end
679
-
759
+
760
+ # Enables dragging for drag and move within parent widget
761
+ # drag_and_move and drag_source are mutually exclusive
762
+ # if shape had drag_source true, it is disabled by deregistering its listeners
680
763
  def drag_and_move=(drag_and_move_value)
764
+ deregister_drag_listeners if @drag_source
681
765
  drag_and_move_old_value = @drag_and_move
682
766
  @drag_and_move = drag_and_move_value
683
767
  if @drag_and_move && !drag_and_move_old_value
684
- @on_drag_detected = handle_observation_request('on_drag_detected') do |event|
768
+ @on_drag_detected ||= handle_observation_request('on_drag_detected') do |event|
685
769
  Shape.dragging = true
686
770
  Shape.dragging_x = event.x
687
771
  Shape.dragging_y = event.y
772
+ Shape.drop_shape_handling_count = 0
688
773
  Shape.dragged_shape = self
689
774
  Shape.dragged_shape_original_x = x
690
775
  Shape.dragged_shape_original_y = y
691
776
  end
692
- @drawable_on_mouse_move = drawable.handle_observation_request('on_mouse_move') do |event|
693
- if Shape.dragging && Shape.dragged_shape == self
777
+ @drawable_on_mouse_move ||= drawable.handle_observation_request('on_mouse_move') do |event|
778
+ if Shape.dragging && Shape.dragged_shape.equal?(self)
694
779
  Shape.dragged_shape.move_by((event.x - Shape.dragging_x), (event.y - Shape.dragging_y))
695
780
  Shape.dragging_x = event.x
696
781
  Shape.dragging_y = event.y
697
782
  end
698
783
  end
699
- @drawable_on_mouse_up = drawable.handle_observation_request('on_mouse_up') do |event|
700
- if Shape.dragging && Shape.dragged_shape == self
784
+ @drawable_on_mouse_up ||= drawable.handle_observation_request('on_mouse_up') do |event|
785
+ if Shape.dragging && Shape.dragged_shape.equal?(self)
701
786
  Shape.dragging = false
702
787
  end
703
788
  end
704
789
  elsif !@drag_and_move && drag_and_move_old_value
705
- @on_drag_detected.deregister
706
- @drawable_on_mouse_move.deregister
707
- @drawable_on_mouse_up.deregister
790
+ deregister_drag_listeners
708
791
  end
709
792
  end
710
793
 
@@ -712,44 +795,55 @@ module Glimmer
712
795
  @drag_and_move
713
796
  end
714
797
 
798
+ # Makes shape a drag source (enables dragging for drag and drop)
799
+ # drag_source and drag_and_move are mutually exclusive
800
+ # if shape had drag_and_move true, it is disabled by deregistering its listeners
715
801
  def drag_source=(drag_source_value)
802
+ deregister_drag_listeners if @drag_and_move
716
803
  drag_source_old_value = @drag_source
717
804
  @drag_source = drag_source_value
718
805
  if @drag_source && !drag_source_old_value
719
- @on_drag_detected = handle_observation_request('on_drag_detected') do |event|
806
+ @on_drag_detected ||= handle_observation_request('on_drag_detected') do |event|
720
807
  Shape.dragging = true
721
808
  Shape.dragging_x = event.x
722
809
  Shape.dragging_y = event.y
810
+ Shape.drop_shape_handling_count = 0
723
811
  Shape.dragged_shape = self
724
812
  Shape.dragged_shape_original_x = x
725
813
  Shape.dragged_shape_original_y = y
726
814
  end
727
- @drawable_on_mouse_move = drawable.handle_observation_request('on_mouse_move') do |event|
728
- if Shape.dragging && Shape.dragged_shape == self
815
+ @drawable_on_mouse_move ||= drawable.handle_observation_request('on_mouse_move') do |event|
816
+ if Shape.dragging && Shape.dragged_shape.equal?(self)
729
817
  Shape.dragged_shape.move_by((event.x - Shape.dragging_x), (event.y - Shape.dragging_y))
730
818
  Shape.dragging_x = event.x
731
819
  Shape.dragging_y = event.y
732
820
  end
733
821
  end
734
- @drawable_on_mouse_up = drawable.handle_observation_request('on_mouse_up') do |event|
735
- if Shape.dragging && Shape.dragged_shape == self && !Shape.drop_shapes.detect {|shape| shape.include_with_children?(event.x, event.y, except_child: Shape.dragged_shape)}
736
- Shape.dragging = false
737
- Shape.dragged_shape.x = Shape.dragged_shape_original_x
738
- Shape.dragged_shape.y = Shape.dragged_shape_original_y
739
- Shape.dragged_shape = nil
740
- end
822
+ @drawable_on_mouse_up ||= drawable.handle_observation_request('on_mouse_up') do |event|
823
+ cancel_dragging! if Shape.dragging && Shape.dragged_shape.equal?(self) && !any_potential_drop_targets?(event.x, event.y)
741
824
  end
742
825
  elsif !@drag_source && drag_source_old_value
743
- @on_drag_detected.deregister
744
- @drawable_on_mouse_move.deregister
745
- @drawable_on_mouse_up.deregister
826
+ deregister_drag_listeners
746
827
  end
747
828
  end
748
-
829
+
749
830
  def drag_source
750
831
  @drag_source
751
832
  end
752
833
 
834
+ def any_potential_drop_targets?(x, y)
835
+ drawable.drop_shapes.any? { |shape| shape.include_with_children?(x, y, except_shape: Shape.dragged_shape) }
836
+ end
837
+
838
+ def cancel_dragging!
839
+ Shape.dragging = false
840
+ if Shape.dragged_shape
841
+ Shape.dragged_shape.x = Shape.dragged_shape_original_x
842
+ Shape.dragged_shape.y = Shape.dragged_shape_original_y
843
+ Shape.dragged_shape = nil
844
+ end
845
+ end
846
+
753
847
  def pattern(*args, type: nil)
754
848
  instance_variable_name = "@#{type}_pattern"
755
849
  the_pattern = instance_variable_get(instance_variable_name)
@@ -772,7 +866,11 @@ module Glimmer
772
866
  end
773
867
 
774
868
  def dispose(dispose_images: true, dispose_patterns: true, redraw: true)
775
- shapes.each { |shape| shape.is_a?(Shape::Path) && shape.dispose } # TODO look into why I'm only disposing paths
869
+ return if drawable.respond_to?(:shell_proxy) && drawable&.shell_proxy&.last_shell_closing?
870
+ return if @disposed
871
+ @disposed = true
872
+ deregister_drag_listeners
873
+ @widget_listener_proxies&.each(&:deregister)
776
874
  if dispose_patterns
777
875
  @background_pattern&.dispose
778
876
  @background_pattern = nil
@@ -783,7 +881,10 @@ module Glimmer
783
881
  @image&.dispose
784
882
  @image = nil
785
883
  end
884
+ shapes.dup.each { |shape| shape.dispose(dispose_images: dispose_images, dispose_patterns: dispose_patterns, redraw: false) }
786
885
  @parent.shapes.delete(self)
886
+ drawable.drop_shapes.delete(self)
887
+ @on_shape_disposed_handlers&.each {|handler| handler.call(self)} # TODO pass a custom event argument to handler
787
888
  drawable.redraw if redraw && !drawable.is_a?(ImageProxy)
788
889
  end
789
890
 
@@ -901,7 +1002,9 @@ module Glimmer
901
1002
  @calculated_args ||= calculate_args!
902
1003
  unless container?
903
1004
  # 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
904
- paint_event.gc.send(@method_name, *@calculated_args) unless (parent.is_a?(Shape) && !parent.calculated_args?)
1005
+ passed_args = @calculated_args.dup
1006
+ passed_args[0] = passed_args[0].to_java(:int) if @method_name == 'drawPolyline' # a weird fix needed for Linux JRuby 9.3.1.0 only (seems to lack a feature from Mac JRuby that automatically converts to appropriate java array type)
1007
+ paint_event.gc.send(@method_name, *passed_args) unless (parent.is_a?(Shape) && !parent.calculated_args?)
905
1008
  @original_gc_properties.each do |method_name, value|
906
1009
  paint_event.gc.send(method_name, value)
907
1010
  end
@@ -924,7 +1027,7 @@ module Glimmer
924
1027
  old_extent = @extent
925
1028
  if ['text', 'string'].include?(@name)
926
1029
  extent_args = [string]
927
- extent_flags = SWTProxy[:draw_transparent] if current_parameter_name?(:is_transparent) && is_transparent
1030
+ extent_flags = SWTProxy[:draw_transparent, :draw_delimiter] if current_parameter_name?(:is_transparent) && is_transparent
928
1031
  extent_flags = flags if current_parameter_name?(:flags)
929
1032
  extent_args << extent_flags unless extent_flags.nil?
930
1033
  self.extent = paint_event.gc.send("#{@name}Extent", *extent_args)
@@ -935,10 +1038,10 @@ module Glimmer
935
1038
  end
936
1039
  end
937
1040
 
938
- def expanded_shapes
1041
+ def expanded_shapes(except_shape: nil)
939
1042
  if shapes.to_a.any?
940
1043
  shapes.map do |shape|
941
- [shape] + shape.expanded_shapes
1044
+ shape.equal?(except_shape) ? [] : ([shape] + shape.expanded_shapes(except_shape: except_shape))
942
1045
  end.flatten
943
1046
  else
944
1047
  []
@@ -946,7 +1049,6 @@ module Glimmer
946
1049
  end
947
1050
 
948
1051
  def calculated_args_changed!(children: true)
949
- # TODO add a children: true option to enable setting to false to avoid recalculating children args
950
1052
  @calculated_args = nil
951
1053
  shapes.each(&:calculated_args_changed!) if children
952
1054
  end
@@ -980,7 +1082,6 @@ module Glimmer
980
1082
 
981
1083
  # args translated to absolute coordinates
982
1084
  def calculate_args!
983
- # TODO add conditions for parent having default width/height too
984
1085
  return @args if parent.is_a?(Drawable) && !default_x? && !default_y? && !default_width? && !default_height? && !max_width? && !max_height?
985
1086
  calculated_args_dependencies = [
986
1087
  x,
@@ -68,6 +68,11 @@ module Glimmer
68
68
  instance # ensure instance
69
69
  @thread
70
70
  end
71
+
72
+ # Current custom widgets, shells, and shapes being rendered. Useful to yoke all observers evaluated during rendering of their custom widgets/shells/shapes for automatical disposal on_widget_disposed/on_shape_disposed
73
+ def current_custom_widgets_and_shapes
74
+ @current_custom_widgets_and_shapes ||= []
75
+ end
71
76
  end
72
77
 
73
78
  # SWT Display object wrapped
@@ -160,21 +165,21 @@ module Glimmer
160
165
  @swt_display.isDisposed
161
166
  end
162
167
 
163
- def method_missing(method, *args, &block)
164
- if can_handle_observation_request?(method)
165
- handle_observation_request(method, &block)
168
+ def method_missing(method_name, *args, &block)
169
+ if block && can_handle_observation_request?(method_name)
170
+ handle_observation_request(method_name, &block)
166
171
  else
167
- swt_display.send(method, *args, &block)
172
+ swt_display.send(method_name, *args, &block)
168
173
  end
169
174
  rescue => e
170
- Glimmer::Config.logger.debug {"Neither DisplayProxy nor #{swt_display.class.name} can handle the method ##{method}"}
175
+ Glimmer::Config.logger.debug {"Neither DisplayProxy nor #{swt_display.class.name} can handle the method ##{method_name}"}
171
176
  super
172
177
  end
173
178
 
174
- def respond_to?(method, *args, &block)
179
+ def respond_to?(method_name, *args, &block)
175
180
  super ||
176
- can_handle_observation_request?(method) ||
177
- swt_display.respond_to?(method, *args, &block)
181
+ can_handle_observation_request?(method_name) ||
182
+ swt_display.respond_to?(method_name, *args, &block)
178
183
  end
179
184
 
180
185
  def can_handle_observation_request?(observation_request)
@@ -195,7 +200,7 @@ module Glimmer
195
200
  if observation_request.start_with?('on_swt_')
196
201
  constant_name = observation_request.sub(/^on_swt_/, '')
197
202
  swt_event_reg = add_swt_event_filter(constant_name, &block)
198
- Glimmer::UI::CustomWidget.current_custom_widgets.last&.observer_registrations&.push(swt_event_reg)
203
+ DisplayProxy.current_custom_widgets_and_shapes.last&.observer_registrations&.push(swt_event_reg)
199
204
  swt_event_reg
200
205
  elsif observation_request.start_with?('on_')
201
206
  event_name = observation_request.sub(/^on_/, '')
@@ -205,7 +210,7 @@ module Glimmer
205
210
  menu_item = system_menu.getItems.find {|menu_item| menu_item.getID == SWTProxy["ID_#{event_name.upcase}"]}
206
211
  listener = ConcreteListener.new(&block)
207
212
  display_mac_event_registration = menu_item.addListener(SWTProxy[:Selection], listener)
208
- Glimmer::UI::CustomWidget.current_custom_widgets.last&.observer_registrations&.push(display_mac_event_registration)
213
+ DisplayProxy.current_custom_widgets_and_shapes.last&.observer_registrations&.push(display_mac_event_registration)
209
214
  display_mac_event_registration
210
215
  end
211
216
  end
@@ -197,15 +197,15 @@ module Glimmer
197
197
  end
198
198
  end
199
199
 
200
- def method_missing(method, *args, &block)
201
- swt_image.send(method, *args, &block)
200
+ def method_missing(method_name, *args, &block)
201
+ swt_image.send(method_name, *args, &block)
202
202
  rescue => e
203
- Glimmer::Config.logger.debug {"Neither ImageProxy nor #{swt_image.class.name} can handle the method ##{method}"}
203
+ Glimmer::Config.logger.debug {"Neither ImageProxy nor #{swt_image.class.name} can handle the method ##{method_name}"}
204
204
  super
205
205
  end
206
206
 
207
- def respond_to?(method, *args, &block)
208
- super || swt_image.respond_to?(method, *args, &block)
207
+ def respond_to?(method_name, *args, &block)
208
+ super || swt_image.respond_to?(method_name, *args, &block)
209
209
  end
210
210
  end
211
211
  end
@@ -80,23 +80,23 @@ module Glimmer
80
80
  end
81
81
  end
82
82
 
83
- def method_missing(method, *args, &block)
83
+ def method_missing(method_name, *args, &block)
84
84
  DisplayProxy.instance.auto_exec do
85
- swt_widget.send(method, *args, &block)
85
+ swt_widget.send(method_name, *args, &block)
86
86
  end
87
87
  rescue => e
88
88
  begin
89
89
  super
90
90
  rescue Exception => inner_error
91
- Glimmer::Config.logger.error {"Neither MessageBoxProxy nor #{swt_widget.class.name} can handle the method ##{method}"}
91
+ Glimmer::Config.logger.error {"Neither MessageBoxProxy nor #{swt_widget.class.name} can handle the method ##{method_name}"}
92
92
  Glimmer::Config.logger.error {e.full_message}
93
93
  raise inner_error
94
94
  end
95
95
  end
96
96
 
97
- def respond_to?(method, *args, &block)
97
+ def respond_to?(method_name, *args, &block)
98
98
  super ||
99
- swt_widget.respond_to?(method, *args, &block)
99
+ swt_widget.respond_to?(method_name, *args, &block)
100
100
  end
101
101
  end
102
102
  end
@@ -0,0 +1,55 @@
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
+ module Glimmer
23
+ module SWT
24
+ # Proxy for widget listeners
25
+ #
26
+ # Follows the Proxy Design Pattern
27
+ class ShapeListenerProxy
28
+
29
+ attr_reader :shape, :observation_request, :widget_listener_proxy
30
+
31
+ def initialize(shape: nil, drawable: nil, shape_listener_block: nil, observation_request: nil, widget_listener_proxy: nil)
32
+ @shape = shape
33
+ @drawable = drawable
34
+ @shape_listener_block = shape_listener_block
35
+ @observation_request = observation_request
36
+ @widget_listener_proxy = widget_listener_proxy
37
+ end
38
+
39
+ # Deregisters shape listener
40
+ def deregister
41
+ if @observation_request == 'on_drop'
42
+ @widget_listener_proxy.deregister
43
+ @shape.widget_listener_proxies.delete(@widget_listener_proxy)
44
+ @drawable.drop_shapes.delete(shape)
45
+ elsif @observation_request == 'on_shape_disposed'
46
+ @shape.remove_shape_disposed_listener(@shape_listener_block)
47
+ else
48
+ @widget_listener_proxy.deregister
49
+ @shape.widget_listener_proxies.delete(@widget_listener_proxy)
50
+ end
51
+ end
52
+ alias unregister deregister # TODO consider dropping unregister (and in Observer too)
53
+ end
54
+ end
55
+ end
@@ -88,7 +88,7 @@ module Glimmer
88
88
  end
89
89
  on_widget_disposed do
90
90
  @last_shell_closing = true if @display.shells.count == 1 && @display.shells.first == @swt_widget
91
- clear_shapes
91
+ clear_shapes unless @last_shell_closing
92
92
  end
93
93
  @display ||= @swt_widget.getDisplay
94
94
  end
@@ -111,14 +111,14 @@ module Glimmer
111
111
  begin
112
112
  super
113
113
  rescue Exception => inner_e
114
- Glimmer::Config.logger.error {"Neither TransformProxy nor #{@swt_transform.class.name} can handle the method ##{method}"}
114
+ Glimmer::Config.logger.error {"Neither TransformProxy nor #{@swt_transform.class.name} can handle the method ##{method_name}"}
115
115
  Glimmer::Config.logger.error {e.full_message}
116
116
  end
117
117
  end
118
118
 
119
- def respond_to?(method, *args, &block)
119
+ def respond_to?(method_name, *args, &block)
120
120
  super ||
121
- @swt_transform.respond_to?(method, *args, &block)
121
+ @swt_transform.respond_to?(method_name, *args, &block)
122
122
  end
123
123
  end
124
124
  end
@@ -41,12 +41,12 @@ module Glimmer
41
41
  @swt_widget = display_proxy.getSystemTray
42
42
  end
43
43
 
44
- def method_missing(method, *args, &block)
45
- @swt_widget.send(method, *args, &block)
44
+ def method_missing(method_name, *args, &block)
45
+ @swt_widget.send(method_name, *args, &block)
46
46
  end
47
47
 
48
- def respond_to?(method, *args, &block)
49
- super || @swt_widget.respond_to?(method, *args, &block)
48
+ def respond_to?(method_name, *args, &block)
49
+ super || @swt_widget.respond_to?(method_name, *args, &block)
50
50
  end
51
51
 
52
52
  def post_initialize_child(child)