jrubyfx 0.9.1-java
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +202 -0
- data/README.md +97 -0
- data/bin/jrubyfx-jarify +90 -0
- data/bin/rubyfx-generator +81 -0
- data/lib/jrubyfx.rb +27 -0
- data/lib/jrubyfx/core_ext/border_pane.rb +29 -0
- data/lib/jrubyfx/core_ext/circle.rb +26 -0
- data/lib/jrubyfx/core_ext/column_constraints.rb +41 -0
- data/lib/jrubyfx/core_ext/duration.rb +28 -0
- data/lib/jrubyfx/core_ext/effects.rb +30 -0
- data/lib/jrubyfx/core_ext/file_chooser.rb +60 -0
- data/lib/jrubyfx/core_ext/labeled.rb +24 -0
- data/lib/jrubyfx/core_ext/media_player.rb +23 -0
- data/lib/jrubyfx/core_ext/node.rb +24 -0
- data/lib/jrubyfx/core_ext/observable_value.rb +36 -0
- data/lib/jrubyfx/core_ext/pagination.rb +26 -0
- data/lib/jrubyfx/core_ext/parallel_transition.rb +28 -0
- data/lib/jrubyfx/core_ext/parent.rb +28 -0
- data/lib/jrubyfx/core_ext/path.rb +41 -0
- data/lib/jrubyfx/core_ext/progress_indicator.rb +38 -0
- data/lib/jrubyfx/core_ext/radial_gradient.rb +37 -0
- data/lib/jrubyfx/core_ext/region.rb +39 -0
- data/lib/jrubyfx/core_ext/rotate.rb +37 -0
- data/lib/jrubyfx/core_ext/scene.rb +29 -0
- data/lib/jrubyfx/core_ext/shape.rb +27 -0
- data/lib/jrubyfx/core_ext/stage.rb +77 -0
- data/lib/jrubyfx/core_ext/stop.rb +29 -0
- data/lib/jrubyfx/core_ext/table_view.rb +35 -0
- data/lib/jrubyfx/core_ext/timeline.rb +47 -0
- data/lib/jrubyfx/core_ext/transition.rb +25 -0
- data/lib/jrubyfx/core_ext/xy_chart.rb +53 -0
- data/lib/jrubyfx/dsl.rb +217 -0
- data/lib/jrubyfx/fxml_application.rb +44 -0
- data/lib/jrubyfx/fxml_controller.rb +270 -0
- data/lib/jrubyfx/fxml_module.rb +98 -0
- data/lib/jrubyfx/java_fx_impl.rb +139 -0
- data/lib/jrubyfx/jfx_imports.rb +107 -0
- data/lib/jrubyfx/utils.rb +56 -0
- data/lib/jrubyfx/utils/__ignore_java_stupid_rdoc.rb +24 -0
- data/lib/jrubyfx/utils/common_converters.rb +140 -0
- data/lib/jrubyfx/utils/common_utils.rb +72 -0
- data/lib/jrubyfx/version.rb +4 -0
- data/lib/jrubyfx_tasks.rb +110 -0
- 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
|
data/lib/jrubyfx/dsl.rb
ADDED
@@ -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
|