glimmer-dsl-swt 4.22.0.0 → 4.22.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +191 -169
  3. data/README.md +5 -5
  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 +98 -20
  8. data/docs/reference/GLIMMER_SAMPLES.md +13 -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 +2 -1
  13. data/lib/glimmer/dsl/swt/observe_expression.rb +2 -1
  14. data/lib/glimmer/dsl/swt/transform_expression.rb +1 -1
  15. data/lib/glimmer/launcher.rb +15 -14
  16. data/lib/glimmer/rake_task/scaffold.rb +2 -14
  17. data/lib/glimmer/swt/color_proxy.rb +5 -5
  18. data/lib/glimmer/swt/custom/drawable.rb +4 -0
  19. data/lib/glimmer/swt/custom/shape/line.rb +0 -1
  20. data/lib/glimmer/swt/custom/shape/path.rb +2 -2
  21. data/lib/glimmer/swt/custom/shape/path_segment.rb +2 -2
  22. data/lib/glimmer/swt/custom/shape/point.rb +8 -1
  23. data/lib/glimmer/swt/custom/shape.rb +170 -69
  24. data/lib/glimmer/swt/display_proxy.rb +15 -10
  25. data/lib/glimmer/swt/image_proxy.rb +5 -5
  26. data/lib/glimmer/swt/message_box_proxy.rb +5 -5
  27. data/lib/glimmer/swt/shape_listener_proxy.rb +55 -0
  28. data/lib/glimmer/swt/transform_proxy.rb +3 -3
  29. data/lib/glimmer/swt/tray_proxy.rb +4 -4
  30. data/lib/glimmer/swt/widget_proxy.rb +5 -7
  31. data/lib/glimmer/ui/custom_shape.rb +34 -10
  32. data/lib/glimmer/ui/custom_widget.rb +3 -8
  33. data/lib/glimmer-dsl-swt.rb +6 -2
  34. data/samples/elaborate/klondike_solitaire/model/column_pile.rb +0 -1
  35. data/samples/elaborate/klondike_solitaire/view/column_pile.rb +3 -16
  36. data/samples/elaborate/klondike_solitaire/view/dealing_pile.rb +1 -1
  37. data/samples/elaborate/klondike_solitaire/view/dealt_pile.rb +12 -5
  38. data/samples/elaborate/klondike_solitaire/view/empty_playing_card.rb +2 -1
  39. data/samples/elaborate/klondike_solitaire/view/foundation_pile.rb +2 -2
  40. data/samples/elaborate/klondike_solitaire/view/hidden_playing_card.rb +2 -2
  41. data/samples/elaborate/klondike_solitaire/view/klondike_solitaire_menu_bar.rb +60 -0
  42. data/samples/elaborate/klondike_solitaire/view/playing_card.rb +3 -2
  43. data/samples/elaborate/klondike_solitaire.rb +13 -55
  44. data/samples/elaborate/mandelbrot_fractal.rb +3 -1
  45. data/samples/elaborate/quarto/model/game.rb +124 -0
  46. data/samples/elaborate/quarto/model/piece/cube.rb +31 -0
  47. data/samples/elaborate/quarto/model/piece/cylinder.rb +31 -0
  48. data/samples/elaborate/quarto/model/piece.rb +70 -0
  49. data/samples/elaborate/quarto/view/available_pieces_area.rb +72 -0
  50. data/samples/elaborate/quarto/view/board.rb +65 -0
  51. data/samples/elaborate/quarto/view/cell.rb +85 -0
  52. data/samples/elaborate/quarto/view/cube.rb +73 -0
  53. data/samples/elaborate/quarto/view/cylinder.rb +72 -0
  54. data/samples/elaborate/quarto/view/message_box_panel.rb +114 -0
  55. data/samples/elaborate/quarto/view/piece.rb +56 -0
  56. data/samples/elaborate/quarto/view/selected_piece_area.rb +69 -0
  57. data/samples/elaborate/quarto.rb +190 -0
  58. data/samples/hello/hello_custom_widget.rb +23 -5
  59. metadata +17 -23
  60. 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
+ observer_registration = nil
682
+ shape_block = lambda do |event|
683
+ if @disposed
684
+ observer_registration.deregister
685
+ @widget_listener_proxies.delete(observer_registration)
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
@@ -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)