glimr 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. data/lib/glimr.rb +2 -0
  2. data/lib/glimr/configurable.rb +37 -0
  3. data/lib/glimr/default_theme/button_bg.png +0 -0
  4. data/lib/glimr/default_theme/button_bg_down.png +0 -0
  5. data/lib/glimr/default_theme/button_cover.png +0 -0
  6. data/lib/glimr/default_theme/button_cover_down.png +0 -0
  7. data/lib/glimr/default_theme/button_focus.png +0 -0
  8. data/lib/glimr/default_theme/checkbox_bg.png +0 -0
  9. data/lib/glimr/default_theme/checkbox_checked_bg.png +0 -0
  10. data/lib/glimr/default_theme/font.ttf +0 -0
  11. data/lib/glimr/default_theme/hscroller_bg.png +0 -0
  12. data/lib/glimr/default_theme/radiobutton_bg.png +0 -0
  13. data/lib/glimr/default_theme/radiobutton_checked_bg.png +0 -0
  14. data/lib/glimr/default_theme/resizer_down.png +0 -0
  15. data/lib/glimr/default_theme/resizer_up.png +0 -0
  16. data/lib/glimr/default_theme/scroll_down_down.png +0 -0
  17. data/lib/glimr/default_theme/scroll_down_up.png +0 -0
  18. data/lib/glimr/default_theme/scroll_hknob_down.png +0 -0
  19. data/lib/glimr/default_theme/scroll_hknob_up.png +0 -0
  20. data/lib/glimr/default_theme/scroll_left_down.png +0 -0
  21. data/lib/glimr/default_theme/scroll_left_up.png +0 -0
  22. data/lib/glimr/default_theme/scroll_right_down.png +0 -0
  23. data/lib/glimr/default_theme/scroll_right_up.png +0 -0
  24. data/lib/glimr/default_theme/scroll_up_down.png +0 -0
  25. data/lib/glimr/default_theme/scroll_up_up.png +0 -0
  26. data/lib/glimr/default_theme/scroll_vknob_down.png +0 -0
  27. data/lib/glimr/default_theme/scroll_vknob_up.png +0 -0
  28. data/lib/glimr/default_theme/text_cursor.png +0 -0
  29. data/lib/glimr/default_theme/text_cursor_insert.png +0 -0
  30. data/lib/glimr/default_theme/text_input_bg.png +0 -0
  31. data/lib/glimr/default_theme/vscroller_bg.png +0 -0
  32. data/lib/glimr/event.rb +41 -0
  33. data/lib/glimr/eventlistener.rb +209 -0
  34. data/lib/glimr/layoutable.rb +520 -0
  35. data/lib/glimr/renderer.rb +2 -0
  36. data/lib/glimr/renderer/camera.rb +63 -0
  37. data/lib/glimr/renderer/geometry.rb +194 -0
  38. data/lib/glimr/renderer/glutwindow.rb +387 -0
  39. data/lib/glimr/renderer/light.rb +43 -0
  40. data/lib/glimr/renderer/material.rb +66 -0
  41. data/lib/glimr/renderer/model.rb +103 -0
  42. data/lib/glimr/renderer/orthoprojection.rb +21 -0
  43. data/lib/glimr/renderer/raw.rb +34 -0
  44. data/lib/glimr/renderer/sceneobject.rb +279 -0
  45. data/lib/glimr/renderer/shader.rb +14 -0
  46. data/lib/glimr/renderer/texture.rb +280 -0
  47. data/lib/glimr/renderer/transform.rb +322 -0
  48. data/lib/glimr/renderer/viewport.rb +349 -0
  49. data/lib/glimr/renderer_core.rb +10 -0
  50. data/lib/glimr/util.rb +247 -0
  51. data/lib/glimr/widget.rb +87 -0
  52. data/lib/glimr/widgets.rb +37 -0
  53. data/lib/glimr/widgets/button.rb +277 -0
  54. data/lib/glimr/widgets/checkbox.rb +82 -0
  55. data/lib/glimr/widgets/container.rb +84 -0
  56. data/lib/glimr/widgets/image.rb +82 -0
  57. data/lib/glimr/widgets/label.rb +91 -0
  58. data/lib/glimr/widgets/layout.rb +227 -0
  59. data/lib/glimr/widgets/list.rb +28 -0
  60. data/lib/glimr/widgets/radiogroup.rb +118 -0
  61. data/lib/glimr/widgets/resizer.rb +31 -0
  62. data/lib/glimr/widgets/scrollable_container.rb +67 -0
  63. data/lib/glimr/widgets/scrollbar.rb +496 -0
  64. data/lib/glimr/widgets/stretchable_image.rb +135 -0
  65. data/lib/glimr/widgets/text_editor.rb +349 -0
  66. data/tests/assets/datatowers_crop.jpg +0 -0
  67. data/tests/assets/download_progress_meter.png +0 -0
  68. data/tests/assets/metalwing2.png +0 -0
  69. data/tests/assets/redhairgreeneyes3.jpg +0 -0
  70. data/tests/demo_apps/spinning_ruby.rb +37 -0
  71. data/tests/integration_tests/run_all.rb +8 -0
  72. data/tests/integration_tests/test_button.rb +22 -0
  73. data/tests/integration_tests/test_checkbox.rb +21 -0
  74. data/tests/integration_tests/test_container.rb +22 -0
  75. data/tests/integration_tests/test_label.rb +12 -0
  76. data/tests/integration_tests/test_layout.rb +43 -0
  77. data/tests/integration_tests/test_radiogroup.rb +16 -0
  78. data/tests/integration_tests/test_renderer.rb +44 -0
  79. data/tests/integration_tests/test_renderer2.rb +36 -0
  80. data/tests/integration_tests/test_scrollable_container.rb +34 -0
  81. data/tests/integration_tests/test_scrollbar.rb +20 -0
  82. data/tests/integration_tests/test_stretchable_image.rb +34 -0
  83. data/tests/integration_tests/test_text_input.rb +20 -0
  84. data/tests/integration_tests/test_zsort.rb +18 -0
  85. data/tests/unit_tests/test_button.rb +93 -0
  86. data/tests/unit_tests/test_checkbox.rb +35 -0
  87. data/tests/unit_tests/test_label.rb +36 -0
  88. data/tests/unit_tests/test_layout.rb +229 -0
  89. data/tests/unit_tests/test_widget.rb +3 -0
  90. metadata +139 -0
@@ -0,0 +1,28 @@
1
+ require 'glimr/widgets/scrollable_container'
2
+
3
+
4
+ module GlimR
5
+
6
+
7
+ # A List is a Scrollable with a VLayout as its content.
8
+ #
9
+ class List < ScrollableContainer
10
+
11
+ def default_config
12
+ super.merge(
13
+ :width => 200,
14
+ :height => 100,
15
+ :content => VLayout.new
16
+ )
17
+ end
18
+
19
+ def initialize(*args, &b)
20
+ super
21
+ end
22
+
23
+ end
24
+
25
+
26
+ end
27
+
28
+
@@ -0,0 +1,118 @@
1
+ require 'glimr/widgets/checkbox'
2
+
3
+
4
+ module GlimR
5
+
6
+ class RadioGroup < VLayout
7
+
8
+ attr_accessor :selected_index, :options
9
+
10
+ def default_config
11
+ super.merge(
12
+ :selected_index => 0,
13
+ :options => ["Default", "Options"]
14
+ )
15
+ end
16
+
17
+ def initialize(*a, &b)
18
+ super
19
+ self.label = @label if @label
20
+ @option_models = []
21
+ self.options = @options
22
+ self.selected_index = @selected_index
23
+ end
24
+
25
+ def label= l
26
+ if @label_model
27
+ @label_model.text = l
28
+ else
29
+ @label_model = Label.new(:text => @label)
30
+ attach @label_model
31
+ end
32
+ end
33
+
34
+ def options=(opts)
35
+ @options = opts
36
+ @option_models.each{|m| m.detach_self }
37
+ @option_models.clear
38
+ @options.each_with_index{|opt, i|
39
+ rb = RadioOption.new(:label => opt)
40
+ rb.on_change{|o,e|
41
+ self.selected_index = i
42
+ dispatch_event(
43
+ Event.new(
44
+ :select,
45
+ {
46
+ :source => self,
47
+ :selected_index => i,
48
+ :option => selection
49
+ }
50
+ )
51
+ )
52
+ }
53
+ @option_models << rb
54
+ }
55
+ attach *@option_models
56
+ end
57
+
58
+ def selected_index=(index)
59
+ @option_models[@selected_index].state = false
60
+ @selected_index = index
61
+ @option_models[@selected_index].state = true
62
+ end
63
+
64
+ def selected_model
65
+ @option_models[@selected_index]
66
+ end
67
+
68
+ def selected_model= s
69
+ @option_models.each_with_index{|e,i|
70
+ if e == s
71
+ self.selected_index = i
72
+ break
73
+ end
74
+ }
75
+ end
76
+
77
+ def selection
78
+ @option_models[@selected_index].label
79
+ end
80
+
81
+ def selection= s
82
+ @option_models.each_with_index{|e,i|
83
+ if e.label == s
84
+ self.selected_index = i
85
+ break
86
+ end
87
+ }
88
+ end
89
+
90
+ end
91
+
92
+
93
+ class RadioOption < Checkbox
94
+
95
+ def default_config
96
+ super.merge(
97
+ :button => RadioOptionButton.new
98
+ )
99
+ end
100
+
101
+ end
102
+
103
+ class RadioOptionButton < CheckboxButton
104
+
105
+ def default_config
106
+ super.merge(
107
+ :up_background => "radiobutton_bg.png",
108
+ :down_background => "radiobutton_checked_bg.png"
109
+ )
110
+ end
111
+
112
+ def activate o,e
113
+ super unless parent.state
114
+ end
115
+
116
+ end
117
+
118
+ end
@@ -0,0 +1,31 @@
1
+ require 'glimr/widgets/button'
2
+
3
+
4
+ module GlimR
5
+
6
+
7
+ class Resizer < EmptyButton
8
+
9
+ attr_accessor :target
10
+
11
+ def default_config
12
+ super.merge(
13
+ :up_background => "resizer_up.png",
14
+ :down_background => "resizer_down.png"
15
+ )
16
+ end
17
+
18
+ def mouse_move(o,e)
19
+ super
20
+ if down and target and e.buttons[:left]
21
+ target.size_changing{
22
+ target.width += e.dx
23
+ target.height += e.dy
24
+ }
25
+ end
26
+ end
27
+
28
+ end
29
+
30
+
31
+ end
@@ -0,0 +1,67 @@
1
+ require 'glimr/widgets/layout'
2
+ require 'glimr/widgets/container'
3
+ require 'glimr/widgets/scrollbar'
4
+ require 'glimr/widgets/resizer'
5
+
6
+
7
+ module GlimR
8
+
9
+
10
+ class ScrollableContainer < Widget
11
+
12
+ ivar_accessor_delegate :@container, :content, :content_view
13
+ attr_accessor :container, :horizontal_scrollbar, :vertical_scrollbar, :resizer
14
+
15
+ def default_config
16
+ super.merge(
17
+ :width => 200,
18
+ :height => 200,
19
+ :content => nil
20
+ )
21
+ end
22
+
23
+ def initialize(*a, &b)
24
+ super
25
+ @resizer = Resizer.new(:target => self)
26
+ vsplit = VLayout.new(
27
+ :item_spacing => 0,
28
+ :expand_width => true, :expand_height => true
29
+ )
30
+ hsplit = HLayout.new(
31
+ :item_spacing => 0,
32
+ :expand_width => true, :expand_height => true
33
+ )
34
+ @container = Container.new(
35
+ :content => @content,
36
+ :expand_width => true, :expand_height => true
37
+ )
38
+ @vertical_scrollbar = VScrollBar.new(:container => @container)
39
+ @horizontal_scrollbar = HScrollBar.new(:container => @container)
40
+ @vertical_scrollbar.on_scroll{|o,e|
41
+ @container.scroll_y = e.y
42
+ }
43
+ @horizontal_scrollbar.on_scroll{|o,e|
44
+ @container.scroll_x = e.x
45
+ }
46
+ bottom_scroller = HLayout.new(:expand_width => true, :item_spacing => 0)
47
+ bottom_scroller << @horizontal_scrollbar << @resizer
48
+ hsplit << @container << @vertical_scrollbar
49
+ vsplit << hsplit << bottom_scroller
50
+ attach vsplit
51
+ @container.on_mouse_down{|o,e|
52
+ case e.button
53
+ when :wheel_up
54
+ @vertical_scrollbar.scroll_up
55
+ when :wheel_down
56
+ @vertical_scrollbar.scroll_down
57
+ end
58
+ }
59
+ self.min_width = @horizontal_scrollbar.min_width + @resizer.width
60
+ self.min_height = @vertical_scrollbar.min_height + @resizer.height
61
+ end
62
+
63
+ end
64
+
65
+
66
+ end
67
+
@@ -0,0 +1,496 @@
1
+ require 'glimr/widgets/layout'
2
+ require 'glimr/widgets/stretchable_image'
3
+ require 'glimr/widgets/button'
4
+
5
+ module GlimR
6
+
7
+ module Scrollable
8
+
9
+ def default_config
10
+ super.merge(
11
+ :default_scroll_horiz => 0.1,
12
+ :default_scroll_vert => 0.1,
13
+ :scroll_x => 0.0,
14
+ :scroll_y => 0.0
15
+ )
16
+ end
17
+
18
+ # Default horizontal scroll amount (=0.1).
19
+ attr_accessor :default_scroll_horiz
20
+
21
+ # Default horizontal scroll amount (=0.1).
22
+ attr_accessor :default_scroll_vert
23
+
24
+ # Accessors for scroll positions
25
+ attr_accessor :scroll_x, :scroll_y
26
+
27
+ # Scrolls to left (decreases scroll_x) by given
28
+ # amount, default is #default_scroll_horiz.
29
+ #
30
+ def scroll_left(amount = default_scroll_horiz)
31
+ self.scroll_x -= amount
32
+ end
33
+
34
+ # Scrolls to right (increases scroll_x) by given
35
+ # amount, default is #default_scroll_horiz.
36
+ #
37
+ def scroll_right(amount = default_scroll_horiz)
38
+ self.scroll_x += amount
39
+ end
40
+
41
+ # Scrolls up (decreases scroll_y) by given
42
+ # amount, default is #default_scroll_vert.
43
+ #
44
+ def scroll_up(amount = default_scroll_vert)
45
+ self.scroll_y -= amount
46
+ end
47
+
48
+ # Scrolls down (increases scroll_y) by given
49
+ # amount, default is #default_scroll_vert.
50
+ #
51
+ def scroll_down(amount = default_scroll_vert)
52
+ self.scroll_y += amount
53
+ end
54
+
55
+ # Scrolls x to nx, calls scroll_to to do the scrolling.
56
+ def scroll_x=(nx)
57
+ scroll_to(nx, scroll_y)
58
+ end
59
+
60
+ # Scrolls y to ny, calls scroll_to to do the scrolling.
61
+ def scroll_y=(ny)
62
+ scroll_to(scroll_x, ny)
63
+ end
64
+
65
+ # Increases both x and y scroll position by given amounts.
66
+ def scroll(x, y)
67
+ scroll_to(@scroll_position.x + x, @scroll_position.y + y)
68
+ end
69
+
70
+ def scroll_x
71
+ (@container and @container.scroll_x) or @scroll_x
72
+ end
73
+
74
+ def scroll_y
75
+ (@container and @container.scroll_y) or @scroll_y
76
+ end
77
+
78
+ # Scrolls to given coordinates, clamped between 0.0 and 1.0, and
79
+ # fires a scroll event.
80
+ def scroll_to(x,y)
81
+ @scroll_x = [[x, 0.0].max, 1.0].min
82
+ @scroll_y = [[y, 0.0].max, 1.0].min
83
+ @container.scroll = [@scroll_x, @scroll_y] if @container
84
+ dispatch_event(Event.new(:scroll, :x => scroll_x, :y => scroll_y, :source => self))
85
+ end
86
+
87
+ end
88
+
89
+
90
+ class HScrollBar < HLayout
91
+ include Scrollable
92
+
93
+ touching_accessor :container
94
+
95
+ def default_config
96
+ super.merge(
97
+ :item_spacing => 0,
98
+ :expand_width => true, :container => nil,
99
+ :left_button => ScrollLeftButton.new,
100
+ :right_button => ScrollRightButton.new,
101
+ :scroller => HScroller.new
102
+ )
103
+ end
104
+
105
+ def initialize(*a, &b)
106
+ super
107
+ attach @left_button, @scroller, @right_button
108
+ @updater = lambda{|o,e| @scroller.update_knob }
109
+ self.container = @container
110
+ on_scroll{ @scroller.knob.scroll_handler if @scroller }
111
+ self.min_width = @left_button.width + @right_button.width + @scroller.min_width
112
+ end
113
+
114
+ def click(o,e)
115
+ case e.button
116
+ when :wheel_down
117
+ scroll_right
118
+ when :wheel_up
119
+ scroll_left
120
+ end
121
+ end
122
+
123
+ def container=(c)
124
+ @container.remove_event_listener(:layout, @updater) if @container
125
+ @container = c
126
+ @container.add_event_listener(:layout, @updater) if @container
127
+ @scroller.update_knob if @scroller
128
+ touch!
129
+ end
130
+
131
+ end
132
+
133
+
134
+ class VScrollBar < VLayout
135
+ include Scrollable
136
+
137
+ touching_accessor :container
138
+
139
+ def default_config
140
+ super.merge(
141
+ :item_spacing => 0,
142
+ :expand_height => true, :container => nil,
143
+ :up_button => ScrollUpButton.new,
144
+ :down_button => ScrollDownButton.new,
145
+ :scroller => VScroller.new
146
+ )
147
+ end
148
+
149
+ def initialize(*a, &b)
150
+ super
151
+ attach @up_button, @scroller, @down_button
152
+ @updater = lambda{|o,e| @scroller.update_knob }
153
+ self.container = @container
154
+ on_scroll{ @scroller.knob.scroll_handler if @scroller }
155
+ self.min_height = @up_button.height + @down_button.height + @scroller.min_height
156
+ end
157
+
158
+ def click(o,e)
159
+ case e.button
160
+ when :wheel_down
161
+ scroll_down
162
+ when :wheel_up
163
+ scroll_up
164
+ end
165
+ end
166
+
167
+ def container=(c)
168
+ @container.remove_event_listener(:layout, @updater) if @container
169
+ @container = c
170
+ @container.add_event_listener(:layout, @updater) if @container
171
+ @scroller.update_knob if @scroller
172
+ end
173
+
174
+ end
175
+
176
+
177
+ class HScroller < Widget
178
+
179
+ touching_accessor :knob
180
+
181
+ def default_config
182
+ super.merge(
183
+ :expand_width => true,
184
+ :knob => HScrollKnob.new,
185
+ :background => GlimR::StretchableImage.load_theme('hscroller_bg.png')
186
+ )
187
+ end
188
+
189
+ def initialize(*a,&b)
190
+ super
191
+ @knob.z = 5
192
+ attach @background, @knob
193
+ self.min_width = @knob.width
194
+ end
195
+
196
+ def click(o,e)
197
+ if e.target == @background.geometry
198
+ distance_from_knob_right = (@knob.x + @knob.width - e.rx)
199
+ distance_from_knob_left = (@knob.x - e.rx)
200
+ if distance_from_knob_right.abs > distance_from_knob_left.abs
201
+ @knob.new_x = e.rx
202
+ else
203
+ @knob.new_x = e.rx - @knob.width
204
+ end
205
+ end
206
+ end
207
+
208
+ def update_knob
209
+ @knob.layout
210
+ end
211
+
212
+ def layout
213
+ return if @layouting
214
+ @layouting = true
215
+ super
216
+ @background.set_dimensions(@width, @height) if @background.width != @width or @background.height != @height
217
+ update_knob
218
+ @layouting = false
219
+ end
220
+
221
+ end
222
+
223
+
224
+ class VScroller < Widget
225
+
226
+ touching_accessor :knob
227
+
228
+ def default_config
229
+ super.merge(
230
+ :expand_height => true,
231
+ :knob => VScrollKnob.new,
232
+ :background => GlimR::StretchableImage.load_theme('vscroller_bg.png')
233
+ )
234
+ end
235
+
236
+ def initialize(*a,&b)
237
+ super
238
+ @knob.z = 5
239
+ attach @background,@knob
240
+ self.min_height = @knob.height
241
+ end
242
+
243
+ def click(o,e)
244
+ if e.target == @background.geometry
245
+ distance_from_knob_bottom = (@knob.y + @knob.height - e.ry)
246
+ distance_from_knob_top = (@knob.y - e.ry)
247
+ if distance_from_knob_bottom.abs > distance_from_knob_top.abs
248
+ @knob.new_y = e.ry
249
+ else
250
+ @knob.new_y = e.ry - @knob.height
251
+ end
252
+ end
253
+ end
254
+
255
+ def update_knob
256
+ @knob.layout
257
+ end
258
+
259
+ def layout
260
+ return if @layouting
261
+ @layouting = true
262
+ super
263
+ @background.set_dimensions(@width, @height) if @background.width != @width or @background.height != @height
264
+ update_knob
265
+ @layouting = false
266
+ end
267
+
268
+ end
269
+
270
+
271
+ class HScrollKnob < EmptyButton
272
+
273
+ def default_config
274
+ super.merge(
275
+ :up_background => "scroll_hknob_up.png",
276
+ :down_background => "scroll_hknob_down.png",
277
+ :up_cover => nil, :down_cover => nil, :focus_indicator => nil,
278
+ :label => nil,
279
+ :padding => 0, :rel_x => 0
280
+ )
281
+ end
282
+
283
+ def initialize(*a,&b)
284
+ super
285
+ on_scroll(:scroll_handler)
286
+ end
287
+
288
+ def container
289
+ parent.parent.container
290
+ rescue NoMethodError
291
+ nil
292
+ end
293
+
294
+ def layout
295
+ return if @layouting
296
+ @layouting = true
297
+ if container
298
+ self.width = [parent.inner_width,
299
+ [
300
+ self.min_width || 0.0,
301
+ (container.width / container.content.width.to_f)*parent.inner_width
302
+ ].max
303
+ ].min.to_i
304
+ @background_model.width = @width if @background_model
305
+ parent.parent.scroll_x = parent.parent.scroll_x
306
+ end
307
+ @layouting = false
308
+ end
309
+
310
+ def mouse_down(o,e)
311
+ super
312
+ @rel_x = e.rx
313
+ end
314
+
315
+ def mouse_move(o,e)
316
+ if @down and e.buttons[:left]
317
+ self.new_x += e.dx
318
+ @rel_x += e.dx
319
+ end
320
+ end
321
+
322
+ def new_x
323
+ @new_x || self.x
324
+ end
325
+
326
+ def new_x=(nx)
327
+ on_frame(:update_scroll) unless @new_x
328
+ @new_x = [scroll_max, [0, nx].max].min
329
+ end
330
+
331
+ # The highest value the scroll knob can have. (Lowest is 0.)
332
+ def scroll_max
333
+ parent.inner_width - self.full_width
334
+ end
335
+
336
+ def scroll_handler(*a)
337
+ self.x = parent.parent.scroll_x * scroll_max
338
+ end
339
+
340
+ def update_scroll(o,e)
341
+ new_scroll = (scroll_max > 0 ? (@new_x.to_f / scroll_max) : (@rel_x.to_f / parent.inner_width))
342
+ parent.parent.scroll_x = new_scroll
343
+ @new_x = nil
344
+ remove_event_listener(:frame, :update_scroll)
345
+ end
346
+
347
+ end
348
+
349
+
350
+ class VScrollKnob < EmptyButton
351
+
352
+ def default_config
353
+ super.merge(
354
+ :up_background => "scroll_vknob_up.png",
355
+ :down_background => "scroll_vknob_down.png",
356
+ :up_cover => nil, :down_cover => nil, :focus_indicator => nil, :label => nil,
357
+ :padding => 0, :rel_y => 0
358
+ )
359
+ end
360
+
361
+ def initialize(*a,&b)
362
+ super
363
+ on_scroll(:scroll_handler)
364
+ end
365
+
366
+ def container
367
+ parent.parent.container
368
+ rescue NoMethodError
369
+ nil
370
+ end
371
+
372
+ def layout
373
+ return if @layouting
374
+ @layouting = true
375
+ if container
376
+ self.height = [parent.inner_height,
377
+ [
378
+ self.min_height || 0.0,
379
+ (container.height / container.content.height.to_f)*parent.inner_height
380
+ ].max
381
+ ].min.to_i
382
+ @background_model.height = @height if @background_model
383
+ parent.parent.scroll_y = parent.parent.scroll_y
384
+ end
385
+ @layouting = false
386
+ end
387
+
388
+ def mouse_down(o,e)
389
+ super
390
+ @rel_y = e.ry
391
+ end
392
+
393
+ def mouse_move(o,e)
394
+ if @down and e.buttons[:left]
395
+ self.new_y += e.dy
396
+ @rel_y += e.dy
397
+ end
398
+ end
399
+
400
+ def new_y
401
+ @new_y || self.y
402
+ end
403
+
404
+ def new_y=(ny)
405
+ on_frame(:update_scroll) unless @new_y
406
+ @new_y = [scroll_max, [0, ny].max].min
407
+ end
408
+
409
+ # The highest value the scroll knob can have. (Lowest is 0.)
410
+ def scroll_max
411
+ parent.inner_height - self.full_height
412
+ end
413
+
414
+ def scroll_handler(*a)
415
+ self.y = parent.parent.scroll_y * scroll_max
416
+ end
417
+
418
+ def update_scroll(o,e)
419
+ new_scroll = (scroll_max > 0 ? (@new_y.to_f / scroll_max) : (@rel_y.to_f / parent.inner_height))
420
+ parent.parent.scroll_y = new_scroll
421
+ @new_y = nil
422
+ remove_event_listener(:frame, :update_scroll)
423
+ end
424
+
425
+ end
426
+
427
+
428
+ class ScrollLeftButton < EmptyButton
429
+
430
+ def default_config
431
+ super.merge(
432
+ :up_background => "scroll_left_up.png",
433
+ :down_background => "scroll_left_down.png",
434
+ :up_cover => nil, :down_cover => nil, :focus_indicator => nil, :label => nil,
435
+ :padding => 0
436
+ )
437
+ end
438
+
439
+ def activate(o,e)
440
+ parent.scroll_left
441
+ end
442
+
443
+ end
444
+
445
+ class ScrollRightButton < EmptyButton
446
+
447
+ def default_config
448
+ super.merge(
449
+ :up_background => "scroll_right_up.png",
450
+ :down_background => "scroll_right_down.png",
451
+ :up_cover => nil, :down_cover => nil, :focus_indicator => nil, :label => nil,
452
+ :padding => 0
453
+ )
454
+ end
455
+
456
+ def activate(o,e)
457
+ parent.scroll_right
458
+ end
459
+
460
+ end
461
+
462
+ class ScrollUpButton < EmptyButton
463
+
464
+ def default_config
465
+ super.merge(
466
+ :up_background => "scroll_up_up.png",
467
+ :down_background => "scroll_up_down.png",
468
+ :up_cover => nil, :down_cover => nil, :focus_indicator => nil, :label => nil,
469
+ :padding => 0
470
+ )
471
+ end
472
+
473
+ def activate(o,e)
474
+ parent.scroll_up
475
+ end
476
+
477
+ end
478
+
479
+ class ScrollDownButton < EmptyButton
480
+
481
+ def default_config
482
+ super.merge(
483
+ :up_background => "scroll_down_up.png",
484
+ :down_background => "scroll_down_down.png",
485
+ :up_cover => nil, :down_cover => nil, :focus_indicator => nil, :label => nil,
486
+ :padding => 0
487
+ )
488
+ end
489
+
490
+ def activate(o,e)
491
+ parent.scroll_down
492
+ end
493
+
494
+ end
495
+
496
+ end