jrubyfx 0.9.1-java

Sign up to get free protection for your applications and to get access to all the features.
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