rubygoo 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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