shoes-swt 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.
Files changed (238) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG +84 -0
  3. data/Gemfile +24 -0
  4. data/Guardfile +11 -0
  5. data/LICENSE +31 -0
  6. data/README.md +201 -0
  7. data/lib/shoes/swt.rb +118 -0
  8. data/lib/shoes/swt/animation.rb +46 -0
  9. data/lib/shoes/swt/app.rb +314 -0
  10. data/lib/shoes/swt/arc.rb +71 -0
  11. data/lib/shoes/swt/background.rb +41 -0
  12. data/lib/shoes/swt/border.rb +41 -0
  13. data/lib/shoes/swt/button.rb +18 -0
  14. data/lib/shoes/swt/check.rb +14 -0
  15. data/lib/shoes/swt/check_button.rb +19 -0
  16. data/lib/shoes/swt/color.rb +49 -0
  17. data/lib/shoes/swt/color_factory.rb +32 -0
  18. data/lib/shoes/swt/common/child.rb +16 -0
  19. data/lib/shoes/swt/common/clickable.rb +68 -0
  20. data/lib/shoes/swt/common/container.rb +28 -0
  21. data/lib/shoes/swt/common/fill.rb +38 -0
  22. data/lib/shoes/swt/common/painter.rb +92 -0
  23. data/lib/shoes/swt/common/painter_updates_position.rb +12 -0
  24. data/lib/shoes/swt/common/remove.rb +30 -0
  25. data/lib/shoes/swt/common/resource.rb +29 -0
  26. data/lib/shoes/swt/common/selection_listener.rb +14 -0
  27. data/lib/shoes/swt/common/stroke.rb +42 -0
  28. data/lib/shoes/swt/common/update_position.rb +15 -0
  29. data/lib/shoes/swt/common/visibility.rb +13 -0
  30. data/lib/shoes/swt/dialog.rb +90 -0
  31. data/lib/shoes/swt/disposed_protection.rb +23 -0
  32. data/lib/shoes/swt/download.rb +24 -0
  33. data/lib/shoes/swt/font.rb +32 -0
  34. data/lib/shoes/swt/gradient.rb +92 -0
  35. data/lib/shoes/swt/image.rb +128 -0
  36. data/lib/shoes/swt/image_pattern.rb +31 -0
  37. data/lib/shoes/swt/input_box.rb +73 -0
  38. data/lib/shoes/swt/key_listener.rb +145 -0
  39. data/lib/shoes/swt/line.rb +60 -0
  40. data/lib/shoes/swt/link.rb +31 -0
  41. data/lib/shoes/swt/link_segment.rb +111 -0
  42. data/lib/shoes/swt/list_box.rb +48 -0
  43. data/lib/shoes/swt/mouse_move_listener.rb +67 -0
  44. data/lib/shoes/swt/oval.rb +52 -0
  45. data/lib/shoes/swt/progress.rb +35 -0
  46. data/lib/shoes/swt/radio.rb +29 -0
  47. data/lib/shoes/swt/radio_group.rb +54 -0
  48. data/lib/shoes/swt/rect.rb +30 -0
  49. data/lib/shoes/swt/rect_painter.rb +23 -0
  50. data/lib/shoes/swt/redrawing_aspect.rb +123 -0
  51. data/lib/shoes/swt/shape.rb +133 -0
  52. data/lib/shoes/swt/shoes_layout.rb +43 -0
  53. data/lib/shoes/swt/slot.rb +39 -0
  54. data/lib/shoes/swt/sound.rb +119 -0
  55. data/lib/shoes/swt/star.rb +50 -0
  56. data/lib/shoes/swt/support/jl1.0.1.jar +0 -0
  57. data/lib/shoes/swt/support/jogg-0.0.7.jar +0 -0
  58. data/lib/shoes/swt/support/jorbis-0.0.15.jar +0 -0
  59. data/lib/shoes/swt/support/log4j-1.2.16.jar +0 -0
  60. data/lib/shoes/swt/support/mp3spi1.9.5.jar +0 -0
  61. data/lib/shoes/swt/support/tritonus_share.jar +0 -0
  62. data/lib/shoes/swt/support/vorbisspi1.0.3.jar +0 -0
  63. data/lib/shoes/swt/swt_button.rb +56 -0
  64. data/lib/shoes/swt/text_block.rb +124 -0
  65. data/lib/shoes/swt/text_block/centered_text_segment.rb +22 -0
  66. data/lib/shoes/swt/text_block/cursor_painter.rb +53 -0
  67. data/lib/shoes/swt/text_block/fitter.rb +212 -0
  68. data/lib/shoes/swt/text_block/painter.rb +47 -0
  69. data/lib/shoes/swt/text_block/text_font_factory.rb +50 -0
  70. data/lib/shoes/swt/text_block/text_segment.rb +108 -0
  71. data/lib/shoes/swt/text_block/text_segment_collection.rb +160 -0
  72. data/lib/shoes/swt/text_block/text_style_factory.rb +88 -0
  73. data/lib/shoes/swt/timer.rb +19 -0
  74. data/lib/shoes/swt/tooling/leak_hunter.rb +35 -0
  75. data/lib/shoes/swt/version.rb +5 -0
  76. data/manifests/common.rb +34 -0
  77. data/manifests/shoes-swt.rb +29 -0
  78. data/shoes-swt.gemspec +24 -0
  79. data/spec/code_coverage.rb +14 -0
  80. data/spec/shoes/animation_spec.rb +65 -0
  81. data/spec/shoes/app_spec.rb +484 -0
  82. data/spec/shoes/arc_spec.rb +51 -0
  83. data/spec/shoes/background_spec.rb +53 -0
  84. data/spec/shoes/border_spec.rb +47 -0
  85. data/spec/shoes/builtin_methods_spec.rb +110 -0
  86. data/spec/shoes/button_spec.rb +44 -0
  87. data/spec/shoes/check_spec.rb +35 -0
  88. data/spec/shoes/cli_spec.rb +15 -0
  89. data/spec/shoes/color_spec.rb +408 -0
  90. data/spec/shoes/common/inspect_spec.rb +26 -0
  91. data/spec/shoes/common/remove_spec.rb +38 -0
  92. data/spec/shoes/common/style_normalizer_spec.rb +28 -0
  93. data/spec/shoes/common/style_spec.rb +147 -0
  94. data/spec/shoes/configuration_spec.rb +36 -0
  95. data/spec/shoes/constants_spec.rb +38 -0
  96. data/spec/shoes/dialog_spec.rb +163 -0
  97. data/spec/shoes/dimension_spec.rb +407 -0
  98. data/spec/shoes/dimensions_spec.rb +837 -0
  99. data/spec/shoes/download_spec.rb +142 -0
  100. data/spec/shoes/flow_spec.rb +133 -0
  101. data/spec/shoes/font_spec.rb +37 -0
  102. data/spec/shoes/framework_learning_spec.rb +30 -0
  103. data/spec/shoes/gradient_spec.rb +32 -0
  104. data/spec/shoes/helpers/fake_element.rb +17 -0
  105. data/spec/shoes/helpers/inspect_helpers.rb +5 -0
  106. data/spec/shoes/helpers/sample17_helper.rb +66 -0
  107. data/spec/shoes/image_spec.rb +49 -0
  108. data/spec/shoes/images/shoe.jpg +0 -0
  109. data/spec/shoes/input_box_spec.rb +80 -0
  110. data/spec/shoes/integration_spec.rb +20 -0
  111. data/spec/shoes/internal_app_spec.rb +141 -0
  112. data/spec/shoes/keypress_spec.rb +11 -0
  113. data/spec/shoes/keyrelease_spec.rb +12 -0
  114. data/spec/shoes/line_spec.rb +49 -0
  115. data/spec/shoes/link_spec.rb +105 -0
  116. data/spec/shoes/list_box_spec.rb +74 -0
  117. data/spec/shoes/logger/ruby_spec.rb +8 -0
  118. data/spec/shoes/logger_spec.rb +45 -0
  119. data/spec/shoes/oval_spec.rb +24 -0
  120. data/spec/shoes/point_spec.rb +71 -0
  121. data/spec/shoes/progress_spec.rb +54 -0
  122. data/spec/shoes/radio_spec.rb +32 -0
  123. data/spec/shoes/rect_spec.rb +39 -0
  124. data/spec/shoes/renamed_delegate_spec.rb +70 -0
  125. data/spec/shoes/shape_spec.rb +95 -0
  126. data/spec/shoes/shared_examples/button.rb +6 -0
  127. data/spec/shoes/shared_examples/changeable.rb +26 -0
  128. data/spec/shoes/shared_examples/clickable.rb +5 -0
  129. data/spec/shoes/shared_examples/common_methods.rb +35 -0
  130. data/spec/shoes/shared_examples/dimensions.rb +32 -0
  131. data/spec/shoes/shared_examples/dsl.rb +44 -0
  132. data/spec/shoes/shared_examples/dsl/animate.rb +29 -0
  133. data/spec/shoes/shared_examples/dsl/arc.rb +45 -0
  134. data/spec/shoes/shared_examples/dsl/background.rb +26 -0
  135. data/spec/shoes/shared_examples/dsl/border.rb +10 -0
  136. data/spec/shoes/shared_examples/dsl/button.rb +5 -0
  137. data/spec/shoes/shared_examples/dsl/cap.rb +6 -0
  138. data/spec/shoes/shared_examples/dsl/check.rb +11 -0
  139. data/spec/shoes/shared_examples/dsl/edit_box.rb +8 -0
  140. data/spec/shoes/shared_examples/dsl/edit_line.rb +8 -0
  141. data/spec/shoes/shared_examples/dsl/editable_element.rb +29 -0
  142. data/spec/shoes/shared_examples/dsl/fill.rb +27 -0
  143. data/spec/shoes/shared_examples/dsl/flow.rb +15 -0
  144. data/spec/shoes/shared_examples/dsl/gradient.rb +62 -0
  145. data/spec/shoes/shared_examples/dsl/image.rb +21 -0
  146. data/spec/shoes/shared_examples/dsl/line.rb +9 -0
  147. data/spec/shoes/shared_examples/dsl/nofill.rb +6 -0
  148. data/spec/shoes/shared_examples/dsl/nostroke.rb +6 -0
  149. data/spec/shoes/shared_examples/dsl/oval.rb +88 -0
  150. data/spec/shoes/shared_examples/dsl/pattern.rb +34 -0
  151. data/spec/shoes/shared_examples/dsl/progress.rb +7 -0
  152. data/spec/shoes/shared_examples/dsl/rect.rb +92 -0
  153. data/spec/shoes/shared_examples/dsl/rgb.rb +26 -0
  154. data/spec/shoes/shared_examples/dsl/shape.rb +21 -0
  155. data/spec/shoes/shared_examples/dsl/star.rb +48 -0
  156. data/spec/shoes/shared_examples/dsl/stroke.rb +30 -0
  157. data/spec/shoes/shared_examples/dsl/strokewidth.rb +19 -0
  158. data/spec/shoes/shared_examples/dsl/style.rb +32 -0
  159. data/spec/shoes/shared_examples/dsl/text_elements.rb +81 -0
  160. data/spec/shoes/shared_examples/dsl/video.rb +5 -0
  161. data/spec/shoes/shared_examples/dsl_app_context.rb +8 -0
  162. data/spec/shoes/shared_examples/hover_leave.rb +11 -0
  163. data/spec/shoes/shared_examples/parent.rb +6 -0
  164. data/spec/shoes/shared_examples/scroll.rb +41 -0
  165. data/spec/shoes/shared_examples/shared_element_method.rb +60 -0
  166. data/spec/shoes/shared_examples/slot.rb +331 -0
  167. data/spec/shoes/shared_examples/state.rb +19 -0
  168. data/spec/shoes/shared_examples/style.rb +82 -0
  169. data/spec/shoes/slot_spec.rb +130 -0
  170. data/spec/shoes/sound_spec.rb +15 -0
  171. data/spec/shoes/span_spec.rb +112 -0
  172. data/spec/shoes/spec_helper.rb +24 -0
  173. data/spec/shoes/stack_spec.rb +79 -0
  174. data/spec/shoes/star_spec.rb +31 -0
  175. data/spec/shoes/text_block_dimensions_spec.rb +75 -0
  176. data/spec/shoes/text_block_spec.rb +270 -0
  177. data/spec/shoes/url_spec.rb +68 -0
  178. data/spec/shoes/widget_spec.rb +70 -0
  179. data/spec/shoes_spec.rb +44 -0
  180. data/spec/spec_helper.rb +18 -0
  181. data/spec/swt_shoes/animation_spec.rb +86 -0
  182. data/spec/swt_shoes/app_spec.rb +84 -0
  183. data/spec/swt_shoes/arc_spec.rb +103 -0
  184. data/spec/swt_shoes/background_spec.rb +67 -0
  185. data/spec/swt_shoes/border_spec.rb +52 -0
  186. data/spec/swt_shoes/button_spec.rb +101 -0
  187. data/spec/swt_shoes/check_spec.rb +28 -0
  188. data/spec/swt_shoes/color_factory_spec.rb +49 -0
  189. data/spec/swt_shoes/color_spec.rb +67 -0
  190. data/spec/swt_shoes/common/painter_spec.rb +49 -0
  191. data/spec/swt_shoes/common/remove_spec.rb +53 -0
  192. data/spec/swt_shoes/configuration_spec.rb +12 -0
  193. data/spec/swt_shoes/dialog_spec.rb +106 -0
  194. data/spec/swt_shoes/disposed_protection_spec.rb +49 -0
  195. data/spec/swt_shoes/flow_spec.rb +36 -0
  196. data/spec/swt_shoes/font_spec.rb +33 -0
  197. data/spec/swt_shoes/gradient_spec.rb +31 -0
  198. data/spec/swt_shoes/image_pattern_spec.rb +35 -0
  199. data/spec/swt_shoes/image_spec.rb +100 -0
  200. data/spec/swt_shoes/input_box_spec.rb +116 -0
  201. data/spec/swt_shoes/integration_spec.rb +27 -0
  202. data/spec/swt_shoes/key_listener_spec.rb +325 -0
  203. data/spec/swt_shoes/line_spec.rb +49 -0
  204. data/spec/swt_shoes/link_segment_spec.rb +120 -0
  205. data/spec/swt_shoes/link_spec.rb +54 -0
  206. data/spec/swt_shoes/list_box_spec.rb +56 -0
  207. data/spec/swt_shoes/minimal.png +0 -0
  208. data/spec/swt_shoes/mouse_move_listener_spec.rb +123 -0
  209. data/spec/swt_shoes/oval_spec.rb +51 -0
  210. data/spec/swt_shoes/progress_spec.rb +44 -0
  211. data/spec/swt_shoes/radio_group_spec.rb +73 -0
  212. data/spec/swt_shoes/radio_spec.rb +56 -0
  213. data/spec/swt_shoes/rect_painter_spec.rb +45 -0
  214. data/spec/swt_shoes/rect_spec.rb +19 -0
  215. data/spec/swt_shoes/shape_spec.rb +84 -0
  216. data/spec/swt_shoes/shared_examples/button.rb +21 -0
  217. data/spec/swt_shoes/shared_examples/clickable.rb +85 -0
  218. data/spec/swt_shoes/shared_examples/movable.rb +36 -0
  219. data/spec/swt_shoes/shared_examples/paintable.rb +7 -0
  220. data/spec/swt_shoes/shared_examples/painter.rb +83 -0
  221. data/spec/swt_shoes/shared_examples/pattern.rb +32 -0
  222. data/spec/swt_shoes/shared_examples/removable.rb +41 -0
  223. data/spec/swt_shoes/shared_examples/swt_app_context.rb +23 -0
  224. data/spec/swt_shoes/shared_examples/visibility.rb +15 -0
  225. data/spec/swt_shoes/shell_control_listener_spec.rb +23 -0
  226. data/spec/swt_shoes/slot_spec.rb +24 -0
  227. data/spec/swt_shoes/sound.rb +10 -0
  228. data/spec/swt_shoes/spec_helper.rb +31 -0
  229. data/spec/swt_shoes/star_spec.rb +47 -0
  230. data/spec/swt_shoes/text_block/centered_text_segment_spec.rb +16 -0
  231. data/spec/swt_shoes/text_block/cursor_painter_spec.rb +120 -0
  232. data/spec/swt_shoes/text_block/fitter_spec.rb +213 -0
  233. data/spec/swt_shoes/text_block/painter_spec.rb +212 -0
  234. data/spec/swt_shoes/text_block/text_font_factory_spec.rb +40 -0
  235. data/spec/swt_shoes/text_block/text_segment_collection_spec.rb +256 -0
  236. data/spec/swt_shoes/text_block/text_segment_spec.rb +135 -0
  237. data/spec/swt_shoes/text_block_spec.rb +199 -0
  238. metadata +496 -0
@@ -0,0 +1,124 @@
1
+ class Shoes
2
+ module Swt
3
+ class TextBlock
4
+ include Common::Remove
5
+ include Common::Visibility
6
+ include Common::Clickable
7
+ include ::Shoes::BackendDimensionsDelegations
8
+
9
+ DEFAULT_SPACING = 4
10
+
11
+ attr_reader :dsl, :app
12
+ attr_accessor :segments
13
+
14
+ def initialize(dsl, app)
15
+ @dsl = dsl
16
+ @app = app
17
+ @segments = []
18
+ @painter = Painter.new @dsl
19
+ @app.add_paint_listener @painter
20
+ end
21
+
22
+ def dispose
23
+ dispose_existing_segments
24
+ end
25
+
26
+ # has a painter, nothing to do
27
+ def update_position
28
+ end
29
+
30
+ def in_bounds?(x, y)
31
+ segments.any? do |segment|
32
+ segment.in_bounds?(x, y)
33
+ end
34
+ end
35
+
36
+ def contents_alignment(current_position)
37
+ dispose_existing_segments
38
+ @segments = Fitter.new(self, current_position).fit_it_in
39
+
40
+ set_absolutes_on_dsl(current_position)
41
+ set_calculated_sizes
42
+ end
43
+
44
+ def adjust_current_position(current_position)
45
+ last_segment = segments.last
46
+ current_position.y = @dsl.absolute_bottom
47
+ current_position.y -= last_segment.last_line_height unless @bumped_to_next_line
48
+ end
49
+
50
+ def set_absolutes_on_dsl(current_position)
51
+ if segments.one?
52
+ set_absolutes(@dsl.absolute_left, @dsl.absolute_top)
53
+ else
54
+ set_absolutes(@dsl.parent.absolute_left, current_position.next_line_start)
55
+ end
56
+
57
+ if trailing_newline?
58
+ bump_absolutes_to_next_line
59
+ else
60
+ @bumped_to_next_line = false
61
+ end
62
+ end
63
+
64
+ def set_absolutes(starting_left, starting_top)
65
+ last_segment = segments.last
66
+
67
+ @dsl.absolute_right = starting_left + last_segment.last_line_width +
68
+ margin_right
69
+
70
+ @dsl.absolute_bottom = starting_top + last_segment.height +
71
+ margin_top + margin_bottom
72
+ end
73
+
74
+ def bump_absolutes_to_next_line
75
+ @dsl.absolute_right = @dsl.parent.absolute_left
76
+ @bumped_to_next_line = true
77
+ end
78
+
79
+ def set_calculated_sizes
80
+ @dsl.calculated_width = segments.last.width
81
+ @dsl.calculated_height = segments.inject(0) do |total, segment|
82
+ total += segment.bounds.height
83
+ end
84
+ end
85
+
86
+ def remove
87
+ super
88
+ clear_contents
89
+ end
90
+
91
+ def replace(*_)
92
+ clear_contents
93
+ end
94
+
95
+ private
96
+
97
+ def clear_contents
98
+ dispose_existing_segments
99
+ clear_links
100
+ end
101
+
102
+ def clear_links
103
+ @dsl.links.each(&:remove)
104
+ end
105
+
106
+ def dispose_existing_segments
107
+ @segments.map(&:dispose)
108
+ @segments.clear
109
+ end
110
+
111
+ def trailing_newline?
112
+ @dsl.text.end_with?("\n")
113
+ end
114
+ end
115
+
116
+ class Banner < TextBlock; end
117
+ class Title < TextBlock; end
118
+ class Subtitle < TextBlock; end
119
+ class Tagline < TextBlock; end
120
+ class Caption < TextBlock; end
121
+ class Para < TextBlock; end
122
+ class Inscription < TextBlock; end
123
+ end
124
+ end
@@ -0,0 +1,22 @@
1
+ class Shoes
2
+ module Swt
3
+ class TextBlock
4
+ # Presently centering always takes the whole line, so this class easily
5
+ # allows us to keep those alternate overrides separate from the main
6
+ # flowing text definitions for a segment.
7
+ class CenteredTextSegment < TextSegment
8
+ def initialize(dsl, width)
9
+ super(dsl, dsl.text, width)
10
+
11
+ # Centered text always takes all the width it's given
12
+ layout.width = width
13
+ end
14
+
15
+ # Overrides to not allow for flowing on final line--whole width only
16
+ def last_line_width
17
+ layout.width
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,53 @@
1
+ class Shoes
2
+ module Swt
3
+ class TextBlock
4
+ class CursorPainter
5
+ def initialize(text_block_dsl, collection)
6
+ @text_block_dsl = text_block_dsl
7
+ @collection = collection
8
+ end
9
+
10
+ def draw
11
+ if @text_block_dsl.cursor
12
+ draw_textcursor
13
+ else
14
+ remove_textcursor
15
+ end
16
+ end
17
+
18
+ def draw_textcursor
19
+ segment = @collection.segment_at_text_position(@text_block_dsl.cursor)
20
+ relative_cursor = @collection.relative_text_position(@text_block_dsl.cursor)
21
+ position = segment.get_location(relative_cursor)
22
+
23
+ move_if_necessary(segment.element_left + position.x,
24
+ segment.element_top + position.y)
25
+
26
+ end
27
+
28
+ # It's important to only move when necessary to avoid constant redraws
29
+ def move_if_necessary(x, y)
30
+ unless textcursor.left == x && textcursor.top == y
31
+ move_textcursor(x, y)
32
+ end
33
+ end
34
+
35
+ def move_textcursor(x, y)
36
+ textcursor.move(x, y)
37
+ textcursor.show
38
+ end
39
+
40
+ def textcursor
41
+ @text_block_dsl.textcursor @collection.cursor_height
42
+ end
43
+
44
+ def remove_textcursor
45
+ return unless @text_block_dsl.has_textcursor?
46
+
47
+ @text_block_dsl.textcursor.remove
48
+ @text_block_dsl.textcursor = nil
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,212 @@
1
+ class Shoes
2
+ module Swt
3
+ class TextBlock
4
+ class Fitter
5
+ attr_reader :parent
6
+
7
+ def initialize(text_block, current_position)
8
+ @text_block = text_block
9
+ @dsl = @text_block.dsl
10
+ @parent = @dsl.parent
11
+ @current_position = current_position
12
+ end
13
+
14
+ # Fitting text works by using either 1 or 2 layouts
15
+ #
16
+ # If the text fits in the height and width available, we use one layout.
17
+ #
18
+ # --------------------------
19
+ # | button | text layout 1 |
20
+ # --------------------------
21
+ #
22
+ # If if the text doesn't fit into that space, then we'll break it into
23
+ # two different layouts.
24
+ #
25
+ # --------------------------
26
+ # | button | text layout 1 |
27
+ # --------------------------
28
+ # | text layout 2 goes here|
29
+ # | in space |
30
+ # --------------------------
31
+ # ^
32
+ #
33
+ # If there wasn't any available space in the first layout (very narrow)
34
+ # then we'll make an empty first layout and flow to the second:
35
+ #
36
+ # --------------------------
37
+ # | big big big big button|| < empty layout 1 still present
38
+ # --------------------------
39
+ # | text layout 2 goes here|
40
+ # | in space |
41
+ # --------------------------
42
+ # ^
43
+ #
44
+ # When flowing, the position for the next element gets set to the end of
45
+ # the text in the second layout (shown as ^ in the diagram).
46
+ #
47
+ # Stacks properly move to the next whole line as you'd expect.
48
+ #
49
+ def fit_it_in
50
+ width, height = available_space
51
+ if @dsl.centered?
52
+ fit_as_centered(width, height)
53
+ elsif no_space_in_first_layout?(width)
54
+ fit_as_empty_first_layout(height)
55
+ else
56
+ fit_into_full_layouts(width, height)
57
+ end
58
+ end
59
+
60
+ def no_space_in_first_layout?(width)
61
+ width <= 0
62
+ end
63
+
64
+ def fits_in_one_layout?(layout, height)
65
+ return true if height == :unbounded || layout.line_count == 1
66
+ layout.bounds.height <= height
67
+ end
68
+
69
+ def fit_into_full_layouts(width, height)
70
+ layout = generate_layout(width, @dsl.text)
71
+ if fits_in_one_layout?(layout, height)
72
+ fit_as_one_layout(layout)
73
+ else
74
+ fit_as_two_layouts(layout, height, width)
75
+ end
76
+ end
77
+
78
+ def fit_as_one_layout(layout)
79
+ [layout.position_at(@dsl.element_left, @dsl.element_top)]
80
+ end
81
+
82
+ def fit_as_two_layouts(layout, height, width)
83
+ first_text, second_text = split_text(layout, height)
84
+
85
+ # Since we regenerate layouts, we must dispose of first try here.
86
+ layout.dispose
87
+ layout = nil
88
+
89
+ first_layout = generate_layout(width, first_text)
90
+
91
+ if second_text.empty?
92
+ fit_as_one_layout(first_layout)
93
+ else
94
+ generate_two_layouts(first_layout, first_text, second_text, height)
95
+ end
96
+ end
97
+
98
+ def fit_as_empty_first_layout(height)
99
+ height += ::Shoes::Slot::NEXT_ELEMENT_OFFSET
100
+ generate_two_layouts(empty_segment, "", @dsl.text, height)
101
+ end
102
+
103
+ def fit_as_centered(width, height)
104
+ if first_element_on_line?
105
+ segment = CenteredTextSegment.new(@dsl, width)
106
+ [segment.position_at(@dsl.element_left, @dsl.element_top)]
107
+ else
108
+ position_two_segments(
109
+ empty_segment,
110
+ CenteredTextSegment.new(@dsl, @dsl.containing_width),
111
+ "",
112
+ height)
113
+ end
114
+ end
115
+
116
+ def first_element_on_line?
117
+ @dsl.left - @dsl.margin_left <= 0
118
+ end
119
+
120
+ def generate_two_layouts(first_layout, first_text, second_text, height)
121
+ second_layout = generate_second_layout(second_text)
122
+ position_two_segments(first_layout, second_layout, first_text, height)
123
+ end
124
+
125
+ def generate_second_layout(second_text)
126
+ generate_layout(@dsl.containing_width, second_text)
127
+ end
128
+
129
+ def position_two_segments(first_layout, second_layout, first_text, height)
130
+ first_height = first_height(first_layout, first_text, height)
131
+
132
+ [
133
+ first_layout.position_at(@dsl.element_left,
134
+ @dsl.element_top),
135
+ second_layout.position_at(parent.absolute_left + @dsl.margin_left,
136
+ @dsl.element_top + first_height + 1)
137
+ ]
138
+ end
139
+
140
+ def available_space
141
+ width = @dsl.desired_width
142
+ height = next_line_start - @dsl.absolute_top - 1
143
+
144
+ if on_new_line?
145
+ height = :unbounded
146
+
147
+ # Try to find a parent container we fit in.
148
+ # If that doesn't work, just bail with [0,0] so we don't crash.
149
+ width = width_from_ancestor if width <= 0
150
+ return [0, 0] if width < 0
151
+ end
152
+
153
+ [width, height]
154
+ end
155
+
156
+ # If we're positioned outside our containing width, look up the parent
157
+ # chain until we find a width that accomodates us.
158
+ def width_from_ancestor
159
+ width = -1
160
+ current_ancestor = @dsl.parent
161
+ until width > 0 || current_ancestor.nil?
162
+ width = @dsl.desired_width(current_ancestor.width)
163
+
164
+ break unless current_ancestor.respond_to?(:parent)
165
+ current_ancestor = current_ancestor.parent
166
+ end
167
+ width
168
+ end
169
+
170
+ def next_line_start
171
+ @current_position.next_line_start
172
+ end
173
+
174
+ def on_new_line?
175
+ next_line_start <= @dsl.absolute_top
176
+ end
177
+
178
+ def generate_layout(width, text)
179
+ TextSegment.new(@dsl, text, width)
180
+ end
181
+
182
+ def empty_segment
183
+ segment = generate_layout(1, @dsl.text)
184
+ segment.text = ""
185
+ segment
186
+ end
187
+
188
+ def split_text(layout, height)
189
+ ending_offset = 0
190
+ height_so_far = 0
191
+
192
+ offsets = layout.line_offsets
193
+ offsets[0...-1].each_with_index do |_, i|
194
+ height_so_far += layout.line_bounds(i).height
195
+ break if height_so_far > height
196
+
197
+ ending_offset = offsets[i+1]
198
+ end
199
+ [layout.text[0...ending_offset], layout.text[ending_offset..-1]]
200
+ end
201
+
202
+ # If first text is empty, height may be smaller than an actual line in
203
+ # the current font. Take our pre-existing allowed height instead.
204
+ def first_height(first_layout, first_text, height)
205
+ first_height = first_layout.bounds.height - first_layout.spacing
206
+ first_height = height if first_text.empty? && height != :unbounded
207
+ first_height
208
+ end
209
+ end
210
+ end
211
+ end
212
+ end
@@ -0,0 +1,47 @@
1
+ class Shoes
2
+ module Swt
3
+ class TextBlock
4
+ class Painter
5
+ include ::Swt::Events::PaintListener
6
+ include Common::Resource
7
+
8
+ attr_reader :app
9
+ def initialize(dsl)
10
+ @dsl = dsl
11
+ @style = @dsl.style
12
+ @app = @dsl.app.gui
13
+ end
14
+
15
+ def paintControl(paint_event)
16
+ reset_graphics_context(paint_event.gc)
17
+ return if @dsl.hidden?
18
+
19
+ draw_layouts(paint_event.gc)
20
+ end
21
+
22
+ def draw_layouts(graphic_context)
23
+ layouts = TextSegmentCollection.new(@dsl,
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
+ }
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end