jrubyfx 0.9.1-java

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 (44) hide show
  1. data/LICENSE +202 -0
  2. data/README.md +97 -0
  3. data/bin/jrubyfx-jarify +90 -0
  4. data/bin/rubyfx-generator +81 -0
  5. data/lib/jrubyfx.rb +27 -0
  6. data/lib/jrubyfx/core_ext/border_pane.rb +29 -0
  7. data/lib/jrubyfx/core_ext/circle.rb +26 -0
  8. data/lib/jrubyfx/core_ext/column_constraints.rb +41 -0
  9. data/lib/jrubyfx/core_ext/duration.rb +28 -0
  10. data/lib/jrubyfx/core_ext/effects.rb +30 -0
  11. data/lib/jrubyfx/core_ext/file_chooser.rb +60 -0
  12. data/lib/jrubyfx/core_ext/labeled.rb +24 -0
  13. data/lib/jrubyfx/core_ext/media_player.rb +23 -0
  14. data/lib/jrubyfx/core_ext/node.rb +24 -0
  15. data/lib/jrubyfx/core_ext/observable_value.rb +36 -0
  16. data/lib/jrubyfx/core_ext/pagination.rb +26 -0
  17. data/lib/jrubyfx/core_ext/parallel_transition.rb +28 -0
  18. data/lib/jrubyfx/core_ext/parent.rb +28 -0
  19. data/lib/jrubyfx/core_ext/path.rb +41 -0
  20. data/lib/jrubyfx/core_ext/progress_indicator.rb +38 -0
  21. data/lib/jrubyfx/core_ext/radial_gradient.rb +37 -0
  22. data/lib/jrubyfx/core_ext/region.rb +39 -0
  23. data/lib/jrubyfx/core_ext/rotate.rb +37 -0
  24. data/lib/jrubyfx/core_ext/scene.rb +29 -0
  25. data/lib/jrubyfx/core_ext/shape.rb +27 -0
  26. data/lib/jrubyfx/core_ext/stage.rb +77 -0
  27. data/lib/jrubyfx/core_ext/stop.rb +29 -0
  28. data/lib/jrubyfx/core_ext/table_view.rb +35 -0
  29. data/lib/jrubyfx/core_ext/timeline.rb +47 -0
  30. data/lib/jrubyfx/core_ext/transition.rb +25 -0
  31. data/lib/jrubyfx/core_ext/xy_chart.rb +53 -0
  32. data/lib/jrubyfx/dsl.rb +217 -0
  33. data/lib/jrubyfx/fxml_application.rb +44 -0
  34. data/lib/jrubyfx/fxml_controller.rb +270 -0
  35. data/lib/jrubyfx/fxml_module.rb +98 -0
  36. data/lib/jrubyfx/java_fx_impl.rb +139 -0
  37. data/lib/jrubyfx/jfx_imports.rb +107 -0
  38. data/lib/jrubyfx/utils.rb +56 -0
  39. data/lib/jrubyfx/utils/__ignore_java_stupid_rdoc.rb +24 -0
  40. data/lib/jrubyfx/utils/common_converters.rb +140 -0
  41. data/lib/jrubyfx/utils/common_utils.rb +72 -0
  42. data/lib/jrubyfx/version.rb +4 -0
  43. data/lib/jrubyfx_tasks.rb +110 -0
  44. metadata +116 -0
@@ -0,0 +1,25 @@
1
+ =begin
2
+ JRubyFX - Write JavaFX and FXML in Ruby
3
+ Copyright (C) 2013 The JRubyFX Team
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
16
+ =end
17
+
18
+ {:Rotate => :angle, :Scale => [:x, :y, :z], :Translate => [:x, :y, :z],
19
+ :Fade => :value, :Fill => :value, :Stroke => :value}.each do |clas, anim_props|
20
+ JavaUtilities.get_proxy_class("javafx.animation.#{clas}Transition").class_eval do
21
+ extend JRubyFX::Utils::CommonConverters
22
+
23
+ animation_converter_for *anim_props
24
+ end
25
+ end
@@ -0,0 +1,53 @@
1
+ =begin
2
+ JRubyFX - Write JavaFX and FXML in Ruby
3
+ Copyright (C) 2013 The JRubyFX Team
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
16
+ =end
17
+ require 'jrubyfx/dsl'
18
+
19
+ # JRubyFX DSL extensions for JavaFX XYCharts
20
+ class Java::javafx::scene::chart::XYChart
21
+ include JRubyFX::DSL
22
+
23
+ ##
24
+ # This will defer to node to construct proper object, but will
25
+ # optionally add paths primary child automatically if it is a
26
+ # PathElement.
27
+ def method_missing(name, *args, &block)
28
+ super.tap do |obj|
29
+ data.add(obj) if obj.kind_of? XYChart::Series
30
+ end
31
+ end
32
+ end
33
+
34
+ # JRubyFX DSL extensions for JavaFX XYChart Series
35
+ class Java::javafx::scene::chart::XYChart::Series
36
+ include JRubyFX::DSL
37
+
38
+ ##
39
+ # This will defer to node to construct proper object, but will
40
+ # optionally add paths primary child automatically if it is a
41
+ # PathElement.
42
+ def method_missing(name, *args, &block)
43
+ super.tap do |obj|
44
+ data.add(obj) if obj.kind_of? XYChart::Data
45
+ end
46
+ end
47
+
48
+ end
49
+
50
+ # JRubyFX DSL extensions for JavaFX XYChart Data
51
+ class Java::javafx::scene::chart::XYChart::Data
52
+ include JRubyFX::DSL
53
+ end
@@ -0,0 +1,217 @@
1
+ =begin
2
+ JRubyFX - Write JavaFX and FXML in Ruby
3
+ Copyright (C) 2013 The JRubyFX Team
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
16
+ =end
17
+ require 'java'
18
+ require 'jrubyfx'
19
+
20
+ module JRubyFX
21
+ # Defines a nice DSL for building JavaFX applications. Include it in a class for
22
+ # access to the DSL. JRubyFX::Application and JRubyFX::Controller include it already.
23
+ module DSL
24
+ include JRubyFX
25
+
26
+ # Contains methods to be defined inside all classes that include JRubyFX
27
+ module ClassUtils
28
+ include JRubyFX::FXImports
29
+
30
+ # Make sure we are added to the mapping. FIXME: is this ever used?
31
+ def register_type(name, type)
32
+ JRubyFX::DSL::NAME_TO_CLASSES[name.to_s] = type
33
+ end
34
+
35
+ # Lots of DSL extensions use these methods, so define them here so multiple classes can use them
36
+
37
+ ##
38
+ # call-seq:
39
+ # include_add
40
+ # include_add :child_getter
41
+ #
42
+ # Include a function to add to child list (optional argument) without need
43
+ # to ask for children
44
+ # include_add
45
+ # include_add :elements
46
+ #
47
+ def include_add(adder = :get_children)
48
+ self.class_eval do
49
+ define_method :add do |value|
50
+ self.send(adder) << value
51
+ end
52
+ end
53
+ end
54
+
55
+ ##
56
+ # Adds a function to the class that Adds rotate to transform (manually
57
+ # added ebcause there is a getRotate on Node already. Use get_rotate
58
+ # to get property
59
+ def include_rotate
60
+ self.class_eval do
61
+ def rotate(*args) #:nodoc:
62
+ transforms << build(Rotate, *args)
63
+ end
64
+ end
65
+ end
66
+
67
+ ##
68
+ # Adds a method_missing that automatically calls add if the DSL builds it
69
+ # as the given type.
70
+ # This will defer to node to construct proper object, but will
71
+ # optionally add paths primary child automatically if it is a
72
+ # PathElement.
73
+ def include_method_missing(type)
74
+ self.class_eval do
75
+ define_method :method_missing do |name, *args, &block|
76
+ # we must manually call super otherwise it will call super(type)
77
+ super(name, *args, &block).tap do |obj|
78
+ add(obj) if obj.kind_of? type
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
84
+
85
+ # When a class includes JRubyFX, extend (add to the metaclass) ClassUtils
86
+ def self.included(mod)
87
+ mod.extend(JRubyFX::DSL::ClassUtils)
88
+ end
89
+
90
+ #--
91
+ # FIXME: This should be broken up with nice override for each type of
92
+ # fx object so we can manually create static overrides.
93
+ #++
94
+ # The list of snake_case names mapped to full java classes to use for DSL mapping.
95
+ # This list is dynamically generated using JRubyFX::FXImports::JFX_CLASS_HIERARCHY and
96
+ # Hash.flat_tree_inject.
97
+ NAME_TO_CLASSES = {
98
+ # observable structs
99
+ 'observable_array_list' => proc { |*args| FXCollections.observable_array_list(*args) },
100
+ 'double_property' => SimpleDoubleProperty,
101
+ 'xy_chart_series' => Java::javafx.scene.chart.XYChart::Series,
102
+ 'xy_chart_data' => Java::javafx.scene.chart.XYChart::Data,
103
+ }.merge(JFX_CLASS_HIERARCHY.flat_tree_inject(Hash) do |res, name, values|
104
+ # Merge in auto-generated list of classes from all the imported classes
105
+ unless values.is_a? Hash
106
+ values.map do |i|
107
+ # this regexp does snake_casing
108
+ # TODO: Anybody got a better way to get the java class instead of evaling its name?
109
+ res.merge!({i.snake_case.gsub(/(h|v)_(line|box)/, '\1\2') => eval(i)})
110
+ end
111
+ res
112
+ else
113
+ # we are not at a leaf node anymore, merge in previous work
114
+ res.merge!(values)
115
+ end
116
+ end)
117
+
118
+ # List of known overrides for enums.
119
+ ENUM_OVERRIDES = {PathTransition::OrientationType => {:orthogonal_to_tangent => :orthogonal},
120
+ BlendMode => {:src_over => :over, :src_atop => :atop, :color_dodge => :dodge, :color_burn => :burn},
121
+ ContentDisplay => {:graphic_only => :graphic, :text_only => :text},
122
+ BlurType => {:one_pass_box => [:one, :one_pass], :two_pass_box => [:two, :two_pass], :three_pass_box => [:three, :three_pass]},
123
+ Modality => {:window_modal => :window, :application_modal => [:application, :app]}}
124
+
125
+ # This is the heart of the DSL. When a method is missing and the name of the
126
+ # method is in the NAME_TO_CLASSES mapping, it calls JRubyFX.build with the
127
+ # Java class. This means that instead of saying
128
+ # build(JavaClass, hash) { ... }
129
+ # you can say
130
+ # java_class(hash) { ... }
131
+ #
132
+ def method_missing(name, *args, &block)
133
+ clazz = NAME_TO_CLASSES[name.to_s]
134
+ super unless clazz
135
+
136
+ build(clazz, *args, &block)
137
+ end
138
+
139
+ alias :node_method_missing :method_missing
140
+
141
+ # Loads the special symbol to enum converter functions into all methods
142
+ # and enums
143
+ def self.load_enum_converter
144
+ # load overrides
145
+ ENUM_OVERRIDES.each do |cls, overrides|
146
+ JRubyFX::Utils::CommonConverters.set_overrides_for cls, overrides
147
+ end
148
+
149
+ # use reflection to load all enums into all_enums and methods that use them
150
+ # into enum_methods
151
+ mod_list = {
152
+ :methods => [],
153
+ :all => []
154
+ }
155
+ JRubyFX::DSL::NAME_TO_CLASSES.each do |n,cls|
156
+ cls.java_class.java_instance_methods.each do |method|
157
+ args = method.argument_types.find_all(&:enum?).tap {|i| mod_list[:all] << i }
158
+
159
+ # one and only, must be a setter style
160
+ if method.argument_types.length == 1 and (args.length == method.argument_types.length)
161
+ mod_list[:methods] << [method.name, cls]
162
+ end
163
+ end if cls.respond_to? :ancestors and cls.ancestors.include? JavaProxy # some are not java classes. ignore those
164
+ end
165
+
166
+ # Get the proper class (only need them once)
167
+ mod_list[:all] = mod_list[:all].flatten.uniq.map {|i| JavaUtilities.get_proxy_class(i) }
168
+
169
+ # Inject our converter into each enum/class
170
+ mod_list[:all].each do |enum|
171
+ inject_symbol_converter enum
172
+ end
173
+
174
+ # finally, "override" each method
175
+ mod_list[:methods].each do |method|
176
+ inject_enum_method_converter *method
177
+ end
178
+ end
179
+
180
+ # Adds `parse_ruby_symbols` method to given enum/class to enable symbol conversion
181
+ def self.inject_symbol_converter(jclass)
182
+ # inject!
183
+ class << jclass
184
+ define_method :parse_ruby_symbols do |const|
185
+ # cache it. It could be expensive
186
+ @map = JRubyFX::Utils::CommonConverters.map_enums(self) if @map == nil
187
+ @map[const.to_s] || const
188
+ end
189
+ end
190
+ end
191
+
192
+ # "overrides" given function name in given class to parse ruby symbols into
193
+ # proper enums. Rewrites method name as `my_method=` from `setMyMethod`
194
+ def self.inject_enum_method_converter(jfunc, in_class)
195
+ jclass = in_class.java_class.java_instance_methods.find_all {|i| i.name == jfunc.to_s}[0].argument_types[0]
196
+ jclass = JavaUtilities.get_proxy_class(jclass)
197
+
198
+ # Define the conversion function as the snake cased assignment, calling parse_ruby
199
+ in_class.class_eval do
200
+ define_method "#{jfunc.to_s.gsub(/^set/i,'').snake_case}=" do |rbenum|
201
+ java_send jfunc, [jclass], jclass.parse_ruby_symbols(rbenum)
202
+ end
203
+ end
204
+ end
205
+
206
+ # This loads the entire DSL. Call this immediately after requiring
207
+ # this file, but not inside this file, or it requires itself twice.
208
+ def self.load_dsl
209
+ rt = "#{File.dirname(__FILE__)}/core_ext/"
210
+ Dir.foreach rt do |file|
211
+ require_relative "core_ext/#{file}" unless [".", ".."].include? file
212
+ end
213
+
214
+ JRubyFX::DSL.load_enum_converter()
215
+ end
216
+ end
217
+ end
@@ -0,0 +1,44 @@
1
+ =begin
2
+ JRubyFX - Write JavaFX and FXML in Ruby
3
+ Copyright (C) 2013 The JRubyFX Team
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
16
+ =end
17
+
18
+ require 'jrubyfx'
19
+
20
+ ##
21
+ # Inherit from this class for FXML Applications. You must use this class for both
22
+ # raw JavaFX and FXML as it contains the launch method.
23
+ class JRubyFX::Application < Java.javafx.application.Application
24
+ include JRubyFX
25
+ include JRubyFX::DSL
26
+
27
+ ##
28
+ # Are we packaged in a jar? This does some comparison, and may get false positives
29
+ # and, if jruby changes, false negatives. If you are using this, it might be a
30
+ # very bad idea... (though it is handy)
31
+ def self.in_jar?()
32
+ $LOAD_PATH.inject(false) { |res,i| res || i.include?(".jar!/META-INF/jruby.home/lib/ruby/")}
33
+ end
34
+
35
+ ##
36
+ # call-seq:
37
+ # launch()
38
+ #
39
+ # When called on a subclass, this is effectively our main method.
40
+ def self.launch(*args)
41
+ #call our custom launcher to avoid a java shim
42
+ JavaFXImpl::Launcher.launch_app(self, *args)
43
+ end
44
+ end
@@ -0,0 +1,270 @@
1
+ =begin
2
+ JRubyFX - Write JavaFX and FXML in Ruby
3
+ Copyright (C) 2013 The JRubyFX Team
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
16
+ =end
17
+
18
+ require 'jrubyfx'
19
+
20
+ # Inherit from this class for FXML controllers
21
+ class JRubyFX::Controller
22
+ include JRubyFX
23
+ include JRubyFX::DSL
24
+ java_import 'java.net.URL'
25
+ java_import 'javafx.fxml.FXMLLoader'
26
+
27
+ # Controllers usually need access to the stage.
28
+ attr_accessor :stage
29
+
30
+ ##
31
+ # call-seq:
32
+ # fx_handler(callback) { |event_info| block } => Method
33
+ # fx_handler(callback, EventType) { |event_info| block } => Method
34
+ # fx_type_handler(callback) { |event_info| block } => Method
35
+ #
36
+ # Registers a function of name `name` for a FXML defined event with the body in the block
37
+ # Note: there are overrides for most of the default types, so you should never
38
+ # need to manually specify the `type` argument unless you have custom events.
39
+ # The overrides are in the format fx_*_handler where * is the event type (ex:
40
+ # fx_key_handler for KeyEvent).
41
+ # === Overloads
42
+ # * fx_key_handler is for KeyEvent
43
+ # * fx_mouse_handler is for MouseEvent
44
+ # * fx_touch_handler is for TouchEvent
45
+ # * fx_gesture_handler is for GestureEvent
46
+ # * fx_context_handler is for ContextMenuEvent
47
+ # * fx_context_menu_handler is for ContextMenuEvent
48
+ # * fx_drag_handler is for DragEvent
49
+ # * fx_ime_handler is for InputMethodEvent
50
+ # * fx_input_method_handler is for InputMethodEvent
51
+ # * fx_window_handler is for WindowEvent
52
+ # * fx_action_handler is for ActionEvent
53
+ # * fx_generic_handler is for Event
54
+ #
55
+ # === Examples
56
+ # fx_handler :click do
57
+ # puts "button clicked"
58
+ # end
59
+ #
60
+ # fx_mouse_handler :moved do |event|
61
+ # puts "Mouse Moved"
62
+ # p event
63
+ # end
64
+ #
65
+ # fx_key_handler :keypress do
66
+ # puts "Key Pressed"
67
+ # end
68
+ #
69
+ # === Equivalent Java
70
+ # @FXML
71
+ # private void click(ActionEvent event) {
72
+ # System.out.println("button clicked");
73
+ # }
74
+ #
75
+ # @FXML
76
+ # private void moved(MouseEvent event) {
77
+ # System.out.println("Mouse Moved");
78
+ # }
79
+ #
80
+ # @FXML
81
+ # private void keypress(KeyEvent event) {
82
+ # System.out.println("Key Pressed");
83
+ # }
84
+ #
85
+ def self.fx_handler(names, type=ActionEvent, &block)
86
+ [names].flatten.each do |name|
87
+ class_eval do
88
+ #must define this way so block executes in class scope, not static scope
89
+ define_method(name, block)
90
+ #the first arg is the return type, the rest are params
91
+ add_method_signature name, [Void::TYPE, type]
92
+ end
93
+ end
94
+ end
95
+
96
+ # Get the singleton class, and add special overloads as fx_EVENT_handler
97
+ # This funky syntax allows us to define methods on self (like define_method("self.method"),
98
+ # except that does not work)
99
+ class << self
100
+ include JRubyFX::FXImports
101
+ {:key => KeyEvent,
102
+ :mouse => MouseEvent,
103
+ :touch => TouchEvent,
104
+ :gesture => GestureEvent,
105
+ :context => ContextMenuEvent,
106
+ :context_menu => ContextMenuEvent,
107
+ :drag => DragEvent,
108
+ :ime => InputMethodEvent,
109
+ :input_method => InputMethodEvent,
110
+ :window => WindowEvent,
111
+ :action => ActionEvent,
112
+ :generic => Event}.each do |method, klass|
113
+ #instance_eval on the self instance so that these are defined as class methods
114
+ self.instance_eval do
115
+ # define the handy overloads that just pass our arguments in
116
+ define_method("fx_#{method}_handler") do |name, &block|
117
+ fx_handler(name, klass, &block)
118
+ end
119
+ end
120
+ end
121
+ end
122
+
123
+ # FXML linked variable names by subclass
124
+ @@fxml_linked_args = {}
125
+
126
+ ##
127
+ # call-seq:
128
+ # fx_id :name, ...
129
+ #
130
+ # Register one or more variable names to bind to a fx:id in the FXML file.
131
+ # === Example
132
+ # fx_id :myVar
133
+ #
134
+ # === Equivalent Java
135
+ # @FXML
136
+ # private ClassName myVar;
137
+ #
138
+ def self.fx_id(*name)
139
+ # we must distinguish between subclasses, hence self.
140
+ (@@fxml_linked_args[self] ||= []).concat(name)
141
+ end
142
+
143
+ ##
144
+ # call-seq:
145
+ # fx_id_optional :name, ...
146
+ #
147
+ # Register one or more variable name to bind to a fx:id in the FXML file if it exists.
148
+ # If the name cannot be found, don't complain.
149
+ # === Example
150
+ # fx_id_optional :myVar
151
+ #
152
+ # === Equivalent Java
153
+ # @FXML
154
+ # private ClassName myVar;
155
+ #
156
+ def self.fx_id_optional(*names)
157
+ fx_id *names.map {|i| {i => :quiet} }
158
+ end
159
+
160
+ ##
161
+ # Set scene object (setter), and update fxml-injected values. If you are manually
162
+ # loading FXML, you MUST call this to link `fx_id` specified names.
163
+ def scene=(s)
164
+ @scene = s
165
+ (@@fxml_linked_args[self.class] ||= []).each do |name|
166
+ quiet = false
167
+ # you can specify name => [quiet/verbose], so we need to check for that
168
+ if name.is_a? Hash
169
+ quiet = name.values[0] == :quiet
170
+ name = name.keys[0]
171
+ end
172
+ # set each instance variable from the lookup on the scene
173
+ val = s.lookup("##{name}")
174
+ if val == nil && !quiet
175
+ puts "[WARNING] fx_id not found: #{name}. Is id set to a different value than fx:id? (if this is expected, use fx_id_optional)"
176
+ end
177
+ instance_variable_set("@#{name}".to_sym, val)
178
+ end
179
+ end
180
+
181
+ ##
182
+ # Return the scene object (getter)
183
+ def scene()
184
+ @scene
185
+ end
186
+
187
+ ##
188
+ # Magic self-java-ifying new call. (Creates a Java instance)
189
+ def self.new_java(*args)
190
+ self.become_java!
191
+ self.new(*args)
192
+ end
193
+
194
+ ##
195
+ # Load given fxml file onto the given stage. `settings` is an optional hash of:
196
+ # * :initialize => [array of arguments to pass to the initialize function]
197
+ # * :width => Default width of the Scene
198
+ # * :height => Default height of the Scene
199
+ # * :fill => Fill color of the Scene's background
200
+ # * :depth_buffer => JavaFX Scene DepthBuffer argument (look it up)
201
+ # * :relative_to => number of calls back, or filename. `filename` is evaluated
202
+ # as being relative to this. Default is relative to caller (1)
203
+ # Returns a scene, either a new one, or the FXML root if its a Scene.
204
+ # === Examples
205
+ #
206
+ # controller = MyFXController.load_fxml("Demo.fxml", stage)
207
+ #
208
+ # === Equivalent Java
209
+ # Parent root = FXMLLoader.load(getClass().getResource("Demo.fxml"));
210
+ # Scene scene = new Scene(root);
211
+ # stage.setScene(scene);
212
+ # controller = root.getController();
213
+ #
214
+ def self.load_fxml(filename, stage, settings={})
215
+ # Create our class as a java class with any arguments it wants
216
+ ctrl = self.new_java *(settings[:initialize] || [])
217
+ # save the stage so we can reference it if needed later
218
+ ctrl.stage = stage
219
+ # load the FXML file
220
+ parent = load_fxml_resource(filename, ctrl, settings[:relative_to] || 1)
221
+ # set the controller and stage scene, so that all the fx_id variables are hooked up
222
+ ctrl.scene = stage.scene = if parent.is_a? Scene
223
+ parent
224
+ elsif settings.has_key? :fill
225
+ Scene.new(parent, settings[:width] || -1, settings[:height] || -1, settings[:fill] || Color::WHITE)
226
+ else
227
+ Scene.new(parent, settings[:width] || -1, settings[:height] || -1, settings[:depth_buffer] || settings[:depthBuffer] || false)
228
+ end
229
+ # return the controller. If they want the new scene, they can call the scene() method on it
230
+ return ctrl
231
+ end
232
+
233
+ ##
234
+ # call-seq:
235
+ # load_fxml_resource(filename) => Parent
236
+ # load_fxml_resource(filename, controller_instance) => Parent
237
+ # load_fxml_resource(filename, controller_instance, relative_to) => Parent
238
+ #
239
+ # Load a FXML file given a filename and a controller and return the root element
240
+ # relative_to can be a file that this should be relative to, or an index
241
+ # of the caller number. If you are calling this from a function, pass 0
242
+ # as you are the immediate caller of this function.
243
+ # === Examples
244
+ # root = JRubyFX::Controller.load_fxml_resource("Demo.fxml")
245
+ #
246
+ # root = JRubyFX::Controller.load_fxml_resource("Demo.fxml", my_controller)
247
+ #
248
+ # === Equivalent Java
249
+ # Parent root = FXMLLoader.load(getClass().getResource("Demo.fxml"));
250
+ #
251
+ def self.load_fxml_resource(filename, ctrlr=nil, relative_to=0)
252
+ fx = FXMLLoader.new()
253
+ fx.location = if JRubyFX::Application.in_jar?
254
+ # If we are in a jar file, use the class loader to get the file from the jar (like java)
255
+ JRuby.runtime.jruby_class_loader.get_resource(filename)
256
+ else
257
+ if relative_to.is_a? Fixnum or relative_to == nil
258
+ # caller[0] returns a string like so:
259
+ # "/home/user/.rvm/rubies/jruby-1.7.1/lib/ruby/1.9/irb/workspace.rb:80:in `eval'"
260
+ # and then we use a regex to filter out the filename
261
+ relative_to = caller[relative_to||0][/(.*):[0-9]+:in /, 1] # the 1 is the first match, aka everything up to the :
262
+ end
263
+ # If we are in the normal filesystem, create a normal file url path relative to the main file
264
+ URL.new(URL.new("file:"), "#{File.dirname(relative_to)}/#{filename}")
265
+ end
266
+ # we must set this here for JFX to call our events
267
+ fx.controller = ctrlr
268
+ return fx.load()
269
+ end
270
+ end