glimmer-dsl-swt 0.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 (79) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +20 -0
  3. data/README.md +47 -0
  4. data/RUBY_VERSION +1 -0
  5. data/VERSION +1 -0
  6. data/bin/girb +10 -0
  7. data/bin/girb_runner.rb +13 -0
  8. data/bin/glimmer +5 -0
  9. data/icons/scaffold_app.icns +0 -0
  10. data/lib/ext/glimmer.rb +13 -0
  11. data/lib/ext/glimmer/config.rb +18 -0
  12. data/lib/glimmer-dsl-swt.rb +12 -0
  13. data/lib/glimmer/data_binding/list_selection_binding.rb +52 -0
  14. data/lib/glimmer/data_binding/model_binding.rb +248 -0
  15. data/lib/glimmer/data_binding/observable.rb +21 -0
  16. data/lib/glimmer/data_binding/observable_array.rb +107 -0
  17. data/lib/glimmer/data_binding/observable_model.rb +108 -0
  18. data/lib/glimmer/data_binding/observable_widget.rb +17 -0
  19. data/lib/glimmer/data_binding/observer.rb +124 -0
  20. data/lib/glimmer/data_binding/shine.rb +23 -0
  21. data/lib/glimmer/data_binding/table_items_binding.rb +56 -0
  22. data/lib/glimmer/data_binding/tree_items_binding.rb +71 -0
  23. data/lib/glimmer/data_binding/widget_binding.rb +33 -0
  24. data/lib/glimmer/dsl/swt/async_exec_expression.rb +14 -0
  25. data/lib/glimmer/dsl/swt/bind_expression.rb +37 -0
  26. data/lib/glimmer/dsl/swt/color_expression.rb +19 -0
  27. data/lib/glimmer/dsl/swt/column_properties_expression.rb +24 -0
  28. data/lib/glimmer/dsl/swt/combo_selection_data_binding_expression.rb +42 -0
  29. data/lib/glimmer/dsl/swt/custom_widget_expression.rb +39 -0
  30. data/lib/glimmer/dsl/swt/data_binding_expression.rb +34 -0
  31. data/lib/glimmer/dsl/swt/dialog_expression.rb +26 -0
  32. data/lib/glimmer/dsl/swt/display_expression.rb +19 -0
  33. data/lib/glimmer/dsl/swt/dsl.rb +34 -0
  34. data/lib/glimmer/dsl/swt/exec_expression.rb +28 -0
  35. data/lib/glimmer/dsl/swt/layout_data_expression.rb +25 -0
  36. data/lib/glimmer/dsl/swt/layout_expression.rb +27 -0
  37. data/lib/glimmer/dsl/swt/list_selection_data_binding_expression.rb +44 -0
  38. data/lib/glimmer/dsl/swt/menu_bar_expression.rb +33 -0
  39. data/lib/glimmer/dsl/swt/menu_expression.rb +32 -0
  40. data/lib/glimmer/dsl/swt/message_box_expression.rb +29 -0
  41. data/lib/glimmer/dsl/swt/observe_expression.rb +32 -0
  42. data/lib/glimmer/dsl/swt/property_expression.rb +22 -0
  43. data/lib/glimmer/dsl/swt/rgb_expression.rb +12 -0
  44. data/lib/glimmer/dsl/swt/rgba_expression.rb +12 -0
  45. data/lib/glimmer/dsl/swt/shell_expression.rb +25 -0
  46. data/lib/glimmer/dsl/swt/swt_expression.rb +25 -0
  47. data/lib/glimmer/dsl/swt/sync_exec_expression.rb +15 -0
  48. data/lib/glimmer/dsl/swt/tab_item_expression.rb +33 -0
  49. data/lib/glimmer/dsl/swt/table_items_data_binding_expression.rb +31 -0
  50. data/lib/glimmer/dsl/swt/tree_items_data_binding_expression.rb +31 -0
  51. data/lib/glimmer/dsl/swt/tree_properties_expression.rb +26 -0
  52. data/lib/glimmer/dsl/swt/widget_expression.rb +35 -0
  53. data/lib/glimmer/dsl/swt/widget_listener_expression.rb +32 -0
  54. data/lib/glimmer/launcher.rb +196 -0
  55. data/lib/glimmer/package.rb +57 -0
  56. data/lib/glimmer/rake_task.rb +62 -0
  57. data/lib/glimmer/scaffold.rb +582 -0
  58. data/lib/glimmer/swt/color_proxy.rb +53 -0
  59. data/lib/glimmer/swt/display_proxy.rb +88 -0
  60. data/lib/glimmer/swt/font_proxy.rb +72 -0
  61. data/lib/glimmer/swt/layout_data_proxy.rb +84 -0
  62. data/lib/glimmer/swt/layout_proxy.rb +82 -0
  63. data/lib/glimmer/swt/menu_proxy.rb +101 -0
  64. data/lib/glimmer/swt/message_box_proxy.rb +48 -0
  65. data/lib/glimmer/swt/packages.rb +13 -0
  66. data/lib/glimmer/swt/shell_proxy.rb +152 -0
  67. data/lib/glimmer/swt/swt_proxy.rb +106 -0
  68. data/lib/glimmer/swt/tab_item_proxy.rb +65 -0
  69. data/lib/glimmer/swt/table_proxy.rb +150 -0
  70. data/lib/glimmer/swt/tree_proxy.rb +120 -0
  71. data/lib/glimmer/swt/widget_listener_proxy.rb +34 -0
  72. data/lib/glimmer/swt/widget_proxy.rb +489 -0
  73. data/lib/glimmer/ui/custom_shell.rb +45 -0
  74. data/lib/glimmer/ui/custom_widget.rb +244 -0
  75. data/lib/glimmer/util/proc_tracker.rb +16 -0
  76. data/vendor/swt/linux/swt.jar +0 -0
  77. data/vendor/swt/mac/swt.jar +0 -0
  78. data/vendor/swt/windows/swt.jar +0 -0
  79. metadata +307 -0
@@ -0,0 +1,53 @@
1
+ require 'glimmer/swt/swt_proxy'
2
+ require 'glimmer/swt/display_proxy'
3
+
4
+ module Glimmer
5
+ module SWT
6
+ # Proxy for org.eclipse.swt.graphics.Color
7
+ #
8
+ # Invoking `#swt_color` returns the SWT color object wrapped by this proxy
9
+ #
10
+ # Follows the Proxy Design Pattern
11
+ class ColorProxy
12
+ include_package 'org.eclipse.swt.graphics'
13
+
14
+ # Initializes a proxy for an SWT Color object
15
+ #
16
+ # Takes a standard color single argument, rgba 3 args, or rgba 4 args
17
+ #
18
+ # A standard color is a string/symbol representing one of the
19
+ # SWT.COLOR_*** constants like SWT.COLOR_RED, but in underscored string
20
+ # format (e.g :color_red).
21
+ # Glimmer can also accept standard color names without the color_ prefix,
22
+ # and it will automatically figure out the SWT.COLOR_*** constant
23
+ # (e.g. :red)
24
+ #
25
+ # rgb is 3 arguments representing Red, Green, Blue numeric values
26
+ #
27
+ # rgba is 4 arguments representing Red, Green, Blue, and Alpha numeric values
28
+ #
29
+ def initialize(*args)
30
+ @args = args
31
+ end
32
+
33
+ def swt_color
34
+ unless @swt_color
35
+ case @args.size
36
+ when 1
37
+ if @args.first.is_a?(String) || @args.first.is_a?(Symbol)
38
+ standard_color = @args.first
39
+ standard_color = "color_#{standard_color}".to_sym unless standard_color.to_s.downcase.include?('color_')
40
+ @swt_color = DisplayProxy.instance.swt_display.getSystemColor(SWTProxy[standard_color])
41
+ else
42
+ @swt_color = @args.first
43
+ end
44
+ when 3..4
45
+ red, green, blue, alpha = @args
46
+ @swt_color = Color.new(DisplayProxy.instance.swt_display, *[red, green, blue, alpha].compact)
47
+ end
48
+ end
49
+ @swt_color
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,88 @@
1
+ require 'glimmer/swt/widget_listener_proxy'
2
+
3
+ module Glimmer
4
+ module SWT
5
+ # Proxy for org.eclipse.swt.widgets.Display
6
+ #
7
+ # Maintains a singleton instance since SWT only supports
8
+ # a single active display at a time.
9
+ #
10
+ # Supports SWT Display's very useful asyncExec and syncExec methods
11
+ # to support proper multi-threaded manipulation of SWT UI objects
12
+ #
13
+ # Invoking `#swt_display` returns the SWT Display object wrapped by this proxy
14
+ #
15
+ # Follows the Proxy Design Pattern
16
+ class DisplayProxy
17
+ include_package 'org.eclipse.swt.widgets'
18
+
19
+ OBSERVED_MENU_ITEMS = ['about', 'preferences']
20
+
21
+ class << self
22
+ # Returns singleton instance
23
+ def instance(*args)
24
+ if @instance.nil? || @instance.swt_display.isDisposed
25
+ @instance = new(*args)
26
+ end
27
+ @instance
28
+ end
29
+ end
30
+
31
+ # SWT Display object wrapped
32
+ attr_reader :swt_display
33
+
34
+ def initialize(*args)
35
+ @swt_display = Display.new(*args)
36
+ end
37
+
38
+ def dispose
39
+ @swt_display.dispose
40
+ end
41
+
42
+ # Executes code block asynchronously with respect to SWT UI thread
43
+ def async_exec(&block)
44
+ @swt_display.asyncExec(&block)
45
+ end
46
+
47
+ # Executes code block synchronously with respect to SWT UI thread
48
+ def sync_exec(&block)
49
+ @swt_display.syncExec(&block)
50
+ end
51
+
52
+ def can_handle_observation_request?(observation_request)
53
+ observation_request = observation_request.to_s
54
+ if observation_request.start_with?('on_event_')
55
+ constant_name = observation_request.sub(/^on_event_/, '')
56
+ SWTProxy.has_constant?(constant_name)
57
+ elsif observation_request.start_with?('on_')
58
+ event_name = observation_request.sub(/^on_/, '')
59
+ OBSERVED_MENU_ITEMS.include?(event_name)
60
+ else
61
+ false
62
+ end
63
+ end
64
+
65
+ def handle_observation_request(observation_request, &block)
66
+ if observation_request.start_with?('on_event_')
67
+ constant_name = observation_request.sub(/^on_event_/, '')
68
+ add_swt_event_listener(constant_name, &block)
69
+ elsif observation_request.start_with?('on_')
70
+ event_name = observation_request.sub(/^on_/, '')
71
+ if OBSERVED_MENU_ITEMS.include?(event_name)
72
+ if OS.mac?
73
+ system_menu = swt_display.getSystemMenu
74
+ menu_item = system_menu.getItems.find {|menu_item| menu_item.getID == SWTProxy["ID_#{event_name.upcase}"]}
75
+ menu_item.addListener(SWTProxy[:Selection], &block)
76
+ end
77
+ end
78
+ end
79
+ end
80
+
81
+ def add_swt_event_listener(swt_constant, &block)
82
+ event_type = SWTProxy[swt_constant]
83
+ @swt_display.addFilter(event_type, &block)
84
+ #WidgetListenerProxy.new(@swt_display.getListeners(event_type).last)
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,72 @@
1
+ require 'glimmer/error'
2
+ require 'glimmer/swt/swt_proxy'
3
+ require 'glimmer/swt/display_proxy'
4
+
5
+ module Glimmer
6
+ module SWT
7
+ # Proxy for org.eclipse.swt.graphics.Font
8
+ #
9
+ # This class is meant to be used with WidgetProxy to manipulate
10
+ # an SWT widget font.
11
+ #
12
+ # It is not meant to create new SWT fonts form scratch without
13
+ # a widget proxy.
14
+ #
15
+ # Invoking `#swt_font` returns the SWT Font object wrapped by this proxy
16
+ #
17
+ # Follows the Proxy Design Pattern
18
+ class FontProxy
19
+ ERROR_INVALID_FONT_STYLE = " is an invalid font style! Valid values are :normal, :bold, and :italic"
20
+ FONT_STYLES = [:normal, :bold, :italic]
21
+
22
+ include_package 'org.eclipse.swt.graphics'
23
+
24
+ attr_reader :widget_proxy, :swt_font
25
+
26
+ # Builds a new font proxy from passed in widget_proxy and font_properties hash,
27
+ #
28
+ # It begins with existing SWT widget font and amends it with font properties.
29
+ #
30
+ # Font properties consist of: :name, :height, and :style (one needed minimum)
31
+ #
32
+ # Style (:style value) can only be one of FontProxy::FONT_STYLES values:
33
+ # that is :normal, :bold, or :italic
34
+ def initialize(widget_proxy, font_properties)
35
+ @widget_proxy = widget_proxy
36
+ detect_invalid_font_property(font_properties)
37
+ font_properties[:style] = SWTProxy[*font_properties[:style]]
38
+ font_data_args = [:name, :height, :style].map do |font_property_name|
39
+ font_properties[font_property_name] || send(font_property_name)
40
+ end
41
+ font_datum = FontData.new(*font_data_args)
42
+ @swt_font = Font.new(DisplayProxy.instance.swt_display, font_datum)
43
+ end
44
+
45
+ def name
46
+ font_datum.getName
47
+ end
48
+
49
+ def height
50
+ font_datum.getHeight
51
+ end
52
+
53
+ def style
54
+ font_datum.getStyle
55
+ end
56
+
57
+ private
58
+
59
+ def font_datum
60
+ @font_datum ||= @widget_proxy.swt_widget.getFont.getFontData[0]
61
+ end
62
+
63
+ def detect_invalid_font_property(font_properties)
64
+ [font_properties[:style]].flatten.select do |style|
65
+ style.is_a?(Symbol) || style.is_a?(String)
66
+ end.each do |style|
67
+ raise Error, style.to_s + ERROR_INVALID_FONT_STYLE if !FONT_STYLES.include?(style.to_sym)
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,84 @@
1
+ require 'glimmer'
2
+ require 'glimmer/swt/swt_proxy'
3
+
4
+ module Glimmer
5
+ module SWT
6
+ # Generic proxy for all SWT layout data objects, such as GridData & RowData
7
+ #
8
+ # This class is meant to be used with an existing WidgetProxy
9
+ # as it figures out the right SWT layout data class name
10
+ # by convention from the parent SWT widget layout class name
11
+ #
12
+ # The convention is:
13
+ # - Start with the parent widget layout package/class name (e.g. org.eclipse.swt.layout.RowLayout)
14
+ # - Replace the word "Layout" with "Data" in the class name
15
+ #
16
+ # Examples of figuring out SWT layout data class:
17
+ # - org.eclipse.swt.layout.RowData for org.eclipse.swt.layout.RowLayout
18
+ # - org.eclipse.swt.layout.GridData for org.eclipse.swt.layout.GridLayout
19
+ #
20
+ # Follows the Proxy Design Pattern
21
+ class LayoutDataProxy
22
+ include_package 'org.eclipse.swt.layout'
23
+
24
+ attr_reader :widget_proxy
25
+ attr_reader :swt_layout_data
26
+
27
+ # Inititalizes with owning widget proxy and layout data arguments
28
+ def initialize(widget_proxy, args)
29
+ @widget_proxy = widget_proxy
30
+ args = SWTProxy.constantify_args(args)
31
+ begin
32
+ @swt_layout_data = swt_layout_data_class.new(*args)
33
+ rescue => e
34
+ Glimmer::Config.logger&.debug "#{e.message}\n#{e.backtrace.join("\n")}"
35
+ @swt_layout_data = args.first if args.count == 1
36
+ end
37
+ @widget_proxy.swt_widget.setLayoutData(@swt_layout_data)
38
+ end
39
+
40
+ # This figures out the right SWT layout data class name
41
+ # by convention from the parent SWT widget layout class name
42
+ #
43
+ # Supports layout data classes in and out of basic SWT library
44
+ #
45
+ # The convention is:
46
+ # - Start with the parent widget layout package/class name (e.g. org.eclipse.swt.layout.RowLayout)
47
+ # - Replace the word "Layout" with "Data" in the class name
48
+ #
49
+ # Examples of figuring out SWT layout data class:
50
+ # - org.eclipse.swt.layout.RowData for org.eclipse.swt.layout.RowLayout
51
+ # - org.eclipse.swt.layout.GridData for org.eclipse.swt.layout.GridLayout
52
+ #
53
+ def swt_layout_data_class
54
+ parent_layout_class_name = @widget_proxy.swt_widget.getParent.getLayout.class.name
55
+ layout_data_class_name = parent_layout_class_name.sub(/Layout$/, 'Data')
56
+ eval(layout_data_class_name)
57
+ end
58
+
59
+ def has_attribute?(attribute_name, *args)
60
+ @swt_layout_data.respond_to?(attribute_setter(attribute_name), args)
61
+ end
62
+
63
+ def set_attribute(attribute_name, *args)
64
+ args = SWTProxy.constantify_args(args)
65
+ if args.first != @swt_layout_data.send(attribute_getter(attribute_name))
66
+ @swt_layout_data.send(attribute_setter(attribute_name), *args)
67
+ @widget_proxy.swt_widget.getShell.pack
68
+ end
69
+ end
70
+
71
+ def get_attribute(attribute_name)
72
+ @swt_layout_data.send(attribute_getter(attribute_name))
73
+ end
74
+
75
+ def attribute_setter(attribute_name)
76
+ "#{attribute_name.to_s.camelcase(:lower)}="
77
+ end
78
+
79
+ def attribute_getter(attribute_name)
80
+ "#{attribute_name.to_s.camelcase(:lower)}"
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,82 @@
1
+ require 'glimmer'
2
+ require 'glimmer/swt/swt_proxy'
3
+
4
+ module Glimmer
5
+ module SWT
6
+ # Proxy for org.eclipse.swt.widgets.Layout
7
+ #
8
+ # This is meant to be used with a WidgetProxy where it will
9
+ # set the layout in the SWT widget upon instantiation.
10
+ #
11
+ # Follows the Proxy Design Pattern
12
+ class LayoutProxy
13
+ attr_reader :widget_proxy, :swt_layout
14
+
15
+ class << self
16
+ include_package 'org.eclipse.swt.layout'
17
+ include_package 'org.eclipse.swt.widgets'
18
+
19
+ def layout_exists?(underscored_layout_name)
20
+ begin
21
+ swt_layout_class_for(underscored_layout_name)
22
+ true
23
+ rescue NameError => e
24
+ false
25
+ end
26
+ end
27
+
28
+ # This supports layouts in and out of basic SWT library
29
+ def swt_layout_class_for(underscored_layout_name)
30
+ swt_layout_name = underscored_layout_name.camelcase(:upper)
31
+ swt_layout_class = eval(swt_layout_name)
32
+ unless swt_layout_class.ancestors.include?(Layout)
33
+ raise NameError, "Class #{swt_layout_class} matching #{underscored_layout_name} is not a subclass of org.eclipse.swt.widgets.Layout"
34
+ end
35
+ swt_layout_class
36
+ rescue => e
37
+ Glimmer::Config.logger&.debug e.message
38
+ # Glimmer::Config.logger&.debug "#{e.message}\n#{e.backtrace.join("\n")}"
39
+ raise e
40
+ end
41
+ end
42
+
43
+ def initialize(underscored_layout_name, widget_proxy, args)
44
+ @underscored_layout_name = underscored_layout_name
45
+ @widget_proxy = widget_proxy
46
+ args = SWTProxy.constantify_args(args)
47
+ @swt_layout = self.class.swt_layout_class_for(underscored_layout_name).new(*args)
48
+ @widget_proxy.swt_widget.setLayout(@swt_layout)
49
+ end
50
+
51
+ def has_attribute?(attribute_name, *args)
52
+ @swt_layout.respond_to?(attribute_setter(attribute_name), args)
53
+ end
54
+
55
+ def set_attribute(attribute_name, *args)
56
+ apply_property_type_converters(attribute_name, args)
57
+ if args.first != @swt_layout.send(attribute_getter(attribute_name))
58
+ @swt_layout.send(attribute_setter(attribute_name), *args)
59
+ @widget_proxy.swt_widget.getShell.pack
60
+ end
61
+ end
62
+
63
+ def get_attribute(attribute_name)
64
+ @swt_layout.send(attribute_getter(attribute_name))
65
+ end
66
+
67
+ def apply_property_type_converters(attribute_name, args)
68
+ if args.count == 1 && SWTProxy.has_constant?(args.first)
69
+ args[0] = SWTProxy.constant(args.first)
70
+ end
71
+ end
72
+
73
+ def attribute_setter(attribute_name)
74
+ "#{attribute_name.to_s.camelcase(:lower)}="
75
+ end
76
+
77
+ def attribute_getter(attribute_name)
78
+ "#{attribute_name.to_s.camelcase(:lower)}"
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,101 @@
1
+ require 'glimmer/swt/widget_proxy'
2
+
3
+ module Glimmer
4
+ module SWT
5
+ # Proxy for org.eclipse.swt.widgets.Menu
6
+ #
7
+ # Functions differently from other widget proxies.
8
+ #
9
+ # Glimmer automatically detects if this is a drop down menu
10
+ # or pop up menu from its parent if no SWT style is passed in.
11
+ #
12
+ # There are 3 possibilities:
13
+ # - SWT :bar style is passed in: Menu Bar
14
+ # - Parent is ShellProxy: Pop Up Menu (having style :pop_up)
15
+ # - Parent is another Menu: Drop Down Menu (having style :drop_down)
16
+ #
17
+ # In order to get the SWT Menu object, one must call `#swt_widget`.
18
+ #
19
+ # In the case of a Drop Down menu, this automatically creates an
20
+ # SWT MenuItem object with style :cascade
21
+ #
22
+ # In order to retrieve the menu item widget proxy, one must call `#menu_item_proxy`
23
+ #
24
+ # Follows the Proxy Design Pattern
25
+ class MenuProxy < WidgetProxy
26
+ include_package 'org.eclipse.swt.widgets'
27
+
28
+ attr_reader :menu_item_proxy, :swt_menu_item, :menu_parent
29
+
30
+ def initialize(parent, args)
31
+ index = args.delete(args.last) if args.last.is_a?(Numeric)
32
+ styles = args.map(&:to_sym)
33
+ if !styles.include?(:bar) && !parent.swt_widget.is_a?(Menu)
34
+ styles = styles.unshift(:pop_up)
35
+ end
36
+
37
+ swt_widget_class = self.class.swt_widget_class_for('menu')
38
+ if parent.swt_widget.is_a?(Menu)
39
+ @menu_item_proxy = SWT::WidgetProxy.new('menu_item', parent, [:cascade] + [index].compact)
40
+ @swt_menu_item = @menu_item_proxy.swt_widget
41
+ @swt_widget = swt_widget_class.new(@menu_item_proxy.swt_widget)
42
+ @swt_menu_item.setMenu(swt_widget)
43
+ elsif parent.swt_widget.is_a?(Shell)
44
+ @swt_widget = swt_widget_class.new(parent.swt_widget, style('menu', styles))
45
+ else
46
+ @swt_widget = swt_widget_class.new(parent.swt_widget)
47
+ end
48
+ DEFAULT_INITIALIZERS['menu']&.call(swt_widget)
49
+
50
+ if styles.include?(:bar)
51
+ parent.swt_widget.setMenuBar(swt_widget)
52
+ elsif styles.include?(:pop_up)
53
+ parent.swt_widget.setMenu(swt_widget)
54
+ end
55
+ end
56
+
57
+ def has_attribute?(attribute_name, *args)
58
+ if attribute_name.to_s == "text"
59
+ true
60
+ else
61
+ super(attribute_name, *args)
62
+ end
63
+ end
64
+
65
+ def set_attribute(attribute_name, *args)
66
+ attribute_name
67
+ if attribute_name.to_s == "text"
68
+ text_value = args[0]
69
+ @swt_menu_item.setText text_value
70
+ else
71
+ super(attribute_name, *args)
72
+ end
73
+ end
74
+
75
+ def get_attribute(attribute_name)
76
+ if attribute_name.to_s == "text"
77
+ @swt_menu_item.getText
78
+ else
79
+ super(attribute_name)
80
+ end
81
+ end
82
+
83
+ def can_handle_observation_request?(observation_request, super_only: false)
84
+ super_result = super(observation_request)
85
+ if observation_request.start_with?('on_') && !super_result && !super_only
86
+ return menu_item_proxy.can_handle_observation_request?(observation_request)
87
+ else
88
+ super_result
89
+ end
90
+ end
91
+
92
+ def handle_observation_request(observation_request, &block)
93
+ if can_handle_observation_request?(observation_request, super_only: true)
94
+ super
95
+ else
96
+ menu_item_proxy.handle_observation_request(observation_request, &block)
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end