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.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/.rspec +2 -0
- data/CHANGELOG.md +31 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +20 -0
- data/README.md +154 -0
- data/Rakefile +38 -0
- data/config/default_schema.yml +216 -0
- data/examples/_all_examples.rb +9 -0
- data/examples/align_example.rb +56 -0
- data/examples/button_and_toggle_button_example.rb +38 -0
- data/examples/color_picker_example.rb +17 -0
- data/examples/color_well_example.rb +25 -0
- data/examples/combo_box_example.rb +24 -0
- data/examples/file_dialog_example.rb +42 -0
- data/examples/grid_packer_example.rb +29 -0
- data/examples/helpers/example_window.rb +17 -0
- data/examples/label_example.rb +23 -0
- data/examples/list_example.rb +23 -0
- data/examples/media/images/head_icon.png +0 -0
- data/examples/menu_pane_example.rb +27 -0
- data/examples/message_dialog_example.rb +65 -0
- data/examples/radio_button_example.rb +37 -0
- data/examples/readme_example.rb +32 -0
- data/examples/scroll_window_example.rb +49 -0
- data/examples/slider_example.rb +34 -0
- data/examples/splash_example.rb +42 -0
- data/examples/text_area_example.rb +33 -0
- data/fidgit.gemspec +35 -0
- data/lib/fidgit.rb +51 -0
- data/lib/fidgit/chingu_ext/window.rb +6 -0
- data/lib/fidgit/cursor.rb +38 -0
- data/lib/fidgit/elements/button.rb +113 -0
- data/lib/fidgit/elements/color_picker.rb +63 -0
- data/lib/fidgit/elements/color_well.rb +39 -0
- data/lib/fidgit/elements/combo_box.rb +115 -0
- data/lib/fidgit/elements/composite.rb +17 -0
- data/lib/fidgit/elements/container.rb +210 -0
- data/lib/fidgit/elements/element.rb +298 -0
- data/lib/fidgit/elements/file_browser.rb +152 -0
- data/lib/fidgit/elements/grid.rb +227 -0
- data/lib/fidgit/elements/group.rb +64 -0
- data/lib/fidgit/elements/horizontal.rb +12 -0
- data/lib/fidgit/elements/image_frame.rb +65 -0
- data/lib/fidgit/elements/label.rb +85 -0
- data/lib/fidgit/elements/list.rb +47 -0
- data/lib/fidgit/elements/main_packer.rb +25 -0
- data/lib/fidgit/elements/menu_pane.rb +163 -0
- data/lib/fidgit/elements/packer.rb +42 -0
- data/lib/fidgit/elements/radio_button.rb +86 -0
- data/lib/fidgit/elements/scroll_area.rb +68 -0
- data/lib/fidgit/elements/scroll_bar.rb +128 -0
- data/lib/fidgit/elements/scroll_window.rb +83 -0
- data/lib/fidgit/elements/slider.rb +125 -0
- data/lib/fidgit/elements/text_area.rb +494 -0
- data/lib/fidgit/elements/text_line.rb +92 -0
- data/lib/fidgit/elements/toggle_button.rb +67 -0
- data/lib/fidgit/elements/tool_tip.rb +35 -0
- data/lib/fidgit/elements/vertical.rb +12 -0
- data/lib/fidgit/event.rb +159 -0
- data/lib/fidgit/gosu_ext/color.rb +136 -0
- data/lib/fidgit/gosu_ext/gosu_module.rb +25 -0
- data/lib/fidgit/history.rb +91 -0
- data/lib/fidgit/redirector.rb +83 -0
- data/lib/fidgit/schema.rb +123 -0
- data/lib/fidgit/selection.rb +106 -0
- data/lib/fidgit/standard_ext/hash.rb +21 -0
- data/lib/fidgit/states/dialog_state.rb +52 -0
- data/lib/fidgit/states/file_dialog.rb +24 -0
- data/lib/fidgit/states/gui_state.rb +331 -0
- data/lib/fidgit/states/message_dialog.rb +61 -0
- data/lib/fidgit/version.rb +5 -0
- data/lib/fidgit/window.rb +19 -0
- data/media/images/arrow.png +0 -0
- data/media/images/combo_arrow.png +0 -0
- data/media/images/file_directory.png +0 -0
- data/media/images/file_file.png +0 -0
- data/media/images/pixel.png +0 -0
- data/spec/fidgit/elements/helpers/helper.rb +3 -0
- data/spec/fidgit/elements/helpers/tex_play_helper.rb +9 -0
- data/spec/fidgit/elements/image_frame_spec.rb +69 -0
- data/spec/fidgit/elements/label_spec.rb +37 -0
- data/spec/fidgit/event_spec.rb +210 -0
- data/spec/fidgit/gosu_ext/color_spec.rb +130 -0
- data/spec/fidgit/gosu_ext/helpers/helper.rb +3 -0
- data/spec/fidgit/helpers/helper.rb +4 -0
- data/spec/fidgit/history_spec.rb +153 -0
- data/spec/fidgit/redirector_spec.rb +78 -0
- data/spec/fidgit/schema_spec.rb +67 -0
- data/spec/fidgit/schema_test.yml +32 -0
- 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
|