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,84 @@
1
+ require 'glimr/widget'
2
+
3
+
4
+ module GlimR
5
+
6
+ class Container < Widget
7
+
8
+ touching_accessor :scroll_x, :scroll_y, :content
9
+ attr_reader :content_view
10
+
11
+ def default_config
12
+ super.merge(
13
+ :scroll_x => 0,
14
+ :scroll_y => 0,
15
+ :width => 200,
16
+ :height => 100,
17
+ :fit_to_children => false
18
+ )
19
+ end
20
+
21
+ def initialize(*a, &b)
22
+ @content_view = Viewport.new(
23
+ :x => 0, :y => 0, :width => 1, :height => 1
24
+ )
25
+ @mirror_event = method(:mirror_event).to_proc
26
+ super
27
+ self.content = @content if @content
28
+ @content_view.on_layout(@mirror_event)
29
+ attach @content_view
30
+ end
31
+
32
+ def mirror_event(o,e)
33
+ process_event e
34
+ end
35
+
36
+ def content= c
37
+ @content_view.detach @content if @content
38
+ @content.remove_event_listener(:layout, @mirror_event) if @content
39
+ @content = c
40
+ @content_view.attach @content if @content
41
+ @content.add_event_listener(:layout, @mirror_event) if @content
42
+ end
43
+
44
+ def scroll_x=(x)
45
+ @scroll_x = x
46
+ if @content
47
+ case x
48
+ when Float
49
+ @content.x = -x*(@content.width-@width).to_i
50
+ else
51
+ @content.x = -x
52
+ end
53
+ end
54
+ end
55
+
56
+ def scroll_y=(y)
57
+ @scroll_y = y
58
+ if @content
59
+ case y
60
+ when Float
61
+ @content.y = -y*(@content.height-@height).to_i
62
+ else
63
+ @content.y = -y
64
+ end
65
+ end
66
+ end
67
+
68
+ def scroll
69
+ [@scroll_x, @scroll_y]
70
+ end
71
+
72
+ def scroll= s
73
+ self.scroll_x, self.scroll_y = *s
74
+ end
75
+
76
+ def layout
77
+ super
78
+ @content_view.width = @width
79
+ @content_view.height = @height
80
+ end
81
+
82
+ end
83
+
84
+ end
@@ -0,0 +1,82 @@
1
+ require 'glimr/widget'
2
+
3
+
4
+ module GlimR
5
+
6
+
7
+ # Image is a quad matching a texture's dimensions.
8
+ class Image < Widget
9
+
10
+ def self.load(filename)
11
+ image = new
12
+ image.load(filename)
13
+ image
14
+ end
15
+
16
+ def self.load_theme(filename)
17
+ load(GlimR.theme + filename)
18
+ end
19
+
20
+ attr_accessor :image, :bound
21
+
22
+ def default_config
23
+ super.merge(
24
+ :fit_children => false,
25
+ :image => nil
26
+ )
27
+ end
28
+
29
+ def initialize(*a,&b)
30
+ super
31
+ if @image
32
+ load(@image)
33
+ end
34
+ end
35
+
36
+ def texture= t
37
+ super
38
+ update_geometry
39
+ end
40
+
41
+ def load(filename,update_geo=true)
42
+ @texture.load(filename)
43
+ update_geometry if update_geo
44
+ end
45
+
46
+ def load_theme(filename,update_geo=true)
47
+ load(GlimR.theme + filename, update_geo)
48
+ end
49
+
50
+ def update_geometry
51
+ @geometry.vertices = create_vertices
52
+ @geometry.normals = create_normals
53
+ @geometry.colors = create_colors
54
+ @geometry.texcoords = create_texcoords
55
+ end
56
+
57
+ def create_colors
58
+ nil
59
+ end
60
+
61
+ def create_vertices
62
+ size_changing do
63
+ @min_width = @width = @texture.width
64
+ @min_height = @height = @texture.height
65
+ end
66
+ [0,0,0, @texture.width,0,0, @texture.width,@texture.height,0, 0,@texture.height,0]
67
+ end
68
+
69
+ def create_normals
70
+ [0,0,1, 0,0,1, 0,0,1, 0,0,1]
71
+ end
72
+
73
+ def create_texcoords
74
+ hb = @texture.height / @texture.bound.to_f
75
+ wb = @texture.width / @texture.bound.to_f
76
+ [0,0, wb,0, wb,hb, 0,hb]
77
+ end
78
+
79
+ end
80
+
81
+
82
+ end
@@ -0,0 +1,91 @@
1
+ require 'glimr/widgets/image'
2
+ require 'sdl'
3
+ SDL::TTF.init
4
+
5
+
6
+ module GlimR
7
+
8
+ class << self
9
+ attr_accessor :label_font, :label_size, :label_color
10
+ end
11
+
12
+ self.label_font = GlimR.theme + 'font.ttf'
13
+ self.label_size = 12
14
+ self.label_color = [0,0,0,1]
15
+
16
+ class Label < Image
17
+
18
+ touching_accessor :font, :size, :text, :valign, :align, :color
19
+
20
+ def default_config
21
+ super.merge(
22
+ :valign => :center,
23
+ :align => :center,
24
+ :font => GlimR.label_font,
25
+ :size => GlimR.label_size,
26
+ :width => 0, :height => 0,
27
+ :color => GlimR.label_color
28
+ )
29
+ end
30
+
31
+ def initialize(a,&b)
32
+ txt = a[:text]
33
+ a.delete(:text)
34
+ super(a, &b)
35
+ self.text = txt if txt
36
+ end
37
+
38
+ def text= t
39
+ @text = t.to_s
40
+ sdl_font = SDL::TTF.open(font, size)
41
+ lines = @text.split("\n")
42
+ w,h = 0,0
43
+ lines.each{|line|
44
+ nw,nh = sdl_font.text_size(line)
45
+ w = nw if nw > w
46
+ }
47
+ h = lines.size * (sdl_font.line_skip+1)
48
+
49
+ texture.width = w
50
+ texture.height = h
51
+ rmask = 0xff000000
52
+ gmask = 0x00ff0000
53
+ bmask = 0x0000ff00
54
+ amask = 0x000000ff
55
+ mask = SDL::Surface.new(
56
+ SDL::SWSURFACE|SDL::SRCALPHA,
57
+ w, h, 32,
58
+ amask,bmask,gmask,rmask)
59
+ mask.fill_rect(0,0, w,h, [0,0,0,255])
60
+ lines.each_with_index{|line,i|
61
+ sdl_font.draw_blended_utf8(
62
+ mask, line,
63
+ 0, i*(sdl_font.line_skip+1),
64
+ 255, 255, 255
65
+ )
66
+ }
67
+ image = SDL::Surface.new(
68
+ SDL::SWSURFACE|SDL::SRCALPHA,
69
+ w, h, 32,
70
+ amask,bmask,gmask,rmask)
71
+ image.fill_rect(0,0,w,h, color.map{|i|(i*255).to_i})
72
+ texture.mode = TEXTURE_2D
73
+ texture.pixels = as_alpha(image.pixels, mask.pixels)
74
+ @width = texture.width
75
+ @height = texture.height
76
+ @bound = texture.bound
77
+ update_geometry
78
+ end
79
+
80
+ def as_alpha(pixels, alpha)
81
+ i = 3
82
+ while i < pixels.size
83
+ pixels[i] = alpha[i-1]
84
+ i += 4
85
+ end
86
+ pixels
87
+ end
88
+
89
+ end
90
+
91
+ end
@@ -0,0 +1,227 @@
1
+ require 'glimr/widget'
2
+
3
+
4
+ module GlimR
5
+
6
+
7
+ # A Layout is a Widget that layouts its child widgets.
8
+ #
9
+ # Layouts come in two breeds: the horizontal layout and
10
+ # the vertical layout. A horizontal layout (or HLayout)
11
+ # arranges its children in a row, while a vertical layout
12
+ # (a.k.a. VLayout) arranges them in a column.
13
+ #
14
+ # A layout has two alignment attributes, the #align and the
15
+ # #valign. Align determines where to put the children
16
+ # on the horizontal axis, and valign does the same on the
17
+ # vertical axis.
18
+ #
19
+ # Align value :left aligns the left border of the layouted widgets and
20
+ # pushes them to the left border of the layout.
21
+ # Using :right as align does the same, except for the right border.
22
+ # The :center align aligns the centerline of the widgets with the layout's
23
+ # centerline. The default align is :left.
24
+ #
25
+ # Valign takes three values as well: :top, :bottom, and :middle. The default
26
+ # is :top, and aligns the top border of the widgets with the top border of
27
+ # the layout. To align to the bottom border, use :bottom. The :middle valign
28
+ # aligns the vertical midpoint of the widgets with the layout's vertical
29
+ # midpoint.
30
+ #
31
+ # Item spacing controls the amount of space between the layouted widgets.
32
+ # The default item spacing is 2.
33
+ #
34
+ # A Layout fits its children by default and doesn't expand to
35
+ # maximum width or height.
36
+ #
37
+ class Layout < Widget
38
+
39
+ attr_accessor :item_spacing, :direction
40
+
41
+ def default_config
42
+ super.merge(
43
+ :item_spacing => 2,
44
+ :direction => :horizontal,
45
+ :fit_children => true
46
+ )
47
+ end
48
+
49
+ def children_change
50
+ @free_width = @free_height = nil
51
+ layout
52
+ end
53
+
54
+ # If direction is vertical, sets width equal to the largest child + padding.
55
+ # If direction is horizontal, sets width to sum of children widths + padding + item spacing.
56
+ def fit_width!
57
+ return super if direction == :vertical
58
+ self.width = layoutable_children.inject(padding_left+padding_right-item_spacing){|s,c|
59
+ s + c.full_width + item_spacing
60
+ } unless layoutable_children.empty?
61
+ end
62
+
63
+ # If direction is horizontal, sets height equal to the largest child + padding.
64
+ # If direction is vertical, sets height to sum of children heights + padding + item spacing.
65
+ def fit_height!
66
+ return super if direction == :horizontal
67
+ self.height = layoutable_children.inject(padding_top+padding_left-item_spacing){|s,c|
68
+ s + c.full_height + item_spacing
69
+ } unless layoutable_children.empty?
70
+ end
71
+
72
+ def layout
73
+ return if @layouting
74
+ c = layoutable_children
75
+ return if c.empty?
76
+ @layouting = true
77
+ size_changing do
78
+ @free_width = @free_height = nil
79
+ @id ||= 0
80
+ @id += 1
81
+ c.each{|ch|
82
+ ch.width = free_width-ch.margin_left-ch.margin_right if ch.expand_width
83
+ ch.height = free_height-ch.margin_top-ch.margin_bottom if ch.expand_height
84
+ }
85
+ fit_to_children! if fit_children?
86
+ if @direction == :horizontal
87
+ horiz_tile(c)
88
+ else
89
+ vert_tile(c)
90
+ end
91
+ end
92
+ @layouting = false
93
+ end
94
+
95
+ def item_spacing= s
96
+ @item_spacing = s
97
+ layout
98
+ end
99
+
100
+ def direction= d
101
+ @direction = d
102
+ layout
103
+ end
104
+
105
+ # Horizontally tile objects inside self.
106
+ def horiz_tile(objs)
107
+ objs_width = objs.inject(-@item_spacing){|s,o|
108
+ s + o.full_width + @item_spacing
109
+ }
110
+ x = case @align
111
+ when :left
112
+ @padding_left
113
+ when :right
114
+ @padding_left + inner_width - objs_width
115
+ when :center, :middle
116
+ @padding_left + (inner_width - objs_width) / 2
117
+ end
118
+ ih = inner_height
119
+ objs.each{|obj|
120
+ obj.x = x + obj.margin_left
121
+ obj.y = case @valign
122
+ when :top
123
+ @padding_top
124
+ when :bottom
125
+ @padding_top + ih - obj.full_height
126
+ when :center, :middle
127
+ @padding_top + (ih - obj.full_height) / 2
128
+ end
129
+ obj.z = 1
130
+ x += obj.full_width + @item_spacing
131
+ }
132
+ end
133
+
134
+ # Vertically tile objects inside self.
135
+ def vert_tile(objs)
136
+ objs_height = objs.inject(-@item_spacing){|s,o|
137
+ s + o.full_height + @item_spacing
138
+ }
139
+ y = case @align
140
+ when :left
141
+ @padding_top
142
+ when :right
143
+ @padding_top + inner_height - objs_height
144
+ when :center, :middle
145
+ @padding_top + (inner_height - objs_height) / 2
146
+ end
147
+ iw = inner_width
148
+ objs.each{|obj|
149
+ obj.y = y + obj.margin_top
150
+ obj.x = case @align
151
+ when :left
152
+ @padding_left
153
+ when :right
154
+ @padding_left + iw - obj.full_width
155
+ when :center, :middle
156
+ @padding_left + (iw - obj.full_width) / 2
157
+ end
158
+ obj.z = 1
159
+ y += obj.full_height + @item_spacing
160
+ }
161
+ end
162
+
163
+ def free_width
164
+ @free_width ||= calculate_free_width
165
+ end
166
+
167
+ def free_height
168
+ @free_height ||= calculate_free_height
169
+ end
170
+
171
+ def calculate_free_width
172
+ return inner_width if @direction == :vertical
173
+ objs = layoutable_children
174
+ fit_width_objs, constant_width_objs = objs.partition{|o| o.expand_width }
175
+ if fit_width_objs.empty?
176
+ 0.0
177
+ else
178
+ const_width = constant_width_objs.inject(0){|cw, o|
179
+ cw + o.full_width
180
+ } + (objs.size - 1) * @item_spacing
181
+ [0.0, (inner_width - const_width) / fit_width_objs.size].max
182
+ end
183
+ end
184
+
185
+ def calculate_free_height
186
+ return inner_height if @direction == :horizontal
187
+ objs = layoutable_children
188
+ fit_height_objs, constant_height_objs = objs.partition{|o| o.expand_height}
189
+ if fit_height_objs.empty?
190
+ 0.0
191
+ else
192
+ const_height = constant_height_objs.inject(0){|cw, o|
193
+ cw + o.full_height
194
+ } + (objs.size - 1) * @item_spacing
195
+ [0.0, (inner_height - const_height) / fit_height_objs.size].max
196
+ end
197
+ end
198
+
199
+ end
200
+
201
+
202
+ class HLayout < Layout
203
+
204
+ def default_config
205
+ super.merge(:direction => :horizontal)
206
+ end
207
+
208
+ end
209
+
210
+
211
+ class VLayout < Layout
212
+
213
+ def default_config
214
+ super.merge(:direction => :vertical)
215
+ end
216
+
217
+ end
218
+
219
+
220
+ # class OverLayout < Layout
221
+ # end
222
+ #
223
+ #
224
+ # class FreeLayout < Layout
225
+ # end
226
+
227
+ end