shoes-dsl 4.0.0.pre2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG +84 -0
- data/Gemfile +24 -0
- data/Guardfile +11 -0
- data/LICENSE +31 -0
- data/README.md +201 -0
- data/ext/install/Rakefile +29 -0
- data/ext/install/shoes.bat +9 -0
- data/fonts/Coolvetica.ttf +0 -0
- data/fonts/Lacuna.ttf +0 -0
- data/lib/shoes/animation.rb +56 -0
- data/lib/shoes/app.rb +131 -0
- data/lib/shoes/arc.rb +25 -0
- data/lib/shoes/background.rb +24 -0
- data/lib/shoes/border.rb +24 -0
- data/lib/shoes/builtin_methods.rb +77 -0
- data/lib/shoes/button.rb +30 -0
- data/lib/shoes/check_button.rb +44 -0
- data/lib/shoes/color.rb +385 -0
- data/lib/shoes/common/background_element.rb +9 -0
- data/lib/shoes/common/changeable.rb +34 -0
- data/lib/shoes/common/clickable.rb +24 -0
- data/lib/shoes/common/inspect.rb +14 -0
- data/lib/shoes/common/positioning.rb +30 -0
- data/lib/shoes/common/registration.rb +33 -0
- data/lib/shoes/common/remove.rb +10 -0
- data/lib/shoes/common/state.rb +18 -0
- data/lib/shoes/common/style.rb +152 -0
- data/lib/shoes/common/style_normalizer.rb +16 -0
- data/lib/shoes/common/ui_element.rb +11 -0
- data/lib/shoes/common/visibility.rb +40 -0
- data/lib/shoes/configuration.rb +96 -0
- data/lib/shoes/dialog.rb +27 -0
- data/lib/shoes/dimension.rb +239 -0
- data/lib/shoes/dimensions.rb +209 -0
- data/lib/shoes/download.rb +121 -0
- data/lib/shoes/dsl.rb +591 -0
- data/lib/shoes/font.rb +49 -0
- data/lib/shoes/gradient.rb +31 -0
- data/lib/shoes/image.rb +29 -0
- data/lib/shoes/image_pattern.rb +12 -0
- data/lib/shoes/input_box.rb +60 -0
- data/lib/shoes/internal_app.rb +219 -0
- data/lib/shoes/key_event.rb +17 -0
- data/lib/shoes/line.rb +87 -0
- data/lib/shoes/link.rb +59 -0
- data/lib/shoes/link_hover.rb +5 -0
- data/lib/shoes/list_box.rb +50 -0
- data/lib/shoes/logger.rb +66 -0
- data/lib/shoes/logger/ruby.rb +18 -0
- data/lib/shoes/mock.rb +31 -0
- data/lib/shoes/mock/animation.rb +8 -0
- data/lib/shoes/mock/app.rb +47 -0
- data/lib/shoes/mock/arc.rb +9 -0
- data/lib/shoes/mock/background.rb +10 -0
- data/lib/shoes/mock/border.rb +7 -0
- data/lib/shoes/mock/button.rb +10 -0
- data/lib/shoes/mock/check.rb +25 -0
- data/lib/shoes/mock/clickable.rb +8 -0
- data/lib/shoes/mock/common_methods.rb +12 -0
- data/lib/shoes/mock/dialog.rb +13 -0
- data/lib/shoes/mock/download.rb +18 -0
- data/lib/shoes/mock/font.rb +17 -0
- data/lib/shoes/mock/image.rb +13 -0
- data/lib/shoes/mock/image_pattern.rb +9 -0
- data/lib/shoes/mock/input_box.rb +30 -0
- data/lib/shoes/mock/keypress.rb +10 -0
- data/lib/shoes/mock/keyrelease.rb +10 -0
- data/lib/shoes/mock/line.rb +14 -0
- data/lib/shoes/mock/link.rb +12 -0
- data/lib/shoes/mock/list_box.rb +19 -0
- data/lib/shoes/mock/oval.rb +12 -0
- data/lib/shoes/mock/progress.rb +10 -0
- data/lib/shoes/mock/radio.rb +27 -0
- data/lib/shoes/mock/rect.rb +14 -0
- data/lib/shoes/mock/shape.rb +20 -0
- data/lib/shoes/mock/slot.rb +16 -0
- data/lib/shoes/mock/sound.rb +8 -0
- data/lib/shoes/mock/star.rb +14 -0
- data/lib/shoes/mock/text_block.rb +36 -0
- data/lib/shoes/mock/timer.rb +8 -0
- data/lib/shoes/not_implemented_error.rb +4 -0
- data/lib/shoes/oval.rb +20 -0
- data/lib/shoes/point.rb +54 -0
- data/lib/shoes/progress.rb +25 -0
- data/lib/shoes/radio.rb +16 -0
- data/lib/shoes/rect.rb +21 -0
- data/lib/shoes/renamed_delegate.rb +15 -0
- data/lib/shoes/shape.rb +158 -0
- data/lib/shoes/slot.rb +271 -0
- data/lib/shoes/slot_contents.rb +50 -0
- data/lib/shoes/sound.rb +18 -0
- data/lib/shoes/span.rb +16 -0
- data/lib/shoes/star.rb +45 -0
- data/lib/shoes/text.rb +24 -0
- data/lib/shoes/text_block.rb +143 -0
- data/lib/shoes/text_block_dimensions.rb +52 -0
- data/lib/shoes/timer.rb +12 -0
- data/lib/shoes/url.rb +44 -0
- data/lib/shoes/version.rb +3 -0
- data/lib/shoes/widget.rb +69 -0
- data/manifests/common.rb +34 -0
- data/manifests/shoes-dsl.rb +34 -0
- data/shoes-dsl.gemspec +19 -0
- data/spec/code_coverage.rb +14 -0
- data/spec/shoes/animation_spec.rb +65 -0
- data/spec/shoes/app_spec.rb +484 -0
- data/spec/shoes/arc_spec.rb +51 -0
- data/spec/shoes/background_spec.rb +53 -0
- data/spec/shoes/border_spec.rb +47 -0
- data/spec/shoes/builtin_methods_spec.rb +110 -0
- data/spec/shoes/button_spec.rb +44 -0
- data/spec/shoes/check_spec.rb +35 -0
- data/spec/shoes/cli_spec.rb +15 -0
- data/spec/shoes/color_spec.rb +408 -0
- data/spec/shoes/common/inspect_spec.rb +26 -0
- data/spec/shoes/common/remove_spec.rb +38 -0
- data/spec/shoes/common/style_normalizer_spec.rb +28 -0
- data/spec/shoes/common/style_spec.rb +147 -0
- data/spec/shoes/configuration_spec.rb +36 -0
- data/spec/shoes/constants_spec.rb +38 -0
- data/spec/shoes/dialog_spec.rb +163 -0
- data/spec/shoes/dimension_spec.rb +407 -0
- data/spec/shoes/dimensions_spec.rb +837 -0
- data/spec/shoes/download_spec.rb +142 -0
- data/spec/shoes/flow_spec.rb +133 -0
- data/spec/shoes/font_spec.rb +37 -0
- data/spec/shoes/framework_learning_spec.rb +30 -0
- data/spec/shoes/gradient_spec.rb +32 -0
- data/spec/shoes/helpers/fake_element.rb +17 -0
- data/spec/shoes/helpers/inspect_helpers.rb +5 -0
- data/spec/shoes/helpers/sample17_helper.rb +66 -0
- data/spec/shoes/image_spec.rb +49 -0
- data/spec/shoes/images/shoe.jpg +0 -0
- data/spec/shoes/input_box_spec.rb +80 -0
- data/spec/shoes/integration_spec.rb +20 -0
- data/spec/shoes/internal_app_spec.rb +141 -0
- data/spec/shoes/keypress_spec.rb +11 -0
- data/spec/shoes/keyrelease_spec.rb +12 -0
- data/spec/shoes/line_spec.rb +49 -0
- data/spec/shoes/link_spec.rb +105 -0
- data/spec/shoes/list_box_spec.rb +74 -0
- data/spec/shoes/logger/ruby_spec.rb +8 -0
- data/spec/shoes/logger_spec.rb +45 -0
- data/spec/shoes/oval_spec.rb +24 -0
- data/spec/shoes/point_spec.rb +71 -0
- data/spec/shoes/progress_spec.rb +54 -0
- data/spec/shoes/radio_spec.rb +32 -0
- data/spec/shoes/rect_spec.rb +39 -0
- data/spec/shoes/renamed_delegate_spec.rb +70 -0
- data/spec/shoes/shape_spec.rb +95 -0
- data/spec/shoes/shared_examples/button.rb +6 -0
- data/spec/shoes/shared_examples/changeable.rb +26 -0
- data/spec/shoes/shared_examples/clickable.rb +5 -0
- data/spec/shoes/shared_examples/common_methods.rb +35 -0
- data/spec/shoes/shared_examples/dimensions.rb +32 -0
- data/spec/shoes/shared_examples/dsl.rb +44 -0
- data/spec/shoes/shared_examples/dsl/animate.rb +29 -0
- data/spec/shoes/shared_examples/dsl/arc.rb +45 -0
- data/spec/shoes/shared_examples/dsl/background.rb +26 -0
- data/spec/shoes/shared_examples/dsl/border.rb +10 -0
- data/spec/shoes/shared_examples/dsl/button.rb +5 -0
- data/spec/shoes/shared_examples/dsl/cap.rb +6 -0
- data/spec/shoes/shared_examples/dsl/check.rb +11 -0
- data/spec/shoes/shared_examples/dsl/edit_box.rb +8 -0
- data/spec/shoes/shared_examples/dsl/edit_line.rb +8 -0
- data/spec/shoes/shared_examples/dsl/editable_element.rb +29 -0
- data/spec/shoes/shared_examples/dsl/fill.rb +27 -0
- data/spec/shoes/shared_examples/dsl/flow.rb +15 -0
- data/spec/shoes/shared_examples/dsl/gradient.rb +62 -0
- data/spec/shoes/shared_examples/dsl/image.rb +21 -0
- data/spec/shoes/shared_examples/dsl/line.rb +9 -0
- data/spec/shoes/shared_examples/dsl/nofill.rb +6 -0
- data/spec/shoes/shared_examples/dsl/nostroke.rb +6 -0
- data/spec/shoes/shared_examples/dsl/oval.rb +88 -0
- data/spec/shoes/shared_examples/dsl/pattern.rb +34 -0
- data/spec/shoes/shared_examples/dsl/progress.rb +7 -0
- data/spec/shoes/shared_examples/dsl/rect.rb +92 -0
- data/spec/shoes/shared_examples/dsl/rgb.rb +26 -0
- data/spec/shoes/shared_examples/dsl/shape.rb +21 -0
- data/spec/shoes/shared_examples/dsl/star.rb +48 -0
- data/spec/shoes/shared_examples/dsl/stroke.rb +30 -0
- data/spec/shoes/shared_examples/dsl/strokewidth.rb +19 -0
- data/spec/shoes/shared_examples/dsl/style.rb +32 -0
- data/spec/shoes/shared_examples/dsl/text_elements.rb +81 -0
- data/spec/shoes/shared_examples/dsl/video.rb +5 -0
- data/spec/shoes/shared_examples/dsl_app_context.rb +8 -0
- data/spec/shoes/shared_examples/hover_leave.rb +11 -0
- data/spec/shoes/shared_examples/parent.rb +6 -0
- data/spec/shoes/shared_examples/scroll.rb +41 -0
- data/spec/shoes/shared_examples/shared_element_method.rb +60 -0
- data/spec/shoes/shared_examples/slot.rb +331 -0
- data/spec/shoes/shared_examples/state.rb +19 -0
- data/spec/shoes/shared_examples/style.rb +82 -0
- data/spec/shoes/slot_spec.rb +130 -0
- data/spec/shoes/sound_spec.rb +15 -0
- data/spec/shoes/span_spec.rb +112 -0
- data/spec/shoes/spec_helper.rb +24 -0
- data/spec/shoes/stack_spec.rb +79 -0
- data/spec/shoes/star_spec.rb +31 -0
- data/spec/shoes/text_block_dimensions_spec.rb +75 -0
- data/spec/shoes/text_block_spec.rb +270 -0
- data/spec/shoes/url_spec.rb +68 -0
- data/spec/shoes/widget_spec.rb +70 -0
- data/spec/shoes_spec.rb +44 -0
- data/spec/spec_helper.rb +18 -0
- data/static/Shoes.icns +0 -0
- data/static/shoes-icon.png +0 -0
- metadata +354 -0
@@ -0,0 +1,15 @@
|
|
1
|
+
module RenamedDelegate
|
2
|
+
include Forwardable
|
3
|
+
|
4
|
+
def renamed_delegate_to(getter, methods, renamings)
|
5
|
+
methods.each do |method|
|
6
|
+
method_name = method.to_s
|
7
|
+
renamed_method_name = renamings.inject(method_name) do |name, (word, sub)|
|
8
|
+
name.gsub word, sub
|
9
|
+
end
|
10
|
+
if renamed_method_name != method_name
|
11
|
+
def_delegator getter, method_name, renamed_method_name
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/shoes/shape.rb
ADDED
@@ -0,0 +1,158 @@
|
|
1
|
+
class Shoes
|
2
|
+
class Shape
|
3
|
+
include Common::UIElement
|
4
|
+
include Common::Style
|
5
|
+
include Common::Clickable
|
6
|
+
|
7
|
+
attr_reader :app, :parent, :dimensions, :gui, :blk, :x, :y
|
8
|
+
attr_reader :left_bound, :top_bound, :right_bound, :bottom_bound
|
9
|
+
style_with :art_styles, :center, :common_styles, :dimensions
|
10
|
+
|
11
|
+
# Creates a new Shoes::Shape
|
12
|
+
#
|
13
|
+
def initialize(app, parent, styles = {}, blk = nil)
|
14
|
+
@app = app
|
15
|
+
@parent = parent
|
16
|
+
style_init styles
|
17
|
+
@dimensions = AbsoluteDimensions.new @style
|
18
|
+
@parent.add_child self
|
19
|
+
@gui = Shoes.backend_for self
|
20
|
+
register_click
|
21
|
+
|
22
|
+
@blk = blk
|
23
|
+
# True until we've asked the pen to draw
|
24
|
+
@before_drawing = true
|
25
|
+
@app.eval_with_additional_context self, &blk
|
26
|
+
end
|
27
|
+
|
28
|
+
def width
|
29
|
+
@app.width
|
30
|
+
end
|
31
|
+
|
32
|
+
def height
|
33
|
+
@app.height
|
34
|
+
end
|
35
|
+
|
36
|
+
# Moves the shape
|
37
|
+
#
|
38
|
+
# @param [Integer] left The new left value
|
39
|
+
# @param [Integer] top The new top value
|
40
|
+
# @return [Shoes::Shape] This shape
|
41
|
+
def move(left, top)
|
42
|
+
self.left = left
|
43
|
+
self.top = top
|
44
|
+
@gui.update_position
|
45
|
+
self
|
46
|
+
end
|
47
|
+
|
48
|
+
# Draws a line from the current position to the given point
|
49
|
+
#
|
50
|
+
# @param [Integer] x The new point's x-value
|
51
|
+
# @param [Integer] y The new point's y-value
|
52
|
+
# @return [Shoes::Shape] This shape
|
53
|
+
def line_to(x, y)
|
54
|
+
update_bounds_rect(@x, @y, x, y)
|
55
|
+
@x, @y = x, y
|
56
|
+
@gui.line_to(x, y)
|
57
|
+
self
|
58
|
+
end
|
59
|
+
|
60
|
+
# Moves the drawing "pen" to the given point
|
61
|
+
#
|
62
|
+
# @param [Integer] x The new point's x-value
|
63
|
+
# @param [Integer] y The new point's y-value
|
64
|
+
# @return [Shoes::Shape] self This shape
|
65
|
+
def move_to(x, y)
|
66
|
+
@x, @y = x, y
|
67
|
+
@gui.move_to(x, y)
|
68
|
+
self
|
69
|
+
end
|
70
|
+
|
71
|
+
# Draws a curve
|
72
|
+
#
|
73
|
+
# @param [Integer] cx1 The first control point's x-value
|
74
|
+
# @param [Integer] cy1 The first control point's y-value
|
75
|
+
# @param [Integer] cx2 The second control point's x-value
|
76
|
+
# @param [Integer] cy2 The second control point's y-value
|
77
|
+
# @param [Integer] x The end point's x-value
|
78
|
+
# @param [Integer] y The end point's y-value
|
79
|
+
# @return [Shoes::Shape] This shape
|
80
|
+
def curve_to(cx1, cy1, cx2, cy2, x, y)
|
81
|
+
update_bounds([@x, cx1, cx2, x], [@y, cy1, cy2, y])
|
82
|
+
@x, @y = x, y
|
83
|
+
@gui.curve_to(cx1, cy1, cx2, cy2, x, y)
|
84
|
+
self
|
85
|
+
end
|
86
|
+
|
87
|
+
# Draws an arc
|
88
|
+
#
|
89
|
+
# @param [Integer] x The left position
|
90
|
+
# @param [Integer] y The top position
|
91
|
+
# @param [Integer] width The width of the arc
|
92
|
+
# @param [Integer] height The height of the arc
|
93
|
+
# @param [Integer] start_angle The start angle
|
94
|
+
# @param [Integer] arc_angle The angular extent of the arc, relative to the start angle
|
95
|
+
# @return [Shoes::Shape] This shape
|
96
|
+
def arc(x, y, width, height, start_angle, arc_angle)
|
97
|
+
update_bounds_rect(x-width/2, y-height/2, x+width/2, y+height/2)
|
98
|
+
@x, @y = x, y
|
99
|
+
@gui.arc(x, y, width, height, start_angle, arc_angle)
|
100
|
+
self
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
# Updates the bounds of this shape to include the rectangle described by
|
105
|
+
# (x1, y1) and (x2, y2)
|
106
|
+
#
|
107
|
+
# @param [Integer] x1 The x-value of the first coordinate
|
108
|
+
# @param [Integer] y1 The y-value of the first coordinate
|
109
|
+
# @param [Integer] x2 The x-value of the second coordinate
|
110
|
+
# @param [Integer] y2 The y-value of the second coordinate
|
111
|
+
# @return nil
|
112
|
+
def update_bounds_rect(x1, y1, x2, y2)
|
113
|
+
update_bounds( [x1, x2], [y1, y2] )
|
114
|
+
end
|
115
|
+
|
116
|
+
# Updates the bounds of this shape to the rectangle covering all
|
117
|
+
# the given coordinates.
|
118
|
+
#
|
119
|
+
# @param [Array<Integer>] xs Array of X coordinates
|
120
|
+
# @param [Array<Integer>] ys Array of Y coordinates
|
121
|
+
# @return nil
|
122
|
+
def update_bounds(xs, ys)
|
123
|
+
all_xs = all_x_values(xs)
|
124
|
+
all_ys = all_y_values(ys)
|
125
|
+
@left_bound = calculate_primary_dimension_value @left_bound, all_xs
|
126
|
+
@top_bound = calculate_primary_dimension_value @top_bound, all_ys
|
127
|
+
@right_bound = calculate_secondary_dimension_value @right_bound, all_xs
|
128
|
+
@bottom_bound = calculate_secondary_dimension_value @bottom_bound, all_ys
|
129
|
+
@before_drawing = false
|
130
|
+
nil
|
131
|
+
end
|
132
|
+
|
133
|
+
def all_x_values(xs)
|
134
|
+
all_values xs, @x, @left_bound, @right_bound
|
135
|
+
end
|
136
|
+
|
137
|
+
def all_y_values(ys)
|
138
|
+
all_values ys, @y, @top_bound, @bottom_bound
|
139
|
+
end
|
140
|
+
|
141
|
+
def all_values(values, current, min, max)
|
142
|
+
additional = @before_drawing ? [current] : [current, min, max]
|
143
|
+
(values + additional).map &:to_i
|
144
|
+
end
|
145
|
+
|
146
|
+
def calculate_primary_dimension_value(current, new)
|
147
|
+
new_min = Array(new).min
|
148
|
+
return new_min if @before_drawing || new_min < current
|
149
|
+
current
|
150
|
+
end
|
151
|
+
|
152
|
+
def calculate_secondary_dimension_value(current, new)
|
153
|
+
new_max = Array(new).max
|
154
|
+
return new_max if @before_drawing || new_max > current
|
155
|
+
current
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
data/lib/shoes/slot.rb
ADDED
@@ -0,0 +1,271 @@
|
|
1
|
+
class Shoes
|
2
|
+
class Slot
|
3
|
+
include Common::UIElement
|
4
|
+
include Common::Clickable
|
5
|
+
include Common::Style
|
6
|
+
|
7
|
+
# We need that offset because otherwise element overlap e.g. occupy
|
8
|
+
# the same pixel - this way they start right next to each other
|
9
|
+
# See #update_current_position
|
10
|
+
NEXT_ELEMENT_OFFSET = 1
|
11
|
+
|
12
|
+
attr_reader :parent, :dimensions, :gui, :contents, :blk, :hover_proc, :leave_proc
|
13
|
+
style_with :art_styles, :attach, :common_styles, :dimensions, :scroll
|
14
|
+
STYLES = {scroll: false}
|
15
|
+
|
16
|
+
def initialize(app, parent, styles = {}, blk = nil)
|
17
|
+
init_attributes(app, parent, styles, blk)
|
18
|
+
@parent.add_child self
|
19
|
+
@gui = Shoes.configuration.backend_for self, @parent.gui
|
20
|
+
eval_block blk
|
21
|
+
contents_alignment
|
22
|
+
end
|
23
|
+
|
24
|
+
def init_attributes(app, parent, styles, blk)
|
25
|
+
@app = app
|
26
|
+
@parent = parent
|
27
|
+
@contents = SlotContents.new
|
28
|
+
@blk = blk
|
29
|
+
style_init styles
|
30
|
+
@dimensions = Dimensions.new parent, @style
|
31
|
+
@fixed_height = height || false
|
32
|
+
@scroll_top = 0
|
33
|
+
set_default_dimension_values
|
34
|
+
@pass_coordinates = true
|
35
|
+
end
|
36
|
+
|
37
|
+
def set_default_dimension_values
|
38
|
+
self.width ||= 1.0
|
39
|
+
self.height ||= 0
|
40
|
+
self.absolute_left ||= 0
|
41
|
+
self.absolute_top ||= 0
|
42
|
+
end
|
43
|
+
|
44
|
+
def clear(&blk)
|
45
|
+
contents.clear
|
46
|
+
eval_block blk
|
47
|
+
end
|
48
|
+
|
49
|
+
def eval_block blk
|
50
|
+
old_current_slot = @app.current_slot
|
51
|
+
@app.current_slot = self
|
52
|
+
blk.call if blk
|
53
|
+
@app.current_slot = old_current_slot
|
54
|
+
end
|
55
|
+
|
56
|
+
def add_child(element)
|
57
|
+
contents.add_element element
|
58
|
+
end
|
59
|
+
|
60
|
+
def remove_child(element)
|
61
|
+
contents.delete element
|
62
|
+
end
|
63
|
+
|
64
|
+
def append(&blk)
|
65
|
+
eval_block blk
|
66
|
+
end
|
67
|
+
|
68
|
+
def prepend(&blk)
|
69
|
+
contents.prepend do
|
70
|
+
eval_block blk
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def contents_alignment(_=nil)
|
75
|
+
position_contents
|
76
|
+
determine_slot_height
|
77
|
+
end
|
78
|
+
|
79
|
+
def hovered?
|
80
|
+
@hovered
|
81
|
+
end
|
82
|
+
|
83
|
+
def hover(blk)
|
84
|
+
@hover_proc = blk
|
85
|
+
@app.add_mouse_hover_control self
|
86
|
+
end
|
87
|
+
|
88
|
+
def leave(blk)
|
89
|
+
@leave_proc = blk
|
90
|
+
@app.add_mouse_hover_control self
|
91
|
+
end
|
92
|
+
|
93
|
+
def mouse_hovered
|
94
|
+
@hovered = true
|
95
|
+
@hover_proc.call(self) if @hover_proc
|
96
|
+
end
|
97
|
+
|
98
|
+
def mouse_left
|
99
|
+
@hovered = false
|
100
|
+
@leave_proc.call(self) if @leave_proc
|
101
|
+
end
|
102
|
+
|
103
|
+
def scroll_height
|
104
|
+
position_contents.y
|
105
|
+
end
|
106
|
+
|
107
|
+
def scroll_max
|
108
|
+
scroll_height - height
|
109
|
+
end
|
110
|
+
|
111
|
+
def scroll_top
|
112
|
+
@scroll_top
|
113
|
+
end
|
114
|
+
|
115
|
+
def scroll_top=(position)
|
116
|
+
@scroll_top = position
|
117
|
+
end
|
118
|
+
|
119
|
+
def app
|
120
|
+
@app.app #return the Shoes::App not the internal app
|
121
|
+
end
|
122
|
+
|
123
|
+
def inspect
|
124
|
+
"#<#{self.class}:0x#{hash.to_s(16)} @contents=#{@contents.inspect} and so much stuff literally breaks the memory limit. Look at it selectively.>"
|
125
|
+
end
|
126
|
+
|
127
|
+
protected
|
128
|
+
CurrentPosition = Struct.new(:x, :y, :next_line_start)
|
129
|
+
|
130
|
+
def position_contents
|
131
|
+
current_position = CurrentPosition.new element_left,
|
132
|
+
element_top,
|
133
|
+
element_top
|
134
|
+
|
135
|
+
contents.each do |element|
|
136
|
+
next if element.hidden?
|
137
|
+
current_position = positioning(element, current_position)
|
138
|
+
end
|
139
|
+
current_position
|
140
|
+
end
|
141
|
+
|
142
|
+
def positioning(element, current_position)
|
143
|
+
return current_position unless element.needs_to_be_positioned?
|
144
|
+
position_element element, current_position
|
145
|
+
element.contents_alignment(current_position) if element.respond_to? :contents_alignment
|
146
|
+
if element.takes_up_space?
|
147
|
+
update_current_position(current_position, element)
|
148
|
+
else
|
149
|
+
current_position
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def position_element(element, current_position)
|
154
|
+
raise 'position_element is a subclass responsibility'
|
155
|
+
end
|
156
|
+
|
157
|
+
def position_in_current_line(element, current_position)
|
158
|
+
position_element_at element,
|
159
|
+
position_x(current_position.x, element),
|
160
|
+
position_y(current_position.y, element)
|
161
|
+
end
|
162
|
+
|
163
|
+
def move_to_next_line(element, current_position)
|
164
|
+
position_element_at element,
|
165
|
+
position_x(self.element_left, element),
|
166
|
+
position_y(current_position.next_line_start, element)
|
167
|
+
end
|
168
|
+
|
169
|
+
def position_element_at(element, x, y)
|
170
|
+
return if element_did_not_move?(element, x, y)
|
171
|
+
element._position x, y
|
172
|
+
end
|
173
|
+
|
174
|
+
def element_did_not_move?(element, x, y)
|
175
|
+
element.absolute_left == x && element.absolute_top == y
|
176
|
+
end
|
177
|
+
|
178
|
+
def update_current_position(current_position, element)
|
179
|
+
return current_position if element.absolutely_positioned?
|
180
|
+
current_position.x = element.absolute_right + NEXT_ELEMENT_OFFSET
|
181
|
+
current_position.y = element.absolute_top
|
182
|
+
next_element_line_start = next_line_start_from element
|
183
|
+
if current_position.next_line_start < next_element_line_start
|
184
|
+
current_position.next_line_start = next_element_line_start
|
185
|
+
end
|
186
|
+
element.adjust_current_position current_position
|
187
|
+
current_position
|
188
|
+
end
|
189
|
+
|
190
|
+
def next_line_start_from element
|
191
|
+
element.absolute_bottom + NEXT_ELEMENT_OFFSET
|
192
|
+
end
|
193
|
+
|
194
|
+
def position_x(relative_x, element)
|
195
|
+
if element.absolute_x_position?
|
196
|
+
absolute_x_position(element)
|
197
|
+
else
|
198
|
+
relative_x
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
def absolute_x_position(element)
|
203
|
+
if element.absolute_left_position?
|
204
|
+
self.absolute_left + element.left
|
205
|
+
elsif element.absolute_right_position?
|
206
|
+
self.absolute_right - (element.right + element.width)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def position_y(relative_y, element)
|
211
|
+
if element.absolute_y_position?
|
212
|
+
absolute_y_position(element)
|
213
|
+
else
|
214
|
+
relative_y
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def absolute_y_position(element)
|
219
|
+
if element.absolute_top_position?
|
220
|
+
self.absolute_top + element.top
|
221
|
+
elsif element.absolute_bottom_position?
|
222
|
+
# TODO: slots grow... to really position it relative to the bottom
|
223
|
+
# we probably need to position it after everything has been positioned
|
224
|
+
self.absolute_bottom - (element.bottom + element.height)
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
def fits_on_the_same_line?(element, current_x)
|
229
|
+
fitting_width = element.width
|
230
|
+
fitting_width = element.fitting_width if element.respond_to?(:fitting_width)
|
231
|
+
current_x + fitting_width - 1 <= element_right
|
232
|
+
end
|
233
|
+
|
234
|
+
def determine_slot_height
|
235
|
+
content_height = compute_content_height
|
236
|
+
self.height = content_height if has_variable_height?
|
237
|
+
content_height
|
238
|
+
end
|
239
|
+
|
240
|
+
def compute_content_height
|
241
|
+
max_bottom = contents.reject(&:hidden?).
|
242
|
+
map(&:absolute_bottom).
|
243
|
+
max
|
244
|
+
if max_bottom
|
245
|
+
max_bottom - self.absolute_top + NEXT_ELEMENT_OFFSET
|
246
|
+
else
|
247
|
+
0
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
def has_variable_height?
|
252
|
+
not @fixed_height
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
class Flow < Slot
|
257
|
+
def position_element(element, current_position)
|
258
|
+
if fits_on_the_same_line?(element, current_position.x)
|
259
|
+
position_in_current_line(element, current_position)
|
260
|
+
else
|
261
|
+
move_to_next_line(element, current_position)
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
class Stack < Slot
|
267
|
+
def position_element(element, current_position)
|
268
|
+
move_to_next_line(element, current_position)
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
class Shoes
|
2
|
+
class SlotContents < SimpleDelegator
|
3
|
+
include Common::Inspect
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@contents = []
|
7
|
+
@prepending = false
|
8
|
+
@prepending_index = 0
|
9
|
+
super(@contents)
|
10
|
+
end
|
11
|
+
|
12
|
+
def add_element(element)
|
13
|
+
if @prepending
|
14
|
+
prepend_element element
|
15
|
+
else
|
16
|
+
append_element element
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def prepend(&blk)
|
21
|
+
@prepending_index = 0
|
22
|
+
@prepending = true
|
23
|
+
blk.call
|
24
|
+
@prepending = false
|
25
|
+
end
|
26
|
+
|
27
|
+
def clear
|
28
|
+
# reverse_each is important as otherwise we always miss to delete one
|
29
|
+
# element
|
30
|
+
@contents.reverse_each do |element|
|
31
|
+
element.is_a?(Shoes::Slot) ? element.clear : element.remove
|
32
|
+
end
|
33
|
+
@contents.clear
|
34
|
+
end
|
35
|
+
|
36
|
+
def inspect
|
37
|
+
super.insert(-2, " @size=#{size} @prepending=#{@prepending} @prepending_index=#{@prepending_index}")
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
def append_element(element)
|
42
|
+
@contents << element
|
43
|
+
end
|
44
|
+
|
45
|
+
def prepend_element(element)
|
46
|
+
@contents.insert @prepending_index, element
|
47
|
+
@prepending_index += 1
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|