fidgit 0.0.2alpha

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 (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