rubygoo 0.0.3

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.
@@ -0,0 +1,8 @@
1
+ # is an rbga color
2
+ class GooColor
3
+ attr_accessor :r,:g,:b,:a
4
+ def initialize(r,g,b,a)
5
+ @r,@g,@b,@a = r,g,b,a
6
+ end
7
+
8
+ end
@@ -0,0 +1,11 @@
1
+ # all events in the system are converted to these for internal use by our
2
+ # adapter
3
+ class GooEvent
4
+ attr_accessor :event_type, :data
5
+
6
+ def initialize(event_type, event_data = nil)
7
+ @event_type = event_type
8
+ @data = event_data
9
+ end
10
+
11
+ end
@@ -0,0 +1,42 @@
1
+ class Label < Widget
2
+ def initialize(text, opts={})
3
+ super opts
4
+ @text = text
5
+ end
6
+
7
+ def added()
8
+ font = theme_property :font
9
+ @font_size = theme_property :font_size
10
+ @color = theme_property :color
11
+ @bg_color = theme_property :bg_color
12
+ @focus_color = theme_property :focus_color
13
+ @border_color = theme_property :border_color
14
+ @font_file = File.join(@app.theme_dir,font)
15
+
16
+ set_text @text
17
+ end
18
+
19
+ def set_text(text)
20
+ @text = text
21
+ @rendered_text = @app.renderer.render_text @text, @font_file, @font_size, @color
22
+ @rect = Rect.new [@x,@y,@rendered_text.width+@x_pad,@rendered_text.height+@y_pad]
23
+ end
24
+
25
+ def draw(screen)
26
+ if @focussed
27
+ screen.fill @focus_color, @rect
28
+ elsif @bg_color
29
+ screen.fill @bg_color, @rect
30
+ end
31
+
32
+ if @border_color
33
+ x1 = @rect[0]
34
+ y1 = @rect[1]
35
+ x2 = @rect[2] + x1
36
+ y2 = @rect[3] + y1
37
+ screen.draw_box x1, y1, x2, y2, @border_color
38
+ end
39
+
40
+ screen.draw_image @rendered_text, @x, @y
41
+ end
42
+ end
@@ -0,0 +1,301 @@
1
+ class TextField < Widget
2
+ SPACE = " "
3
+
4
+ def initialize(text, opts={})
5
+ super opts
6
+ @text = text
7
+
8
+ # TODO make widget respect these?
9
+ @max_length = opts[:max_length]
10
+ @min_length = opts[:min_length]
11
+
12
+ @key_handlers = {}
13
+ end
14
+
15
+ # Allows for registering callbacks for various key presses.
16
+ # note: this will override default behavior such as K_RIGHT and
17
+ # such
18
+ # Example:
19
+ # text_field.on_key K_RETURN, K_KP_ENTER do |evt|
20
+ # puts "BOO-YAH"
21
+ # end
22
+ def on_key(*keys, &block)
23
+ for key in keys
24
+ @key_handlers[key] ||= []
25
+ @key_handlers[key] << block
26
+ end
27
+ end
28
+
29
+ def added()
30
+ font = theme_property :font
31
+ @font_size = theme_property :font_size
32
+ @color = theme_property :color
33
+ @fg_color = theme_property :fg_color
34
+ @bg_color = theme_property :bg_color
35
+ @bg_select_color = theme_property :bg_select_color
36
+ @fg_select_color = theme_property :fg_select_color
37
+ @focus_color = theme_property :focus_color
38
+ @border_color = theme_property :border_color
39
+
40
+ @font_file = File.join(@app.theme_dir,font)
41
+
42
+ if @w == 1
43
+ # we have the default from widget, we want to set the
44
+ # default to 6 chars wide and 1 char tall
45
+ size = @app.renderer.size_text "MMMMMM", @font_file, @font_size
46
+ @min_w = size[0]
47
+ @min_h = size[1]
48
+ end
49
+
50
+ set_text @text
51
+ end
52
+
53
+ def render()
54
+ if @text.empty?
55
+ w = [@w,@min_w].max + @x_pad
56
+ h = [@h,@min_h].max + @y_pad
57
+ @rendered_text = nil
58
+ @rect = Rect.new [@x,@y,w,h]
59
+ else
60
+ @rendered_text = @app.renderer.render_text @text, @font_file, @font_size, @color
61
+ w = [@rendered_text.width,@min_w].max + @x_pad
62
+ h = [@rendered_text.height,@min_h].max + @y_pad
63
+ @rect = Rect.new [@x,@y,w,h]
64
+ end
65
+ end
66
+
67
+ def set_text(text)
68
+ if text.nil?
69
+ @text = ""
70
+ @caret_pos = 0
71
+ @select_pos = 0
72
+ else
73
+ @text = text
74
+ @caret_pos = text.length
75
+ @select_pos = @caret_pos
76
+ end
77
+
78
+ render
79
+
80
+ end
81
+
82
+ def draw(screen)
83
+ screen.fill @fg_color, @rect
84
+ screen.fill @bg_color, [@rect[0]-2,@rect[1]-2,@rect[2]+4,@rect[3]+4]
85
+ if @border_color
86
+ x1 = @rect[0] - 2
87
+ y1 = @rect[1] - 2
88
+ x2 = @rect[2] + x1 + 4
89
+ y2 = @rect[3] + y1 + 4
90
+ screen.draw_box x1, y1, x2, y2, @border_color
91
+ end
92
+ defaultY = @app.renderer.size_text(@text.slice(0,1),@font_file,@font_size)[1]
93
+ x,y,w,h = @rect
94
+ if @focussed
95
+ caretX = @app.renderer.size_text(@text.slice(0,@caret_pos),@font_file,@font_size)[0]
96
+ unless @select_pos.nil?
97
+ # draw selection highlight
98
+ selectX = @app.renderer.size_text(@text.slice(0,@select_pos),@font_file,@font_size)[0]
99
+ selectX0 = [caretX, selectX].min
100
+ selectX1 = [caretX, selectX].max
101
+ if selectX0 < selectX1
102
+ # TODO cache this height
103
+ screen.fill(@bg_select_color, [x+1+selectX0, y+1, selectX1-selectX0, defaultY])
104
+ end
105
+ end
106
+ end
107
+
108
+ unless @text.nil? or @text.empty?
109
+ @rendered_text = @app.renderer.render_text @text, @font_file, @font_size, @color
110
+ screen.draw_image @rendered_text, x+1, y+1
111
+ end
112
+
113
+ # draw caret
114
+ if @focussed
115
+ screen.fill(@fg_select_color, [x+1+caretX, y+1, 1, defaultY])
116
+ end
117
+
118
+ # don't really need this??
119
+ return @rect
120
+ end
121
+
122
+ def on_unfocus()
123
+ @caret_pos = 0
124
+ @select_pos = 0
125
+ end
126
+
127
+ def on_focus()
128
+ @select_pos = @text.length
129
+ @caret_pos = @text.length
130
+ end
131
+
132
+ def find_mouse_position(pos)
133
+ # put hit position in window relative coords
134
+ x = pos[0] - @rect[0]
135
+ y = pos[1] - @rect[1]
136
+
137
+ # find the horizontal position within the text by binary search
138
+ l,r = 0, @text.length
139
+ c = 0
140
+ while l < r
141
+ c = (l + r + 1) / 2
142
+ w = @app.renderer.size_text(@text.slice(l,c-l), @font_file, @font_size)[0]
143
+ if x >= w
144
+ l = c
145
+ x -= w
146
+ else
147
+ if r == c
148
+ if x > w / 2
149
+ l = l + 1
150
+ end
151
+ break
152
+ end
153
+
154
+ r = c
155
+ end
156
+ end
157
+ return l
158
+ end
159
+
160
+ def mouse_down(event)
161
+ x = event.data[:x]
162
+ y = event.data[:y]
163
+ return 0 unless contains?([x,y])
164
+
165
+ # TODO rework focus and mouse events
166
+ # getFocus()
167
+ @caret_pos = find_mouse_position([x,y])
168
+ @select_pos = @caret_pos
169
+ @dragging = true
170
+ render
171
+ end
172
+
173
+ def mouse_motion(event)
174
+ return 0 unless @dragging
175
+ x = event.data[:x]
176
+ y = event.data[:y]
177
+ @caret_pos = find_mouse_position([x,y])
178
+ render
179
+ end
180
+
181
+ def mouse_up(event)
182
+ if not @dragging
183
+ return 0
184
+ end
185
+ x = event.data[:x]
186
+ y = event.data[:y]
187
+ @caret_pos = find_mouse_position([x,y])
188
+ @dragging = false
189
+ render
190
+ end
191
+
192
+ def delete_selected()
193
+ return if @select_pos == @caret_pos
194
+ if @caret_pos > @select_pos
195
+ @caret_pos, @select_pos = @select_pos, @caret_pos
196
+ end
197
+
198
+ @text = @text.slice(0, @caret_pos) +
199
+ @text.slice(@select_pos,@text.length-@select_pos)
200
+ render
201
+ @select_pos = @caret_pos
202
+ end
203
+
204
+ def key_pressed(event)
205
+ return if not @focussed
206
+ @dragging = false
207
+
208
+ mods = event.data[:mods]
209
+ handlers = @key_handlers[event.data[:key]]
210
+ unless handlers.nil?
211
+ for handler in handlers
212
+ handler.call event
213
+ end
214
+
215
+ render
216
+ return
217
+ end
218
+
219
+ case event.data[:key]
220
+ when K_LEFT
221
+ if @caret_pos > 0
222
+ @caret_pos -= 1
223
+ end
224
+ if mods.include? K_LCTRL or mods.include? K_RCTRL
225
+ while @caret_pos > 0 and @text.slice(@caret_pos - 1,1) == SPACE
226
+ @caret_pos -= 1
227
+ end
228
+ while @caret_pos > 0 and not @text.slice(@caret_pos - 1,1) == SPACE
229
+ @caret_pos -= 1
230
+ end
231
+ end
232
+
233
+ unless mods.include? K_LSHIFT or mods.include? K_RSHIFT
234
+ @select_pos = @caret_pos
235
+ end
236
+
237
+ when K_RIGHT
238
+ if @caret_pos < @text.length
239
+ @caret_pos += 1
240
+ end
241
+ if mods.include? K_LCTRL or mods.include? K_RCTRL
242
+ while @caret_pos < @text.length and not @text.slice(@caret_pos,1) == SPACE
243
+ @caret_pos += 1
244
+ end
245
+ while @caret_pos < @text.length and @text.slice(@caret_pos,1) == SPACE
246
+ @caret_pos += 1
247
+ end
248
+ end
249
+ unless mods.include? K_LSHIFT or mods.include? K_RSHIFT
250
+ @select_pos = @caret_pos
251
+ end
252
+
253
+ when K_HOME
254
+ @caret_pos = 0
255
+ unless mods.include? K_LSHIFT or mods.include? K_RSHIFT
256
+ @select_pos = @caret_pos
257
+ end
258
+
259
+ when K_END
260
+ @caret_pos = @text.length
261
+ unless mods.include? K_LSHIFT or mods.include? K_RSHIFT
262
+ @select_pos = @caret_pos
263
+ end
264
+
265
+ when K_BACKSPACE
266
+ if @select_pos != @caret_pos
267
+ delete_selected()
268
+ elsif @caret_pos > 0
269
+ @text = @text.slice(0,@caret_pos-1) + @text.slice(@caret_pos,@text.length-@caret_pos)
270
+ @caret_pos -= 1
271
+ @select_pos = @caret_pos
272
+ end
273
+
274
+ when K_DELETE
275
+ if @select_pos != @caret_pos:
276
+ delete_selected()
277
+ elsif @caret_pos < @text.length:
278
+ @text = @text.slice(0,@caret_pos) + @text.slice(@caret_pos+1,@text.length-@caret_pos-1)
279
+ @select_pos = @caret_pos
280
+ end
281
+
282
+ # TODO these key numbers are Rubygame specific
283
+ when (32..127)
284
+ # add regular text to the box
285
+ if @caret_pos == @select_pos
286
+ @text = @text.slice(0,@caret_pos) + event.data[:string] + @text.slice(@caret_pos,@text.length-@caret_pos)
287
+ @caret_pos += 1
288
+ else
289
+ positions = [@caret_pos,@select_pos]
290
+ min = positions.min
291
+ max = positions.max
292
+ @text = @text.slice(0,min) + event.data[:string] + @text.slice(max,@text.length-max)
293
+ @caret_pos = min + 1
294
+ end
295
+
296
+ @select_pos = @caret_pos
297
+ end
298
+
299
+ render
300
+ end
301
+ end
@@ -0,0 +1,144 @@
1
+ require 'publisher'
2
+ require 'css_colors'
3
+ require 'goo_color'
4
+ class Widget
5
+ extend Publisher
6
+ can_fire :clicked
7
+ attr_accessor :enabled, :parent, :container,
8
+ :x, :y, :w, :h, :app, :x_pad, :y_pad, :focussed,
9
+ :focus_priority
10
+
11
+ DEFAULT_PARAMS = {
12
+ :x => 0,
13
+ :y => 0,
14
+ :w => 1,
15
+ :h => 1,
16
+ :x_pad => 2,
17
+ :y_pad => 2,
18
+ }
19
+ def initialize(opts={})
20
+ merged_opts = DEFAULT_PARAMS.merge opts
21
+ @x = merged_opts[:x]
22
+ @y = merged_opts[:y]
23
+ @x_pad = merged_opts[:x_pad]
24
+ @y_pad = merged_opts[:y_pad]
25
+ @w = merged_opts[:w]
26
+ @h = merged_opts[:h]
27
+ update_rect
28
+ end
29
+
30
+ def update_rect()
31
+ @rect = Rect.new [@x,@y,@w+@x_pad,@h+@y_pad]
32
+ end
33
+
34
+ # called when the widget is added to a container
35
+ def added()
36
+ end
37
+
38
+ # called when the widget is removed from a container
39
+ def removed()
40
+ end
41
+
42
+ def contains?(pos)
43
+ @rect.collide_point? pos[0], pos[1]
44
+ end
45
+
46
+ def enabled?()
47
+ @enabled
48
+ end
49
+
50
+ def update(millis)
51
+ end
52
+
53
+ # draw ourself on the screen
54
+ def draw(screen)
55
+ end
56
+
57
+ # called when there is a mouse click
58
+ def mouse_down(event)
59
+ end
60
+
61
+ # called when there is a mouse motion
62
+ def mouse_motion(event)
63
+ end
64
+
65
+ # called when there is a mouse release
66
+ def mouse_up(event)
67
+ end
68
+
69
+ # called when a key press is sent to us
70
+ def key_pressed(event)
71
+ end
72
+
73
+ # called when a key release is sent to us
74
+ def key_released(event)
75
+ end
76
+
77
+ # called when the widget receives focus
78
+ def on_focus()
79
+ end
80
+
81
+ def focus()
82
+ @focussed = true
83
+ on_focus
84
+ end
85
+
86
+ # called when the widget loses focus
87
+ def on_unfocus()
88
+ end
89
+
90
+ def unfocus()
91
+ @focussed = false
92
+ on_unfocus
93
+ end
94
+
95
+ def focussed?()
96
+ @focussed
97
+ end
98
+
99
+ # gets the property for the class asking for it.
100
+ # it will walk up the object hierarchy if needed
101
+ def theme_property(prop_key)
102
+ prop = nil
103
+ parent = self.class
104
+ until parent == Object
105
+ class_theme = app.theme[parent.to_s]
106
+ if class_theme
107
+ class_prop = class_theme[prop_key]
108
+ if class_prop
109
+ prop = class_prop
110
+ break
111
+ end
112
+ end
113
+ parent = parent.superclass
114
+ end
115
+ if prop_key.to_s.match /color/i
116
+ get_color prop
117
+ else
118
+ prop
119
+ end
120
+ end
121
+
122
+ def get_color(color)
123
+ new_color = nil
124
+ if color.is_a? Array
125
+ if color.size > 3
126
+ new_color = color
127
+ else
128
+ # fill in zeros for all other colors
129
+ 3-color.size.times do
130
+ color << 0
131
+ end
132
+ # fill in alpha as 255
133
+ color << 255
134
+ end
135
+ elsif color.is_a? Symbol
136
+ new_color = CSS_COLORS[color]
137
+ else
138
+ raise "invalid color"
139
+ end
140
+
141
+ GooColor.new *new_color
142
+ end
143
+
144
+ end