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,65 @@
1
+ module Fidgit
2
+ # A wrapper around a Gosu::Image to show it in the GUI.
3
+ class ImageFrame < Element
4
+ ENABLED_COLOR = Gosu::Color::WHITE
5
+ DISABLED_COLOR = Gosu::Color.rgb(150, 150, 150)
6
+
7
+ attr_reader :image, :factor_x, :factor_y
8
+
9
+ def thumbnail?; @thumbnail; end
10
+
11
+ # @param (see Element#initialize)
12
+ # @param [Gosu::Image] image Gosu image to display.
13
+ #
14
+ # @option (see Element#initialize)
15
+ # @option options [Boolean] :thumbnail (false) Is the image expanded to be square?
16
+ def initialize(image, options = {})
17
+ options = {
18
+ thumbnail: false,
19
+ factor: 1,
20
+ }.merge! options
21
+
22
+ @thumbnail = options[:thumbnail]
23
+ @factor_x = options[:factor_x] || options[:factor]
24
+ @factor_y = options[:factor_y] || options[:factor]
25
+
26
+ super(options)
27
+
28
+ self.image = image
29
+ end
30
+
31
+ def image=(image)
32
+ @image = image
33
+
34
+ recalc
35
+
36
+ image
37
+ end
38
+
39
+
40
+ def draw_foreground
41
+ @image.draw(x + padding_left, y + padding_top, z, factor_x, factor_y, enabled? ? ENABLED_COLOR : DISABLED_COLOR) if @image
42
+ end
43
+
44
+ protected
45
+ def layout
46
+ if @image
47
+ if @thumbnail
48
+ size = [@image.width, @image.height].max
49
+ rect.width = size * @factor_x
50
+ rect.height = size * @factor_y
51
+ else
52
+ rect.width = @image.width * @factor_x
53
+ rect.height = @image.height * @factor_y
54
+ end
55
+ else
56
+ rect.width = rect.height = 0
57
+ end
58
+
59
+ rect.width += padding_left + padding_right
60
+ rect.height += padding_top + padding_bottom
61
+
62
+ nil
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,85 @@
1
+ # encoding: utf-8
2
+
3
+ module Fidgit
4
+ class Label < Composite
5
+ ICON_POSITIONS = [:top, :bottom, :left, :right]
6
+
7
+ attr_reader :icon_position
8
+
9
+ attr_accessor :background_color, :border_color
10
+
11
+ def_delegators :@text, :text, :color, :font, :color=, :text=
12
+
13
+ def icon; @icon ? @icon.image : nil; end
14
+
15
+ def hit_element(x, y)
16
+ # The sub-elements should never get events.
17
+ hit?(x, y) ? self : nil
18
+ end
19
+
20
+ def icon=(icon)
21
+ raise ArgumentError.new("Icon must be a Gosu::Image") unless icon.is_a? Gosu::Image or icon.nil?
22
+
23
+ @contents.remove(@icon) if @icon.image
24
+ @icon.image = icon
25
+ position = [:left, :top].include?(icon_position) ? 0 : 1
26
+ @contents.insert(position, @icon) if @icon.image
27
+
28
+ icon
29
+ end
30
+
31
+ # Set the position of the icon, respective to the text.
32
+ def icon_position=(position)
33
+ raise ArgumentError.new("icon_position must be one of #{ICON_POSITIONS}") unless ICON_POSITIONS.include? position
34
+
35
+ @icon_position = position
36
+
37
+ case @icon_position
38
+ when :top, :bottom
39
+ @contents.instance_variable_set :@type, :fixed_columns
40
+ @contents.instance_variable_set :@num_columns, 1
41
+ when :left, :right
42
+ @contents.instance_variable_set :@type, :fixed_rows
43
+ @contents.instance_variable_set :@num_rows, 1
44
+ end
45
+
46
+ self.icon = @icon.image if @icon.image # Force the icon into the correct position.
47
+
48
+ position
49
+ end
50
+
51
+ # @param (see Element#initialize)
52
+ # @param [String] text The string to display in the label.
53
+ #
54
+ # @option (see Element#initialize)
55
+ # @option options [Gosu::Image, nil] :icon (nil)
56
+ # @option options [:left, :right, :center] :justify (:left) Text justification.
57
+ def initialize(text, options = {})
58
+ options = {
59
+ color: default(:color),
60
+ justify: default(:justify),
61
+ background_color: default(:background_color),
62
+ border_color: default(:border_color),
63
+ icon_options: {},
64
+ font_name: default(:font_name),
65
+ font_height: default(:font_height),
66
+ icon_position: default(:icon_position),
67
+ }.merge! options
68
+
69
+ super(options)
70
+
71
+ # Bit of a fudge since font info is managed circularly here!
72
+ # By using a grid, we'll be able to turn it around easily (in theory).
73
+ @contents = grid num_rows: 1, padding: 0, spacing_h: spacing_h, spacing_v: spacing_v, width: options[:width], height: options[:height], z: z do |contents|
74
+ @text = TextLine.new(text, parent: contents, justify: options[:justify], color: options[:color], padding: 0, z: z,
75
+ font_name: options[:font_name], font_height: options[:font_height], align_h: :fill, align_v: :center)
76
+ end
77
+
78
+ # Create an image frame, but don't show it unless there is an image in it.
79
+ @icon = ImageFrame.new(nil, options[:icon_options].merge(z: z, align: :center))
80
+ @icon.image = options[:icon]
81
+
82
+ self.icon_position = options[:icon_position]
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,47 @@
1
+ # encoding: utf-8
2
+
3
+ module Fidgit
4
+ class List < Composite
5
+ class Item < RadioButton
6
+ end
7
+
8
+ event :changed
9
+
10
+ def size; @items.size; end
11
+ def clear; @items.clear; end
12
+
13
+ def initialize(options = {})
14
+ options = {
15
+ background_color: default(:background_color),
16
+ border_color: default(:border_color),
17
+ }.merge! options
18
+
19
+ super options
20
+
21
+ group do
22
+ subscribe :changed do |sender, value|
23
+ publish :changed, value
24
+ end
25
+
26
+ @items = vertical spacing: 0
27
+ end
28
+ end
29
+
30
+ # @param [String] text
31
+ # @option options [Gosu::Image] :icon
32
+ def item(text, value, options = {}, &block)
33
+ Item.new(text, value, { parent: @items }.merge!(options), &block)
34
+ end
35
+
36
+ protected
37
+ def layout
38
+ super
39
+ if @items
40
+ max_width = @items.each.to_a.map {|c| c.width }.max || 0
41
+ @items.each {|c| c.rect.width = max_width }
42
+ end
43
+
44
+ nil
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,25 @@
1
+ require_relative "vertical"
2
+
3
+ module Fidgit
4
+ # Main container that can contains a single "proper" packing element.
5
+ class MainPacker < Vertical
6
+ def initialize(options = {})
7
+ options = {
8
+ width: $window.width,
9
+ height: $window.height,
10
+ }.merge! options
11
+
12
+ super options
13
+ end
14
+
15
+ def width; $window.width; end
16
+ def height; $window.height; end
17
+ def width=(value); ; end
18
+ def height=(value); ; end
19
+
20
+ def add(element)
21
+ raise "MainPacker can only contain packing elements" unless element.is_a? Packer
22
+ super(element)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,163 @@
1
+ require 'forwardable'
2
+
3
+ module Fidgit
4
+ class MenuPane < Composite
5
+ # An item within the menu.
6
+ class Item < Button
7
+ attr_reader :value, :shortcut_text
8
+
9
+ # @param (see Button#initialize)
10
+ #
11
+ # @option (see Button#initialize)
12
+ # @param [any] value Value if the user picks this item
13
+ # @option options [String] :shortcut_text ('')
14
+ def initialize(text, value, options = {})
15
+ options = {
16
+ enabled: true,
17
+ border_color: default(:border_color),
18
+ shortcut_text: '',
19
+ }.merge! options
20
+
21
+ @value = value
22
+ @shortcut_text = options[:shortcut_text]
23
+
24
+ super(text, options)
25
+ end
26
+
27
+ def draw_foreground
28
+ super
29
+
30
+ unless @shortcut_text.empty?
31
+ font.draw_rel("#{@shortcut_text}", rect.right - padding_right, y + ((height - font.height) / 2).floor, z, 1, 0, 1, 1, color)
32
+ end
33
+
34
+ nil
35
+ end
36
+
37
+ protected
38
+ def layout
39
+ super
40
+
41
+ # Ignore layout request when asked before TextLine has been created.
42
+ rect.width += font.text_width(" #{@shortcut_text}") unless @shortcut_text.empty? or @text.nil?
43
+
44
+ nil
45
+ end
46
+ end
47
+
48
+ class Separator < Label
49
+ # @param (see Item#initialize)
50
+ #
51
+ # @option (see Item#initialize)
52
+ def initialize(options = {})
53
+ options = {
54
+ height: default(:line_height),
55
+ background_color: default(:background_color),
56
+ padding: 0,
57
+ }.merge! options
58
+
59
+ super '', options
60
+ end
61
+ end
62
+
63
+ extend Forwardable
64
+
65
+ def_delegators :@items, :each, :clear, :size, :[]
66
+
67
+ event :selected
68
+
69
+ def index(value); @items.index find(value); end
70
+ def x=(value); super(value); recalc; end
71
+ def y=(value); super(value); recalc; end
72
+
73
+ # @option (see Composite#initialize)
74
+ # @option options [Float] :x (cursor x, if in a GuiState)
75
+ # @option options [Float] :y (cursor y, if in a GuiState)
76
+ # @option options [Boolean] :show (true) Whether to show immediately (show later with #show).
77
+ def initialize(options = {}, &block)
78
+ options = {
79
+ background_color: default(:color),
80
+ z: Float::INFINITY,
81
+ show: true,
82
+ }.merge! options
83
+
84
+ state = $window.current_game_state
85
+ if state.is_a? GuiState
86
+ cursor = $window.current_game_state.cursor
87
+ options = {
88
+ x: cursor.x,
89
+ y: cursor.y,
90
+ }.merge! options
91
+ end
92
+
93
+ @items = nil
94
+
95
+ super(options)
96
+
97
+ @items = vertical spacing: 0, padding: 0
98
+
99
+ if options[:show] and state.is_a? GuiState
100
+ show
101
+ end
102
+ end
103
+
104
+ def find(value)
105
+ @items.find {|c| c.value == value }
106
+ end
107
+
108
+ def separator(options = {})
109
+ options[:z] = z
110
+
111
+ Separator.new({ parent: @items }.merge!(options))
112
+ end
113
+
114
+ def item(text, value, options = {}, &block)
115
+ options = options.merge({
116
+ parent: @items,
117
+ z: z,
118
+ })
119
+ item = Item.new(text, value, options, &block)
120
+
121
+ item.subscribe :left_mouse_button, method(:item_selected)
122
+ item.subscribe :right_mouse_button, method(:item_selected)
123
+
124
+ item
125
+ end
126
+
127
+ def item_selected(sender, x, y)
128
+ publish(:selected, sender.value)
129
+
130
+ $window.game_state_manager.current_game_state.hide_menu
131
+
132
+ nil
133
+ end
134
+
135
+ def show
136
+ $window.game_state_manager.current_game_state.show_menu self
137
+ nil
138
+ end
139
+
140
+ protected
141
+ def layout
142
+ super
143
+
144
+ if @items
145
+ # Ensure the menu can't go over the edge of the screen. If it can't be avoided, align with top-left edge of screen.
146
+ rect.x = [[x, $window.width - width - padding_right].min, 0].max
147
+ rect.y = [[y, $window.height - height - padding_bottom].min, 0].max
148
+
149
+ # Move the actual list if the menu has moved to keep on the screen.
150
+ @items.x = x + padding_left
151
+ @items.y = y + padding_top
152
+
153
+ # Ensure that all items are of the same width.
154
+ max_width = @items.map(&:width).max || 0
155
+ @items.each {|c| c.rect.width = max_width }
156
+
157
+ @items.recalc # Move all the items inside the packer to correct ones.
158
+ end
159
+
160
+ nil
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,42 @@
1
+ # encoding: utf-8
2
+
3
+ module Fidgit
4
+ # Container that auto-packs elements.
5
+ #
6
+ # @abstract
7
+ class Packer < Container
8
+ attr_reader :spacing_h, :spacing_v
9
+
10
+ # @param (see Container#initialize)
11
+ #
12
+ # @option (see Container#initialize)
13
+ def initialize(options = {})
14
+ options = {
15
+ }.merge! options
16
+
17
+ @spacing_h = options[:spacing_h] || options[:spacing] || default(:spacing_h)
18
+ @spacing_v = options[:spacing_v] || options[:spacing] || default(:spacing_v)
19
+
20
+ super(options)
21
+ end
22
+
23
+ protected
24
+ # Recalculate the size of the container.
25
+ # Should be overridden by any descendant that manages the positions of its children.
26
+ def layout
27
+ # This assumes that the container overlaps all the children.
28
+
29
+ # Move all children if we have moved.
30
+ @children.each.with_index do |child, index|
31
+ child.x = padding_left + x
32
+ child.y = padding_top + y
33
+ end
34
+
35
+ # Make us as wrap around the largest child.
36
+ rect.width = (@children.map {|c| c.width }.max || 0) + padding_left + padding_right
37
+ rect.height = (@children.map {|c| c.height }.max || 0) + padding_top + padding_bottom
38
+
39
+ super
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,86 @@
1
+ # encoding: utf-8
2
+
3
+ module Fidgit
4
+ class RadioButton < Button
5
+ attr_reader :group, :value
6
+
7
+ event :changed
8
+
9
+ def checked?; @checked; end
10
+
11
+ # @param (see Button#initialize)
12
+ # @param [Object] value
13
+ #
14
+ # @option (see Button#initialize)
15
+ # @option options [Boolean] :checked
16
+ def initialize(text, value, options = {}, &block)
17
+ options = {
18
+ checked: false,
19
+ checked_border_color: default(:checked, :border_color),
20
+ }.merge! options
21
+
22
+ @checked = options[:checked]
23
+ @value = value
24
+
25
+ super(text, options)
26
+
27
+ @checked_border_color = options[:checked_border_color].dup
28
+ @unchecked_border_color = border_color
29
+ add_to_group
30
+
31
+ @border_color = (checked? ? @checked_border_color : @unchecked_border_color).dup
32
+ end
33
+
34
+ def clicked_left_mouse_button(sender, x, y)
35
+ super
36
+ check
37
+ nil
38
+ end
39
+
40
+ # Check the button and update its group. This may uncheck another button in the group if one is selected.
41
+ def check
42
+ return if checked?
43
+
44
+ @checked = true
45
+ @group.value = value
46
+ @border_color = @checked_border_color.dup
47
+ publish :changed, @checked
48
+
49
+ nil
50
+ end
51
+
52
+ # Uncheck the button and update its group.
53
+ def uncheck
54
+ return unless checked?
55
+
56
+ @checked = false
57
+ @group.value = value
58
+ @border_color = @unchecked_border_color.dup
59
+ publish :changed, @checked
60
+
61
+ nil
62
+ end
63
+
64
+ protected
65
+ def parent=(parent)
66
+ @group.remove_button self if @parent
67
+ super(parent)
68
+ add_to_group if parent
69
+ parent
70
+ end
71
+
72
+ protected
73
+ def add_to_group
74
+ container = parent
75
+ while container and not container.is_a? Group
76
+ container = container.parent
77
+ end
78
+
79
+ raise "#{self.class.name} must be placed inside a group element" unless container
80
+
81
+ @group = container
82
+ @group.add_button self
83
+ nil
84
+ end
85
+ end
86
+ end