metro-ld25 0.3.3
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.
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/.rvmrc +1 -0
- data/.travis.yml +6 -0
- data/Gemfile +12 -0
- data/Guardfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +189 -0
- data/Rakefile +18 -0
- data/bin/metro +16 -0
- data/changelog.md +157 -0
- data/lib/assets/menu-movement.wav +0 -0
- data/lib/assets/menu-selection.wav +0 -0
- data/lib/assets/missing.ogg +0 -0
- data/lib/assets/missing.png +0 -0
- data/lib/assets/missing.wav +0 -0
- data/lib/assets/missing_animation.png +0 -0
- data/lib/commands/generate_game.rb +13 -0
- data/lib/commands/generate_model.rb +25 -0
- data/lib/commands/generate_scene.rb +36 -0
- data/lib/commands/generate_view.rb +21 -0
- data/lib/commands/thor.rb +83 -0
- data/lib/core_ext/class.rb +14 -0
- data/lib/core_ext/numeric.rb +59 -0
- data/lib/gosu_ext/color.rb +62 -0
- data/lib/gosu_ext/gosu_constants.rb +53 -0
- data/lib/locale/en.yml +35 -0
- data/lib/locale/locale.rb +1 -0
- data/lib/metro.rb +140 -0
- data/lib/metro/animation.rb +135 -0
- data/lib/metro/animation/after_interval_factory.rb +12 -0
- data/lib/metro/animation/animation_factory.rb +15 -0
- data/lib/metro/animation/easing/ease_in.rb +15 -0
- data/lib/metro/animation/easing/easing.rb +51 -0
- data/lib/metro/animation/easing/linear.rb +15 -0
- data/lib/metro/animation/has_animations.rb +70 -0
- data/lib/metro/animation/implicit_animation.rb +100 -0
- data/lib/metro/animation/on_update_operation.rb +96 -0
- data/lib/metro/animation/scene_animation.rb +16 -0
- data/lib/metro/asset_path.rb +97 -0
- data/lib/metro/events/control_definition.rb +11 -0
- data/lib/metro/events/controls.rb +42 -0
- data/lib/metro/events/event_data.rb +60 -0
- data/lib/metro/events/event_dictionary.rb +52 -0
- data/lib/metro/events/event_factory.rb +17 -0
- data/lib/metro/events/event_relay.rb +300 -0
- data/lib/metro/events/event_state_manager.rb +63 -0
- data/lib/metro/events/events.rb +3 -0
- data/lib/metro/events/has_events.rb +108 -0
- data/lib/metro/events/hit_list.rb +75 -0
- data/lib/metro/events/unknown_sender.rb +5 -0
- data/lib/metro/font.rb +69 -0
- data/lib/metro/game.rb +102 -0
- data/lib/metro/game/dsl.rb +68 -0
- data/lib/metro/image.rb +68 -0
- data/lib/metro/logging.rb +33 -0
- data/lib/metro/missing_scene.rb +21 -0
- data/lib/metro/models/audio/song.rb +33 -0
- data/lib/metro/models/draws.rb +86 -0
- data/lib/metro/models/key_value_coding.rb +38 -0
- data/lib/metro/models/model.rb +236 -0
- data/lib/metro/models/model_factory.rb +32 -0
- data/lib/metro/models/models.rb +62 -0
- data/lib/metro/models/properties/animation_property.rb +115 -0
- data/lib/metro/models/properties/array_property.rb +24 -0
- data/lib/metro/models/properties/boolean_property.rb +27 -0
- data/lib/metro/models/properties/color_property.rb +116 -0
- data/lib/metro/models/properties/dimensions_property.rb +84 -0
- data/lib/metro/models/properties/font_property.rb +130 -0
- data/lib/metro/models/properties/image_property.rb +96 -0
- data/lib/metro/models/properties/model_property.rb +84 -0
- data/lib/metro/models/properties/numeric_property.rb +29 -0
- data/lib/metro/models/properties/options_property/no_option.rb +29 -0
- data/lib/metro/models/properties/options_property/options.rb +94 -0
- data/lib/metro/models/properties/options_property/options_property.rb +125 -0
- data/lib/metro/models/properties/position_property.rb +90 -0
- data/lib/metro/models/properties/property.rb +221 -0
- data/lib/metro/models/properties/property_owner.rb +137 -0
- data/lib/metro/models/properties/sample_property.rb +84 -0
- data/lib/metro/models/properties/scale_property.rb +80 -0
- data/lib/metro/models/properties/song_property.rb +89 -0
- data/lib/metro/models/properties/text_property.rb +75 -0
- data/lib/metro/models/ui/animated_sprite.rb +85 -0
- data/lib/metro/models/ui/border.rb +95 -0
- data/lib/metro/models/ui/fps.rb +54 -0
- data/lib/metro/models/ui/generic.rb +66 -0
- data/lib/metro/models/ui/grid_drawer.rb +74 -0
- data/lib/metro/models/ui/image.rb +87 -0
- data/lib/metro/models/ui/label.rb +175 -0
- data/lib/metro/models/ui/menu.rb +214 -0
- data/lib/metro/models/ui/model_label.rb +65 -0
- data/lib/metro/models/ui/model_labeler.rb +79 -0
- data/lib/metro/models/ui/rectangle.rb +59 -0
- data/lib/metro/models/ui/sprite.rb +79 -0
- data/lib/metro/models/ui/tile_map.rb +162 -0
- data/lib/metro/models/ui/ui.rb +13 -0
- data/lib/metro/parameters/command_line_args_parser.rb +68 -0
- data/lib/metro/parameters/options.rb +25 -0
- data/lib/metro/parameters/parameters.rb +2 -0
- data/lib/metro/sample.rb +40 -0
- data/lib/metro/scene.rb +477 -0
- data/lib/metro/scenes.rb +154 -0
- data/lib/metro/song.rb +56 -0
- data/lib/metro/template_message.rb +60 -0
- data/lib/metro/transitions/edit_transition_scene.rb +100 -0
- data/lib/metro/transitions/fade_transition_scene.rb +66 -0
- data/lib/metro/transitions/scene_transitions.rb +44 -0
- data/lib/metro/transitions/transition_scene.rb +19 -0
- data/lib/metro/units/bounds.rb +8 -0
- data/lib/metro/units/calculation_validations.rb +74 -0
- data/lib/metro/units/dimensions.rb +60 -0
- data/lib/metro/units/point.rb +51 -0
- data/lib/metro/units/rectangle_bounds.rb +85 -0
- data/lib/metro/units/scale.rb +46 -0
- data/lib/metro/units/units.rb +6 -0
- data/lib/metro/version.rb +32 -0
- data/lib/metro/views/json_view.rb +60 -0
- data/lib/metro/views/no_view.rb +34 -0
- data/lib/metro/views/parsers.rb +42 -0
- data/lib/metro/views/scene_view.rb +107 -0
- data/lib/metro/views/view.rb +133 -0
- data/lib/metro/views/writers.rb +43 -0
- data/lib/metro/views/yaml_view.rb +94 -0
- data/lib/metro/window.rb +94 -0
- data/lib/setup_handlers/exit_if_dry_run.rb +26 -0
- data/lib/setup_handlers/game_execution.rb +65 -0
- data/lib/setup_handlers/load_game_configuration.rb +65 -0
- data/lib/setup_handlers/load_game_files.rb +101 -0
- data/lib/setup_handlers/move_to_game_directory.rb +25 -0
- data/lib/setup_handlers/reload_game_on_game_file_changes.rb +79 -0
- data/lib/templates/game/README.md.tt +52 -0
- data/lib/templates/game/assets/brand.jpg +0 -0
- data/lib/templates/game/assets/hero.png +0 -0
- data/lib/templates/game/lib/custom_easing.rb +32 -0
- data/lib/templates/game/metro.tt +63 -0
- data/lib/templates/game/models/hero.rb +62 -0
- data/lib/templates/game/scenes/brand_scene.rb +19 -0
- data/lib/templates/game/scenes/brand_to_title_scene.rb +13 -0
- data/lib/templates/game/scenes/first_scene.rb +28 -0
- data/lib/templates/game/scenes/game_scene.rb +43 -0
- data/lib/templates/game/scenes/title_scene.rb +15 -0
- data/lib/templates/game/views/brand.yaml +4 -0
- data/lib/templates/game/views/brand_to_title.yaml +8 -0
- data/lib/templates/game/views/first.yaml +26 -0
- data/lib/templates/game/views/title.yaml +11 -0
- data/lib/templates/message.erb +23 -0
- data/lib/templates/model.rb.tt +111 -0
- data/lib/templates/scene.rb.tt +140 -0
- data/lib/templates/view.yaml.tt +11 -0
- data/lib/tmxed_ext/tile_set.rb +34 -0
- data/metro.gemspec +56 -0
- data/spec/core_ext/numeric_spec.rb +78 -0
- data/spec/core_ext/string_spec.rb +33 -0
- data/spec/gosu_ext/color_spec.rb +80 -0
- data/spec/metro/events/event_state_manager_spec.rb +5 -0
- data/spec/metro/models/key_value_coding_spec.rb +61 -0
- data/spec/metro/models/properties/array_property_spec.rb +60 -0
- data/spec/metro/models/properties/color_property_spec.rb +85 -0
- data/spec/metro/models/properties/dimensions_spec.rb +29 -0
- data/spec/metro/models/properties/font_property_spec.rb +127 -0
- data/spec/metro/models/properties/numeric_property_spec.rb +46 -0
- data/spec/metro/models/properties/options_property/no_option_spec.rb +25 -0
- data/spec/metro/models/properties/options_property/options_property_spec.rb +133 -0
- data/spec/metro/models/properties/options_property/options_spec.rb +125 -0
- data/spec/metro/models/properties/position_property_spec.rb +90 -0
- data/spec/metro/models/ui/label_spec.rb +259 -0
- data/spec/metro/parameters/command_line_args_parser_spec.rb +42 -0
- data/spec/metro/scene_spec.rb +15 -0
- data/spec/metro/scene_views/json_view_spec.rb +27 -0
- data/spec/metro/scene_views/yaml_view_spec.rb +38 -0
- data/spec/metro/scenes_spec.rb +77 -0
- data/spec/metro/units/point_spec.rb +132 -0
- data/spec/metro/views/view_spec.rb +53 -0
- data/spec/setup_handlers/exit_if_dry_run_spec.rb +27 -0
- data/spec/setup_handlers/reload_game_on_game_file_changes_spec.rb +68 -0
- data/spec/spec_helper.rb +20 -0
- metadata +374 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
module Metro
|
|
2
|
+
module UI
|
|
3
|
+
|
|
4
|
+
class FPS < Model
|
|
5
|
+
|
|
6
|
+
property :placement, type: :text, default: 'top'
|
|
7
|
+
property :color, default: "rgba(255,255,255,1.0)"
|
|
8
|
+
|
|
9
|
+
property :label, type: :model do
|
|
10
|
+
create "metro::ui::label", text: "FPS: 0", color: color
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def valid_placements
|
|
14
|
+
@valid_placements ||= begin
|
|
15
|
+
{
|
|
16
|
+
top_left: { position: Game.bounds.top_left, align: 'left', vertical_align: 'top' },
|
|
17
|
+
top: { position: Point.at(Game.center.x, Game.bounds.top), align: 'center', vertical_align: 'top' },
|
|
18
|
+
top_right: { position: Game.bounds.top_right, align: 'right', vertical_align: 'top' },
|
|
19
|
+
right: { position: Point.at(Game.bounds.right, Game.center.y), align: 'right', vertical_align: 'center' },
|
|
20
|
+
bottom_right: { position: Game.bounds.bottom_right, align: 'right', vertical_align: 'bottom' },
|
|
21
|
+
bottom: { position: Point.at(Game.center.x, Game.bounds.bottom), align: 'right', vertical_align: 'bottom' },
|
|
22
|
+
bottom_left: { position: Game.bounds.bottom_right, align: 'left', vertical_align: 'bottom' },
|
|
23
|
+
left: { position: Point.at(Game.bounds.left, Game.center.y), align: 'left', vertical_align: 'center' }
|
|
24
|
+
}
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
@valid_placements.default = :top
|
|
28
|
+
@valid_placements
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def show
|
|
32
|
+
place_label
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def place_label
|
|
36
|
+
placement_hash = valid_placements[placement.to_sym]
|
|
37
|
+
|
|
38
|
+
label.align = placement_hash[:align]
|
|
39
|
+
label.vertical_align = placement_hash[:vertical_align]
|
|
40
|
+
label.position = placement_hash[:position]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def update
|
|
44
|
+
label.text = "FPS: #{Gosu.fps}"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def draw
|
|
48
|
+
label.draw
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
module Metro
|
|
2
|
+
module UI
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
# Generic model is used when no model can be found.
|
|
6
|
+
#
|
|
7
|
+
# @example Defining an actor in a scene without the model
|
|
8
|
+
#
|
|
9
|
+
# class IntroScene < GameScene
|
|
10
|
+
#
|
|
11
|
+
# draw :game_title, text: "Super Game Title", position: Game.center
|
|
12
|
+
# color: "rgba(255,255,255,1.0)"
|
|
13
|
+
#
|
|
14
|
+
# end
|
|
15
|
+
#
|
|
16
|
+
# The above `game_title` actor was likely suppose to be a `metro::ui::label`, but
|
|
17
|
+
# the model was not specified. So this warning would be generated.
|
|
18
|
+
#
|
|
19
|
+
class Generic < Model
|
|
20
|
+
|
|
21
|
+
# @attribute
|
|
22
|
+
# Sets whether the generic model has warned the user in the logs about it
|
|
23
|
+
# being a generic model.
|
|
24
|
+
property :warned, type: :boolean, default: false
|
|
25
|
+
|
|
26
|
+
def show
|
|
27
|
+
self.saveable_to_view = false
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def draw
|
|
31
|
+
log.warn cannot_draw_message unless warned
|
|
32
|
+
self.warned = true
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def cannot_draw_message
|
|
38
|
+
%{Unable to draw #{name} in #{scene}
|
|
39
|
+
|
|
40
|
+
The actor named '#{name}' does not specify a suitable model so it could not be drawn in the scene.
|
|
41
|
+
|
|
42
|
+
#{properties}
|
|
43
|
+
|
|
44
|
+
Did you mean to use one of the following models:
|
|
45
|
+
|
|
46
|
+
Models defined in #{Game.name}:
|
|
47
|
+
|
|
48
|
+
#{user_defined_models.join(', ')}
|
|
49
|
+
|
|
50
|
+
Models defined in Metro:
|
|
51
|
+
|
|
52
|
+
#{metro_models.join(', ')}
|
|
53
|
+
}
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def metro_models
|
|
57
|
+
Models.list.find_all {|m| m =~ /metro(::|\/).+(::|\/).+/i }
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def user_defined_models
|
|
61
|
+
Models.list - metro_models
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
module Metro
|
|
2
|
+
module UI
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
# The grid drawer will draw a grid from the specified position out to the specified
|
|
6
|
+
# dimensions at the spacing interval provided. This is currently used when the edit
|
|
7
|
+
# mode is enabled.
|
|
8
|
+
#
|
|
9
|
+
# @example Drawing a white, translucent, 100 by 100 grid starting at (20,20).
|
|
10
|
+
#
|
|
11
|
+
# class BuildScene < GameScene
|
|
12
|
+
# draw :grid, model: "metro::ui::grid_drawer", position: "20,20",
|
|
13
|
+
# color: "rgba(255,255,255,0.5)", spacing: 20, dimensions: "100,100"
|
|
14
|
+
# end
|
|
15
|
+
#
|
|
16
|
+
class GridDrawer < Model
|
|
17
|
+
|
|
18
|
+
# @attribute
|
|
19
|
+
# The position to start drawing the grid
|
|
20
|
+
property :position, default: Point.at(0,0,100)
|
|
21
|
+
|
|
22
|
+
# @attribute
|
|
23
|
+
# The color of the grid lines
|
|
24
|
+
property :color, default: "rgba(255,255,255,0.1)"
|
|
25
|
+
|
|
26
|
+
# @attribute
|
|
27
|
+
# The interval which to draw the lines
|
|
28
|
+
property :spacing, type: :numeric, default: 10
|
|
29
|
+
|
|
30
|
+
# @attribute
|
|
31
|
+
# The dimension of the grid
|
|
32
|
+
property :dimensions do
|
|
33
|
+
Dimensions.of Game.width, Game.height
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# @attribute
|
|
37
|
+
# This controls whether the grid should be drawn. By default
|
|
38
|
+
# the grid will be drawn.
|
|
39
|
+
property :enabled, type: :boolean, default: true
|
|
40
|
+
|
|
41
|
+
def show
|
|
42
|
+
self.saveable_to_view = false
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def draw
|
|
46
|
+
return unless enabled
|
|
47
|
+
draw_horizontal_lines
|
|
48
|
+
draw_vertical_lines
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
def draw_vertical_lines
|
|
54
|
+
xs = (width / spacing + 1).to_i.times.map {|segment| segment * spacing }
|
|
55
|
+
xs.each do |x|
|
|
56
|
+
draw_line(x,1,x,height)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def draw_horizontal_lines
|
|
61
|
+
ys = (height / spacing + 1).to_i.times.map {|segment| segment * spacing }
|
|
62
|
+
ys.each do |y|
|
|
63
|
+
draw_line(1,y,width,y)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def draw_line(start_x,start_y,finish_x,finish_y)
|
|
68
|
+
window.draw_line(position.x + start_x, position.y + start_y, color,
|
|
69
|
+
position.x + finish_x, position.y + finish_y, color, 0, :additive)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
module Metro
|
|
2
|
+
module UI
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
# The image will draw an image with the specifie path, color, rotation, and scale.
|
|
6
|
+
#
|
|
7
|
+
# @example Drawing the 'player.png' image at (320,240)
|
|
8
|
+
#
|
|
9
|
+
# class MainScene < GameScene
|
|
10
|
+
# draw :player, model: "metro::ui::image", position: "320,240",
|
|
11
|
+
# image: "player.png"
|
|
12
|
+
# end
|
|
13
|
+
#
|
|
14
|
+
class Image < Model
|
|
15
|
+
|
|
16
|
+
# @attribute
|
|
17
|
+
# The position of the image
|
|
18
|
+
property :position
|
|
19
|
+
|
|
20
|
+
# @attribute
|
|
21
|
+
# The scale of the image
|
|
22
|
+
property :scale, default: Scale.one
|
|
23
|
+
|
|
24
|
+
# @attribute
|
|
25
|
+
# The color of the image, by default this is white to display the image
|
|
26
|
+
# as normal, but this can be used to augment the look of the image. Mostly
|
|
27
|
+
# color is use for the sub-property :alpha which allows an image to be
|
|
28
|
+
# faded-in and faded-out
|
|
29
|
+
property :color
|
|
30
|
+
|
|
31
|
+
# @attribute
|
|
32
|
+
# The angle at which to draw the image
|
|
33
|
+
property :angle, type: :numeric, default: 0
|
|
34
|
+
|
|
35
|
+
# @attribute
|
|
36
|
+
# The center x position of the image as expressed in a scale of from left
|
|
37
|
+
# to right (0.0 to 1.0).
|
|
38
|
+
property :center_x, type: :numeric, default: 0.5
|
|
39
|
+
|
|
40
|
+
# @attribute
|
|
41
|
+
# The center y position of the image as expressed in a scale of from top
|
|
42
|
+
# to bottom (0.0 to 1.0).
|
|
43
|
+
property :center_y, type: :numeric, default: 0.5
|
|
44
|
+
|
|
45
|
+
# @attribute
|
|
46
|
+
# The image asset to draw.
|
|
47
|
+
property :image
|
|
48
|
+
|
|
49
|
+
# @attribute
|
|
50
|
+
# The dimensions of the image.
|
|
51
|
+
property :dimensions do
|
|
52
|
+
image.dimensions
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def bounds
|
|
56
|
+
Bounds.new left: left_x, right: right_x, top: top_y, bottom: bottom_y
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def draw
|
|
60
|
+
image.draw_rot x, y, z_order,
|
|
61
|
+
angle.to_f,
|
|
62
|
+
center_x, center_y,
|
|
63
|
+
x_factor, y_factor,
|
|
64
|
+
color
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
private
|
|
68
|
+
|
|
69
|
+
def left_x
|
|
70
|
+
x - (width * center_x)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def right_x
|
|
74
|
+
left_x + width
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def top_y
|
|
78
|
+
y - (height * center_y)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def bottom_y
|
|
82
|
+
top_y + height
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
end
|
|
87
|
+
end
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
module Metro
|
|
2
|
+
module UI
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
# The label will draw the specified text with the font, position, color,
|
|
6
|
+
# and alignment provided.
|
|
7
|
+
#
|
|
8
|
+
# @example Drawing a label
|
|
9
|
+
#
|
|
10
|
+
# class TitleScene < GameScene
|
|
11
|
+
# draw :game_title, model: "metro::ui::label", position: "320,240",
|
|
12
|
+
# vertical_align: "center", align: "center", color: "rgba(255,255,255,1.0)",
|
|
13
|
+
# text: "Super Awesome Game\n2"
|
|
14
|
+
# end
|
|
15
|
+
#
|
|
16
|
+
class Label < Model
|
|
17
|
+
|
|
18
|
+
# @attribute
|
|
19
|
+
# The position of the label
|
|
20
|
+
property :position
|
|
21
|
+
|
|
22
|
+
# @attribute
|
|
23
|
+
# The scale of the text
|
|
24
|
+
property :scale, default: Scale.one
|
|
25
|
+
|
|
26
|
+
# @attribute
|
|
27
|
+
# The text color
|
|
28
|
+
property :color, default: "rgba(255,255,255,1.0)"
|
|
29
|
+
|
|
30
|
+
# @attribute
|
|
31
|
+
# The font to use for the label text
|
|
32
|
+
property :font, default: { size: 20 }
|
|
33
|
+
|
|
34
|
+
# @attribute
|
|
35
|
+
# The text to appear on the label
|
|
36
|
+
property :text
|
|
37
|
+
|
|
38
|
+
# @attribute
|
|
39
|
+
# The alignment for the label. This influences where the text draws in
|
|
40
|
+
# relation to the specified position. Your choices are 'left', 'center',
|
|
41
|
+
# and 'right'. The default is 'left'.
|
|
42
|
+
property :align, type: :text, default: "left"
|
|
43
|
+
|
|
44
|
+
# @attribute
|
|
45
|
+
# The vertical alignment for the label. This influences where the text
|
|
46
|
+
# draws in relation to the specified position. Your choices are 'top',
|
|
47
|
+
# 'center', and 'bottom'. This default is 'top'
|
|
48
|
+
property :vertical_align, type: :text, default: "top"
|
|
49
|
+
|
|
50
|
+
# @attribute
|
|
51
|
+
# When calculating the dimensions of the label, this is the minimum
|
|
52
|
+
# dimensions. This is necessary in cases when the text is blank. This
|
|
53
|
+
# allows for the label to have size when in the edit mode.
|
|
54
|
+
property :minimum_dimensions, type: :dimensions, default: "16,16"
|
|
55
|
+
|
|
56
|
+
# @attribute
|
|
57
|
+
# The dimensions of label. If the label text is blank, then the dimensions
|
|
58
|
+
# of the label will return a minimum dimension.
|
|
59
|
+
property :dimensions do
|
|
60
|
+
calculated = Dimensions.of (longest_line * x_factor), (line_height * line_count * y_factor)
|
|
61
|
+
[ calculated, minimum_dimensions ].max
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def bounds
|
|
65
|
+
Bounds.new left: left_x, right: right_x, top: top_y, bottom: bottom_y
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def draw
|
|
69
|
+
parsed_text.each_with_index do |line,index|
|
|
70
|
+
font.draw line, x_position(index), y_position(index), z_order, x_factor, y_factor, color
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
private
|
|
75
|
+
|
|
76
|
+
def left_x
|
|
77
|
+
line_count.times.map { |index| x_position(index) }.min
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def right_x
|
|
81
|
+
left_x + width
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def top_y
|
|
85
|
+
y_position(0)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def bottom_y
|
|
89
|
+
top_y + height
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def line_height
|
|
93
|
+
font.height
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def line_width(line)
|
|
97
|
+
font.text_width(line)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def half_line_height
|
|
101
|
+
line_height / 2
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def longest_line
|
|
105
|
+
parsed_text.map { |line| line_width(line) }.max || 0
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def line_count
|
|
109
|
+
parsed_text.count
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def parsed_text
|
|
113
|
+
text.split("\n")
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def x_left_alignment(index)
|
|
117
|
+
x
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def x_center_alignment(index)
|
|
121
|
+
x - line_width(parsed_text[index]) / 2
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def x_right_alignment(index)
|
|
125
|
+
x - line_width(parsed_text[index])
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def horizontal_alignments
|
|
129
|
+
{ left: :x_left_alignment,
|
|
130
|
+
center: :x_center_alignment,
|
|
131
|
+
right: :x_right_alignment }
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def x_position(index)
|
|
135
|
+
alignment = horizontal_alignments[align.to_sym]
|
|
136
|
+
send(alignment,index)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def y_top_alignment(index)
|
|
140
|
+
y + (index * line_height)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def y_bottom_alignment(index)
|
|
144
|
+
y - line_height * (line_count - index)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def y_center_alignment(index)
|
|
148
|
+
if line_count.even?
|
|
149
|
+
full_height = (line_count / 2 - index) * line_height
|
|
150
|
+
else
|
|
151
|
+
offset = (line_count / 2 - index)
|
|
152
|
+
if offset < 0
|
|
153
|
+
full_height = (offset + 1) * line_height - half_line_height
|
|
154
|
+
else
|
|
155
|
+
full_height = offset * line_height + half_line_height
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
y - full_height
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def vertical_alignments
|
|
163
|
+
{ top: :y_top_alignment,
|
|
164
|
+
center: :y_center_alignment,
|
|
165
|
+
bottom: :y_bottom_alignment }
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def y_position(index)
|
|
169
|
+
alignment = vertical_alignments[vertical_align.to_sym]
|
|
170
|
+
send(alignment,index)
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
end
|