shoes-swt 4.0.0.pre3 → 4.0.0.pre4
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 +4 -4
- data/bin/shoes-swt +2 -2
- data/lib/shoes/swt.rb +90 -72
- data/lib/shoes/swt/app.rb +5 -0
- data/lib/shoes/swt/click_listener.rb +0 -1
- data/lib/shoes/swt/color.rb +7 -7
- data/lib/shoes/swt/common/fill.rb +9 -3
- data/lib/shoes/swt/common/painter.rb +14 -11
- data/lib/shoes/swt/common/stroke.rb +9 -3
- data/lib/shoes/swt/dialog.rb +2 -2
- data/lib/shoes/swt/gradient.rb +13 -11
- data/lib/shoes/swt/image.rb +1 -3
- data/lib/shoes/swt/image_pattern.rb +2 -2
- data/lib/shoes/swt/line.rb +0 -2
- data/lib/shoes/swt/list_box.rb +6 -1
- data/lib/shoes/swt/progress.rb +9 -8
- data/lib/shoes/swt/redrawing_aspect.rb +1 -1
- data/lib/shoes/swt/shape.rb +3 -1
- data/lib/shoes/swt/shoes_layout.rb +38 -24
- data/lib/shoes/swt/text_block.rb +41 -12
- data/lib/shoes/swt/text_block/cursor_painter.rb +1 -1
- data/lib/shoes/swt/text_block/fitter.rb +8 -3
- data/lib/shoes/swt/text_block/painter.rb +9 -28
- data/lib/shoes/swt/text_block/text_segment.rb +16 -6
- data/lib/shoes/swt/text_block/text_segment_collection.rb +17 -5
- data/lib/shoes/swt/tooling/leak_hunter.rb +1 -1
- data/lib/shoes/swt/version.rb +1 -1
- data/shoes-swt.gemspec +2 -2
- data/spec/shoes/cli_spec.rb +1 -1
- data/spec/shoes/swt/app_spec.rb +15 -6
- data/spec/shoes/swt/color_spec.rb +8 -7
- data/spec/shoes/swt/common/painter_spec.rb +30 -5
- data/spec/shoes/swt/disposed_protection_spec.rb +0 -1
- data/spec/shoes/swt/font_spec.rb +2 -2
- data/spec/shoes/swt/gradient_spec.rb +5 -2
- data/spec/shoes/swt/image_pattern_spec.rb +11 -1
- data/spec/shoes/swt/list_box_spec.rb +24 -4
- data/spec/shoes/swt/mouse_move_listener_spec.rb +1 -1
- data/spec/shoes/swt/oval_spec.rb +0 -1
- data/spec/shoes/swt/progress_spec.rb +3 -4
- data/spec/shoes/swt/radio_group_spec.rb +4 -4
- data/spec/shoes/swt/radio_spec.rb +1 -1
- data/spec/shoes/swt/shape_spec.rb +8 -1
- data/spec/shoes/swt/shared_examples/paintable.rb +0 -1
- data/spec/shoes/swt/shared_examples/pattern.rb +2 -6
- data/spec/shoes/swt/shared_examples/swt_app_context.rb +0 -1
- data/spec/shoes/swt/shell_control_listener_spec.rb +4 -4
- data/spec/shoes/swt/shoes_layout_spec.rb +84 -0
- data/spec/shoes/swt/slot_spec.rb +1 -1
- data/spec/shoes/swt/spec_helper.rb +2 -0
- data/spec/shoes/swt/text_block/cursor_painter_spec.rb +2 -2
- data/spec/shoes/swt/text_block/fitter_spec.rb +19 -4
- data/spec/shoes/swt/text_block/painter_spec.rb +15 -189
- data/spec/shoes/swt/text_block/text_segment_collection_spec.rb +10 -5
- data/spec/shoes/swt/text_block/text_segment_spec.rb +4 -4
- data/spec/shoes/swt/text_block_spec.rb +28 -15
- metadata +8 -6
data/lib/shoes/swt/list_box.rb
CHANGED
@@ -25,10 +25,14 @@ class Shoes
|
|
25
25
|
@dsl.call_change_listeners
|
26
26
|
end
|
27
27
|
update_items
|
28
|
+
|
29
|
+
# Set initial selection without triggering callbacks!
|
30
|
+
choice = @dsl.style[:choose]
|
31
|
+
@real.text = choice if choice
|
28
32
|
end
|
29
33
|
|
30
34
|
def update_items
|
31
|
-
@real.items = @dsl.items.map(&:to_s)
|
35
|
+
@real.items = @dsl.items.to_a.map(&:to_s)
|
32
36
|
end
|
33
37
|
|
34
38
|
def text
|
@@ -38,6 +42,7 @@ class Shoes
|
|
38
42
|
|
39
43
|
def choose(item)
|
40
44
|
@real.text = item
|
45
|
+
@dsl.call_change_listeners
|
41
46
|
end
|
42
47
|
|
43
48
|
def enabled(value)
|
data/lib/shoes/swt/progress.rb
CHANGED
@@ -5,9 +5,10 @@ class Shoes
|
|
5
5
|
include Common::Remove
|
6
6
|
include Common::Visibility
|
7
7
|
include Common::UpdatePosition
|
8
|
+
include DisposedProtection
|
8
9
|
include ::Shoes::BackendDimensionsDelegations
|
9
10
|
|
10
|
-
attr_reader :parent, :
|
11
|
+
attr_reader :parent, :dsl
|
11
12
|
|
12
13
|
def initialize(dsl, parent)
|
13
14
|
@dsl = dsl
|
@@ -15,20 +16,20 @@ class Shoes
|
|
15
16
|
|
16
17
|
@real = ::Swt::Widgets::ProgressBar.new(@parent.real,
|
17
18
|
::Swt::SWT::SMOOTH)
|
18
|
-
|
19
|
-
|
19
|
+
real.minimum = 0
|
20
|
+
real.maximum = 100
|
20
21
|
|
21
22
|
if @dsl.element_width && @dsl.element_height
|
22
|
-
|
23
|
+
real.setSize dsl.element_width, dsl.element_height
|
23
24
|
else
|
24
|
-
|
25
|
-
@dsl.element_width =
|
26
|
-
@dsl.element_height =
|
25
|
+
real.pack
|
26
|
+
@dsl.element_width = real.size.x
|
27
|
+
@dsl.element_height = real.size.y
|
27
28
|
end
|
28
29
|
end
|
29
30
|
|
30
31
|
def fraction=(value)
|
31
|
-
|
32
|
+
real.selection = (value * 100).to_i
|
32
33
|
end
|
33
34
|
end
|
34
35
|
end
|
@@ -25,7 +25,7 @@ class Shoes
|
|
25
25
|
|
26
26
|
# These need to trigger a redraw
|
27
27
|
SAME_POSITION = { Common::Visibility => [:update_visibility],
|
28
|
-
Image => [:
|
28
|
+
Image => [:create_image],
|
29
29
|
::Shoes::Common::Style => [:update_style],
|
30
30
|
::Shoes::Common::Remove => [:remove],
|
31
31
|
::Shoes::Slot => [:mouse_hovered,
|
data/lib/shoes/swt/shape.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
class Shoes
|
2
2
|
module Swt
|
3
3
|
class Shape
|
4
|
+
include Common::Clickable
|
5
|
+
include Common::Visibility
|
4
6
|
include Common::Remove
|
5
7
|
include Common::Fill
|
6
8
|
include Common::Stroke
|
@@ -41,7 +43,7 @@ class Shoes
|
|
41
43
|
@element.cubic_to(cx1, cy1, cx2, cy2, x, y)
|
42
44
|
end
|
43
45
|
|
44
|
-
def
|
46
|
+
def arc_to(x, y, width, height, start_angle, arc_angle)
|
45
47
|
@element.add_arc(x - (width / 2), y - (height / 2), width, height,
|
46
48
|
-start_angle * 180 / ::Shoes::PI,
|
47
49
|
(start_angle - arc_angle) * 180 / ::Shoes::PI)
|
@@ -4,42 +4,56 @@ class Shoes
|
|
4
4
|
attr_accessor :gui_app
|
5
5
|
|
6
6
|
def layout(*_dontcare)
|
7
|
-
|
8
|
-
|
9
|
-
scrollable_height = dsl_app.top_slot.contents_alignment
|
10
|
-
set_gui_size(height, scrollable_height)
|
11
|
-
|
12
|
-
dsl_app.top_slot.width = dsl_app.width
|
13
|
-
dsl_app.top_slot.height = [scrollable_height, height].max
|
7
|
+
height, scroll_height, is_scrolling = gather_height_info(@gui_app.dsl)
|
8
|
+
set_heights(@gui_app.dsl, @gui_app.real, height, scroll_height)
|
14
9
|
|
15
|
-
|
16
|
-
|
17
|
-
if scrollable_height > height
|
18
|
-
handle_scroll_bar(vertical_bar, height, scrollable_height)
|
10
|
+
if is_scrolling
|
11
|
+
show_scrollbar(vertical_scrollbar, height, scroll_height)
|
19
12
|
else
|
20
|
-
|
13
|
+
hide_scrollbar(vertical_scrollbar, @gui_app.real)
|
21
14
|
end
|
22
15
|
end
|
23
16
|
|
24
17
|
private
|
25
18
|
|
26
|
-
def
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
@gui_app.real.set_size(size.width, size.height)
|
19
|
+
def gather_height_info(dsl_app)
|
20
|
+
height = dsl_app.height
|
21
|
+
scroll_height = dsl_app.top_slot.contents_alignment
|
22
|
+
[height, scroll_height, scroll_height > height]
|
31
23
|
end
|
32
24
|
|
33
|
-
def
|
34
|
-
|
35
|
-
|
36
|
-
|
25
|
+
def set_heights(dsl_app, real_app, height, scroll_height)
|
26
|
+
maximum_height = [height, scroll_height].max
|
27
|
+
set_real_size(dsl_app, real_app, maximum_height)
|
28
|
+
set_top_slot_size(dsl_app, maximum_height)
|
37
29
|
end
|
38
30
|
|
39
|
-
def
|
40
|
-
|
31
|
+
def set_real_size(dsl_app, real_app, maximum_height)
|
32
|
+
size = real_app.compute_trim 0, 0, dsl_app.width, maximum_height
|
33
|
+
real_app.set_size(size.width, size.height)
|
34
|
+
end
|
35
|
+
|
36
|
+
def set_top_slot_size(dsl_app, maximum_height)
|
37
|
+
dsl_app.top_slot.width = dsl_app.width
|
38
|
+
dsl_app.top_slot.height = maximum_height
|
39
|
+
end
|
40
|
+
|
41
|
+
def show_scrollbar(scrollbar, height, scroll_height)
|
42
|
+
scrollbar.visible = true
|
43
|
+
scrollbar.thumb = height * height / scroll_height
|
44
|
+
scrollbar.maximum = scroll_height - height + scrollbar.thumb
|
45
|
+
scrollbar.increment = 10
|
46
|
+
end
|
47
|
+
|
48
|
+
def hide_scrollbar(scrollbar, real_app)
|
49
|
+
scrollbar.visible = false
|
50
|
+
location = real_app.location
|
41
51
|
location.y = 0
|
42
|
-
|
52
|
+
real_app.location = location
|
53
|
+
end
|
54
|
+
|
55
|
+
def vertical_scrollbar
|
56
|
+
@gui_app.shell.vertical_bar
|
43
57
|
end
|
44
58
|
end
|
45
59
|
end
|
data/lib/shoes/swt/text_block.rb
CHANGED
@@ -7,15 +7,16 @@ class Shoes
|
|
7
7
|
include ::Shoes::BackendDimensionsDelegations
|
8
8
|
|
9
9
|
DEFAULT_SPACING = 4
|
10
|
+
NEXT_ELEMENT_OFFSET = 1
|
10
11
|
|
11
12
|
attr_reader :dsl, :app
|
12
13
|
attr_accessor :segments
|
13
14
|
|
14
15
|
def initialize(dsl, app)
|
15
|
-
@dsl
|
16
|
-
@app
|
17
|
-
@segments
|
18
|
-
@painter
|
16
|
+
@dsl = dsl
|
17
|
+
@app = app
|
18
|
+
@segments = TextSegmentCollection.new(@dsl, [], default_text_styles)
|
19
|
+
@painter = Painter.new @dsl
|
19
20
|
@app.add_paint_listener @painter
|
20
21
|
end
|
21
22
|
|
@@ -35,16 +36,45 @@ class Shoes
|
|
35
36
|
|
36
37
|
def contents_alignment(current_position)
|
37
38
|
dispose_existing_segments
|
38
|
-
|
39
|
+
raw_segments = Fitter.new(self, current_position).fit_it_in
|
39
40
|
|
40
|
-
|
41
|
-
|
41
|
+
if raw_segments && raw_segments.any?
|
42
|
+
@segments = TextSegmentCollection.new(@dsl, raw_segments, default_text_styles)
|
43
|
+
set_absolutes_on_dsl(current_position)
|
44
|
+
set_calculated_sizes
|
45
|
+
else
|
46
|
+
@segments = TextSegmentCollection.new(@dsl, [], default_text_styles)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def default_text_styles
|
51
|
+
style = @dsl.style
|
52
|
+
|
53
|
+
{
|
54
|
+
fg: style[:fg],
|
55
|
+
bg: style[:bg],
|
56
|
+
strikecolor: style[:strikecolor],
|
57
|
+
undercolor: style[:undercolor],
|
58
|
+
font_detail: {
|
59
|
+
name: @dsl.font,
|
60
|
+
size: @dsl.size,
|
61
|
+
styles: [::Swt::SWT::NORMAL]
|
62
|
+
}
|
63
|
+
}
|
42
64
|
end
|
43
65
|
|
44
66
|
def adjust_current_position(current_position)
|
67
|
+
current_position.y = @dsl.absolute_bottom + NEXT_ELEMENT_OFFSET
|
68
|
+
|
45
69
|
last_segment = segments.last
|
46
|
-
|
47
|
-
|
70
|
+
if last_segment && !@bumped_to_next_line
|
71
|
+
# Not quite sure why this is necessary. Could be a problem in some
|
72
|
+
# other part of positioning, or something about how text layouts
|
73
|
+
# actually draw themselves.
|
74
|
+
current_position.x -= 1
|
75
|
+
|
76
|
+
current_position.y -= last_segment.last_line_height
|
77
|
+
end
|
48
78
|
end
|
49
79
|
|
50
80
|
def set_absolutes_on_dsl(current_position)
|
@@ -65,10 +95,10 @@ class Shoes
|
|
65
95
|
last_segment = segments.last
|
66
96
|
|
67
97
|
@dsl.absolute_right = starting_left + last_segment.last_line_width +
|
68
|
-
margin_right
|
98
|
+
margin_right - NEXT_ELEMENT_OFFSET
|
69
99
|
|
70
100
|
@dsl.absolute_bottom = starting_top + last_segment.height +
|
71
|
-
margin_top + margin_bottom
|
101
|
+
margin_top + margin_bottom - NEXT_ELEMENT_OFFSET
|
72
102
|
end
|
73
103
|
|
74
104
|
def bump_absolutes_to_next_line
|
@@ -104,7 +134,6 @@ class Shoes
|
|
104
134
|
end
|
105
135
|
|
106
136
|
def dispose_existing_segments
|
107
|
-
@segments.map(&:dispose)
|
108
137
|
@segments.clear
|
109
138
|
end
|
110
139
|
|
@@ -95,6 +95,10 @@ class Shoes
|
|
95
95
|
end
|
96
96
|
|
97
97
|
def fit_as_empty_first_layout(height)
|
98
|
+
if height == :unbounded || height == 0
|
99
|
+
return []
|
100
|
+
end
|
101
|
+
|
98
102
|
height += ::Shoes::Slot::NEXT_ELEMENT_OFFSET
|
99
103
|
generate_two_layouts(empty_segment, "", @dsl.text, height)
|
100
104
|
end
|
@@ -117,6 +121,7 @@ class Shoes
|
|
117
121
|
end
|
118
122
|
|
119
123
|
def generate_two_layouts(first_layout, first_text, second_text, height)
|
124
|
+
first_layout.fill_background = true
|
120
125
|
second_layout = generate_second_layout(second_text)
|
121
126
|
position_two_segments(first_layout, second_layout, first_text, height)
|
122
127
|
end
|
@@ -132,7 +137,7 @@ class Shoes
|
|
132
137
|
first_layout.position_at(@dsl.element_left,
|
133
138
|
@dsl.element_top),
|
134
139
|
second_layout.position_at(parent.absolute_left + @dsl.margin_left,
|
135
|
-
@dsl.element_top + first_height
|
140
|
+
@dsl.element_top + first_height)
|
136
141
|
]
|
137
142
|
end
|
138
143
|
|
@@ -193,10 +198,10 @@ class Shoes
|
|
193
198
|
|
194
199
|
offsets = layout.line_offsets
|
195
200
|
offsets[0...-1].each_with_index do |_, i|
|
196
|
-
height_so_far += layout.line_bounds(i).height
|
201
|
+
height_so_far += layout.line_bounds(i).height + TextBlock::NEXT_ELEMENT_OFFSET
|
197
202
|
ending_offset = offsets[i + 1]
|
198
203
|
|
199
|
-
break if height_so_far
|
204
|
+
break if height_so_far >= height
|
200
205
|
end
|
201
206
|
[layout.text[0...ending_offset], layout.text[ending_offset..-1]]
|
202
207
|
end
|
@@ -6,40 +6,21 @@ class Shoes
|
|
6
6
|
include Common::Resource
|
7
7
|
|
8
8
|
attr_reader :app
|
9
|
+
|
9
10
|
def initialize(dsl)
|
10
11
|
@dsl = dsl
|
11
|
-
@style = @dsl.style
|
12
|
-
@app = @dsl.app.gui
|
13
12
|
end
|
14
13
|
|
15
14
|
def paintControl(paint_event)
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
15
|
+
# See #636 for discussion, contents_alignment may not run or if the
|
16
|
+
# space is very narrow we might squish things down to be very narrow.
|
17
|
+
# If paint is triggered then, code later on will crash.
|
18
|
+
return if @dsl.hidden? ||
|
19
|
+
@dsl.gui.segments.nil? ||
|
20
|
+
@dsl.gui.segments.empty?
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
@dsl.gui.segments,
|
25
|
-
default_text_styles)
|
26
|
-
layouts.paint_control(graphic_context)
|
27
|
-
end
|
28
|
-
|
29
|
-
private
|
30
|
-
|
31
|
-
def default_text_styles
|
32
|
-
{
|
33
|
-
fg: @style[:fg],
|
34
|
-
bg: @style[:bg],
|
35
|
-
strikecolor: @style[:strikecolor],
|
36
|
-
undercolor: @style[:undercolor],
|
37
|
-
font_detail: {
|
38
|
-
name: @dsl.font,
|
39
|
-
size: @dsl.size,
|
40
|
-
styles: [::Swt::SWT::NORMAL]
|
41
|
-
}
|
42
|
-
}
|
22
|
+
reset_graphics_context(paint_event.gc)
|
23
|
+
@dsl.gui.segments.paint_control(paint_event.gc)
|
43
24
|
end
|
44
25
|
end
|
45
26
|
end
|
@@ -14,7 +14,8 @@ class Shoes
|
|
14
14
|
class TextSegment
|
15
15
|
DEFAULT_SPACING = 4
|
16
16
|
|
17
|
-
attr_reader
|
17
|
+
attr_reader :layout, :element_left, :element_top
|
18
|
+
attr_accessor :fill_background
|
18
19
|
|
19
20
|
extend Forwardable
|
20
21
|
def_delegators :@layout, :text, :text=, :bounds, :width, :spacing,
|
@@ -23,11 +24,14 @@ class Shoes
|
|
23
24
|
def initialize(dsl, text, width)
|
24
25
|
@dsl = dsl
|
25
26
|
@layout = ::Swt::TextLayout.new Shoes.display
|
27
|
+
@fill_background = false
|
28
|
+
|
26
29
|
@font_factory = TextFontFactory.new
|
27
30
|
@style_factory = TextStyleFactory.new
|
31
|
+
@color_factory = ColorFactory.new
|
28
32
|
|
29
33
|
layout.text = text
|
30
|
-
layout.width = width
|
34
|
+
layout.width = width
|
31
35
|
style_from(font_styling, @dsl.style)
|
32
36
|
end
|
33
37
|
|
@@ -35,6 +39,7 @@ class Shoes
|
|
35
39
|
@layout.dispose unless @layout.disposed?
|
36
40
|
@font_factory.dispose
|
37
41
|
@style_factory.dispose
|
42
|
+
@color_factory.dispose
|
38
43
|
end
|
39
44
|
|
40
45
|
def position_at(element_left, element_top)
|
@@ -78,10 +83,6 @@ class Shoes
|
|
78
83
|
}
|
79
84
|
end
|
80
85
|
|
81
|
-
def layout_fits_in?(width)
|
82
|
-
layout.bounds.width <= width
|
83
|
-
end
|
84
|
-
|
85
86
|
def height
|
86
87
|
layout.bounds.height - layout.spacing
|
87
88
|
end
|
@@ -95,6 +96,15 @@ class Shoes
|
|
95
96
|
end
|
96
97
|
|
97
98
|
def draw(graphics_context)
|
99
|
+
# Why not use TextLayout's background? Unfortunately it doesn't draw
|
100
|
+
# all the way to the edges--just around the literal text. This leaves
|
101
|
+
# things jagged when we flow, so do it ourselves.
|
102
|
+
if fill_background && @dsl.style[:fill]
|
103
|
+
background_color = @color_factory.create(@dsl.style[:fill])
|
104
|
+
background_color.apply_as_fill(graphics_context)
|
105
|
+
graphics_context.fill_rectangle(element_left, element_top, width, height)
|
106
|
+
end
|
107
|
+
|
98
108
|
layout.draw(graphics_context, element_left, element_top)
|
99
109
|
end
|
100
110
|
|
@@ -3,7 +3,8 @@ class Shoes
|
|
3
3
|
class TextBlock
|
4
4
|
class TextSegmentCollection
|
5
5
|
extend Forwardable
|
6
|
-
def_delegators :@segments, :length
|
6
|
+
def_delegators :@segments, :length, :last, :inject,
|
7
|
+
:one?, :any?, :empty?
|
7
8
|
|
8
9
|
attr_reader :dsl, :default_text_styles
|
9
10
|
|
@@ -13,14 +14,26 @@ class Shoes
|
|
13
14
|
@default_text_styles = default_text_styles
|
14
15
|
end
|
15
16
|
|
17
|
+
def clear
|
18
|
+
@segments.map(&:dispose)
|
19
|
+
@segments.clear
|
20
|
+
end
|
21
|
+
|
16
22
|
def paint_control(graphic_context)
|
17
|
-
|
18
|
-
style_segment_ranges(dsl.text_styles)
|
19
|
-
create_links(dsl.text_styles)
|
23
|
+
ensure_styled
|
20
24
|
draw(graphic_context)
|
21
25
|
draw_cursor
|
22
26
|
end
|
23
27
|
|
28
|
+
def ensure_styled
|
29
|
+
return if @styled
|
30
|
+
|
31
|
+
style_from(@dsl.style)
|
32
|
+
style_segment_ranges(@dsl.text_styles)
|
33
|
+
create_links(@dsl.text_styles)
|
34
|
+
@styled = true
|
35
|
+
end
|
36
|
+
|
24
37
|
def style_from(style)
|
25
38
|
@segments.each do |segment|
|
26
39
|
segment.style_from(default_text_styles, style)
|
@@ -82,7 +95,6 @@ class Shoes
|
|
82
95
|
# be in either, or both, of the segments. This method figures out which
|
83
96
|
# segments apply, and what the relative ranges within each segment to use.
|
84
97
|
def segment_ranges(text_range)
|
85
|
-
return [] unless @segments.first # TODO WTF #636
|
86
98
|
return [] unless text_range.any?
|
87
99
|
|
88
100
|
first_text = @segments.first.text
|