glimmer-dsl-swt 4.22.0.0 → 4.22.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +207 -169
  3. data/README.md +10 -10
  4. data/RUBY_VERSION +1 -1
  5. data/VERSION +1 -1
  6. data/docs/reference/GLIMMER_COMMAND.md +21 -7
  7. data/docs/reference/GLIMMER_CONFIGURATION.md +14 -3
  8. data/docs/reference/GLIMMER_GIRB.md +1 -1
  9. data/docs/reference/GLIMMER_GUI_DSL_SYNTAX.md +743 -113
  10. data/docs/reference/GLIMMER_SAMPLES.md +22 -8
  11. data/glimmer-dsl-swt.gemspec +0 -0
  12. data/lib/ext/glimmer/config.rb +41 -24
  13. data/lib/glimmer/data_binding/observable_widget.rb +6 -6
  14. data/lib/glimmer/data_binding/widget_binding.rb +2 -1
  15. data/lib/glimmer/dsl/swt/dsl.rb +1 -1
  16. data/lib/glimmer/dsl/swt/observe_expression.rb +2 -1
  17. data/lib/glimmer/dsl/swt/shape_expression.rb +1 -0
  18. data/lib/glimmer/dsl/swt/shine_data_binding_expression.rb +3 -8
  19. data/lib/glimmer/dsl/swt/transform_expression.rb +1 -1
  20. data/lib/glimmer/launcher.rb +16 -15
  21. data/lib/glimmer/rake_task/scaffold.rb +5 -16
  22. data/lib/glimmer/swt/color_proxy.rb +5 -5
  23. data/lib/glimmer/swt/custom/drawable.rb +4 -0
  24. data/lib/glimmer/swt/custom/shape/line.rb +0 -1
  25. data/lib/glimmer/swt/custom/shape/path.rb +2 -2
  26. data/lib/glimmer/swt/custom/shape/path_segment.rb +2 -2
  27. data/lib/glimmer/swt/custom/shape/point.rb +8 -1
  28. data/lib/glimmer/swt/custom/shape.rb +171 -69
  29. data/lib/glimmer/swt/display_proxy.rb +15 -10
  30. data/lib/glimmer/swt/image_proxy.rb +5 -5
  31. data/lib/glimmer/swt/message_box_proxy.rb +5 -5
  32. data/lib/glimmer/swt/shape_listener_proxy.rb +55 -0
  33. data/lib/glimmer/swt/shell_proxy.rb +1 -0
  34. data/lib/glimmer/swt/transform_proxy.rb +3 -3
  35. data/lib/glimmer/swt/tray_proxy.rb +4 -4
  36. data/lib/glimmer/swt/widget_proxy.rb +5 -7
  37. data/lib/glimmer/ui/custom_shape.rb +34 -10
  38. data/lib/glimmer/ui/custom_widget.rb +3 -8
  39. data/lib/glimmer-dsl-swt.rb +6 -2
  40. data/samples/elaborate/klondike_solitaire/model/column_pile.rb +0 -1
  41. data/samples/elaborate/klondike_solitaire/view/column_pile.rb +3 -16
  42. data/samples/elaborate/klondike_solitaire/view/dealing_pile.rb +1 -1
  43. data/samples/elaborate/klondike_solitaire/view/dealt_pile.rb +12 -5
  44. data/samples/elaborate/klondike_solitaire/view/empty_playing_card.rb +2 -1
  45. data/samples/elaborate/klondike_solitaire/view/foundation_pile.rb +2 -2
  46. data/samples/elaborate/klondike_solitaire/view/hidden_playing_card.rb +2 -2
  47. data/samples/elaborate/klondike_solitaire/view/klondike_solitaire_menu_bar.rb +60 -0
  48. data/samples/elaborate/klondike_solitaire/view/playing_card.rb +3 -2
  49. data/samples/elaborate/klondike_solitaire.rb +13 -55
  50. data/samples/elaborate/mandelbrot_fractal.rb +3 -1
  51. data/samples/elaborate/quarto/model/game.rb +124 -0
  52. data/samples/elaborate/quarto/model/piece/cube.rb +31 -0
  53. data/samples/elaborate/quarto/model/piece/cylinder.rb +31 -0
  54. data/samples/elaborate/quarto/model/piece.rb +70 -0
  55. data/samples/elaborate/quarto/view/available_pieces_area.rb +72 -0
  56. data/samples/elaborate/quarto/view/board.rb +65 -0
  57. data/samples/elaborate/quarto/view/cell.rb +85 -0
  58. data/samples/elaborate/quarto/view/cube.rb +73 -0
  59. data/samples/elaborate/quarto/view/cylinder.rb +72 -0
  60. data/samples/elaborate/quarto/view/message_box_panel.rb +114 -0
  61. data/samples/elaborate/quarto/view/piece.rb +56 -0
  62. data/samples/elaborate/quarto/view/selected_piece_area.rb +69 -0
  63. data/samples/elaborate/quarto.rb +188 -0
  64. data/samples/hello/hello_canvas_data_binding.rb +7 -7
  65. data/samples/hello/hello_custom_widget.rb +23 -5
  66. metadata +35 -40
  67. 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,20 +228,47 @@ 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)
271
+ # TODO avoid Matrix usage directly by relying on SWT Transform#invert method instead (much simpler)
246
272
  matrix = Matrix[[inverse_transform_array[0], inverse_transform_array[1]], [inverse_transform_array[2], inverse_transform_array[3]]]
247
273
  result = matrix * Matrix.column_vector([x, y])
248
274
  x, y = result.to_a.flatten
@@ -315,6 +341,7 @@ module Glimmer
315
341
  end
316
342
 
317
343
  def content(&block)
344
+ # TODO consider supporting adding content without redraw (redraw: false)
318
345
  Glimmer::SWT::DisplayProxy.instance.auto_exec do
319
346
  Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::SWT::ShapeExpression.new, @name, &block)
320
347
  calculated_args_changed!(children: false)
@@ -601,17 +628,27 @@ module Glimmer
601
628
  end
602
629
 
603
630
  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)
631
+ observation_request = observation_request.to_s
632
+ observation_request.start_with?('on_') &&
633
+ (
634
+ observation_request == 'on_shape_disposed' ||
635
+ (
636
+ drawable.respond_to?(:can_handle_observation_request?) &&
637
+ drawable.can_handle_observation_request?(observation_request)
638
+ )
639
+ )
640
+ end
641
+
642
+ def handle_observation_request(observation_request, source_observation_request: nil, &block)
643
+ if observation_request.to_s == 'on_shape_disposed'
644
+ @on_shape_disposed_handlers ||= []
645
+ @on_shape_disposed_handlers << block
646
+ return ShapeListenerProxy.new(shape: self, drawable: drawable, shape_listener_block: block, observation_request: 'on_shape_disposed')
610
647
  end
611
648
  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)
649
+ drawable.drop_shapes << self
650
+ handle_observation_request('on_mouse_up', source_observation_request: 'on_drop') do |event|
651
+ if Shape.dragging && include_with_children?(event.x, event.y, except_shape: Shape.dragged_shape)
615
652
  drop_event = DropEvent.new(
616
653
  doit: true,
617
654
  dragged_shape: Shape.dragged_shape,
@@ -619,29 +656,56 @@ module Glimmer
619
656
  dragged_shape_original_y: Shape.dragged_shape_original_y,
620
657
  dragging_x: Shape.dragging_x,
621
658
  dragging_y: Shape.dragging_y,
622
- drop_shapes: Shape.drop_shapes,
659
+ drop_shapes: drawable.drop_shapes,
623
660
  x: event.x,
624
661
  y: event.y
625
662
  )
626
663
  begin
627
664
  block.call(drop_event)
628
665
  rescue => e
629
- Glimmer::Config.logger.error e.full_message
666
+ Glimmer::Config.logger.error {e.full_message}
630
667
  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
668
+ if drop_event.doit
669
+ Shape.dragging = false
670
+ Shape.dragged_shape = nil
671
+ elsif Shape.drop_shape_handling_count.to_i >= drawable.drop_shapes.count && Shape.dragged_shape
672
+ cancel_dragging!
635
673
  end
636
- Shape.dragged_shape = nil
674
+ end
675
+ else
676
+ if Shape.drop_shape_handling_count.to_i >= drawable.drop_shapes.count
677
+ cancel_dragging!
637
678
  end
638
679
  end
639
680
  end
640
681
  else
641
- drawable.handle_observation_request(observation_request, &shape_block)
682
+ widget_listener_proxy = nil
683
+ shape_block = lambda do |event|
684
+ if @disposed
685
+ widget_listener_proxy.deregister
686
+ @widget_listener_proxies.delete(widget_listener_proxy)
687
+ else
688
+ Shape.drop_shape_handling_count += 1 if source_observation_request == 'on_drop' && event.x == Shape.dragging_x && event.y == Shape.dragging_y
689
+ if !event.respond_to?(:x) || !event.respond_to?(:y) || include_with_children?(event.x, event.y)
690
+ block.call(event)
691
+ elsif source_observation_request == 'on_drop' && Shape.drop_shape_handling_count.to_i >= drawable.drop_shapes.count
692
+ cancel_dragging!
693
+ end
694
+ end
695
+ end
696
+ widget_listener_proxy = drawable.respond_to?(:handle_observation_request) && drawable.handle_observation_request(observation_request, &shape_block)
697
+ @widget_listener_proxies ||= []
698
+ if widget_listener_proxy
699
+ @widget_listener_proxies << widget_listener_proxy
700
+ ShapeListenerProxy.new(shape: self, drawable: drawable, shape_listener_block: shape_block, observation_request: source_observation_request || observation_request, widget_listener_proxy: widget_listener_proxy)
701
+ end
642
702
  end
643
703
  end
644
704
 
705
+ def remove_shape_disposed_listener(listener_block)
706
+ @on_shape_disposed_handlers.delete(listener_block)
707
+ end
708
+
645
709
  # Sets data just like SWT widgets
646
710
  def set_data(key=nil, value)
647
711
  @data ||= {}
@@ -656,55 +720,75 @@ module Glimmer
656
720
  end
657
721
  alias getData get_data # for compatibility with SWT APIs
658
722
  alias data get_data # for compatibility with SWT APIs
723
+
724
+ def shell_proxy
725
+ drawable.shell_proxy
726
+ end
659
727
 
728
+ def respond_to?(method_name, *args, &block)
729
+ options = args.last if args.last.is_a?(Hash)
730
+ super_invocation = options && options[:super]
731
+ if !super_invocation && has_attribute?(method_name)
732
+ true
733
+ else
734
+ result = super
735
+ return true if result
736
+ can_handle_observation_request?(method_name)
737
+ end
738
+ end
739
+
660
740
  def method_missing(method_name, *args, &block)
661
741
  if method_name.to_s.end_with?('=')
662
742
  set_attribute(method_name, *args)
663
743
  elsif has_attribute?(method_name)
664
744
  get_attribute(method_name)
665
- else # TODO support proxying calls to handle_observation_request for listeners just like WidgetProxy
745
+ elsif block && can_handle_observation_request?(method_name)
746
+ handle_observation_request(method_name, &block)
747
+ else
666
748
  super
667
749
  end
668
750
  end
669
751
 
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
752
+ def deregister_drag_listeners
753
+ @on_drag_detected&.deregister
754
+ @on_drag_detected = nil
755
+ @drawable_on_mouse_move&.deregister
756
+ @drawable_on_mouse_move = nil
757
+ @drawable_on_mouse_up&.deregister
758
+ @drawable_on_mouse_up = nil
678
759
  end
679
-
760
+
761
+ # Enables dragging for drag and move within parent widget
762
+ # drag_and_move and drag_source are mutually exclusive
763
+ # if shape had drag_source true, it is disabled by deregistering its listeners
680
764
  def drag_and_move=(drag_and_move_value)
765
+ deregister_drag_listeners if @drag_source
681
766
  drag_and_move_old_value = @drag_and_move
682
767
  @drag_and_move = drag_and_move_value
683
768
  if @drag_and_move && !drag_and_move_old_value
684
- @on_drag_detected = handle_observation_request('on_drag_detected') do |event|
769
+ @on_drag_detected ||= handle_observation_request('on_drag_detected') do |event|
685
770
  Shape.dragging = true
686
771
  Shape.dragging_x = event.x
687
772
  Shape.dragging_y = event.y
773
+ Shape.drop_shape_handling_count = 0
688
774
  Shape.dragged_shape = self
689
775
  Shape.dragged_shape_original_x = x
690
776
  Shape.dragged_shape_original_y = y
691
777
  end
692
- @drawable_on_mouse_move = drawable.handle_observation_request('on_mouse_move') do |event|
693
- if Shape.dragging && Shape.dragged_shape == self
778
+ @drawable_on_mouse_move ||= drawable.handle_observation_request('on_mouse_move') do |event|
779
+ if Shape.dragging && Shape.dragged_shape.equal?(self)
694
780
  Shape.dragged_shape.move_by((event.x - Shape.dragging_x), (event.y - Shape.dragging_y))
695
781
  Shape.dragging_x = event.x
696
782
  Shape.dragging_y = event.y
697
783
  end
698
784
  end
699
- @drawable_on_mouse_up = drawable.handle_observation_request('on_mouse_up') do |event|
700
- if Shape.dragging && Shape.dragged_shape == self
785
+ @drawable_on_mouse_up ||= drawable.handle_observation_request('on_mouse_up') do |event|
786
+ if Shape.dragging && Shape.dragged_shape.equal?(self)
701
787
  Shape.dragging = false
702
788
  end
703
789
  end
704
790
  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
791
+ deregister_drag_listeners
708
792
  end
709
793
  end
710
794
 
@@ -712,44 +796,55 @@ module Glimmer
712
796
  @drag_and_move
713
797
  end
714
798
 
799
+ # Makes shape a drag source (enables dragging for drag and drop)
800
+ # drag_source and drag_and_move are mutually exclusive
801
+ # if shape had drag_and_move true, it is disabled by deregistering its listeners
715
802
  def drag_source=(drag_source_value)
803
+ deregister_drag_listeners if @drag_and_move
716
804
  drag_source_old_value = @drag_source
717
805
  @drag_source = drag_source_value
718
806
  if @drag_source && !drag_source_old_value
719
- @on_drag_detected = handle_observation_request('on_drag_detected') do |event|
807
+ @on_drag_detected ||= handle_observation_request('on_drag_detected') do |event|
720
808
  Shape.dragging = true
721
809
  Shape.dragging_x = event.x
722
810
  Shape.dragging_y = event.y
811
+ Shape.drop_shape_handling_count = 0
723
812
  Shape.dragged_shape = self
724
813
  Shape.dragged_shape_original_x = x
725
814
  Shape.dragged_shape_original_y = y
726
815
  end
727
- @drawable_on_mouse_move = drawable.handle_observation_request('on_mouse_move') do |event|
728
- if Shape.dragging && Shape.dragged_shape == self
816
+ @drawable_on_mouse_move ||= drawable.handle_observation_request('on_mouse_move') do |event|
817
+ if Shape.dragging && Shape.dragged_shape.equal?(self)
729
818
  Shape.dragged_shape.move_by((event.x - Shape.dragging_x), (event.y - Shape.dragging_y))
730
819
  Shape.dragging_x = event.x
731
820
  Shape.dragging_y = event.y
732
821
  end
733
822
  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
823
+ @drawable_on_mouse_up ||= drawable.handle_observation_request('on_mouse_up') do |event|
824
+ cancel_dragging! if Shape.dragging && Shape.dragged_shape.equal?(self) && !any_potential_drop_targets?(event.x, event.y)
741
825
  end
742
826
  elsif !@drag_source && drag_source_old_value
743
- @on_drag_detected.deregister
744
- @drawable_on_mouse_move.deregister
745
- @drawable_on_mouse_up.deregister
827
+ deregister_drag_listeners
746
828
  end
747
829
  end
748
-
830
+
749
831
  def drag_source
750
832
  @drag_source
751
833
  end
752
834
 
835
+ def any_potential_drop_targets?(x, y)
836
+ drawable.drop_shapes.any? { |shape| shape.include_with_children?(x, y, except_shape: Shape.dragged_shape) }
837
+ end
838
+
839
+ def cancel_dragging!
840
+ Shape.dragging = false
841
+ if Shape.dragged_shape
842
+ Shape.dragged_shape.x = Shape.dragged_shape_original_x
843
+ Shape.dragged_shape.y = Shape.dragged_shape_original_y
844
+ Shape.dragged_shape = nil
845
+ end
846
+ end
847
+
753
848
  def pattern(*args, type: nil)
754
849
  instance_variable_name = "@#{type}_pattern"
755
850
  the_pattern = instance_variable_get(instance_variable_name)
@@ -772,7 +867,11 @@ module Glimmer
772
867
  end
773
868
 
774
869
  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
870
+ return if drawable.respond_to?(:shell_proxy) && drawable&.shell_proxy&.last_shell_closing?
871
+ return if @disposed
872
+ @disposed = true
873
+ deregister_drag_listeners
874
+ @widget_listener_proxies&.each(&:deregister)
776
875
  if dispose_patterns
777
876
  @background_pattern&.dispose
778
877
  @background_pattern = nil
@@ -783,7 +882,10 @@ module Glimmer
783
882
  @image&.dispose
784
883
  @image = nil
785
884
  end
885
+ shapes.dup.each { |shape| shape.dispose(dispose_images: dispose_images, dispose_patterns: dispose_patterns, redraw: false) }
786
886
  @parent.shapes.delete(self)
887
+ drawable.drop_shapes.delete(self)
888
+ @on_shape_disposed_handlers&.each {|handler| handler.call(self)} # TODO pass a custom event argument to handler
787
889
  drawable.redraw if redraw && !drawable.is_a?(ImageProxy)
788
890
  end
789
891
 
@@ -901,7 +1003,9 @@ module Glimmer
901
1003
  @calculated_args ||= calculate_args!
902
1004
  unless container?
903
1005
  # 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?)
1006
+ passed_args = @calculated_args.dup
1007
+ 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)
1008
+ paint_event.gc.send(@method_name, *passed_args) unless (parent.is_a?(Shape) && !parent.calculated_args?)
905
1009
  @original_gc_properties.each do |method_name, value|
906
1010
  paint_event.gc.send(method_name, value)
907
1011
  end
@@ -924,7 +1028,7 @@ module Glimmer
924
1028
  old_extent = @extent
925
1029
  if ['text', 'string'].include?(@name)
926
1030
  extent_args = [string]
927
- extent_flags = SWTProxy[:draw_transparent] if current_parameter_name?(:is_transparent) && is_transparent
1031
+ extent_flags = SWTProxy[:draw_transparent, :draw_delimiter] if current_parameter_name?(:is_transparent) && is_transparent
928
1032
  extent_flags = flags if current_parameter_name?(:flags)
929
1033
  extent_args << extent_flags unless extent_flags.nil?
930
1034
  self.extent = paint_event.gc.send("#{@name}Extent", *extent_args)
@@ -935,10 +1039,10 @@ module Glimmer
935
1039
  end
936
1040
  end
937
1041
 
938
- def expanded_shapes
1042
+ def expanded_shapes(except_shape: nil)
939
1043
  if shapes.to_a.any?
940
1044
  shapes.map do |shape|
941
- [shape] + shape.expanded_shapes
1045
+ shape.equal?(except_shape) ? [] : ([shape] + shape.expanded_shapes(except_shape: except_shape))
942
1046
  end.flatten
943
1047
  else
944
1048
  []
@@ -946,7 +1050,6 @@ module Glimmer
946
1050
  end
947
1051
 
948
1052
  def calculated_args_changed!(children: true)
949
- # TODO add a children: true option to enable setting to false to avoid recalculating children args
950
1053
  @calculated_args = nil
951
1054
  shapes.each(&:calculated_args_changed!) if children
952
1055
  end
@@ -980,7 +1083,6 @@ module Glimmer
980
1083
 
981
1084
  # args translated to absolute coordinates
982
1085
  def calculate_args!
983
- # TODO add conditions for parent having default width/height too
984
1086
  return @args if parent.is_a?(Drawable) && !default_x? && !default_y? && !default_width? && !default_height? && !max_width? && !max_height?
985
1087
  calculated_args_dependencies = [
986
1088
  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
@@ -105,6 +105,7 @@ module Glimmer
105
105
  @swt_widget.setLocation(location_x, location_y)
106
106
  end
107
107
  end
108
+ alias center_in_display center_within_display
108
109
 
109
110
  # Opens shell and starts SWT's UI thread event loop
110
111
  def open
@@ -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)