fidgit 0.2.4 → 0.2.5

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 (85) hide show
  1. data/.gitignore +7 -7
  2. data/.rspec +2 -2
  3. data/CHANGELOG.md +30 -30
  4. data/Gemfile +3 -3
  5. data/LICENSE.txt +19 -19
  6. data/README.textile +139 -139
  7. data/Rakefile +37 -37
  8. data/config/default_schema.yml +216 -216
  9. data/examples/_all_examples.rb +9 -9
  10. data/examples/align_example.rb +55 -55
  11. data/examples/button_and_toggle_button_example.rb +37 -37
  12. data/examples/color_picker_example.rb +16 -16
  13. data/examples/color_well_example.rb +24 -24
  14. data/examples/combo_box_example.rb +23 -23
  15. data/examples/file_dialog_example.rb +41 -41
  16. data/examples/grid_packer_example.rb +28 -28
  17. data/examples/helpers/example_window.rb +16 -16
  18. data/examples/label_example.rb +22 -22
  19. data/examples/list_example.rb +22 -22
  20. data/examples/menu_pane_example.rb +26 -26
  21. data/examples/message_dialog_example.rb +64 -64
  22. data/examples/radio_button_example.rb +36 -36
  23. data/examples/readme_example.rb +31 -31
  24. data/examples/scroll_window_example.rb +48 -48
  25. data/examples/slider_example.rb +33 -33
  26. data/examples/splash_example.rb +41 -41
  27. data/examples/text_area_example.rb +32 -32
  28. data/fidgit.gemspec +35 -35
  29. data/lib/fidgit.rb +50 -50
  30. data/lib/fidgit/chingu_ext/window.rb +5 -5
  31. data/lib/fidgit/cursor.rb +37 -37
  32. data/lib/fidgit/elements/button.rb +112 -112
  33. data/lib/fidgit/elements/color_picker.rb +62 -62
  34. data/lib/fidgit/elements/color_well.rb +38 -38
  35. data/lib/fidgit/elements/combo_box.rb +113 -113
  36. data/lib/fidgit/elements/composite.rb +16 -16
  37. data/lib/fidgit/elements/container.rb +208 -208
  38. data/lib/fidgit/elements/element.rb +297 -297
  39. data/lib/fidgit/elements/file_browser.rb +151 -151
  40. data/lib/fidgit/elements/grid.rb +226 -226
  41. data/lib/fidgit/elements/group.rb +64 -64
  42. data/lib/fidgit/elements/horizontal.rb +11 -11
  43. data/lib/fidgit/elements/image_frame.rb +64 -64
  44. data/lib/fidgit/elements/label.rb +84 -84
  45. data/lib/fidgit/elements/list.rb +46 -46
  46. data/lib/fidgit/elements/main_packer.rb +24 -24
  47. data/lib/fidgit/elements/menu_pane.rb +160 -160
  48. data/lib/fidgit/elements/packer.rb +41 -41
  49. data/lib/fidgit/elements/radio_button.rb +85 -85
  50. data/lib/fidgit/elements/scroll_area.rb +67 -67
  51. data/lib/fidgit/elements/scroll_bar.rb +127 -127
  52. data/lib/fidgit/elements/scroll_window.rb +82 -82
  53. data/lib/fidgit/elements/slider.rb +124 -124
  54. data/lib/fidgit/elements/text_area.rb +493 -493
  55. data/lib/fidgit/elements/text_line.rb +91 -91
  56. data/lib/fidgit/elements/toggle_button.rb +66 -66
  57. data/lib/fidgit/elements/tool_tip.rb +34 -34
  58. data/lib/fidgit/elements/vertical.rb +11 -11
  59. data/lib/fidgit/event.rb +158 -158
  60. data/lib/fidgit/gosu_ext/color.rb +135 -135
  61. data/lib/fidgit/gosu_ext/gosu_module.rb +24 -24
  62. data/lib/fidgit/history.rb +90 -90
  63. data/lib/fidgit/redirector.rb +82 -82
  64. data/lib/fidgit/schema.rb +123 -123
  65. data/lib/fidgit/selection.rb +105 -105
  66. data/lib/fidgit/standard_ext/hash.rb +20 -20
  67. data/lib/fidgit/states/dialog_state.rb +51 -51
  68. data/lib/fidgit/states/file_dialog.rb +24 -24
  69. data/lib/fidgit/states/gui_state.rb +329 -329
  70. data/lib/fidgit/states/message_dialog.rb +60 -60
  71. data/lib/fidgit/version.rb +4 -4
  72. data/lib/fidgit/window.rb +19 -19
  73. data/spec/fidgit/elements/helpers/helper.rb +2 -2
  74. data/spec/fidgit/elements/helpers/tex_play_helper.rb +8 -8
  75. data/spec/fidgit/elements/image_frame_spec.rb +68 -68
  76. data/spec/fidgit/elements/label_spec.rb +36 -36
  77. data/spec/fidgit/event_spec.rb +209 -209
  78. data/spec/fidgit/gosu_ext/color_spec.rb +129 -129
  79. data/spec/fidgit/gosu_ext/helpers/helper.rb +2 -2
  80. data/spec/fidgit/helpers/helper.rb +3 -3
  81. data/spec/fidgit/history_spec.rb +153 -153
  82. data/spec/fidgit/redirector_spec.rb +77 -77
  83. data/spec/fidgit/schema_spec.rb +66 -66
  84. data/spec/fidgit/schema_test.yml +32 -32
  85. metadata +67 -22
@@ -1,209 +1,209 @@
1
- # encoding: utf-8
2
-
3
- module Fidgit
4
- # A container that contains Elements.
5
- # @abstract
6
- class Container < Element
7
- extend Forwardable
8
-
9
- def_delegators :@children, :size, :each, :find, :index, :[], :empty?, :map, :select, :inject
10
-
11
- def x=(value)
12
- @children.each {|c| c.x += value - x }
13
- super(value)
14
- end
15
-
16
- def y=(value)
17
- @children.each {|c| c.y += value - y }
18
- super(value)
19
- end
20
-
21
- # @param (see Element#initialize)
22
- #
23
- # @option (see Element#initialize)
24
- def initialize(options = {})
25
- options[:border_color] = default(:debug, :border_color) if Fidgit.debug_mode?
26
-
27
- @children = []
28
-
29
- super(options)
30
- end
31
-
32
- def add(element)
33
- element.send :parent=, self
34
- @children.push element
35
-
36
- recalc
37
- nil
38
- end
39
-
40
- def remove(element)
41
- @children.delete element
42
- element.send :parent=, nil
43
-
44
- recalc
45
- nil
46
- end
47
-
48
- def insert(position, element)
49
- @children.insert position, element
50
- element.send :parent=, self
51
-
52
- recalc
53
- nil
54
- end
55
-
56
- # Create a button within the container.
57
- def button(text, options = {}, &block)
58
- Button.new(text, {parent: self}.merge!(options), &block)
59
- end
60
-
61
- # Create a color picker within the container.
62
- def color_picker(options = {}, &block)
63
- ColorPicker.new({parent: self}.merge!(options), &block)
64
- end
65
-
66
- # Create a color well within the container.
67
- def color_well(options = {}, &block)
68
- ColorWell.new({parent: self}.merge!(options), &block)
69
- end
70
-
71
- def combo_box(options = {}, &block)
72
- ComboBox.new({parent: self}.merge!(options), &block)
73
- end
74
-
75
- def file_browser(type, options = {}, &block)
76
- FileBrowser.new(type, {parent: self}.merge!(options), &block)
77
- end
78
-
79
- def group(options = {}, &block)
80
- Group.new({parent: self}.merge!(options), &block)
81
- end
82
-
83
- # Create an icon.
84
- def image_frame(image, options = {}, &block)
85
- ImageFrame.new(image, {parent: self}.merge!(options), &block)
86
- end
87
-
88
- # Create a label within the container.
89
- def label(text, options = {})
90
- Label.new(text, {parent: self}.merge!(options))
91
- end
92
-
93
- def list(options = {}, &block)
94
- List.new({parent: self}.merge!(options), &block)
95
- end
96
-
97
- public
98
- # Pack elements within the block horizontally.
99
- def horizontal(options = {}, &block)
100
- Horizontal.new({ parent: self }.merge!(options), &block)
101
- end
102
-
103
- public
104
- # Pack elements within the blockvertically.
105
- def vertical(options = {}, &block)
106
- Vertical.new({ parent: self }.merge!(options), &block)
107
- end
108
-
109
- public
110
- # Pack elements within the block in a grid (matrix) formation.
111
- def grid(options = {}, &block)
112
- Grid.new({ parent: self }.merge!(options), &block)
113
- end
114
-
115
- def radio_button(text, value, options = {}, &block)
116
- RadioButton.new(text, value, {parent: self}.merge!(options), &block)
117
- end
118
-
119
- def scroll_area(options = {}, &block)
120
- ScrollArea.new({parent: self}.merge!(options), &block)
121
- end
122
-
123
- def scroll_window(options = {}, &block)
124
- ScrollWindow.new({parent: self}.merge!(options), &block)
125
- end
126
-
127
- def slider(options = {}, &block)
128
- Slider.new({parent: self}.merge!(options), &block)
129
- end
130
-
131
- def text_area(options = {}, &block)
132
- TextArea.new({parent: self}.merge!(options), &block)
133
- end
134
-
135
- def toggle_button(text, options = {}, &block)
136
- ToggleButton.new(text, {parent: self}.merge!(options), &block)
137
- end
138
-
139
- def clear
140
- @children.each {|child| child.send :parent=, nil }
141
- @children.clear
142
-
143
- recalc
144
-
145
- nil
146
- end
147
-
148
- def update
149
- @children.each { |c| c.update }
150
-
151
- nil
152
- end
153
-
154
- # Returns the element within this container that was hit,
155
- # @return [Element, nil] The element hit, otherwise nil.
156
- def hit_element(x, y)
157
- @children.reverse_each do |child|
158
- case child
159
- when Container, Composite
160
- if element = child.hit_element(x, y)
161
- return element
162
- end
163
- else
164
- return child if child.hit?(x, y)
165
- end
166
- end
167
-
168
- self if hit?(x, y)
169
- end
170
-
171
- protected
172
- def draw_foreground
173
- @children.each {|c| c.draw }
174
-
175
- font.draw self.class.name, x, y, z if Fidgit.debug_mode?
176
-
177
- nil
178
- end
179
-
180
- protected
181
- # Any container passed a block will allow you access to its methods.
182
- def post_init_block(&block)
183
- with(&block)
184
- end
185
-
186
- public
187
- def to_s
188
- "#{super} [#{@children.size} #{@children.size == 1 ? 'child' : 'children'}]"
189
- end
190
-
191
- public
192
- def write_tree(indent = "", index = 0)
193
- puts self
194
-
195
- indent = indent + " "
196
-
197
- @children.each.with_index do |element, i|
198
- print "#{indent}#{i}: "
199
-
200
- case element
201
- when Container
202
- element.write_tree(indent)
203
- else
204
- puts element
205
- end
206
- end
207
- end
208
- end
1
+ # encoding: utf-8
2
+
3
+ module Fidgit
4
+ # A container that contains Elements.
5
+ # @abstract
6
+ class Container < Element
7
+ extend Forwardable
8
+
9
+ def_delegators :@children, :size, :each, :find, :index, :[], :empty?, :map, :select, :inject
10
+
11
+ def x=(value)
12
+ @children.each {|c| c.x += value - x }
13
+ super(value)
14
+ end
15
+
16
+ def y=(value)
17
+ @children.each {|c| c.y += value - y }
18
+ super(value)
19
+ end
20
+
21
+ # @param (see Element#initialize)
22
+ #
23
+ # @option (see Element#initialize)
24
+ def initialize(options = {})
25
+ options[:border_color] = default(:debug, :border_color) if Fidgit.debug_mode?
26
+
27
+ @children = []
28
+
29
+ super(options)
30
+ end
31
+
32
+ def add(element)
33
+ element.send :parent=, self
34
+ @children.push element
35
+
36
+ recalc
37
+ nil
38
+ end
39
+
40
+ def remove(element)
41
+ @children.delete element
42
+ element.send :parent=, nil
43
+
44
+ recalc
45
+ nil
46
+ end
47
+
48
+ def insert(position, element)
49
+ @children.insert position, element
50
+ element.send :parent=, self
51
+
52
+ recalc
53
+ nil
54
+ end
55
+
56
+ # Create a button within the container.
57
+ def button(text, options = {}, &block)
58
+ Button.new(text, {parent: self}.merge!(options), &block)
59
+ end
60
+
61
+ # Create a color picker within the container.
62
+ def color_picker(options = {}, &block)
63
+ ColorPicker.new({parent: self}.merge!(options), &block)
64
+ end
65
+
66
+ # Create a color well within the container.
67
+ def color_well(options = {}, &block)
68
+ ColorWell.new({parent: self}.merge!(options), &block)
69
+ end
70
+
71
+ def combo_box(options = {}, &block)
72
+ ComboBox.new({parent: self}.merge!(options), &block)
73
+ end
74
+
75
+ def file_browser(type, options = {}, &block)
76
+ FileBrowser.new(type, {parent: self}.merge!(options), &block)
77
+ end
78
+
79
+ def group(options = {}, &block)
80
+ Group.new({parent: self}.merge!(options), &block)
81
+ end
82
+
83
+ # Create an icon.
84
+ def image_frame(image, options = {}, &block)
85
+ ImageFrame.new(image, {parent: self}.merge!(options), &block)
86
+ end
87
+
88
+ # Create a label within the container.
89
+ def label(text, options = {})
90
+ Label.new(text, {parent: self}.merge!(options))
91
+ end
92
+
93
+ def list(options = {}, &block)
94
+ List.new({parent: self}.merge!(options), &block)
95
+ end
96
+
97
+ public
98
+ # Pack elements within the block horizontally.
99
+ def horizontal(options = {}, &block)
100
+ Horizontal.new({ parent: self }.merge!(options), &block)
101
+ end
102
+
103
+ public
104
+ # Pack elements within the blockvertically.
105
+ def vertical(options = {}, &block)
106
+ Vertical.new({ parent: self }.merge!(options), &block)
107
+ end
108
+
109
+ public
110
+ # Pack elements within the block in a grid (matrix) formation.
111
+ def grid(options = {}, &block)
112
+ Grid.new({ parent: self }.merge!(options), &block)
113
+ end
114
+
115
+ def radio_button(text, value, options = {}, &block)
116
+ RadioButton.new(text, value, {parent: self}.merge!(options), &block)
117
+ end
118
+
119
+ def scroll_area(options = {}, &block)
120
+ ScrollArea.new({parent: self}.merge!(options), &block)
121
+ end
122
+
123
+ def scroll_window(options = {}, &block)
124
+ ScrollWindow.new({parent: self}.merge!(options), &block)
125
+ end
126
+
127
+ def slider(options = {}, &block)
128
+ Slider.new({parent: self}.merge!(options), &block)
129
+ end
130
+
131
+ def text_area(options = {}, &block)
132
+ TextArea.new({parent: self}.merge!(options), &block)
133
+ end
134
+
135
+ def toggle_button(text, options = {}, &block)
136
+ ToggleButton.new(text, {parent: self}.merge!(options), &block)
137
+ end
138
+
139
+ def clear
140
+ @children.each {|child| child.send :parent=, nil }
141
+ @children.clear
142
+
143
+ recalc
144
+
145
+ nil
146
+ end
147
+
148
+ def update
149
+ @children.each { |c| c.update }
150
+
151
+ nil
152
+ end
153
+
154
+ # Returns the element within this container that was hit,
155
+ # @return [Element, nil] The element hit, otherwise nil.
156
+ def hit_element(x, y)
157
+ @children.reverse_each do |child|
158
+ case child
159
+ when Container, Composite
160
+ if element = child.hit_element(x, y)
161
+ return element
162
+ end
163
+ else
164
+ return child if child.hit?(x, y)
165
+ end
166
+ end
167
+
168
+ self if hit?(x, y)
169
+ end
170
+
171
+ protected
172
+ def draw_foreground
173
+ @children.each {|c| c.draw }
174
+
175
+ font.draw self.class.name, x, y, z if Fidgit.debug_mode?
176
+
177
+ nil
178
+ end
179
+
180
+ protected
181
+ # Any container passed a block will allow you access to its methods.
182
+ def post_init_block(&block)
183
+ with(&block)
184
+ end
185
+
186
+ public
187
+ def to_s
188
+ "#{super} [#{@children.size} #{@children.size == 1 ? 'child' : 'children'}]"
189
+ end
190
+
191
+ public
192
+ def write_tree(indent = "", index = 0)
193
+ puts self
194
+
195
+ indent = indent + " "
196
+
197
+ @children.each.with_index do |element, i|
198
+ print "#{indent}#{i}: "
199
+
200
+ case element
201
+ when Container
202
+ element.write_tree(indent)
203
+ else
204
+ puts element
205
+ end
206
+ end
207
+ end
208
+ end
209
209
  end
@@ -1,298 +1,298 @@
1
- # encoding: utf-8
2
-
3
- # The Fidgit GUI framework for Gosu.
4
- module Fidgit
5
- class << self
6
- attr_accessor :debug_mode
7
- end
8
-
9
- self.debug_mode = false
10
-
11
- def self.debug_mode?; debug_mode; end
12
-
13
- # An element within the GUI environment.
14
- # @abstract
15
- class Element
16
- include Event
17
-
18
- event :left_mouse_button
19
- event :holding_left_mouse_button
20
- event :released_left_mouse_button
21
- event :clicked_left_mouse_button
22
-
23
- event :right_mouse_button
24
- event :holding_right_mouse_button
25
- event :released_right_mouse_button
26
- event :clicked_right_mouse_button
27
-
28
- event :middle_mouse_button
29
- event :holding_middle_mouse_button
30
- event :released_middle_mouse_button
31
- event :clicked_middle_mouse_button
32
-
33
- event :mouse_wheel_up
34
- event :mouse_wheel_down
35
-
36
- event :enter
37
- event :hover
38
- event :leave
39
-
40
- DEFAULT_SCHEMA_FILE = File.expand_path(File.join(__FILE__, '..', '..', '..', '..', 'config', 'default_schema.yml'))
41
-
42
- VALID_ALIGN_H = [:left, :center, :right, :fill]
43
- VALID_ALIGN_V = [:top, :center, :bottom, :fill]
44
-
45
- attr_reader :z, :tip, :padding_top, :padding_right, :padding_bottom, :padding_left,
46
- :align_h, :align_v, :parent, :border_thickness, :font
47
-
48
- attr_accessor :background_color
49
- attr_writer :tip
50
-
51
- def x; rect.x; end
52
- def x=(value); rect.x = value; end
53
-
54
- def y; rect.y; end
55
- def y=(value); rect.y = value; end
56
-
57
- # Width not including border.
58
- def width; rect.width; end
59
- def width=(value); rect.width = [[value, @width_range.max].min, @width_range.min].max; end
60
- def min_width; @width_range.min; end
61
- def max_width; @width_range.max; end
62
- # Width including border thickness.
63
- def outer_width; rect.width + @border_thickness * 2; end
64
-
65
- # Height not including border.
66
- def height; rect.height; end
67
- def height=(value); rect.height = [[value, @height_range.max].min, @height_range.min].max; end
68
- def min_height; @height_range.min; end
69
- def max_height; @height_range.max; end
70
- # Height including border thickness.
71
- def outer_height; rect.height + @border_thickness * 2; end
72
-
73
- # Can the object be dragged?
74
- def drag?(button); false; end
75
-
76
- def enabled?; @enabled; end
77
-
78
- def enabled=(value)
79
- if @mouse_over and enabled? and not value
80
- $window.current_game_state.unset_mouse_over
81
- end
82
-
83
- @enabled = value
84
- end
85
-
86
- def rect; @rect; end; protected :rect
87
-
88
- def self.schema; @@schema ||= Schema.new(YAML.load(File.read(DEFAULT_SCHEMA_FILE)));; end
89
-
90
- class << self
91
- alias_method :original_new, :new
92
-
93
- def new(*args, &block)
94
- obj = original_new(*args) # Block should be ignored.
95
- obj.send :post_init
96
- obj.send :post_init_block, &block if block_given?
97
- obj
98
- end
99
- end
100
-
101
- # Get the default value from the schema.
102
- #
103
- # @param [Symbol, Array<Symbol>] names
104
- def default(*names)
105
- self.class.schema.default(self.class, names)
106
- end
107
-
108
- # @param [Element, nil] parent
109
- #
110
- # @option options [Number] :x (0)
111
- # @option options [Number] :y (0)
112
- # @option options [Number] :z (0)
113
- #
114
- # @option options [Number] :width (auto)
115
- # @option options [Number] :min_width (value of :width option)
116
- # @option options [Number] :max_width (value of :width option)
117
- #
118
- # @option options [Number] :height (auto)
119
- # @option options [Number] :min_height (value of :height option)
120
- # @option options [Number] :max_height (value of :height option)
121
- #
122
- # @option options [String] :tip ('') Tool-tip text
123
- # @option options [String, :default] :font_name (:default, which resolves as the default Gosu font)
124
- # @option options [String] :font_height (30)
125
- # @option options [Gosu::Font] :font Use this instead of :font_name and :font_height
126
- #
127
- # @option options [Gosu::Color] :background_color (transparent)
128
- # @option options [Gosu::Color] :border_color (transparent)
129
- #
130
- # @option options [Boolean] :enabled (true)
131
- #
132
- # @option options [Number] :padding (4)
133
- # @option options [Number] :padding_h (:padding option)
134
- # @option options [Number] :padding_v (:padding option)
135
- # @option options [Number] :padding_top (:padding_v option)
136
- # @option options [Number] :padding_right (:padding_h option)
137
- # @option options [Number] :padding_bottom (:padding_v option)
138
- # @option options [Number] :padding_left (:padding_h option)
139
- #
140
- # @option options [Symbol] :align Align both horizontally and vertically. One of :center, :fill or [<align_v>, <align_h>] such as [:top, :right].
141
- # @option options [Symbol] :align_h (value or :align else :left) One of :left, :center, :right :fill
142
- # @option options [Symbol] :align_v (value of :align else :top) One of :top, :center, :bottom, :fill
143
-
144
- # @yield instance_methods_eval with respect to self.
145
- def initialize(options = {}, &block)
146
- options = {
147
- x: 0,
148
- y: 0,
149
- z: 0,
150
- tip: '',
151
- font_name: default(:font_name),
152
- font_height: default(:font_height),
153
- background_color: default(:background_color),
154
- border_color: default(:border_color),
155
- border_thickness: default(:border_thickness),
156
- enabled: true,
157
- }.merge! options
158
-
159
- @enabled = options[:enabled]
160
-
161
- @mouse_over = false
162
-
163
- # Alignment and min/max dimensions.
164
- @align_h = options[:align_h] || Array(options[:align]).last || default(:align_h)
165
- raise ArgumentError, "Invalid align_h: #{@align_h}" unless VALID_ALIGN_H.include? @align_h
166
-
167
- min_width = (options[:min_width] || options[:width] || 0)
168
- max_width = (options[:max_width] || options[:width] || Float::INFINITY)
169
- @width_range = min_width..max_width
170
-
171
- @align_v = options[:align_v] || Array(options[:align]).first || default(:align_v)
172
- raise ArgumentError, "Invalid align_v: #{@align_v}" unless VALID_ALIGN_V.include? @align_v
173
-
174
- min_height = (options[:min_height] || options[:height] || 0)
175
- max_height = (options[:max_height] || options[:height] || Float::INFINITY)
176
- @height_range = min_height..max_height
177
-
178
- @background_color = options[:background_color].dup
179
- @border_color = options[:border_color].dup
180
- @border_thickness = options[:border_thickness]
181
-
182
- @padding_top = options[:padding_top] || options[:padding_v] || options[:padding] || default(:padding_top)
183
- @padding_right = options[:padding_right] || options[:padding_h] || options[:padding] || default(:padding_right)
184
- @padding_bottom = options[:padding_bottom] || options[:padding_v] || options[:padding] || default(:padding_bottom)
185
- @padding_left = options[:padding_left] || options[:padding_h] || options[:padding] || default(:padding_left)
186
- self.parent = options[:parent]
187
-
188
- @z = options[:z]
189
- @tip = options[:tip].dup
190
- font_name = if options[:font_name].nil? or options[:font_name] == :default
191
- Gosu::default_font_name
192
- else
193
- options[:font_name].dup
194
- end
195
-
196
- @font = options[:font] || Gosu::Font[font_name, options[:font_height]]
197
-
198
- @rect = Chingu::Rect.new(options[:x], options[:y], options[:width] || 0, options[:height] || 0)
199
- end
200
-
201
- def font=(font)
202
- raise TypeError unless font.is_a? Gosu::Font
203
- @font = font
204
- recalc
205
- font
206
- end
207
-
208
- def recalc
209
- old_width, old_height = width, height
210
- layout
211
- parent.recalc if parent and (width != old_width or height != old_height)
212
-
213
- nil
214
- end
215
-
216
- # Check if a point (screen coordinates) is over the element.
217
- def hit?(x, y)
218
- @rect.collide_point?(x, y)
219
- end
220
-
221
- # Redraw the element.
222
- def draw
223
- draw_background
224
- draw_border
225
- draw_foreground
226
- nil
227
- end
228
-
229
- # Update the element.
230
- def update
231
- nil
232
- end
233
-
234
- def draw_rect(*args)
235
- $window.current_game_state.draw_rect(*args)
236
- end
237
-
238
- def draw_frame(*args)
239
- $window.current_game_state.draw_frame(*args)
240
- end
241
-
242
- protected
243
- def parent=(parent); @parent = parent; end
244
-
245
- protected
246
- def draw_background
247
- draw_rect(x, y, width, height, z, @background_color) unless @background_color.transparent?
248
- end
249
-
250
- protected
251
- def draw_border
252
- draw_frame(x, y, width, height, @border_thickness, z, @border_color) if @border_thickness > 0 and not @border_color.transparent?
253
- end
254
-
255
- protected
256
- def draw_foreground
257
- nil
258
- end
259
-
260
- protected
261
- # Should be overridden in children to recalculate the width and height of the element and, if a container
262
- # manage the positions of its children.
263
- def layout
264
- nil
265
- end
266
-
267
- protected
268
- def post_init
269
- recalc
270
- @parent.send :add, self if @parent
271
- end
272
-
273
- public
274
- # Evaluate a block, just like it was a constructor block.
275
- def with(&block)
276
- raise ArgumentError.new("Must pass a block") unless block_given?
277
- case block.arity
278
- when 1
279
- yield self
280
- when 0
281
- instance_methods_eval(&block)
282
- else
283
- raise "block arity must be 0 or 1"
284
- end
285
- end
286
-
287
- protected
288
- # By default, elements do not accept block arguments.
289
- def post_init_block(&block)
290
- raise ArgumentError, "does not accept a block"
291
- end
292
-
293
- public
294
- def to_s
295
- "#{self.class} (#{x}, #{y}) #{width}x#{height}"
296
- end
297
- end
1
+ # encoding: utf-8
2
+
3
+ # The Fidgit GUI framework for Gosu.
4
+ module Fidgit
5
+ class << self
6
+ attr_accessor :debug_mode
7
+ end
8
+
9
+ self.debug_mode = false
10
+
11
+ def self.debug_mode?; debug_mode; end
12
+
13
+ # An element within the GUI environment.
14
+ # @abstract
15
+ class Element
16
+ include Event
17
+
18
+ event :left_mouse_button
19
+ event :holding_left_mouse_button
20
+ event :released_left_mouse_button
21
+ event :clicked_left_mouse_button
22
+
23
+ event :right_mouse_button
24
+ event :holding_right_mouse_button
25
+ event :released_right_mouse_button
26
+ event :clicked_right_mouse_button
27
+
28
+ event :middle_mouse_button
29
+ event :holding_middle_mouse_button
30
+ event :released_middle_mouse_button
31
+ event :clicked_middle_mouse_button
32
+
33
+ event :mouse_wheel_up
34
+ event :mouse_wheel_down
35
+
36
+ event :enter
37
+ event :hover
38
+ event :leave
39
+
40
+ DEFAULT_SCHEMA_FILE = File.expand_path(File.join(__FILE__, '..', '..', '..', '..', 'config', 'default_schema.yml'))
41
+
42
+ VALID_ALIGN_H = [:left, :center, :right, :fill]
43
+ VALID_ALIGN_V = [:top, :center, :bottom, :fill]
44
+
45
+ attr_reader :z, :tip, :padding_top, :padding_right, :padding_bottom, :padding_left,
46
+ :align_h, :align_v, :parent, :border_thickness, :font
47
+
48
+ attr_accessor :background_color
49
+ attr_writer :tip
50
+
51
+ def x; rect.x; end
52
+ def x=(value); rect.x = value; end
53
+
54
+ def y; rect.y; end
55
+ def y=(value); rect.y = value; end
56
+
57
+ # Width not including border.
58
+ def width; rect.width; end
59
+ def width=(value); rect.width = [[value, @width_range.max].min, @width_range.min].max; end
60
+ def min_width; @width_range.min; end
61
+ def max_width; @width_range.max; end
62
+ # Width including border thickness.
63
+ def outer_width; rect.width + @border_thickness * 2; end
64
+
65
+ # Height not including border.
66
+ def height; rect.height; end
67
+ def height=(value); rect.height = [[value, @height_range.max].min, @height_range.min].max; end
68
+ def min_height; @height_range.min; end
69
+ def max_height; @height_range.max; end
70
+ # Height including border thickness.
71
+ def outer_height; rect.height + @border_thickness * 2; end
72
+
73
+ # Can the object be dragged?
74
+ def drag?(button); false; end
75
+
76
+ def enabled?; @enabled; end
77
+
78
+ def enabled=(value)
79
+ if @mouse_over and enabled? and not value
80
+ $window.current_game_state.unset_mouse_over
81
+ end
82
+
83
+ @enabled = value
84
+ end
85
+
86
+ def rect; @rect; end; protected :rect
87
+
88
+ def self.schema; @@schema ||= Schema.new(YAML.load(File.read(DEFAULT_SCHEMA_FILE)));; end
89
+
90
+ class << self
91
+ alias_method :original_new, :new
92
+
93
+ def new(*args, &block)
94
+ obj = original_new(*args) # Block should be ignored.
95
+ obj.send :post_init
96
+ obj.send :post_init_block, &block if block_given?
97
+ obj
98
+ end
99
+ end
100
+
101
+ # Get the default value from the schema.
102
+ #
103
+ # @param [Symbol, Array<Symbol>] names
104
+ def default(*names)
105
+ self.class.schema.default(self.class, names)
106
+ end
107
+
108
+ # @param [Element, nil] parent
109
+ #
110
+ # @option options [Number] :x (0)
111
+ # @option options [Number] :y (0)
112
+ # @option options [Number] :z (0)
113
+ #
114
+ # @option options [Number] :width (auto)
115
+ # @option options [Number] :min_width (value of :width option)
116
+ # @option options [Number] :max_width (value of :width option)
117
+ #
118
+ # @option options [Number] :height (auto)
119
+ # @option options [Number] :min_height (value of :height option)
120
+ # @option options [Number] :max_height (value of :height option)
121
+ #
122
+ # @option options [String] :tip ('') Tool-tip text
123
+ # @option options [String, :default] :font_name (:default, which resolves as the default Gosu font)
124
+ # @option options [String] :font_height (30)
125
+ # @option options [Gosu::Font] :font Use this instead of :font_name and :font_height
126
+ #
127
+ # @option options [Gosu::Color] :background_color (transparent)
128
+ # @option options [Gosu::Color] :border_color (transparent)
129
+ #
130
+ # @option options [Boolean] :enabled (true)
131
+ #
132
+ # @option options [Number] :padding (4)
133
+ # @option options [Number] :padding_h (:padding option)
134
+ # @option options [Number] :padding_v (:padding option)
135
+ # @option options [Number] :padding_top (:padding_v option)
136
+ # @option options [Number] :padding_right (:padding_h option)
137
+ # @option options [Number] :padding_bottom (:padding_v option)
138
+ # @option options [Number] :padding_left (:padding_h option)
139
+ #
140
+ # @option options [Symbol] :align Align both horizontally and vertically. One of :center, :fill or [<align_v>, <align_h>] such as [:top, :right].
141
+ # @option options [Symbol] :align_h (value or :align else :left) One of :left, :center, :right :fill
142
+ # @option options [Symbol] :align_v (value of :align else :top) One of :top, :center, :bottom, :fill
143
+
144
+ # @yield instance_methods_eval with respect to self.
145
+ def initialize(options = {}, &block)
146
+ options = {
147
+ x: 0,
148
+ y: 0,
149
+ z: 0,
150
+ tip: '',
151
+ font_name: default(:font_name),
152
+ font_height: default(:font_height),
153
+ background_color: default(:background_color),
154
+ border_color: default(:border_color),
155
+ border_thickness: default(:border_thickness),
156
+ enabled: true,
157
+ }.merge! options
158
+
159
+ @enabled = options[:enabled]
160
+
161
+ @mouse_over = false
162
+
163
+ # Alignment and min/max dimensions.
164
+ @align_h = options[:align_h] || Array(options[:align]).last || default(:align_h)
165
+ raise ArgumentError, "Invalid align_h: #{@align_h}" unless VALID_ALIGN_H.include? @align_h
166
+
167
+ min_width = (options[:min_width] || options[:width] || 0)
168
+ max_width = (options[:max_width] || options[:width] || Float::INFINITY)
169
+ @width_range = min_width..max_width
170
+
171
+ @align_v = options[:align_v] || Array(options[:align]).first || default(:align_v)
172
+ raise ArgumentError, "Invalid align_v: #{@align_v}" unless VALID_ALIGN_V.include? @align_v
173
+
174
+ min_height = (options[:min_height] || options[:height] || 0)
175
+ max_height = (options[:max_height] || options[:height] || Float::INFINITY)
176
+ @height_range = min_height..max_height
177
+
178
+ @background_color = options[:background_color].dup
179
+ @border_color = options[:border_color].dup
180
+ @border_thickness = options[:border_thickness]
181
+
182
+ @padding_top = options[:padding_top] || options[:padding_v] || options[:padding] || default(:padding_top)
183
+ @padding_right = options[:padding_right] || options[:padding_h] || options[:padding] || default(:padding_right)
184
+ @padding_bottom = options[:padding_bottom] || options[:padding_v] || options[:padding] || default(:padding_bottom)
185
+ @padding_left = options[:padding_left] || options[:padding_h] || options[:padding] || default(:padding_left)
186
+ self.parent = options[:parent]
187
+
188
+ @z = options[:z]
189
+ @tip = options[:tip].dup
190
+ font_name = if options[:font_name].nil? or options[:font_name] == :default
191
+ Gosu::default_font_name
192
+ else
193
+ options[:font_name].dup
194
+ end
195
+
196
+ @font = options[:font] || Gosu::Font[font_name, options[:font_height]]
197
+
198
+ @rect = Chingu::Rect.new(options[:x], options[:y], options[:width] || 0, options[:height] || 0)
199
+ end
200
+
201
+ def font=(font)
202
+ raise TypeError unless font.is_a? Gosu::Font
203
+ @font = font
204
+ recalc
205
+ font
206
+ end
207
+
208
+ def recalc
209
+ old_width, old_height = width, height
210
+ layout
211
+ parent.recalc if parent and (width != old_width or height != old_height)
212
+
213
+ nil
214
+ end
215
+
216
+ # Check if a point (screen coordinates) is over the element.
217
+ def hit?(x, y)
218
+ @rect.collide_point?(x, y)
219
+ end
220
+
221
+ # Redraw the element.
222
+ def draw
223
+ draw_background
224
+ draw_border
225
+ draw_foreground
226
+ nil
227
+ end
228
+
229
+ # Update the element.
230
+ def update
231
+ nil
232
+ end
233
+
234
+ def draw_rect(*args)
235
+ $window.current_game_state.draw_rect(*args)
236
+ end
237
+
238
+ def draw_frame(*args)
239
+ $window.current_game_state.draw_frame(*args)
240
+ end
241
+
242
+ protected
243
+ def parent=(parent); @parent = parent; end
244
+
245
+ protected
246
+ def draw_background
247
+ draw_rect(x, y, width, height, z, @background_color) unless @background_color.transparent?
248
+ end
249
+
250
+ protected
251
+ def draw_border
252
+ draw_frame(x, y, width, height, @border_thickness, z, @border_color) if @border_thickness > 0 and not @border_color.transparent?
253
+ end
254
+
255
+ protected
256
+ def draw_foreground
257
+ nil
258
+ end
259
+
260
+ protected
261
+ # Should be overridden in children to recalculate the width and height of the element and, if a container
262
+ # manage the positions of its children.
263
+ def layout
264
+ nil
265
+ end
266
+
267
+ protected
268
+ def post_init
269
+ recalc
270
+ @parent.send :add, self if @parent
271
+ end
272
+
273
+ public
274
+ # Evaluate a block, just like it was a constructor block.
275
+ def with(&block)
276
+ raise ArgumentError.new("Must pass a block") unless block_given?
277
+ case block.arity
278
+ when 1
279
+ yield self
280
+ when 0
281
+ instance_methods_eval(&block)
282
+ else
283
+ raise "block arity must be 0 or 1"
284
+ end
285
+ end
286
+
287
+ protected
288
+ # By default, elements do not accept block arguments.
289
+ def post_init_block(&block)
290
+ raise ArgumentError, "does not accept a block"
291
+ end
292
+
293
+ public
294
+ def to_s
295
+ "#{self.class} (#{x}, #{y}) #{width}x#{height}"
296
+ end
297
+ end
298
298
  end