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,39 @@
1
+ # encoding: utf-8
2
+
3
+ module Fidgit
4
+ class ColorWell < RadioButton
5
+ alias_method :color, :value
6
+
7
+ # @param (see RadioButton#initialize)
8
+ # @option (see RadioButton#initialize)
9
+ def initialize(options = {}, &block)
10
+ options = {
11
+ width: default(:width),
12
+ height: default(:height),
13
+ color: default(:color),
14
+ outline_color: default(:outline_color),
15
+ checked_border_color: default(:checked, :border_color),
16
+ }.merge! options
17
+
18
+ @outline_color = options[:outline_color].dup
19
+
20
+ super('', (options[:color] || options[:value]).dup, options)
21
+ end
22
+
23
+ protected
24
+ def draw_background
25
+ super
26
+
27
+ draw_frame x + 2, y + 2, width - 4, height - 4, 1, z, @outline_color
28
+
29
+ nil
30
+ end
31
+
32
+ protected
33
+ def draw_foreground
34
+ draw_rect x + 3, y + 3, width - 6, height - 6, z, value
35
+
36
+ nil
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,115 @@
1
+ # encoding: utf-8
2
+ require 'forwardable'
3
+
4
+ module Fidgit
5
+ class ComboBox < Button
6
+ extend Forwardable
7
+
8
+ ARROW_IMAGE = "combo_arrow.png"
9
+
10
+ def_delegators :@menu, :each
11
+
12
+ event :changed
13
+
14
+ def index; @menu.index(@value) end
15
+ def value; @value; end
16
+
17
+ def value=(value)
18
+ if @value != value
19
+ @value = value
20
+ item = @menu.find(@value)
21
+ self.text = item.text
22
+ self.icon = item.icon
23
+ publish :changed, @value
24
+ end
25
+
26
+ value
27
+ end
28
+
29
+ def index=(index)
30
+ if index.between?(0, @menu.size - 1)
31
+ self.value = @menu[index].value
32
+ end
33
+
34
+ index
35
+ end
36
+
37
+ # @param (see Button#initialize)
38
+ # @option (see Button#initialize)
39
+ # @option options [] :value
40
+ def initialize(options = {}, &block)
41
+ options = {
42
+ background_color: default(:background_color),
43
+ border_color: default(:border_color),
44
+ }.merge! options
45
+
46
+ @value = options[:value]
47
+
48
+ @hover_index = 0
49
+
50
+ @menu = MenuPane.new(show: false) do
51
+ subscribe :selected do |widget, value|
52
+ self.value = value
53
+ end
54
+ end
55
+
56
+ @@arrow ||= Gosu::Image[ARROW_IMAGE]
57
+
58
+ super('', options)
59
+
60
+ rect.height = [height, font.height + padding_top + padding_bottom].max
61
+ rect.width = [width, font.height * 4 + padding_left + padding_right].max
62
+ end
63
+
64
+ def item(text, value, options = {}, &block)
65
+ item = @menu.item(text, value, options, &block)
66
+
67
+ # Force text to be updated if the item added has the same value.
68
+ if item.value == @value
69
+ self.text = item.text
70
+ self.icon = item.icon
71
+ end
72
+
73
+ recalc
74
+
75
+ item
76
+ end
77
+
78
+ def draw
79
+ super
80
+ size = height / @@arrow.width.to_f
81
+ @@arrow.draw x + width - height, y, z, size, size
82
+ end
83
+
84
+ def clicked_left_mouse_button(sender, x, y)
85
+ @menu.x = self.x
86
+ @menu.y = self.y + height + border_thickness
87
+ $window.game_state_manager.current_game_state.show_menu @menu
88
+
89
+ nil
90
+ end
91
+
92
+ def clear
93
+ self.text = ""
94
+ self.icon = nil
95
+ @menu.clear
96
+ end
97
+
98
+ protected
99
+ def layout
100
+ super
101
+
102
+ # Max width of all items + allow size for the arrow.
103
+ rect.width = [@menu.width + height, min_width].max
104
+
105
+ nil
106
+ end
107
+
108
+
109
+ protected
110
+ # Any combo-box passed a block will allow you access to its methods.
111
+ def post_init_block(&block)
112
+ with(&block)
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,17 @@
1
+ # encoding: utf-8
2
+
3
+ module Fidgit
4
+ # A composite element, made up of other elements (but manages them internally).
5
+ class Composite < Packer
6
+ DEBUG_BORDER_COLOR = Gosu::Color.rgba(0, 255, 0, 100) # Color to draw an outline in when debugging layout.
7
+
8
+ # @param (see Element#initialize)
9
+ #
10
+ # @option (see Element#initialize)
11
+ def initialize(options = {})
12
+ options[:border_color] = DEBUG_BORDER_COLOR if Fidgit.debug_mode?
13
+
14
+ super(options)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,210 @@
1
+ # encoding: utf-8
2
+ require 'forwardable'
3
+
4
+ module Fidgit
5
+ # A container that contains Elements.
6
+ # @abstract
7
+ class Container < Element
8
+ extend Forwardable
9
+
10
+ def_delegators :@children, :size, :each, :find, :index, :[], :empty?, :map, :select, :inject
11
+
12
+ def x=(value)
13
+ @children.each {|c| c.x += value - x }
14
+ super(value)
15
+ end
16
+
17
+ def y=(value)
18
+ @children.each {|c| c.y += value - y }
19
+ super(value)
20
+ end
21
+
22
+ # @param (see Element#initialize)
23
+ #
24
+ # @option (see Element#initialize)
25
+ def initialize(options = {})
26
+ options[:border_color] = default(:debug, :border_color) if Fidgit.debug_mode?
27
+
28
+ @children = []
29
+
30
+ super(options)
31
+ end
32
+
33
+ def add(element)
34
+ element.send :parent=, self
35
+ @children.push element
36
+
37
+ recalc
38
+ nil
39
+ end
40
+
41
+ def remove(element)
42
+ @children.delete element
43
+ element.send :parent=, nil
44
+
45
+ recalc
46
+ nil
47
+ end
48
+
49
+ def insert(position, element)
50
+ @children.insert position, element
51
+ element.send :parent=, self
52
+
53
+ recalc
54
+ nil
55
+ end
56
+
57
+ # Create a button within the container.
58
+ def button(text, options = {}, &block)
59
+ Button.new(text, {parent: self}.merge!(options), &block)
60
+ end
61
+
62
+ # Create a color picker within the container.
63
+ def color_picker(options = {}, &block)
64
+ ColorPicker.new({parent: self}.merge!(options), &block)
65
+ end
66
+
67
+ # Create a color well within the container.
68
+ def color_well(options = {}, &block)
69
+ ColorWell.new({parent: self}.merge!(options), &block)
70
+ end
71
+
72
+ def combo_box(options = {}, &block)
73
+ ComboBox.new({parent: self}.merge!(options), &block)
74
+ end
75
+
76
+ def file_browser(type, options = {}, &block)
77
+ FileBrowser.new(type, {parent: self}.merge!(options), &block)
78
+ end
79
+
80
+ def group(options = {}, &block)
81
+ Group.new({parent: self}.merge!(options), &block)
82
+ end
83
+
84
+ # Create an icon.
85
+ def image_frame(image, options = {}, &block)
86
+ ImageFrame.new(image, {parent: self}.merge!(options), &block)
87
+ end
88
+
89
+ # Create a label within the container.
90
+ def label(text, options = {})
91
+ Label.new(text, {parent: self}.merge!(options))
92
+ end
93
+
94
+ def list(options = {}, &block)
95
+ List.new({parent: self}.merge!(options), &block)
96
+ end
97
+
98
+ public
99
+ # Pack elements within the block horizontally.
100
+ def horizontal(options = {}, &block)
101
+ Horizontal.new({ parent: self }.merge!(options), &block)
102
+ end
103
+
104
+ public
105
+ # Pack elements within the blockvertically.
106
+ def vertical(options = {}, &block)
107
+ Vertical.new({ parent: self }.merge!(options), &block)
108
+ end
109
+
110
+ public
111
+ # Pack elements within the block in a grid (matrix) formation.
112
+ def grid(options = {}, &block)
113
+ Grid.new({ parent: self }.merge!(options), &block)
114
+ end
115
+
116
+ def radio_button(text, value, options = {}, &block)
117
+ RadioButton.new(text, value, {parent: self}.merge!(options), &block)
118
+ end
119
+
120
+ def scroll_area(options = {}, &block)
121
+ ScrollArea.new({parent: self}.merge!(options), &block)
122
+ end
123
+
124
+ def scroll_window(options = {}, &block)
125
+ ScrollWindow.new({parent: self}.merge!(options), &block)
126
+ end
127
+
128
+ def slider(options = {}, &block)
129
+ Slider.new({parent: self}.merge!(options), &block)
130
+ end
131
+
132
+ def text_area(options = {}, &block)
133
+ TextArea.new({parent: self}.merge!(options), &block)
134
+ end
135
+
136
+ def toggle_button(text, options = {}, &block)
137
+ ToggleButton.new(text, {parent: self}.merge!(options), &block)
138
+ end
139
+
140
+ def clear
141
+ @children.each {|child| child.send :parent=, nil }
142
+ @children.clear
143
+
144
+ recalc
145
+
146
+ nil
147
+ end
148
+
149
+ def update
150
+ @children.each { |c| c.update }
151
+
152
+ nil
153
+ end
154
+
155
+ # Returns the element within this container that was hit,
156
+ # @return [Element, nil] The element hit, otherwise nil.
157
+ def hit_element(x, y)
158
+ @children.reverse_each do |child|
159
+ case child
160
+ when Container, Composite
161
+ if element = child.hit_element(x, y)
162
+ return element
163
+ end
164
+ else
165
+ return child if child.hit?(x, y)
166
+ end
167
+ end
168
+
169
+ self if hit?(x, y)
170
+ end
171
+
172
+ protected
173
+ def draw_foreground
174
+ @children.each {|c| c.draw }
175
+
176
+ font.draw self.class.name, x, y, z if Fidgit.debug_mode?
177
+
178
+ nil
179
+ end
180
+
181
+ protected
182
+ # Any container passed a block will allow you access to its methods.
183
+ def post_init_block(&block)
184
+ with(&block)
185
+ end
186
+
187
+ public
188
+ def to_s
189
+ "#{super} [#{@children.size} #{@children.size == 1 ? 'child' : 'children'}]"
190
+ end
191
+
192
+ public
193
+ def write_tree(indent = "", index = 0)
194
+ puts self
195
+
196
+ indent = indent + " "
197
+
198
+ @children.each.with_index do |element, i|
199
+ print "#{indent}#{i}: "
200
+
201
+ case element
202
+ when Container
203
+ element.write_tree(indent)
204
+ else
205
+ puts element
206
+ end
207
+ end
208
+ end
209
+ end
210
+ end
@@ -0,0 +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
298
+ end