fidgit 0.0.2alpha
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +8 -0
- data/.rspec +2 -0
- data/COPYING.txt +674 -0
- data/Gemfile +4 -0
- data/README.textile +138 -0
- data/Rakefile +38 -0
- data/config/default_schema.yml +180 -0
- data/examples/_all_examples.rb +9 -0
- data/examples/align_example.rb +56 -0
- data/examples/button_and_toggle_button_example.rb +27 -0
- data/examples/color_picker_example.rb +17 -0
- data/examples/color_well_example.rb +25 -0
- data/examples/combo_box_example.rb +24 -0
- data/examples/file_dialog_example.rb +42 -0
- data/examples/grid_packer_example.rb +29 -0
- data/examples/helpers/example_window.rb +17 -0
- data/examples/label_example.rb +17 -0
- data/examples/list_example.rb +23 -0
- data/examples/media/images/head_icon.png +0 -0
- data/examples/menu_pane_example.rb +27 -0
- data/examples/message_dialog_example.rb +65 -0
- data/examples/radio_button_example.rb +37 -0
- data/examples/readme_example.rb +32 -0
- data/examples/scroll_window_example.rb +49 -0
- data/examples/slider_example.rb +30 -0
- data/examples/splash_example.rb +42 -0
- data/examples/text_area_example.rb +28 -0
- data/fidgit.gemspec +28 -0
- data/lib/fidgit.rb +4 -0
- data/lib/fidgit/chingu_ext/window.rb +6 -0
- data/lib/fidgit/clipboard.rb +23 -0
- data/lib/fidgit/cursor.rb +38 -0
- data/lib/fidgit/elements/button.rb +68 -0
- data/lib/fidgit/elements/color_picker.rb +63 -0
- data/lib/fidgit/elements/color_well.rb +39 -0
- data/lib/fidgit/elements/combo_box.rb +85 -0
- data/lib/fidgit/elements/composite.rb +17 -0
- data/lib/fidgit/elements/container.rb +187 -0
- data/lib/fidgit/elements/element.rb +252 -0
- data/lib/fidgit/elements/file_browser.rb +152 -0
- data/lib/fidgit/elements/grid_packer.rb +219 -0
- data/lib/fidgit/elements/group.rb +66 -0
- data/lib/fidgit/elements/horizontal_packer.rb +12 -0
- data/lib/fidgit/elements/label.rb +77 -0
- data/lib/fidgit/elements/list.rb +47 -0
- data/lib/fidgit/elements/menu_pane.rb +149 -0
- data/lib/fidgit/elements/packer.rb +42 -0
- data/lib/fidgit/elements/radio_button.rb +86 -0
- data/lib/fidgit/elements/scroll_area.rb +75 -0
- data/lib/fidgit/elements/scroll_bar.rb +114 -0
- data/lib/fidgit/elements/scroll_window.rb +92 -0
- data/lib/fidgit/elements/slider.rb +119 -0
- data/lib/fidgit/elements/text_area.rb +351 -0
- data/lib/fidgit/elements/toggle_button.rb +67 -0
- data/lib/fidgit/elements/tool_tip.rb +35 -0
- data/lib/fidgit/elements/vertical_packer.rb +12 -0
- data/lib/fidgit/event.rb +99 -0
- data/lib/fidgit/gosu_ext/color.rb +123 -0
- data/lib/fidgit/history.rb +85 -0
- data/lib/fidgit/redirector.rb +83 -0
- data/lib/fidgit/schema.rb +123 -0
- data/lib/fidgit/selection.rb +106 -0
- data/lib/fidgit/standard_ext/hash.rb +21 -0
- data/lib/fidgit/states/dialog_state.rb +42 -0
- data/lib/fidgit/states/file_dialog.rb +24 -0
- data/lib/fidgit/states/gui_state.rb +301 -0
- data/lib/fidgit/states/message_dialog.rb +61 -0
- data/lib/fidgit/thumbnail.rb +29 -0
- data/lib/fidgit/version.rb +5 -0
- data/lib/fidgit/window.rb +19 -0
- data/media/images/arrow.png +0 -0
- data/media/images/file_directory.png +0 -0
- data/media/images/file_file.png +0 -0
- data/media/images/pixel.png +0 -0
- data/spec/fidgit/elements/helpers/helper.rb +3 -0
- data/spec/fidgit/elements/label_spec.rb +49 -0
- data/spec/fidgit/event_spec.rb +149 -0
- data/spec/fidgit/gosu_ext/color_spec.rb +130 -0
- data/spec/fidgit/gosu_ext/helpers/helper.rb +3 -0
- data/spec/fidgit/helpers/helper.rb +4 -0
- data/spec/fidgit/helpers/tex_play_helper.rb +9 -0
- data/spec/fidgit/history_spec.rb +144 -0
- data/spec/fidgit/redirector_spec.rb +78 -0
- data/spec/fidgit/schema_spec.rb +67 -0
- data/spec/fidgit/schema_test.yml +32 -0
- data/spec/fidgit/thumbnail_spec.rb +50 -0
- metadata +177 -0
@@ -0,0 +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
|
106
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class Hash
|
2
|
+
# Merge not only the hashes, but all nested hashes as well.
|
3
|
+
# Written by Stefan Rusterholz (apeiros) from http://www.ruby-forum.com/topic/142809
|
4
|
+
def deep_merge!(other)
|
5
|
+
merger = lambda do |key, a, b|
|
6
|
+
(a.is_a?(Hash) && b.is_a?(Hash)) ? a.merge!(b, &merger) : b
|
7
|
+
end
|
8
|
+
|
9
|
+
merge!(other, &merger)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Merge not only the hashes, but all nested hashes as well.
|
13
|
+
# Written by Stefan Rusterholz (apeiros) from http://www.ruby-forum.com/topic/142809
|
14
|
+
def deep_merge(other)
|
15
|
+
merger = lambda do |key, a, b|
|
16
|
+
(a.is_a?(Hash) && b.is_a?(Hash)) ? a.merge(b, &merger) : b
|
17
|
+
end
|
18
|
+
|
19
|
+
merge(other, &merger)
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Fidgit
|
2
|
+
# A modal dialog.
|
3
|
+
# @abstract
|
4
|
+
class DialogState < GuiState
|
5
|
+
DEFAULT_BACKGROUND_COLOR = Gosu::Color.rgb(75, 75, 75)
|
6
|
+
DEFAULT_BORDER_COLOR = Gosu::Color.rgb(255, 255, 255)
|
7
|
+
|
8
|
+
DEFAULT_SHADOW_COLOR = Gosu::Color.rgba(0, 0, 0, 100)
|
9
|
+
DEFAULT_SHADOW_OFFSET = 8
|
10
|
+
|
11
|
+
def initialize(options = {})
|
12
|
+
# @option options [Gosu::Color] :shadow_color (transparent black) Color of the shadow.
|
13
|
+
# @option options [Gosu::Color] :shadow_offset (8) Distance shadow is offset to bottom and left.
|
14
|
+
# @option options [Gosu::Color] :shadow_full (false) Shadow fills whole screen. Ignores :shadow_offset option if true.
|
15
|
+
options = {
|
16
|
+
shadow_color: DEFAULT_SHADOW_COLOR,
|
17
|
+
shadow_offset: DEFAULT_SHADOW_OFFSET,
|
18
|
+
shadow_full: false,
|
19
|
+
}.merge! options
|
20
|
+
|
21
|
+
@shadow_color = options[:shadow_color].dup
|
22
|
+
@shadow_offset = options[:shadow_offset]
|
23
|
+
@shadow_full = options[:shadow_full]
|
24
|
+
|
25
|
+
super()
|
26
|
+
end
|
27
|
+
|
28
|
+
def draw
|
29
|
+
$window.game_state_manager.previous_game_state.draw # Keep the underlying state being shown.
|
30
|
+
$window.flush
|
31
|
+
|
32
|
+
if @shadow_full
|
33
|
+
draw_rect 0, 0, $window.width, $window.height, -Float::INFINITY, @shadow_color
|
34
|
+
elsif @shadow_offset > 0
|
35
|
+
dialog = container[0]
|
36
|
+
draw_rect dialog.x + @shadow_offset, dialog.y + @shadow_offset, dialog.width, dialog.height, -Float::INFINITY, @shadow_color
|
37
|
+
end
|
38
|
+
|
39
|
+
super
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Fidgit
|
2
|
+
# A simple dialog that manages a message with a set of buttons beneath it.
|
3
|
+
class FileDialog < DialogState
|
4
|
+
def initialize(type, options = {}, &block)
|
5
|
+
options = {
|
6
|
+
show: true,
|
7
|
+
background_color: DEFAULT_BACKGROUND_COLOR,
|
8
|
+
border_color: DEFAULT_BORDER_COLOR,
|
9
|
+
}.merge! options
|
10
|
+
|
11
|
+
super(options)
|
12
|
+
|
13
|
+
pack :vertical, align: :center, padding: 0 do |packer|
|
14
|
+
FileBrowser.new(type, { parent: packer }.merge!(options)) do |sender, result, file_name|
|
15
|
+
hide
|
16
|
+
block.call result, file_name if block
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
show if options[:show]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
@@ -0,0 +1,301 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Fidgit
|
4
|
+
class GuiState < Chingu::GameState
|
5
|
+
# A 1x1 white pixel used for drawing.
|
6
|
+
PIXEL_IMAGE = 'pixel.png'
|
7
|
+
|
8
|
+
# The Container that contains all the elements for this GuiState.
|
9
|
+
# @return [Packer]
|
10
|
+
attr_reader :container
|
11
|
+
|
12
|
+
# The element with focus.
|
13
|
+
# @return [Element]
|
14
|
+
attr_reader :focus
|
15
|
+
|
16
|
+
# The Cursor.
|
17
|
+
# @return [Cursor]
|
18
|
+
def cursor; @@cursor; end
|
19
|
+
|
20
|
+
# Sets the focus to a particular element.
|
21
|
+
def focus=(element)
|
22
|
+
@focus.publish :blur if @focus and element
|
23
|
+
@focus = element
|
24
|
+
end
|
25
|
+
|
26
|
+
# Delay, in ms, before a tool-tip will appear.
|
27
|
+
def tool_tip_delay
|
28
|
+
500 # TODO: configure this.
|
29
|
+
end
|
30
|
+
|
31
|
+
# Show a file_dialog.
|
32
|
+
# (see FileDialog#initialize)
|
33
|
+
def file_dialog(type, options = {}, &block)
|
34
|
+
FileDialog.new(type, options, &block)
|
35
|
+
end
|
36
|
+
|
37
|
+
# (see MenuPane#initialize)
|
38
|
+
def menu(options = {}, &block); MenuPane.new(options, &block); end
|
39
|
+
|
40
|
+
# (see MessageDialog#initialize)
|
41
|
+
def message(text, options = {}, &block); MessageDialog.new(text, options, &block); end
|
42
|
+
|
43
|
+
# (see Container#pack)
|
44
|
+
def pack(*args, &block); @container.pack *args, █ end
|
45
|
+
|
46
|
+
# (see Container#clear)
|
47
|
+
def clear(*args, &block); @container.clear *args, █ end
|
48
|
+
|
49
|
+
def initialize
|
50
|
+
# The container is where the user puts their content.
|
51
|
+
@container = VerticalPacker.new(padding: 0, width: $window.width, height: $window.height)
|
52
|
+
|
53
|
+
unless defined? @@draw_pixel
|
54
|
+
media_dir = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'media'))
|
55
|
+
Gosu::Image.autoload_dirs << File.join(media_dir, 'images')
|
56
|
+
Gosu::Sample.autoload_dirs << File.join(media_dir, 'sounds')
|
57
|
+
|
58
|
+
@@draw_pixel = Gosu::Image.new($window, File.join(media_dir, 'images', PIXEL_IMAGE), true) # Must be tileable or it will blur.
|
59
|
+
@@cursor = Cursor.new
|
60
|
+
end
|
61
|
+
|
62
|
+
@min_drag_distance = 0
|
63
|
+
|
64
|
+
super()
|
65
|
+
|
66
|
+
add_inputs(
|
67
|
+
left_mouse_button: ->{ redirect_mouse_button(:left) },
|
68
|
+
holding_left_mouse_button: ->{ redirect_holding_mouse_button(:left) },
|
69
|
+
released_left_mouse_button: ->{ redirect_released_mouse_button(:left) },
|
70
|
+
|
71
|
+
middle_mouse_button: ->{ redirect_mouse_button(:middle) },
|
72
|
+
holding_middle_mouse_button: ->{ redirect_holding_mouse_button(:middle) },
|
73
|
+
released_middle_mouse_button: ->{ redirect_released_mouse_button(:middle) },
|
74
|
+
|
75
|
+
right_mouse_button: ->{ redirect_mouse_button(:right) },
|
76
|
+
holding_right_mouse_button: ->{ redirect_holding_mouse_button(:right) },
|
77
|
+
released_right_mouse_button: ->{ redirect_released_mouse_button(:right) },
|
78
|
+
|
79
|
+
mouse_wheel_up: :redirect_mouse_wheel_up,
|
80
|
+
mouse_wheel_down: :redirect_mouse_wheel_down
|
81
|
+
)
|
82
|
+
end
|
83
|
+
|
84
|
+
# Internationalisation helper.
|
85
|
+
def t(*args); I18n.t(*args); end
|
86
|
+
|
87
|
+
# Clear the data which is specific to the current $window.
|
88
|
+
def self.clear
|
89
|
+
remove_class_variable '@@cursor' if defined? @@cursor
|
90
|
+
remove_class_variable '@@draw_pixel' if defined? @@draw_pixel
|
91
|
+
end
|
92
|
+
|
93
|
+
def update
|
94
|
+
cursor.update
|
95
|
+
@tool_tip.update if @tool_tip
|
96
|
+
@menu.update if @menu
|
97
|
+
@container.update
|
98
|
+
|
99
|
+
# Check menu first, then other elements.
|
100
|
+
new_mouse_over = @menu.hit_element(cursor.x, cursor.y) if @menu
|
101
|
+
new_mouse_over = @container.hit_element(cursor.x, cursor.y) unless new_mouse_over
|
102
|
+
|
103
|
+
if new_mouse_over
|
104
|
+
new_mouse_over.publish :enter if new_mouse_over != @mouse_over
|
105
|
+
new_mouse_over.publish :hover, cursor.x, cursor.y
|
106
|
+
end
|
107
|
+
|
108
|
+
@mouse_over.publish :leave if @mouse_over and new_mouse_over != @mouse_over
|
109
|
+
|
110
|
+
@mouse_over = new_mouse_over
|
111
|
+
|
112
|
+
# Check if the mouse has moved, and no menu is shown, so we can show a tooltip.
|
113
|
+
if [cursor.x, cursor.y] == @last_cursor_pos and (not @menu)
|
114
|
+
if @mouse_over and (Gosu::milliseconds - @mouse_moved_at) > tool_tip_delay
|
115
|
+
if text = @mouse_over.tip and not text.empty?
|
116
|
+
@tool_tip ||= ToolTip.new
|
117
|
+
@tool_tip.text = text
|
118
|
+
@tool_tip.x = cursor.x
|
119
|
+
@tool_tip.y = cursor.y + cursor.height # Place the tip beneath the cursor.
|
120
|
+
else
|
121
|
+
@tool_tip = nil
|
122
|
+
@mouse_moved_at = Gosu::milliseconds
|
123
|
+
end
|
124
|
+
end
|
125
|
+
else
|
126
|
+
@tool_tip = nil
|
127
|
+
@mouse_moved_at = Gosu::milliseconds
|
128
|
+
end
|
129
|
+
|
130
|
+
# The element that grabs input.
|
131
|
+
@active_element = @dragging_element || @focus || @mouse_over
|
132
|
+
|
133
|
+
@last_cursor_pos = [cursor.x, cursor.y]
|
134
|
+
|
135
|
+
super
|
136
|
+
end
|
137
|
+
|
138
|
+
def draw
|
139
|
+
@container.draw
|
140
|
+
@menu.draw if @menu
|
141
|
+
@tool_tip.draw if @tool_tip
|
142
|
+
cursor.draw
|
143
|
+
|
144
|
+
nil
|
145
|
+
end
|
146
|
+
|
147
|
+
def setup
|
148
|
+
super
|
149
|
+
|
150
|
+
@tool_tip = nil
|
151
|
+
@mouse_over = nil # Element the mouse is hovering over.
|
152
|
+
@mouse_down_on = Hash.new # Element that each button was pressed over.
|
153
|
+
@mouse_down_pos = Hash.new # Position that each button was pressed down at.
|
154
|
+
@drag_button = nil
|
155
|
+
@dragging_element = nil
|
156
|
+
@focus = nil
|
157
|
+
@mouse_moved_at = Gosu::milliseconds
|
158
|
+
|
159
|
+
nil
|
160
|
+
end
|
161
|
+
|
162
|
+
def finalize
|
163
|
+
@tool_tip = nil
|
164
|
+
|
165
|
+
nil
|
166
|
+
end
|
167
|
+
|
168
|
+
# Set the menu pane to be displayed.
|
169
|
+
#
|
170
|
+
# @param [MenuPane] menu Menu to display.
|
171
|
+
# @return nil
|
172
|
+
def show_menu(menu)
|
173
|
+
hide_menu if @menu
|
174
|
+
@menu = menu
|
175
|
+
|
176
|
+
nil
|
177
|
+
end
|
178
|
+
|
179
|
+
# Hides the currently shown menu, if any.
|
180
|
+
# @return nil
|
181
|
+
def hide_menu
|
182
|
+
@menu = nil
|
183
|
+
|
184
|
+
nil
|
185
|
+
end
|
186
|
+
|
187
|
+
# Flush all pending drawing to the screen.
|
188
|
+
def flush
|
189
|
+
$window.flush
|
190
|
+
end
|
191
|
+
|
192
|
+
# Draw a filled rectangle.
|
193
|
+
def draw_rect(x, y, width, height, z, color, mode = :default)
|
194
|
+
@@draw_pixel.draw x, y, z, width, height, color, mode
|
195
|
+
|
196
|
+
nil
|
197
|
+
end
|
198
|
+
|
199
|
+
# Draw an unfilled rectangle.
|
200
|
+
def draw_frame(x, y, width, height, thickness, z, color, mode = :default)
|
201
|
+
draw_rect(x - thickness, y, thickness, height, z, color, mode) # left
|
202
|
+
draw_rect(x - thickness, y - thickness, width + thickness * 2, thickness, z, color, mode) # top (full)
|
203
|
+
draw_rect(x + width, y, thickness, height, z, color, mode) # right
|
204
|
+
draw_rect(x - thickness, y + height, width + thickness * 2, thickness, z, color, mode) # bottom (full)
|
205
|
+
|
206
|
+
nil
|
207
|
+
end
|
208
|
+
|
209
|
+
def distance(x1, y1, x2, y2)
|
210
|
+
Gosu.distance(x1, y1, x2, y2)
|
211
|
+
end
|
212
|
+
|
213
|
+
def show
|
214
|
+
$window.game_state_manager.push self unless $window.game_state_manager.game_states.include? self
|
215
|
+
nil
|
216
|
+
end
|
217
|
+
|
218
|
+
def hide
|
219
|
+
$window.game_state_manager.pop if $window.game_state_manager.current == self
|
220
|
+
nil
|
221
|
+
end
|
222
|
+
|
223
|
+
protected
|
224
|
+
def redirect_mouse_button(button)
|
225
|
+
# Ensure that if the user clicks away from a menu, it is automatically closed.
|
226
|
+
hide_menu unless @menu and @menu == @mouse_over
|
227
|
+
|
228
|
+
# Blur if clicking outside the focused element.
|
229
|
+
if @focus and @mouse_over != @focus
|
230
|
+
@focus.publish :blur
|
231
|
+
@focus = nil
|
232
|
+
end
|
233
|
+
|
234
|
+
# Publish :left_mouse_button for the element that is clicked.
|
235
|
+
if @mouse_over
|
236
|
+
@mouse_down_pos[button] = [cursor.x, cursor.y]
|
237
|
+
@mouse_down_on[button] = @mouse_over
|
238
|
+
@mouse_over.publish :"#{button}_mouse_button", *@mouse_down_pos[button]
|
239
|
+
else
|
240
|
+
@mouse_down_pos[button] = nil
|
241
|
+
@mouse_down_on[button] = nil
|
242
|
+
end
|
243
|
+
|
244
|
+
nil
|
245
|
+
end
|
246
|
+
|
247
|
+
protected
|
248
|
+
def redirect_released_mouse_button(button)
|
249
|
+
# Ensure that if the user clicks away from a menu, it is automatically closed.
|
250
|
+
hide_menu if @menu and @mouse_over != @menu
|
251
|
+
|
252
|
+
if @mouse_over
|
253
|
+
@mouse_over.publish :"released_#{button}_mouse_button", cursor.x, cursor.y
|
254
|
+
@mouse_over.publish :"clicked_#{button}_mouse_button", cursor.x, cursor.y if @mouse_over == @mouse_down_on[button]
|
255
|
+
end
|
256
|
+
|
257
|
+
if @dragging_element and @drag_button == button
|
258
|
+
@dragging_element.publish :end_drag, cursor.x, cursor.y, @drag_button, @mouse_over
|
259
|
+
@dragging_element = nil
|
260
|
+
@drag_button = nil
|
261
|
+
end
|
262
|
+
|
263
|
+
@mouse_down_on[button] = nil
|
264
|
+
@mouse_down_pos[button] = nil
|
265
|
+
|
266
|
+
nil
|
267
|
+
end
|
268
|
+
|
269
|
+
protected
|
270
|
+
def redirect_holding_mouse_button(button)
|
271
|
+
if not @dragging_element and @mouse_down_on[button] and @mouse_down_on[button].drag?(button) and
|
272
|
+
distance(*@mouse_down_pos[button], cursor.x, cursor.y) > @min_drag_distance
|
273
|
+
@drag_button = button
|
274
|
+
@dragging_element = @mouse_down_on[button]
|
275
|
+
@dragging_element.publish :begin_drag, *@mouse_down_pos[button], :left
|
276
|
+
end
|
277
|
+
|
278
|
+
if @dragging_element
|
279
|
+
if @drag_button == button
|
280
|
+
@dragging_element.publish :update_drag, cursor.x, cursor.y
|
281
|
+
end
|
282
|
+
else
|
283
|
+
@mouse_over.publish :"holding_#{button}_mouse_button", cursor.x, cursor.y if @mouse_over
|
284
|
+
end
|
285
|
+
|
286
|
+
nil
|
287
|
+
end
|
288
|
+
|
289
|
+
protected
|
290
|
+
def redirect_mouse_wheel_up
|
291
|
+
@active_element.publish :mouse_wheel_up, cursor.x, cursor.y if @active_element
|
292
|
+
nil
|
293
|
+
end
|
294
|
+
|
295
|
+
protected
|
296
|
+
def redirect_mouse_wheel_down
|
297
|
+
@active_element.publish :mouse_wheel_down, cursor.x, cursor.y if @active_element
|
298
|
+
nil
|
299
|
+
end
|
300
|
+
end
|
301
|
+
end
|