colstrom-fidgit 0.2.7

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 (92) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.rspec +2 -0
  4. data/CHANGELOG.md +31 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +20 -0
  7. data/README.md +154 -0
  8. data/Rakefile +38 -0
  9. data/config/default_schema.yml +216 -0
  10. data/examples/_all_examples.rb +9 -0
  11. data/examples/align_example.rb +56 -0
  12. data/examples/button_and_toggle_button_example.rb +38 -0
  13. data/examples/color_picker_example.rb +17 -0
  14. data/examples/color_well_example.rb +25 -0
  15. data/examples/combo_box_example.rb +24 -0
  16. data/examples/file_dialog_example.rb +42 -0
  17. data/examples/grid_packer_example.rb +29 -0
  18. data/examples/helpers/example_window.rb +17 -0
  19. data/examples/label_example.rb +23 -0
  20. data/examples/list_example.rb +23 -0
  21. data/examples/media/images/head_icon.png +0 -0
  22. data/examples/menu_pane_example.rb +27 -0
  23. data/examples/message_dialog_example.rb +65 -0
  24. data/examples/radio_button_example.rb +37 -0
  25. data/examples/readme_example.rb +32 -0
  26. data/examples/scroll_window_example.rb +49 -0
  27. data/examples/slider_example.rb +34 -0
  28. data/examples/splash_example.rb +42 -0
  29. data/examples/text_area_example.rb +33 -0
  30. data/fidgit.gemspec +35 -0
  31. data/lib/fidgit.rb +51 -0
  32. data/lib/fidgit/chingu_ext/window.rb +6 -0
  33. data/lib/fidgit/cursor.rb +38 -0
  34. data/lib/fidgit/elements/button.rb +113 -0
  35. data/lib/fidgit/elements/color_picker.rb +63 -0
  36. data/lib/fidgit/elements/color_well.rb +39 -0
  37. data/lib/fidgit/elements/combo_box.rb +115 -0
  38. data/lib/fidgit/elements/composite.rb +17 -0
  39. data/lib/fidgit/elements/container.rb +210 -0
  40. data/lib/fidgit/elements/element.rb +298 -0
  41. data/lib/fidgit/elements/file_browser.rb +152 -0
  42. data/lib/fidgit/elements/grid.rb +227 -0
  43. data/lib/fidgit/elements/group.rb +64 -0
  44. data/lib/fidgit/elements/horizontal.rb +12 -0
  45. data/lib/fidgit/elements/image_frame.rb +65 -0
  46. data/lib/fidgit/elements/label.rb +85 -0
  47. data/lib/fidgit/elements/list.rb +47 -0
  48. data/lib/fidgit/elements/main_packer.rb +25 -0
  49. data/lib/fidgit/elements/menu_pane.rb +163 -0
  50. data/lib/fidgit/elements/packer.rb +42 -0
  51. data/lib/fidgit/elements/radio_button.rb +86 -0
  52. data/lib/fidgit/elements/scroll_area.rb +68 -0
  53. data/lib/fidgit/elements/scroll_bar.rb +128 -0
  54. data/lib/fidgit/elements/scroll_window.rb +83 -0
  55. data/lib/fidgit/elements/slider.rb +125 -0
  56. data/lib/fidgit/elements/text_area.rb +494 -0
  57. data/lib/fidgit/elements/text_line.rb +92 -0
  58. data/lib/fidgit/elements/toggle_button.rb +67 -0
  59. data/lib/fidgit/elements/tool_tip.rb +35 -0
  60. data/lib/fidgit/elements/vertical.rb +12 -0
  61. data/lib/fidgit/event.rb +159 -0
  62. data/lib/fidgit/gosu_ext/color.rb +136 -0
  63. data/lib/fidgit/gosu_ext/gosu_module.rb +25 -0
  64. data/lib/fidgit/history.rb +91 -0
  65. data/lib/fidgit/redirector.rb +83 -0
  66. data/lib/fidgit/schema.rb +123 -0
  67. data/lib/fidgit/selection.rb +106 -0
  68. data/lib/fidgit/standard_ext/hash.rb +21 -0
  69. data/lib/fidgit/states/dialog_state.rb +52 -0
  70. data/lib/fidgit/states/file_dialog.rb +24 -0
  71. data/lib/fidgit/states/gui_state.rb +331 -0
  72. data/lib/fidgit/states/message_dialog.rb +61 -0
  73. data/lib/fidgit/version.rb +5 -0
  74. data/lib/fidgit/window.rb +19 -0
  75. data/media/images/arrow.png +0 -0
  76. data/media/images/combo_arrow.png +0 -0
  77. data/media/images/file_directory.png +0 -0
  78. data/media/images/file_file.png +0 -0
  79. data/media/images/pixel.png +0 -0
  80. data/spec/fidgit/elements/helpers/helper.rb +3 -0
  81. data/spec/fidgit/elements/helpers/tex_play_helper.rb +9 -0
  82. data/spec/fidgit/elements/image_frame_spec.rb +69 -0
  83. data/spec/fidgit/elements/label_spec.rb +37 -0
  84. data/spec/fidgit/event_spec.rb +210 -0
  85. data/spec/fidgit/gosu_ext/color_spec.rb +130 -0
  86. data/spec/fidgit/gosu_ext/helpers/helper.rb +3 -0
  87. data/spec/fidgit/helpers/helper.rb +4 -0
  88. data/spec/fidgit/history_spec.rb +153 -0
  89. data/spec/fidgit/redirector_spec.rb +78 -0
  90. data/spec/fidgit/schema_spec.rb +67 -0
  91. data/spec/fidgit/schema_test.yml +32 -0
  92. metadata +320 -0
@@ -0,0 +1,152 @@
1
+ # encoding: utf-8
2
+
3
+ module Fidgit
4
+ class FileBrowser < Composite
5
+ VALID_TYPES = [:open, :save]
6
+
7
+ event :selected
8
+
9
+ attr_reader :pattern, :base_directory
10
+
11
+ def show_extension?; @show_extension; end
12
+ def directory
13
+ dir = File.join(*@directories)
14
+ dir = File.join(@base_directory, dir) unless @base_directory.empty?
15
+ dir
16
+ end
17
+ def file_name; @file_name_text.text; end
18
+ def file_path; File.join(directory, file_name); end
19
+
20
+ # @param [Symbol] type One of :open, :save
21
+ # @option options [String] :base_directory ('') Outermost directory that the browser will see.
22
+ # @option options [String] :directory (current working directory).
23
+ # @option options [String] :file_name ('') Initially selected file in the directory.
24
+ # @option options [String] :pattern ('*.*')
25
+ # @option options [Boolean] :show_extension (true)
26
+ def initialize(type, options = {})
27
+ options = {
28
+ base_directory: '',
29
+ directory: Dir.pwd,
30
+ file_name: '',
31
+ pattern: default(:pattern),
32
+ show_extension: default(:show_extension),
33
+ width: 400,
34
+ save_text: "Save",
35
+ open_text: "Open",
36
+ cancel_text: "Cancel",
37
+ }.merge! options
38
+
39
+ @type = type
40
+ raise ArgumentError, "type must be one of #{VALID_TYPES}, not #{@type}" unless VALID_TYPES.include? @type
41
+
42
+ @pattern = options[:pattern]
43
+ @show_extension = options[:show_extension]
44
+ @base_directory = options[:base_directory].chomp File::SEPARATOR
45
+
46
+ @directories = options[:directory].sub(/^#{@base_directory}/, '').split(File::SEPARATOR)
47
+ if @directories.first == ''
48
+ @directories[0] = File::SEPARATOR
49
+ end
50
+
51
+ super options
52
+
53
+ vertical do
54
+ @nav_buttons = horizontal padding: 0, spacing: 2
55
+
56
+ @scroll_window = scroll_window(height: 250, width: options[:width]) do
57
+ @files_list = list(width: options[:width]) do
58
+ subscribe :changed do |sender, file_path|
59
+ if file_path
60
+ file_name = File.basename file_path
61
+ if File.directory? file_path
62
+ @directories.push file_name
63
+ create_nav_buttons
64
+ update_files_list
65
+ else
66
+ @file_name_text.text = file_name
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ @file_name_text = text_area(text: options[:file_name], max_height: font.height * 1.5, width: options[:width], border_thickness: 1)
74
+
75
+ create_nav_buttons
76
+
77
+ horizontal align: :center, padding: 0 do
78
+ @action_button = button(options[:"#{type}_text"]) do
79
+ publish :selected, @type, file_path
80
+ end
81
+
82
+ button(options[:cancel_text]) do
83
+ publish :selected, :cancel, file_path
84
+ end
85
+ end
86
+
87
+ # Ensure that the open/save button is enabled only when the path is sensible.
88
+ @file_name_text.subscribe :changed do |sender, text|
89
+ @action_button.enabled = case @type
90
+ when :open
91
+ File.exists? file_path and not File.directory? file_path
92
+ when :save
93
+ not text.empty?
94
+ end
95
+ end
96
+
97
+ update_files_list
98
+ end
99
+ end
100
+
101
+ protected
102
+ def create_nav_buttons(size = @directories.size)
103
+ @nav_buttons.clear
104
+
105
+ @directories = @directories[0..size]
106
+
107
+ @directories.each_with_index do |dir, i|
108
+ if i < @directories.size - 1
109
+ @nav_buttons.button(dir) do
110
+ create_nav_buttons(i)
111
+ end
112
+ else
113
+ @nav_buttons.label dir, border_color: @@schema.default(Button, :border_color), border_thickness: @@schema.default(Button, :border_thickness)
114
+ end
115
+ end
116
+
117
+ update_files_list
118
+ end
119
+
120
+ protected
121
+ def update_files_list
122
+ @files_list.clear
123
+ @file_name_text.text = ''
124
+ @scroll_window.offset_x = @scroll_window.offset_y = 0
125
+
126
+ # Add folders.
127
+ Dir.glob(File.join(directory, "*")).each do |file_path|
128
+ if File.directory? file_path
129
+ @files_list.item File.basename(file_path), file_path, icon: Gosu::Image["file_directory.png"]
130
+ end
131
+ end
132
+
133
+ # Add files that match the pattern.
134
+ Dir.glob(File.join(directory, pattern)).each do |file_path|
135
+ unless File.directory? file_path
136
+ file_name = if @show_extension
137
+ File.basename(file_path)
138
+ else
139
+ File.basename(file_path, File.extname(file_path))
140
+ end
141
+
142
+ @files_list.item file_name, file_path, icon: Gosu::Image["file_file.png"]
143
+ end
144
+ end
145
+ end
146
+
147
+ protected
148
+ def post_init_block(&block)
149
+ subscribe :selected, &block
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,227 @@
1
+ # encoding: utf-8
2
+
3
+ module Fidgit
4
+ # A vertically aligned element packing container.
5
+
6
+ class Grid < Packer
7
+ # @return [Symbol]
8
+ attr_reader :type
9
+
10
+ # @return [Integer]
11
+ attr_reader :num_rows
12
+
13
+ # @return [Integer]
14
+ attr_reader :num_columns
15
+
16
+ # @note Currently only supports +num_columns+ mode (not +num_rows+).
17
+ #
18
+ # @param (see Packer#initialize)
19
+ #
20
+ # @option (see Packer#initialize)
21
+ # @option options [Integer] :num_columns Maximum number of columns to use (incompatible with :num_rows)
22
+ # @option options [Integer] :num_rows Maximum number of rows to use (incompatible with :num_columns)
23
+ def initialize(options = {})
24
+ options = {
25
+ cell_border_color: default(:cell_border_color),
26
+ cell_background_color: default(:cell_background_color),
27
+ cell_border_thickness: default(:cell_border_thickness),
28
+ }.merge! options
29
+
30
+ @num_columns = options[:num_columns]
31
+ @num_rows = options[:num_rows]
32
+ raise ArgumentError, "options :num_rows and :num_columns are not compatible" if @num_rows and @num_columns
33
+
34
+ @cell_border_color = options[:cell_border_color].dup
35
+ @cell_border_thickness = options[:cell_border_thickness]
36
+ @cell_background_color = options[:cell_background_color].dup
37
+
38
+ @type = @num_rows ? :fixed_rows : :fixed_columns
39
+
40
+ super options
41
+ end
42
+
43
+ protected
44
+ def layout
45
+ rearrange
46
+ repack
47
+ end
48
+
49
+ protected
50
+ # Rearrange the cells based on changes to the number of rows/columns or adding/removing elements.
51
+ def rearrange
52
+ # Calculate the number of the dynamic dimension.
53
+ case @type
54
+ when :fixed_rows
55
+ @num_columns = (size / @num_rows.to_f).ceil
56
+ when :fixed_columns
57
+ @num_rows = (size / @num_columns.to_f).ceil
58
+ end
59
+
60
+ # Create an array containing all the rows.
61
+ @rows = case @type
62
+ when :fixed_rows
63
+ # Rearrange the list, arranged by columns, into rows.
64
+ rows = Array.new(@num_rows) { [] }
65
+ @children.each_with_index do |child, i|
66
+ rows[i % @num_rows].push child
67
+ end
68
+ rows
69
+ when :fixed_columns
70
+ @children.each_slice(@num_columns).to_a
71
+ end
72
+
73
+ nil
74
+ end
75
+
76
+ protected
77
+ # Repack all the elements into their positions.
78
+ def repack
79
+ @widths = Array.new(@rows.empty? ? 0 : @rows[0].size, 0)
80
+ @heights = Array.new(@rows.size, 0)
81
+
82
+ filled_columns = []
83
+ filled_rows = []
84
+
85
+ # Calculate the maximum widths of each column and the maximum height of each row.
86
+ @rows.each_with_index do |row, row_num|
87
+ row.each_with_index do |element, column_num|
88
+ fills = (element.align_h == :fill)
89
+ @widths[column_num] = [fills ? element.min_width : element.outer_width, @widths[column_num]].max
90
+ filled_columns.push fills
91
+
92
+ fills = (element.align_v == :fill)
93
+ @heights[row_num] = [fills ? element.min_width : element.outer_height, @heights[row_num]].max
94
+ filled_rows.push fills
95
+ end
96
+ end
97
+
98
+ # Expand the size of each filled column to make the minimum size required.
99
+ unless @widths.empty?
100
+ num_filled_columns = filled_columns.select {|value| value }.count
101
+ total_width = @widths.inject(0, :+) + (padding_left + padding_right) + ((@num_columns - 1) * spacing_h)
102
+ extra_width = min_width - total_width
103
+ if extra_width > 0
104
+ if num_filled_columns > 0
105
+ @widths[filled_columns.index true] += extra_width
106
+ else
107
+ @widths[-1] += extra_width
108
+ end
109
+ end
110
+ end
111
+
112
+ # Expand the size of each filled row to make the minimum size required.
113
+ unless @heights.empty?
114
+ num_filled_rows = filled_rows.select {|value| value }.count
115
+ total_height = @heights.inject(0, :+) + (padding_left + padding_right) + ((@num_rows - 1) * spacing_v)
116
+ extra_height = min_height - total_height
117
+ if extra_height > 0
118
+ if num_filled_rows > 0
119
+ @heights[filled_rows.index true] += extra_height
120
+ else
121
+ @heights[-1] += extra_height
122
+ end
123
+ end
124
+ end
125
+
126
+ # Actually place all the elements into the grid positions, modified by valign and align.
127
+ current_y = y + padding_top
128
+ @rows.each_with_index do |row, row_num|
129
+ current_x = x + padding_left
130
+
131
+ row.each_with_index do |element, column_num|
132
+ element.x = current_x + element.border_thickness
133
+
134
+ case element.align_h # Take horizontal alignment into consideration.
135
+ when :fill
136
+ if element.width < @widths[column_num]
137
+ element.width = @widths[column_num]
138
+ element.send :repack if element.is_a? Grid
139
+ end
140
+ when :center
141
+ element.x += (@widths[column_num] - element.width) / 2
142
+ when :right
143
+ element.x += @widths[column_num] - element.width
144
+ end
145
+
146
+ current_x += @widths[column_num]
147
+ current_x += spacing_h unless column_num == @num_columns - 1
148
+
149
+ element.y = current_y + element.border_thickness
150
+
151
+ case element.align_v # Take horizontal alignment into consideration.
152
+ when :fill
153
+ if element.height < @heights[row_num]
154
+ element.height = @heights[row_num]
155
+ element.send :repack if element.is_a? Grid
156
+ end
157
+ when :center
158
+ element.y += (@heights[row_num] - element.height) / 2
159
+ when :bottom
160
+ element.y += @heights[row_num] - element.height
161
+ else
162
+ end
163
+ end
164
+
165
+ self.width = current_x - x + padding_left if row_num == 0
166
+
167
+ current_y += @heights[row_num] unless row.empty?
168
+ current_y += spacing_h unless row_num == num_rows - 1
169
+ end
170
+
171
+ self.height = current_y - y + padding_top
172
+
173
+ nil
174
+ end
175
+
176
+ protected
177
+ # @yield The rectangle of each cell within the grid.
178
+ # @yieldparam [Number] x
179
+ # @yieldparam [Number] y
180
+ # @yieldparam [Number] width
181
+ # @yieldparam [Number] height
182
+ def each_cell_rect
183
+ x = self.x + padding_left
184
+
185
+ @widths.each_with_index do |width, column_num|
186
+ y = self.y + padding_top
187
+
188
+ @heights.each_with_index do |height, row_num|
189
+ yield x, y, width, height if @rows[row_num][column_num]
190
+ y += height + spacing_v
191
+ end
192
+
193
+ x += width + spacing_h
194
+ end
195
+
196
+ nil
197
+ end
198
+
199
+ protected
200
+ def draw_background
201
+ super
202
+
203
+ # Draw the cell backgrounds.
204
+ unless @cell_background_color.transparent?
205
+ each_cell_rect do |x, y, width, height|
206
+ draw_rect x, y, width, height, z, @cell_background_color
207
+ end
208
+ end
209
+
210
+ nil
211
+ end
212
+
213
+ protected
214
+ def draw_border
215
+ super
216
+
217
+ # Draw the cell borders.
218
+ if @cell_border_thickness > 0 and not @cell_border_color.transparent?
219
+ each_cell_rect do |x, y, width, height|
220
+ draw_frame x, y, width, height, @cell_border_thickness, z, @cell_border_color
221
+ end
222
+ end
223
+
224
+ nil
225
+ end
226
+ end
227
+ end
@@ -0,0 +1,64 @@
1
+ module Fidgit
2
+ class Group < Packer
3
+ attr_reader :selected
4
+
5
+ event :changed
6
+
7
+ def value; @selected ? @selected.value : nil; end
8
+
9
+ # @example
10
+ # group do
11
+ # horizontal do
12
+ # radio_button 1, text: '1', checked: true
13
+ # radio_button 2, text: '2'
14
+ # subscribe :changed do |sender, value|
15
+ # puts value
16
+ # end
17
+ # end
18
+ # end
19
+ #
20
+ # @param (see Packer#initialize)
21
+ #
22
+ # @option (see Packer#initialize)
23
+ def initialize(options = {}, &block)
24
+ super(options)
25
+
26
+ @selected = nil
27
+ @buttons = []
28
+ end
29
+
30
+ def add_button(button)
31
+ @buttons.push button
32
+ self.value = button.value if button.checked?
33
+ nil
34
+ end
35
+
36
+ def remove_button(button)
37
+ self.value = nil if button == @selected
38
+ @buttons.delete button
39
+ nil
40
+ end
41
+
42
+ # @example
43
+ # @my_group = group do
44
+ # horizontal do
45
+ # radio_button(1, text: '1', checked: true)
46
+ # radio_button(2, text: '2')
47
+ # end
48
+ # end
49
+ #
50
+ # # later
51
+ # @my_group.value = 2
52
+ def value=(value)
53
+ if value != self.value
54
+ button = @buttons.find { |b| b.value == value }
55
+ @selected.uncheck if @selected and @selected.checked?
56
+ @selected = button
57
+ @selected.check if @selected and not @selected.checked?
58
+ publish :changed, self.value
59
+ end
60
+
61
+ value
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,12 @@
1
+ # encoding: utf-8
2
+
3
+ module Fidgit
4
+ # A vertically aligned element packing container.
5
+ class Horizontal < Grid
6
+ def initialize(options = {})
7
+ options[:num_rows] = 1
8
+
9
+ super options
10
+ end
11
+ end
12
+ end