fidgit 0.0.2alpha

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. data/.gitignore +8 -0
  2. data/.rspec +2 -0
  3. data/COPYING.txt +674 -0
  4. data/Gemfile +4 -0
  5. data/README.textile +138 -0
  6. data/Rakefile +38 -0
  7. data/config/default_schema.yml +180 -0
  8. data/examples/_all_examples.rb +9 -0
  9. data/examples/align_example.rb +56 -0
  10. data/examples/button_and_toggle_button_example.rb +27 -0
  11. data/examples/color_picker_example.rb +17 -0
  12. data/examples/color_well_example.rb +25 -0
  13. data/examples/combo_box_example.rb +24 -0
  14. data/examples/file_dialog_example.rb +42 -0
  15. data/examples/grid_packer_example.rb +29 -0
  16. data/examples/helpers/example_window.rb +17 -0
  17. data/examples/label_example.rb +17 -0
  18. data/examples/list_example.rb +23 -0
  19. data/examples/media/images/head_icon.png +0 -0
  20. data/examples/menu_pane_example.rb +27 -0
  21. data/examples/message_dialog_example.rb +65 -0
  22. data/examples/radio_button_example.rb +37 -0
  23. data/examples/readme_example.rb +32 -0
  24. data/examples/scroll_window_example.rb +49 -0
  25. data/examples/slider_example.rb +30 -0
  26. data/examples/splash_example.rb +42 -0
  27. data/examples/text_area_example.rb +28 -0
  28. data/fidgit.gemspec +28 -0
  29. data/lib/fidgit.rb +4 -0
  30. data/lib/fidgit/chingu_ext/window.rb +6 -0
  31. data/lib/fidgit/clipboard.rb +23 -0
  32. data/lib/fidgit/cursor.rb +38 -0
  33. data/lib/fidgit/elements/button.rb +68 -0
  34. data/lib/fidgit/elements/color_picker.rb +63 -0
  35. data/lib/fidgit/elements/color_well.rb +39 -0
  36. data/lib/fidgit/elements/combo_box.rb +85 -0
  37. data/lib/fidgit/elements/composite.rb +17 -0
  38. data/lib/fidgit/elements/container.rb +187 -0
  39. data/lib/fidgit/elements/element.rb +252 -0
  40. data/lib/fidgit/elements/file_browser.rb +152 -0
  41. data/lib/fidgit/elements/grid_packer.rb +219 -0
  42. data/lib/fidgit/elements/group.rb +66 -0
  43. data/lib/fidgit/elements/horizontal_packer.rb +12 -0
  44. data/lib/fidgit/elements/label.rb +77 -0
  45. data/lib/fidgit/elements/list.rb +47 -0
  46. data/lib/fidgit/elements/menu_pane.rb +149 -0
  47. data/lib/fidgit/elements/packer.rb +42 -0
  48. data/lib/fidgit/elements/radio_button.rb +86 -0
  49. data/lib/fidgit/elements/scroll_area.rb +75 -0
  50. data/lib/fidgit/elements/scroll_bar.rb +114 -0
  51. data/lib/fidgit/elements/scroll_window.rb +92 -0
  52. data/lib/fidgit/elements/slider.rb +119 -0
  53. data/lib/fidgit/elements/text_area.rb +351 -0
  54. data/lib/fidgit/elements/toggle_button.rb +67 -0
  55. data/lib/fidgit/elements/tool_tip.rb +35 -0
  56. data/lib/fidgit/elements/vertical_packer.rb +12 -0
  57. data/lib/fidgit/event.rb +99 -0
  58. data/lib/fidgit/gosu_ext/color.rb +123 -0
  59. data/lib/fidgit/history.rb +85 -0
  60. data/lib/fidgit/redirector.rb +83 -0
  61. data/lib/fidgit/schema.rb +123 -0
  62. data/lib/fidgit/selection.rb +106 -0
  63. data/lib/fidgit/standard_ext/hash.rb +21 -0
  64. data/lib/fidgit/states/dialog_state.rb +42 -0
  65. data/lib/fidgit/states/file_dialog.rb +24 -0
  66. data/lib/fidgit/states/gui_state.rb +301 -0
  67. data/lib/fidgit/states/message_dialog.rb +61 -0
  68. data/lib/fidgit/thumbnail.rb +29 -0
  69. data/lib/fidgit/version.rb +5 -0
  70. data/lib/fidgit/window.rb +19 -0
  71. data/media/images/arrow.png +0 -0
  72. data/media/images/file_directory.png +0 -0
  73. data/media/images/file_file.png +0 -0
  74. data/media/images/pixel.png +0 -0
  75. data/spec/fidgit/elements/helpers/helper.rb +3 -0
  76. data/spec/fidgit/elements/label_spec.rb +49 -0
  77. data/spec/fidgit/event_spec.rb +149 -0
  78. data/spec/fidgit/gosu_ext/color_spec.rb +130 -0
  79. data/spec/fidgit/gosu_ext/helpers/helper.rb +3 -0
  80. data/spec/fidgit/helpers/helper.rb +4 -0
  81. data/spec/fidgit/helpers/tex_play_helper.rb +9 -0
  82. data/spec/fidgit/history_spec.rb +144 -0
  83. data/spec/fidgit/redirector_spec.rb +78 -0
  84. data/spec/fidgit/schema_spec.rb +67 -0
  85. data/spec/fidgit/schema_test.yml +32 -0
  86. data/spec/fidgit/thumbnail_spec.rb +50 -0
  87. metadata +177 -0
@@ -0,0 +1,351 @@
1
+ # encoding: utf-8
2
+
3
+ module Fidgit
4
+ class TextArea < Element
5
+ # @return [Number]
6
+ attr_reader :min_height
7
+ # @return [Number]
8
+ attr_reader :max_height
9
+
10
+ # @return [Number]
11
+ attr_reader :line_spacing
12
+
13
+ # @param [Boolean] value
14
+ # @return [Boolean]
15
+ attr_writer :editable
16
+
17
+ event :changed
18
+ event :focus
19
+ event :blur
20
+
21
+ # Is the area editable?
22
+ def editable?
23
+ enabled?
24
+ end
25
+
26
+ # Text within the element.
27
+ # @return [String]
28
+ def text
29
+ @text_input.text.force_encoding 'UTF-8'
30
+ end
31
+
32
+ # Returns the range of the selection.
33
+ #
34
+ # @return [Range]
35
+ def selection_range
36
+ from = [@text_input.selection_start, caret_position].min
37
+ to = [@text_input.selection_start, caret_position].max
38
+
39
+ (from...to)
40
+ end
41
+
42
+ # Returns the text within the selection.
43
+ #
44
+ # @return [String]
45
+ def selection_text
46
+ text[selection_range]
47
+ end
48
+
49
+ # Position of the caret.
50
+ #
51
+ # @return [Integer] Number in range 0..text.length
52
+ def caret_position
53
+ @text_input.caret_pos
54
+ end
55
+
56
+ # Position of the caret.
57
+ #
58
+ # @param [Integer] pos Position of caret in the text.
59
+ # @return [Integer] New position of caret.
60
+ def caret_position=(position)
61
+ raise ArgumentError, "Caret position must be in the range 0 to the length of the text (inclusive)" unless position.between?(0, text.length)
62
+ @text_input.caret_pos = position
63
+
64
+ position
65
+ end
66
+
67
+ # Sets caret to the end of the text.
68
+ #
69
+ # @param [String] text
70
+ # @return [String] Current string (may be the old one if passed on was too long).
71
+ def text=(text)
72
+ @text_input.text = text
73
+ recalc # This may roll back the text if it is too long.
74
+ publish :changed, self.text
75
+ self.text
76
+ end
77
+
78
+
79
+ # @param (see Element#initialize)
80
+ #
81
+ # @option (see Element#initialize)
82
+ # @option options [String] :text ("")
83
+ # @option options [Integer] :height Sets both min and max height at once.
84
+ # @option options [Integer] :min_height
85
+ # @option options [Integer] :max_height (Infinite)
86
+ # @option options [Number] :line_spacing (0)
87
+ def initialize(options = {}, &block)
88
+ options = {
89
+ text: '',
90
+ max_height: Float::INFINITY,
91
+ line_spacing: default(:line_spacing),
92
+ background_color: default(:background_color),
93
+ border_color: default(:border_color),
94
+ caret_color: default(:caret_color),
95
+ caret_period: default(:caret_period),
96
+ focused_border_color: default(:focused, :border_color),
97
+ selection_color: default(:selection_color),
98
+ }.merge! options
99
+
100
+ @line_spacing = options[:line_spacing]
101
+ @caret_color = options[:caret_color].dup
102
+ @caret_period = options[:caret_period]
103
+ @focused_border_color = options[:focused_border_color].dup
104
+ @selection_color = options[:selection_color].dup
105
+
106
+ @lines = [''] # List of lines of wrapped text.
107
+ @caret_positions = [[0, 0]] # [x, y] of each position the caret can be in.
108
+ @char_widths = [] # Width of each character in the text.
109
+ @text_input = Gosu::TextInput.new
110
+ @old_text = ''
111
+ @old_caret_position = 0
112
+ @old_selection_start = 0
113
+
114
+ @text_input.text = options[:text].dup
115
+
116
+ super(options)
117
+
118
+ min_height = padding_left + padding_right + font_size
119
+ if options[:height]
120
+ @max_height = @min_height = [options[:height], min_height].max
121
+ else
122
+ @max_height = [options[:max_height], min_height].max
123
+ @min_height = options[:min_height] ? [options[:min_height], min_height].max : min_height
124
+ end
125
+ rect.height = [padding_left + padding_right + font_size, @min_height].max
126
+
127
+ subscribe :left_mouse_button, method(:click_in_text)
128
+ subscribe :right_mouse_button, method(:click_in_text)
129
+ end
130
+
131
+ # @return [nil]
132
+ def click_in_text(sender, x, y)
133
+ publish :focus unless focused?
134
+
135
+ # Move caret to position the user clicks on.
136
+ mouse_x, mouse_y = x - (self.x + padding_left), y - (self.y + padding_top)
137
+ @char_widths.each_with_index do |width, i|
138
+ char_x, char_y = @caret_positions[i]
139
+ if mouse_x.between?(char_x, char_x + width) and mouse_y.between?(char_y, char_y + font_size)
140
+ self.caret_position = @text_input.selection_start = i
141
+ break
142
+ end
143
+ end
144
+
145
+ nil
146
+ end
147
+
148
+ # Does the element have the focus?
149
+ def focused?; @focused; end
150
+
151
+ # @return [nil]
152
+ def focus(sender)
153
+ @focused = true
154
+ $window.current_game_state.focus = self
155
+ $window.text_input = @text_input
156
+
157
+ nil
158
+ end
159
+
160
+ # @return [nil]
161
+ def blur(sender)
162
+ if focused?
163
+ $window.current_game_state.focus = nil
164
+ $window.text_input = nil
165
+ end
166
+
167
+ @focused = false
168
+
169
+ nil
170
+ end
171
+
172
+ # Draw the text area.
173
+ #
174
+ # @return [nil]
175
+ def draw_foreground
176
+ # Always roll back changes made by the user unless the text is editable.
177
+ if not editable? and text != @old_text
178
+ @text_input.text = @old_text
179
+ @text_input.selection_start = @old_selection_start
180
+ self.caret_position = @old_caret_position
181
+ else
182
+ recalc if focused? # Workaround for Windows draw/update bug.
183
+ @old_caret_position = caret_position
184
+ @old_selection_start = @text_input.selection_start
185
+ end
186
+
187
+ # Draw the selection.
188
+ selection_range.each do |pos|
189
+ char_x, char_y = @caret_positions[pos]
190
+ char_width = @char_widths[pos]
191
+ left, top = x + padding_left + char_x, y + padding_top + char_y
192
+ draw_rect left, top, char_width, font_size, z, @selection_color
193
+ end
194
+
195
+ # Draw text.
196
+ @lines.each_with_index do |line, index|
197
+ font.draw(line, x + padding_left, y + padding_top + y_at_line(index), z)
198
+ end
199
+
200
+ # Draw the caret.
201
+ if focused? and ((Gosu::milliseconds / @caret_period) % 2 == 0)
202
+ caret_x, caret_y = @caret_positions[caret_position]
203
+ left, top = x + padding_left + caret_x, y + padding_top + caret_y
204
+ draw_rect left, top, 1, font_size, z, @caret_color
205
+ end
206
+ end
207
+
208
+ # y position of the
209
+ protected
210
+ def y_at_line(lines_number)
211
+ lines_number * (font_size + line_spacing)
212
+ end
213
+
214
+ protected
215
+ # Helper for #recalc
216
+ # @return [Integer]
217
+ def position_letters_in_word(word, line_width)
218
+ word.each_char do |c|
219
+ char_width = font.text_width(c)
220
+ line_width += char_width
221
+ @caret_positions.push [line_width, y_at_line(@lines.size)]
222
+ @char_widths.push char_width
223
+ end
224
+
225
+ line_width
226
+ end
227
+
228
+ protected
229
+ # @return [nil]
230
+ def layout
231
+ # Don't need to re-layout if the text hasn't changed.
232
+ return if @old_text == text
233
+
234
+ publish :changed, self.text
235
+
236
+ # Save these in case we are too long.
237
+ old_lines = @lines
238
+ old_caret_positions = @caret_positions
239
+ old_char_widths = @char_widths
240
+
241
+ @lines = []
242
+ @caret_positions = [[0, 0]] # Position 0 is before the first character.
243
+ @char_widths = []
244
+
245
+ space_width = font.text_width ' '
246
+ max_width = width - padding_left - padding_right - space_width
247
+
248
+ line = ''
249
+ line_width = 0
250
+ word = ''
251
+ word_width = 0
252
+
253
+ text.each_char do |char|
254
+ char_width = font.text_width(char)
255
+
256
+ overall_width = line_width + (line_width == 0 ? 0 : space_width) + word_width + char_width
257
+ if overall_width > max_width and not (char == ' ' and not word.empty?)
258
+ if line.empty?
259
+ # The current word is longer than the whole word, so split it.
260
+ # Go back and set all the character positions we have.
261
+ position_letters_in_word(word, line_width)
262
+
263
+ # Push as much of the current word as possible as a complete line.
264
+ @lines.push word + (char == ' ' ? '' : '-')
265
+ line_width = font.text_width(word)
266
+
267
+ word = ''
268
+ word_width = 0
269
+ else
270
+
271
+ # Adding the current word would be too wide, so add the current line and start a new one.
272
+ @lines.push line
273
+ line = ''
274
+ end
275
+
276
+ @char_widths[-1] += (width - line_width - padding_left - padding_right) unless @char_widths.empty?
277
+ line_width = 0
278
+ end
279
+
280
+ case char
281
+ when "\n"
282
+ # A new-line ends the word and puts it on the line.
283
+ line += word
284
+ line_width = position_letters_in_word(word, line_width)
285
+ @caret_positions.push [line_width, y_at_line(@lines.size)]
286
+ @char_widths[-1] += (width - line_width - (padding_left + padding_right)) unless @char_widths.empty?
287
+ @char_widths.push 0
288
+ @lines.push line
289
+ word = ''
290
+ word_width = 0
291
+ line = ''
292
+ line_width = 0
293
+
294
+ when ' '
295
+ # A space ends a word and puts it on the line.
296
+ line += word + char
297
+ line_width = position_letters_in_word(word, line_width)
298
+ line_width += space_width
299
+ @caret_positions.push [line_width, y_at_line(@lines.size)]
300
+ @char_widths.push space_width
301
+
302
+ word = ''
303
+ word_width = 0
304
+
305
+ else
306
+ # If there was a previous line and we start a new line, put the caret pos on the current line.
307
+ if line.empty?
308
+ @caret_positions[-1] = [0, y_at_line(@lines.size)]
309
+ end
310
+
311
+ # Start building up a new word.
312
+ word += char
313
+ word_width += char_width
314
+ end
315
+ end
316
+
317
+ # Add any remaining word on the last line.
318
+ unless word.empty?
319
+ position_letters_in_word(word, line_width)
320
+ line += word
321
+ end
322
+
323
+ @lines.push line if @lines.empty? or not line.empty?
324
+
325
+ # Roll back if the height is too long.
326
+ new_height = padding_left + padding_right + y_at_line(@lines.size)
327
+ if new_height <= max_height
328
+ @old_text = text
329
+ rect.height = [new_height, @min_height].max
330
+ @old_caret_position = caret_position
331
+ @old_selection_start = @text_input.selection_start
332
+ else
333
+ # Roll back!
334
+ @lines = old_lines
335
+ @caret_positions = old_caret_positions
336
+ @char_widths = old_char_widths
337
+ @text_input.text = @old_text
338
+ self.caret_position = @old_caret_position
339
+ @text_input.selection_start = @old_selection_start
340
+ end
341
+
342
+ nil
343
+ end
344
+
345
+ protected
346
+ # Use block as an event handler.
347
+ def post_init_block(&block)
348
+ subscribe :changed, &block
349
+ end
350
+ end
351
+ end
@@ -0,0 +1,67 @@
1
+ # encoding: utf-8
2
+
3
+ module Fidgit
4
+ # A button that toggles its value from false<->true when clicked.
5
+ class ToggleButton < Button
6
+ event :changed
7
+
8
+ attr_reader :value
9
+ def value=(value); @value = value; update_status; end
10
+
11
+ # @param (see Button#initialize)
12
+ #
13
+ # @option (see Button#initialize)
14
+ def initialize(text, options = {}, &block)
15
+ options = {
16
+ value: false
17
+ }.merge! options
18
+
19
+ @value = options[:value]
20
+
21
+ super(text, options)
22
+
23
+ @text_on = (options[:text_on] || text).dup
24
+ @icon_on = options[:icon_on] || icon
25
+ @tip_on = (options[:tip_on] || tip).dup
26
+ @border_color_on = (options[:border_color_on] || options[:border_color] || default(:toggled, :border_color)).dup
27
+
28
+ @text_off = (options[:text_off] || text).dup
29
+ @icon_off = options[:icon_off] || icon
30
+ @tip_off = (options[:tip_off] || tip).dup
31
+ @border_color_off = (options[:border_color_off] || options[:border_color] || default(:border_color)).dup
32
+
33
+ update_status
34
+
35
+ subscribe :clicked_left_mouse_button do |sender, x, y|
36
+ @value = (not @value)
37
+ update_status
38
+ publish :changed, @value
39
+ end
40
+ end
41
+
42
+ protected
43
+ # The block for a toggle-button is connected to :changed event.
44
+ def post_init_block(&block)
45
+ subscribe :changed, &block
46
+ end
47
+
48
+ protected
49
+ def update_status
50
+ if @value
51
+ @text = @text_on.dup
52
+ @icon = @icon_on ? @icon_on.dup : nil
53
+ @tip = @tip_on.dup
54
+ @border_color = @border_color_on.dup
55
+ else
56
+ @text = @text_off.dup
57
+ @icon = @icon_off ? @icon_off.dup : nil
58
+ @tip = @tip_off.dup
59
+ @border_color = @border_color_off.dup
60
+ end
61
+
62
+ recalc
63
+
64
+ nil
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,35 @@
1
+ # encoding: utf-8
2
+
3
+ module Fidgit
4
+ class ToolTip < Label
5
+ def x=(value); super(value); recalc; value; end
6
+ def y=(value); super(value); recalc; value; end
7
+ def hit?(x, y); false; end
8
+
9
+
10
+ # @param (see Label#initialize)
11
+ #
12
+ # @option (see Label#initialize)
13
+ def initialize(options = {}, &block)
14
+ options = {
15
+ z: Float::INFINITY,
16
+ background_color: default(:background_color),
17
+ border_color: default(:border_color),
18
+ text: '',
19
+ }.merge! options
20
+
21
+ super(options[:text], options)
22
+ end
23
+
24
+ protected
25
+ def layout
26
+ super
27
+
28
+ # Ensure the tip can't go over the edge of the screen. If it can't be avoided, align with left edge of screen.
29
+ rect.x = [[x, $window.width - width - padding_right].min, 0].max
30
+ rect.y = [[y, $window.height - height - padding_bottom].min, 0].max
31
+
32
+ nil
33
+ end
34
+ end
35
+ end