fidgit 0.2.4 → 0.2.5
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +7 -7
- data/.rspec +2 -2
- data/CHANGELOG.md +30 -30
- data/Gemfile +3 -3
- data/LICENSE.txt +19 -19
- data/README.textile +139 -139
- data/Rakefile +37 -37
- data/config/default_schema.yml +216 -216
- data/examples/_all_examples.rb +9 -9
- data/examples/align_example.rb +55 -55
- data/examples/button_and_toggle_button_example.rb +37 -37
- data/examples/color_picker_example.rb +16 -16
- data/examples/color_well_example.rb +24 -24
- data/examples/combo_box_example.rb +23 -23
- data/examples/file_dialog_example.rb +41 -41
- data/examples/grid_packer_example.rb +28 -28
- data/examples/helpers/example_window.rb +16 -16
- data/examples/label_example.rb +22 -22
- data/examples/list_example.rb +22 -22
- data/examples/menu_pane_example.rb +26 -26
- data/examples/message_dialog_example.rb +64 -64
- data/examples/radio_button_example.rb +36 -36
- data/examples/readme_example.rb +31 -31
- data/examples/scroll_window_example.rb +48 -48
- data/examples/slider_example.rb +33 -33
- data/examples/splash_example.rb +41 -41
- data/examples/text_area_example.rb +32 -32
- data/fidgit.gemspec +35 -35
- data/lib/fidgit.rb +50 -50
- data/lib/fidgit/chingu_ext/window.rb +5 -5
- data/lib/fidgit/cursor.rb +37 -37
- data/lib/fidgit/elements/button.rb +112 -112
- data/lib/fidgit/elements/color_picker.rb +62 -62
- data/lib/fidgit/elements/color_well.rb +38 -38
- data/lib/fidgit/elements/combo_box.rb +113 -113
- data/lib/fidgit/elements/composite.rb +16 -16
- data/lib/fidgit/elements/container.rb +208 -208
- data/lib/fidgit/elements/element.rb +297 -297
- data/lib/fidgit/elements/file_browser.rb +151 -151
- data/lib/fidgit/elements/grid.rb +226 -226
- data/lib/fidgit/elements/group.rb +64 -64
- data/lib/fidgit/elements/horizontal.rb +11 -11
- data/lib/fidgit/elements/image_frame.rb +64 -64
- data/lib/fidgit/elements/label.rb +84 -84
- data/lib/fidgit/elements/list.rb +46 -46
- data/lib/fidgit/elements/main_packer.rb +24 -24
- data/lib/fidgit/elements/menu_pane.rb +160 -160
- data/lib/fidgit/elements/packer.rb +41 -41
- data/lib/fidgit/elements/radio_button.rb +85 -85
- data/lib/fidgit/elements/scroll_area.rb +67 -67
- data/lib/fidgit/elements/scroll_bar.rb +127 -127
- data/lib/fidgit/elements/scroll_window.rb +82 -82
- data/lib/fidgit/elements/slider.rb +124 -124
- data/lib/fidgit/elements/text_area.rb +493 -493
- data/lib/fidgit/elements/text_line.rb +91 -91
- data/lib/fidgit/elements/toggle_button.rb +66 -66
- data/lib/fidgit/elements/tool_tip.rb +34 -34
- data/lib/fidgit/elements/vertical.rb +11 -11
- data/lib/fidgit/event.rb +158 -158
- data/lib/fidgit/gosu_ext/color.rb +135 -135
- data/lib/fidgit/gosu_ext/gosu_module.rb +24 -24
- data/lib/fidgit/history.rb +90 -90
- data/lib/fidgit/redirector.rb +82 -82
- data/lib/fidgit/schema.rb +123 -123
- data/lib/fidgit/selection.rb +105 -105
- data/lib/fidgit/standard_ext/hash.rb +20 -20
- data/lib/fidgit/states/dialog_state.rb +51 -51
- data/lib/fidgit/states/file_dialog.rb +24 -24
- data/lib/fidgit/states/gui_state.rb +329 -329
- data/lib/fidgit/states/message_dialog.rb +60 -60
- data/lib/fidgit/version.rb +4 -4
- data/lib/fidgit/window.rb +19 -19
- data/spec/fidgit/elements/helpers/helper.rb +2 -2
- data/spec/fidgit/elements/helpers/tex_play_helper.rb +8 -8
- data/spec/fidgit/elements/image_frame_spec.rb +68 -68
- data/spec/fidgit/elements/label_spec.rb +36 -36
- data/spec/fidgit/event_spec.rb +209 -209
- data/spec/fidgit/gosu_ext/color_spec.rb +129 -129
- data/spec/fidgit/gosu_ext/helpers/helper.rb +2 -2
- data/spec/fidgit/helpers/helper.rb +3 -3
- data/spec/fidgit/history_spec.rb +153 -153
- data/spec/fidgit/redirector_spec.rb +77 -77
- data/spec/fidgit/schema_spec.rb +66 -66
- data/spec/fidgit/schema_test.yml +32 -32
- metadata +67 -22
data/lib/fidgit/redirector.rb
CHANGED
@@ -1,83 +1,83 @@
|
|
1
|
-
module Fidgit
|
2
|
-
# Redirects methods to an object, but does not mask methods and ivars from the calling context.
|
3
|
-
module RedirectorMethods
|
4
|
-
# Evaluate a block accessing methods and ivars from the calling context, but calling public methods
|
5
|
-
# (not ivars or non-public methods) on this object in preference.
|
6
|
-
def instance_methods_eval(&block)
|
7
|
-
raise ArgumentError, "block required" unless block_given?
|
8
|
-
|
9
|
-
context = eval('self', block.binding)
|
10
|
-
|
11
|
-
context.send :push_redirection_target, self
|
12
|
-
|
13
|
-
begin
|
14
|
-
yield context
|
15
|
-
ensure
|
16
|
-
context.send :pop_redirection_target
|
17
|
-
end
|
18
|
-
|
19
|
-
self
|
20
|
-
end
|
21
|
-
|
22
|
-
protected
|
23
|
-
def push_redirection_target(target)
|
24
|
-
meta_class = class << self; self; end
|
25
|
-
base_methods = Object.public_instance_methods
|
26
|
-
|
27
|
-
# Redirect just the public methods of the target, less those that are on Object.
|
28
|
-
methods_to_redirect = target.public_methods - base_methods
|
29
|
-
|
30
|
-
# Only hide those public/private/protected methods that are being redirected.
|
31
|
-
methods_overridden = []
|
32
|
-
[:public, :protected, :private].each do |access|
|
33
|
-
methods_to_hide = meta_class.send("#{access}_instance_methods", false) & methods_to_redirect
|
34
|
-
methods_to_hide.each do |meth|
|
35
|
-
# Take a reference to the method we are about to override.
|
36
|
-
methods_overridden.push [meth, method(meth), access]
|
37
|
-
meta_class.send :remove_method, meth
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
# Add a method, to redirect calls to the target.
|
42
|
-
methods_to_redirect.each do |meth|
|
43
|
-
meta_class.send :define_method, meth do |*args, &block|
|
44
|
-
target.send meth, *args, &block
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
redirection_stack.push [target, methods_overridden, methods_to_redirect]
|
49
|
-
|
50
|
-
target
|
51
|
-
end
|
52
|
-
|
53
|
-
protected
|
54
|
-
def pop_redirection_target
|
55
|
-
meta_class = class << self; self; end
|
56
|
-
|
57
|
-
target, methods_to_recreate, methods_to_remove = redirection_stack.pop
|
58
|
-
|
59
|
-
# Remove the redirection methods
|
60
|
-
methods_to_remove.reverse_each do |meth|
|
61
|
-
meta_class.send :remove_method, meth
|
62
|
-
end
|
63
|
-
|
64
|
-
# Replace with the previous versions of the methods.
|
65
|
-
methods_to_recreate.reverse_each do |meth, reference, access|
|
66
|
-
meta_class.send :define_method, meth, reference
|
67
|
-
meta_class.send access, meth unless access == :public
|
68
|
-
end
|
69
|
-
|
70
|
-
target
|
71
|
-
end
|
72
|
-
|
73
|
-
# Direct access to the redirection stack.
|
74
|
-
private
|
75
|
-
def redirection_stack
|
76
|
-
@_redirection_stack ||= []
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
class Object
|
82
|
-
include Fidgit::RedirectorMethods
|
1
|
+
module Fidgit
|
2
|
+
# Redirects methods to an object, but does not mask methods and ivars from the calling context.
|
3
|
+
module RedirectorMethods
|
4
|
+
# Evaluate a block accessing methods and ivars from the calling context, but calling public methods
|
5
|
+
# (not ivars or non-public methods) on this object in preference.
|
6
|
+
def instance_methods_eval(&block)
|
7
|
+
raise ArgumentError, "block required" unless block_given?
|
8
|
+
|
9
|
+
context = eval('self', block.binding)
|
10
|
+
|
11
|
+
context.send :push_redirection_target, self
|
12
|
+
|
13
|
+
begin
|
14
|
+
yield context
|
15
|
+
ensure
|
16
|
+
context.send :pop_redirection_target
|
17
|
+
end
|
18
|
+
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
protected
|
23
|
+
def push_redirection_target(target)
|
24
|
+
meta_class = class << self; self; end
|
25
|
+
base_methods = Object.public_instance_methods
|
26
|
+
|
27
|
+
# Redirect just the public methods of the target, less those that are on Object.
|
28
|
+
methods_to_redirect = target.public_methods - base_methods
|
29
|
+
|
30
|
+
# Only hide those public/private/protected methods that are being redirected.
|
31
|
+
methods_overridden = []
|
32
|
+
[:public, :protected, :private].each do |access|
|
33
|
+
methods_to_hide = meta_class.send("#{access}_instance_methods", false) & methods_to_redirect
|
34
|
+
methods_to_hide.each do |meth|
|
35
|
+
# Take a reference to the method we are about to override.
|
36
|
+
methods_overridden.push [meth, method(meth), access]
|
37
|
+
meta_class.send :remove_method, meth
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Add a method, to redirect calls to the target.
|
42
|
+
methods_to_redirect.each do |meth|
|
43
|
+
meta_class.send :define_method, meth do |*args, &block|
|
44
|
+
target.send meth, *args, &block
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
redirection_stack.push [target, methods_overridden, methods_to_redirect]
|
49
|
+
|
50
|
+
target
|
51
|
+
end
|
52
|
+
|
53
|
+
protected
|
54
|
+
def pop_redirection_target
|
55
|
+
meta_class = class << self; self; end
|
56
|
+
|
57
|
+
target, methods_to_recreate, methods_to_remove = redirection_stack.pop
|
58
|
+
|
59
|
+
# Remove the redirection methods
|
60
|
+
methods_to_remove.reverse_each do |meth|
|
61
|
+
meta_class.send :remove_method, meth
|
62
|
+
end
|
63
|
+
|
64
|
+
# Replace with the previous versions of the methods.
|
65
|
+
methods_to_recreate.reverse_each do |meth, reference, access|
|
66
|
+
meta_class.send :define_method, meth, reference
|
67
|
+
meta_class.send access, meth unless access == :public
|
68
|
+
end
|
69
|
+
|
70
|
+
target
|
71
|
+
end
|
72
|
+
|
73
|
+
# Direct access to the redirection stack.
|
74
|
+
private
|
75
|
+
def redirection_stack
|
76
|
+
@_redirection_stack ||= []
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
class Object
|
82
|
+
include Fidgit::RedirectorMethods
|
83
83
|
end
|
data/lib/fidgit/schema.rb
CHANGED
@@ -1,123 +1,123 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Fidgit
|
4
|
-
# An object that manages Schema values. Usually loaded from a YAML file.
|
5
|
-
#
|
6
|
-
# @example
|
7
|
-
# schema = Schema.new(YAML.load(file.read('default_schema.yml')))
|
8
|
-
# default_color = schema.default(Element, :disabled, :color)
|
9
|
-
# schema.merge_schema!(YAML.load(file.read('override_schema.yml'))
|
10
|
-
# overridden_color = schema.default(Element, :disabled, :color)
|
11
|
-
class Schema
|
12
|
-
CONSTANT_PREFIX = '?'
|
13
|
-
|
14
|
-
# @param [Hash<Symbol => Hash>] schema data containing
|
15
|
-
def initialize(schema)
|
16
|
-
@constants = {}
|
17
|
-
@elements = {}
|
18
|
-
|
19
|
-
merge_schema! schema
|
20
|
-
end
|
21
|
-
|
22
|
-
# Merge in a hash containing constant values.
|
23
|
-
#
|
24
|
-
# @param [Hash<Symbol => Hash>] constants_hash Containing :colors, :constants and :elements hashes.
|
25
|
-
def merge_schema!(schema)
|
26
|
-
merge_constants!(schema[:constants]) if schema[:constants]
|
27
|
-
merge_elements!(schema[:elements]) if schema[:elements]
|
28
|
-
|
29
|
-
self
|
30
|
-
end
|
31
|
-
|
32
|
-
# Merge in a hash containing constant values. Arrays will be resolved as colors in RGBA or RGB format.
|
33
|
-
#
|
34
|
-
# @param [Hash<Symbol => Object>] constants_hash
|
35
|
-
def merge_constants!(constants_hash)
|
36
|
-
constants_hash.each_pair do |name, value|
|
37
|
-
@constants[name] = case value
|
38
|
-
when Array
|
39
|
-
case value.size
|
40
|
-
when 3 then Gosu::Color.rgb(*value)
|
41
|
-
when 4 then Gosu::Color.rgba(*value)
|
42
|
-
else
|
43
|
-
raise "Colors must be in 0..255, RGB or RGBA array format"
|
44
|
-
end
|
45
|
-
else
|
46
|
-
value
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
self
|
51
|
-
end
|
52
|
-
|
53
|
-
# Merge in a hash containing default values for each element.
|
54
|
-
#
|
55
|
-
# @param [Hash<Symbol => Hash>] elements_hash
|
56
|
-
def merge_elements!(elements_hash)
|
57
|
-
elements_hash.each_pair do |klass_names, data|
|
58
|
-
klass = Fidgit
|
59
|
-
klass_names.to_s.split('::').each do |klass_name|
|
60
|
-
klass = klass.const_get klass_name
|
61
|
-
end
|
62
|
-
|
63
|
-
raise "elements must be names of classes derived from #{Element}" unless klass.ancestors.include? Fidgit::Element
|
64
|
-
@elements[klass] ||= {}
|
65
|
-
@elements[klass].deep_merge! data
|
66
|
-
end
|
67
|
-
|
68
|
-
self
|
69
|
-
end
|
70
|
-
|
71
|
-
# Get the constant value associated with +name+.
|
72
|
-
#
|
73
|
-
# @param [Symbol] name
|
74
|
-
# @return [Object]
|
75
|
-
def constant(name)
|
76
|
-
@constants[name]
|
77
|
-
end
|
78
|
-
|
79
|
-
# @param [Class] klass Class to look for defaults for.
|
80
|
-
# @param [Symbol, Array<Symbol>] names Hash names to search for in that class's schema.
|
81
|
-
def default(klass, names)
|
82
|
-
raise ArgumentError, "#{klass} is not a descendent of the #{Element} class" unless klass.ancestors.include? Element
|
83
|
-
value = default_internal(klass, Array(names), true)
|
84
|
-
raise("Failed to find named value #{names.inspect} for class #{klass}") unless value
|
85
|
-
value
|
86
|
-
end
|
87
|
-
|
88
|
-
protected
|
89
|
-
# @param [Class] klass Class to look for defaults for.
|
90
|
-
# @param [Array<Symbol>] names Hash names to search for in that class's schema.
|
91
|
-
# @param [Boolean] default_to_outer Whether to default to an outer value (used internally)
|
92
|
-
def default_internal(klass, names, default_to_outer)
|
93
|
-
# Find the value by moving through the nested hash via the names.
|
94
|
-
value = @elements[klass]
|
95
|
-
|
96
|
-
names.each do |name|
|
97
|
-
break unless value.is_a? Hash
|
98
|
-
value = value.has_key?(name) ? value[name] : nil
|
99
|
-
end
|
100
|
-
|
101
|
-
# Convert the value to a color/constant if they are symbols.
|
102
|
-
value = if value.is_a? String and value[0] == CONSTANT_PREFIX
|
103
|
-
str = value[1..-1]
|
104
|
-
constant(str.to_sym) || value # If the value isn't a constant, return the string.
|
105
|
-
else
|
106
|
-
value
|
107
|
-
end
|
108
|
-
|
109
|
-
# If we didn't find the value for this class, default to parent class value.
|
110
|
-
if value.nil? and klass != Element and klass.ancestors.include? Element
|
111
|
-
# Check if any ancestors define the fully named value.
|
112
|
-
value = default_internal(klass.superclass, names, false)
|
113
|
-
end
|
114
|
-
|
115
|
-
if value.nil? and default_to_outer and names.size > 1
|
116
|
-
# Check the outer values (e.g. if [:hover, :color] is not defined, try [:color]).
|
117
|
-
value = default_internal(klass, names[1..-1], true)
|
118
|
-
end
|
119
|
-
|
120
|
-
value
|
121
|
-
end
|
122
|
-
end
|
123
|
-
end
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Fidgit
|
4
|
+
# An object that manages Schema values. Usually loaded from a YAML file.
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# schema = Schema.new(YAML.load(file.read('default_schema.yml')))
|
8
|
+
# default_color = schema.default(Element, :disabled, :color)
|
9
|
+
# schema.merge_schema!(YAML.load(file.read('override_schema.yml'))
|
10
|
+
# overridden_color = schema.default(Element, :disabled, :color)
|
11
|
+
class Schema
|
12
|
+
CONSTANT_PREFIX = '?'
|
13
|
+
|
14
|
+
# @param [Hash<Symbol => Hash>] schema data containing
|
15
|
+
def initialize(schema)
|
16
|
+
@constants = {}
|
17
|
+
@elements = {}
|
18
|
+
|
19
|
+
merge_schema! schema
|
20
|
+
end
|
21
|
+
|
22
|
+
# Merge in a hash containing constant values.
|
23
|
+
#
|
24
|
+
# @param [Hash<Symbol => Hash>] constants_hash Containing :colors, :constants and :elements hashes.
|
25
|
+
def merge_schema!(schema)
|
26
|
+
merge_constants!(schema[:constants]) if schema[:constants]
|
27
|
+
merge_elements!(schema[:elements]) if schema[:elements]
|
28
|
+
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
# Merge in a hash containing constant values. Arrays will be resolved as colors in RGBA or RGB format.
|
33
|
+
#
|
34
|
+
# @param [Hash<Symbol => Object>] constants_hash
|
35
|
+
def merge_constants!(constants_hash)
|
36
|
+
constants_hash.each_pair do |name, value|
|
37
|
+
@constants[name] = case value
|
38
|
+
when Array
|
39
|
+
case value.size
|
40
|
+
when 3 then Gosu::Color.rgb(*value)
|
41
|
+
when 4 then Gosu::Color.rgba(*value)
|
42
|
+
else
|
43
|
+
raise "Colors must be in 0..255, RGB or RGBA array format"
|
44
|
+
end
|
45
|
+
else
|
46
|
+
value
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
self
|
51
|
+
end
|
52
|
+
|
53
|
+
# Merge in a hash containing default values for each element.
|
54
|
+
#
|
55
|
+
# @param [Hash<Symbol => Hash>] elements_hash
|
56
|
+
def merge_elements!(elements_hash)
|
57
|
+
elements_hash.each_pair do |klass_names, data|
|
58
|
+
klass = Fidgit
|
59
|
+
klass_names.to_s.split('::').each do |klass_name|
|
60
|
+
klass = klass.const_get klass_name
|
61
|
+
end
|
62
|
+
|
63
|
+
raise "elements must be names of classes derived from #{Element}" unless klass.ancestors.include? Fidgit::Element
|
64
|
+
@elements[klass] ||= {}
|
65
|
+
@elements[klass].deep_merge! data
|
66
|
+
end
|
67
|
+
|
68
|
+
self
|
69
|
+
end
|
70
|
+
|
71
|
+
# Get the constant value associated with +name+.
|
72
|
+
#
|
73
|
+
# @param [Symbol] name
|
74
|
+
# @return [Object]
|
75
|
+
def constant(name)
|
76
|
+
@constants[name]
|
77
|
+
end
|
78
|
+
|
79
|
+
# @param [Class] klass Class to look for defaults for.
|
80
|
+
# @param [Symbol, Array<Symbol>] names Hash names to search for in that class's schema.
|
81
|
+
def default(klass, names)
|
82
|
+
raise ArgumentError, "#{klass} is not a descendent of the #{Element} class" unless klass.ancestors.include? Element
|
83
|
+
value = default_internal(klass, Array(names), true)
|
84
|
+
raise("Failed to find named value #{names.inspect} for class #{klass}") unless value
|
85
|
+
value
|
86
|
+
end
|
87
|
+
|
88
|
+
protected
|
89
|
+
# @param [Class] klass Class to look for defaults for.
|
90
|
+
# @param [Array<Symbol>] names Hash names to search for in that class's schema.
|
91
|
+
# @param [Boolean] default_to_outer Whether to default to an outer value (used internally)
|
92
|
+
def default_internal(klass, names, default_to_outer)
|
93
|
+
# Find the value by moving through the nested hash via the names.
|
94
|
+
value = @elements[klass]
|
95
|
+
|
96
|
+
names.each do |name|
|
97
|
+
break unless value.is_a? Hash
|
98
|
+
value = value.has_key?(name) ? value[name] : nil
|
99
|
+
end
|
100
|
+
|
101
|
+
# Convert the value to a color/constant if they are symbols.
|
102
|
+
value = if value.is_a? String and value[0] == CONSTANT_PREFIX
|
103
|
+
str = value[1..-1]
|
104
|
+
constant(str.to_sym) || value # If the value isn't a constant, return the string.
|
105
|
+
else
|
106
|
+
value
|
107
|
+
end
|
108
|
+
|
109
|
+
# If we didn't find the value for this class, default to parent class value.
|
110
|
+
if value.nil? and klass != Element and klass.ancestors.include? Element
|
111
|
+
# Check if any ancestors define the fully named value.
|
112
|
+
value = default_internal(klass.superclass, names, false)
|
113
|
+
end
|
114
|
+
|
115
|
+
if value.nil? and default_to_outer and names.size > 1
|
116
|
+
# Check the outer values (e.g. if [:hover, :color] is not defined, try [:color]).
|
117
|
+
value = default_internal(klass, names[1..-1], true)
|
118
|
+
end
|
119
|
+
|
120
|
+
value
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
data/lib/fidgit/selection.rb
CHANGED
@@ -1,106 +1,106 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Fidgit
|
4
|
-
class Selection
|
5
|
-
MIN_DRAG_DISTANCE = 2
|
6
|
-
|
7
|
-
def size; @items.size; end
|
8
|
-
def empty?; @items.empty?; end
|
9
|
-
def [](index); @items[index]; end
|
10
|
-
def each(&block); @items.each(&block); end
|
11
|
-
def to_a; @items.dup; end
|
12
|
-
def include?(object); @items.include? object; end
|
13
|
-
|
14
|
-
# Current being dragged?
|
15
|
-
def dragging?; @dragging; end
|
16
|
-
|
17
|
-
# Actually moved during a dragging operation?
|
18
|
-
def moved?; @moved; end
|
19
|
-
|
20
|
-
def initialize
|
21
|
-
@items = []
|
22
|
-
@moved = false
|
23
|
-
@dragging = false
|
24
|
-
end
|
25
|
-
|
26
|
-
def add(object)
|
27
|
-
object.selected = true
|
28
|
-
@items.push(object)
|
29
|
-
|
30
|
-
self
|
31
|
-
end
|
32
|
-
|
33
|
-
def remove(object)
|
34
|
-
@items.delete(object)
|
35
|
-
object.selected = false
|
36
|
-
object.dragging = false
|
37
|
-
|
38
|
-
self
|
39
|
-
end
|
40
|
-
|
41
|
-
def clear
|
42
|
-
end_drag if dragging?
|
43
|
-
@items.each { |o| o.selected = false; o.dragging = false }
|
44
|
-
@items.clear
|
45
|
-
|
46
|
-
self
|
47
|
-
end
|
48
|
-
|
49
|
-
def begin_drag(x, y)
|
50
|
-
@initial_x, @initial_y = x, y
|
51
|
-
@last_x, @last_y = x, y
|
52
|
-
@dragging = true
|
53
|
-
@moved = false
|
54
|
-
|
55
|
-
self
|
56
|
-
end
|
57
|
-
|
58
|
-
def end_drag
|
59
|
-
@items.each do |object|
|
60
|
-
object.x, object.y = object.x.round, object.y.round
|
61
|
-
object.dragging = false
|
62
|
-
end
|
63
|
-
@dragging = false
|
64
|
-
@moved = false
|
65
|
-
|
66
|
-
self
|
67
|
-
end
|
68
|
-
|
69
|
-
# Move all dragged object back to original positions.
|
70
|
-
def reset_drag
|
71
|
-
if moved?
|
72
|
-
@items.each do |o|
|
73
|
-
o.x += @initial_x - @last_x
|
74
|
-
o.y += @initial_y - @last_y
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
self.end_drag
|
79
|
-
|
80
|
-
self
|
81
|
-
end
|
82
|
-
|
83
|
-
def update_drag(x, y)
|
84
|
-
x, y = x.round, y.round
|
85
|
-
|
86
|
-
# If the mouse has been dragged far enough from the initial click position, then 'pick up' the objects and drag.
|
87
|
-
unless moved?
|
88
|
-
if distance(@initial_x, @initial_y, x, y) > MIN_DRAG_DISTANCE
|
89
|
-
@items.each { |o| o.dragging = true }
|
90
|
-
@moved = true
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
if moved?
|
95
|
-
@items.each do |o|
|
96
|
-
o.x += x - @last_x
|
97
|
-
o.y += y - @last_y
|
98
|
-
end
|
99
|
-
|
100
|
-
@last_x, @last_y = x, y
|
101
|
-
end
|
102
|
-
|
103
|
-
self
|
104
|
-
end
|
105
|
-
end
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Fidgit
|
4
|
+
class Selection
|
5
|
+
MIN_DRAG_DISTANCE = 2
|
6
|
+
|
7
|
+
def size; @items.size; end
|
8
|
+
def empty?; @items.empty?; end
|
9
|
+
def [](index); @items[index]; end
|
10
|
+
def each(&block); @items.each(&block); end
|
11
|
+
def to_a; @items.dup; end
|
12
|
+
def include?(object); @items.include? object; end
|
13
|
+
|
14
|
+
# Current being dragged?
|
15
|
+
def dragging?; @dragging; end
|
16
|
+
|
17
|
+
# Actually moved during a dragging operation?
|
18
|
+
def moved?; @moved; end
|
19
|
+
|
20
|
+
def initialize
|
21
|
+
@items = []
|
22
|
+
@moved = false
|
23
|
+
@dragging = false
|
24
|
+
end
|
25
|
+
|
26
|
+
def add(object)
|
27
|
+
object.selected = true
|
28
|
+
@items.push(object)
|
29
|
+
|
30
|
+
self
|
31
|
+
end
|
32
|
+
|
33
|
+
def remove(object)
|
34
|
+
@items.delete(object)
|
35
|
+
object.selected = false
|
36
|
+
object.dragging = false
|
37
|
+
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
def clear
|
42
|
+
end_drag if dragging?
|
43
|
+
@items.each { |o| o.selected = false; o.dragging = false }
|
44
|
+
@items.clear
|
45
|
+
|
46
|
+
self
|
47
|
+
end
|
48
|
+
|
49
|
+
def begin_drag(x, y)
|
50
|
+
@initial_x, @initial_y = x, y
|
51
|
+
@last_x, @last_y = x, y
|
52
|
+
@dragging = true
|
53
|
+
@moved = false
|
54
|
+
|
55
|
+
self
|
56
|
+
end
|
57
|
+
|
58
|
+
def end_drag
|
59
|
+
@items.each do |object|
|
60
|
+
object.x, object.y = object.x.round, object.y.round
|
61
|
+
object.dragging = false
|
62
|
+
end
|
63
|
+
@dragging = false
|
64
|
+
@moved = false
|
65
|
+
|
66
|
+
self
|
67
|
+
end
|
68
|
+
|
69
|
+
# Move all dragged object back to original positions.
|
70
|
+
def reset_drag
|
71
|
+
if moved?
|
72
|
+
@items.each do |o|
|
73
|
+
o.x += @initial_x - @last_x
|
74
|
+
o.y += @initial_y - @last_y
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
self.end_drag
|
79
|
+
|
80
|
+
self
|
81
|
+
end
|
82
|
+
|
83
|
+
def update_drag(x, y)
|
84
|
+
x, y = x.round, y.round
|
85
|
+
|
86
|
+
# If the mouse has been dragged far enough from the initial click position, then 'pick up' the objects and drag.
|
87
|
+
unless moved?
|
88
|
+
if distance(@initial_x, @initial_y, x, y) > MIN_DRAG_DISTANCE
|
89
|
+
@items.each { |o| o.dragging = true }
|
90
|
+
@moved = true
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
if moved?
|
95
|
+
@items.each do |o|
|
96
|
+
o.x += x - @last_x
|
97
|
+
o.y += y - @last_y
|
98
|
+
end
|
99
|
+
|
100
|
+
@last_x, @last_y = x, y
|
101
|
+
end
|
102
|
+
|
103
|
+
self
|
104
|
+
end
|
105
|
+
end
|
106
106
|
end
|