colstrom-fidgit 0.2.7

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