thinreports 0.10.0 → 0.12.0

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 (191) hide show
  1. checksums.yaml +5 -5
  2. data/.github/CONTRIBUTING.md +2 -2
  3. data/.github/workflows/test.yml +51 -0
  4. data/.gitignore +1 -0
  5. data/CHANGELOG.md +49 -0
  6. data/Dockerfile +12 -0
  7. data/Gemfile +2 -1
  8. data/README.md +46 -21
  9. data/Rakefile +13 -29
  10. data/gemfiles/prawn-2.2.gemfile +5 -0
  11. data/gemfiles/prawn-2.3.gemfile +5 -0
  12. data/gemfiles/prawn-2.4.gemfile +5 -0
  13. data/lib/thinreports.rb +5 -0
  14. data/lib/thinreports/core/shape.rb +4 -3
  15. data/lib/thinreports/core/shape/base/interface.rb +0 -1
  16. data/lib/thinreports/core/shape/basic/format.rb +5 -0
  17. data/lib/thinreports/core/shape/image_block.rb +1 -1
  18. data/lib/thinreports/core/shape/list.rb +1 -1
  19. data/lib/thinreports/core/shape/list/manager.rb +1 -4
  20. data/lib/thinreports/core/shape/list/page.rb +2 -5
  21. data/lib/thinreports/core/shape/manager/internal.rb +0 -1
  22. data/lib/thinreports/core/shape/page_number.rb +1 -1
  23. data/lib/thinreports/core/shape/page_number/internal.rb +0 -1
  24. data/lib/thinreports/core/shape/stack_view.rb +17 -0
  25. data/lib/thinreports/core/shape/stack_view/format.rb +27 -0
  26. data/lib/thinreports/core/shape/stack_view/interface.rb +17 -0
  27. data/lib/thinreports/core/shape/stack_view/internal.rb +22 -0
  28. data/lib/thinreports/core/shape/stack_view/row_format.rb +39 -0
  29. data/lib/thinreports/core/shape/style/basic.rb +4 -1
  30. data/lib/thinreports/core/shape/text.rb +1 -1
  31. data/lib/thinreports/core/shape/text_block.rb +1 -1
  32. data/lib/thinreports/core/shape/text_block/formatter/number.rb +21 -9
  33. data/lib/thinreports/core/shape/text_block/internal.rb +0 -2
  34. data/lib/thinreports/core/utils.rb +6 -3
  35. data/lib/thinreports/generate.rb +11 -0
  36. data/lib/thinreports/generator/pdf/document/draw_shape.rb +31 -11
  37. data/lib/thinreports/generator/pdf/document/draw_template_items.rb +1 -2
  38. data/lib/thinreports/generator/pdf/document/font.rb +16 -10
  39. data/lib/thinreports/generator/pdf/document/graphics/attributes.rb +0 -1
  40. data/lib/thinreports/generator/pdf/document/graphics/basic.rb +0 -1
  41. data/lib/thinreports/generator/pdf/document/graphics/image.rb +19 -1
  42. data/lib/thinreports/generator/pdf/document/graphics/text.rb +10 -8
  43. data/lib/thinreports/generator/pdf/document/page.rb +13 -4
  44. data/lib/thinreports/generator/pdf/drawer/list.rb +0 -1
  45. data/lib/thinreports/generator/pdf/prawn_ext/calc_image_dimensions.rb +1 -3
  46. data/lib/thinreports/generator/pdf/prawn_ext/width_of.rb +7 -7
  47. data/lib/thinreports/layout/base.rb +2 -4
  48. data/lib/thinreports/layout/format.rb +0 -1
  49. data/lib/thinreports/layout/legacy_schema.rb +2 -6
  50. data/lib/thinreports/layout/version.rb +1 -1
  51. data/lib/thinreports/report/internal.rb +4 -4
  52. data/lib/thinreports/report/page.rb +2 -7
  53. data/lib/thinreports/section_report/build.rb +32 -0
  54. data/lib/thinreports/section_report/builder/item_builder.rb +49 -0
  55. data/lib/thinreports/section_report/builder/report_builder.rb +82 -0
  56. data/lib/thinreports/section_report/builder/report_data.rb +13 -0
  57. data/lib/thinreports/section_report/builder/stack_view_builder.rb +55 -0
  58. data/lib/thinreports/section_report/builder/stack_view_data.rb +11 -0
  59. data/lib/thinreports/section_report/generate.rb +26 -0
  60. data/lib/thinreports/section_report/pdf/render.rb +23 -0
  61. data/lib/thinreports/section_report/pdf/renderer/draw_item.rb +68 -0
  62. data/lib/thinreports/section_report/pdf/renderer/group_renderer.rb +57 -0
  63. data/lib/thinreports/section_report/pdf/renderer/headers_renderer.rb +24 -0
  64. data/lib/thinreports/section_report/pdf/renderer/section_height.rb +100 -0
  65. data/lib/thinreports/section_report/pdf/renderer/section_renderer.rb +39 -0
  66. data/lib/thinreports/section_report/pdf/renderer/stack_view_renderer.rb +55 -0
  67. data/lib/thinreports/section_report/pdf/renderer/stack_view_row_renderer.rb +38 -0
  68. data/lib/thinreports/section_report/schema/loader.rb +28 -0
  69. data/lib/thinreports/section_report/schema/parser.rb +52 -0
  70. data/lib/thinreports/section_report/schema/report.rb +30 -0
  71. data/lib/thinreports/section_report/schema/section.rb +47 -0
  72. data/lib/thinreports/version.rb +1 -1
  73. data/thinreports.gemspec +11 -11
  74. metadata +48 -164
  75. data/.rubocop.yml +0 -41
  76. data/.travis.yml +0 -17
  77. data/examples/character_spacing/character_spacing.rb +0 -8
  78. data/examples/character_spacing/character_spacing.tlf +0 -293
  79. data/examples/dynamic_image/dynamic_image.rb +0 -31
  80. data/examples/dynamic_image/dynamic_image.tlf +0 -661
  81. data/examples/dynamic_image/img200x100.png +0 -0
  82. data/examples/dynamic_image/img50x50.png +0 -0
  83. data/examples/dynamic_style/dynamic_style.rb +0 -150
  84. data/examples/dynamic_style/dynamic_style.tlf +0 -1835
  85. data/examples/dynamic_style/dynamic_style_in_list.tlf +0 -344
  86. data/examples/dynamic_style/image.png +0 -0
  87. data/examples/eudc/eudc.rb +0 -20
  88. data/examples/eudc/eudc.tlf +0 -180
  89. data/examples/eudc/eudc.ttf +0 -0
  90. data/examples/helper.rb +0 -50
  91. data/examples/hidden_shapes/hidden_shapes.rb +0 -9
  92. data/examples/hidden_shapes/hidden_shapes.tlf +0 -449
  93. data/examples/list_events/list_events.rb +0 -32
  94. data/examples/list_events/list_events.tlf +0 -361
  95. data/examples/list_manual_generation/list_manual_generation.rb +0 -22
  96. data/examples/list_manual_generation/list_manual_generation.tlf +0 -132
  97. data/examples/list_page_number/list_page_number.rb +0 -17
  98. data/examples/list_page_number/list_page_number.tlf +0 -254
  99. data/examples/page_number/page_number.rb +0 -33
  100. data/examples/page_number/page_number.tlf +0 -215
  101. data/examples/palleted_png/palleted_png.png +0 -0
  102. data/examples/palleted_png/palleted_png.rb +0 -9
  103. data/examples/palleted_png/palleted_png.tlf +0 -47
  104. data/examples/password_setting/password_setting.rb +0 -10
  105. data/examples/password_setting/password_setting.tlf +0 -45
  106. data/examples/report_callbacks/report_callbacks.rb +0 -14
  107. data/examples/report_callbacks/report_callbacks.tlf +0 -147
  108. data/examples/single_line_tblock/single_line_tblock.rb +0 -13
  109. data/examples/single_line_tblock/single_line_tblock.tlf +0 -170
  110. data/examples/tblock_overflow/tblock_overflow.rb +0 -20
  111. data/examples/tblock_overflow/tblock_overflow.tlf +0 -538
  112. data/examples/tblock_styles/font_size.tlf +0 -383
  113. data/examples/tblock_styles/tblock_styles.rb +0 -43
  114. data/examples/tblock_styles/tblock_styles.tlf +0 -889
  115. data/examples/text_align/text_align.rb +0 -8
  116. data/examples/text_align/text_align.tlf +0 -241
  117. data/examples/typeB_page_size/B4_ISO.tlf +0 -45
  118. data/examples/typeB_page_size/B4_JIS.tlf +0 -45
  119. data/examples/typeB_page_size/typeB_page_size.rb +0 -17
  120. data/examples/word_wrap/word_wrap.rb +0 -26
  121. data/examples/word_wrap/word_wrap.tlf +0 -297
  122. data/test/data/font.ttf +0 -0
  123. data/test/data/image_normal.jpg +0 -0
  124. data/test/data/image_normal.png +0 -0
  125. data/test/data/image_normal_jpg_noext +0 -0
  126. data/test/data/image_normal_png_noext +0 -0
  127. data/test/data/image_pallete_based.png +0 -0
  128. data/test/data/legacy_layout/all-items.tlf +0 -1
  129. data/test/schema_helper.rb +0 -122
  130. data/test/test_helper.rb +0 -48
  131. data/test/tmp/.gitkeep +0 -0
  132. data/test/unit/core/format/test_base.rb +0 -152
  133. data/test/unit/core/shape/base/test_internal.rb +0 -87
  134. data/test/unit/core/shape/basic/test_block_format.rb +0 -23
  135. data/test/unit/core/shape/basic/test_block_interface.rb +0 -29
  136. data/test/unit/core/shape/basic/test_block_internal.rb +0 -55
  137. data/test/unit/core/shape/basic/test_format.rb +0 -37
  138. data/test/unit/core/shape/basic/test_interface.rb +0 -108
  139. data/test/unit/core/shape/basic/test_internal.rb +0 -55
  140. data/test/unit/core/shape/image_block/test_interface.rb +0 -24
  141. data/test/unit/core/shape/image_block/test_internal.rb +0 -31
  142. data/test/unit/core/shape/list/test_format.rb +0 -111
  143. data/test/unit/core/shape/list/test_manager.rb +0 -67
  144. data/test/unit/core/shape/list/test_page.rb +0 -82
  145. data/test/unit/core/shape/list/test_page_state.rb +0 -31
  146. data/test/unit/core/shape/list/test_section_format.rb +0 -36
  147. data/test/unit/core/shape/list/test_section_interface.rb +0 -75
  148. data/test/unit/core/shape/list/test_section_internal.rb +0 -50
  149. data/test/unit/core/shape/manager/test_format.rb +0 -38
  150. data/test/unit/core/shape/manager/test_internal.rb +0 -132
  151. data/test/unit/core/shape/manager/test_target.rb +0 -140
  152. data/test/unit/core/shape/page_number/test_format.rb +0 -55
  153. data/test/unit/core/shape/page_number/test_interface.rb +0 -33
  154. data/test/unit/core/shape/page_number/test_internal.rb +0 -81
  155. data/test/unit/core/shape/styles/test_base.rb +0 -191
  156. data/test/unit/core/shape/styles/test_basic.rb +0 -24
  157. data/test/unit/core/shape/styles/test_graphic.rb +0 -50
  158. data/test/unit/core/shape/styles/test_text.rb +0 -97
  159. data/test/unit/core/shape/text/test_format.rb +0 -44
  160. data/test/unit/core/shape/text/test_internal.rb +0 -20
  161. data/test/unit/core/shape/text_block/formatter/test_basic.rb +0 -24
  162. data/test/unit/core/shape/text_block/formatter/test_datetime.rb +0 -49
  163. data/test/unit/core/shape/text_block/formatter/test_number.rb +0 -76
  164. data/test/unit/core/shape/text_block/formatter/test_padding.rb +0 -77
  165. data/test/unit/core/shape/text_block/test_format.rb +0 -169
  166. data/test/unit/core/shape/text_block/test_formatter.rb +0 -28
  167. data/test/unit/core/shape/text_block/test_interface.rb +0 -63
  168. data/test/unit/core/shape/text_block/test_internal.rb +0 -128
  169. data/test/unit/core/test_shape.rb +0 -52
  170. data/test/unit/core/test_utils.rb +0 -68
  171. data/test/unit/generator/pdf/document/graphics/test_attributes.rb +0 -135
  172. data/test/unit/generator/pdf/document/graphics/test_basic.rb +0 -46
  173. data/test/unit/generator/pdf/document/graphics/test_image.rb +0 -46
  174. data/test/unit/generator/pdf/document/graphics/test_text.rb +0 -171
  175. data/test/unit/generator/pdf/document/test_font.rb +0 -84
  176. data/test/unit/generator/pdf/document/test_graphics.rb +0 -42
  177. data/test/unit/generator/pdf/document/test_page.rb +0 -122
  178. data/test/unit/generator/pdf/document/test_parse_color.rb +0 -30
  179. data/test/unit/generator/pdf/prawn_ext/test_calc_image_dimensions.rb +0 -41
  180. data/test/unit/generator/pdf/prawn_ext/test_width_of.rb +0 -22
  181. data/test/unit/generator/pdf/test_document.rb +0 -22
  182. data/test/unit/generator/test_pdf.rb +0 -26
  183. data/test/unit/layout/test_base.rb +0 -41
  184. data/test/unit/layout/test_format.rb +0 -100
  185. data/test/unit/layout/test_legacy_schema.rb +0 -574
  186. data/test/unit/layout/test_version.rb +0 -26
  187. data/test/unit/report/test_base.rb +0 -248
  188. data/test/unit/report/test_internal.rb +0 -206
  189. data/test/unit/test_config.rb +0 -36
  190. data/test/unit/test_layout.rb +0 -12
  191. data/test/unit/test_report.rb +0 -18
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thinreports
4
+ module SectionReport
5
+ module Builder
6
+ module ReportData
7
+ Main = Struct.new :schema, :groups
8
+ Group = Struct.new :headers, :details, :footers
9
+ Section = Struct.new :schema, :items, :min_height
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'stack_view_data'
4
+
5
+ module Thinreports
6
+ module SectionReport
7
+ module Builder
8
+ class StackViewBuilder
9
+ def initialize(item)
10
+ @item = item
11
+ end
12
+
13
+ def update(params)
14
+ rows_params = params[:rows] || {}
15
+ rows_schema = item.internal.format.rows
16
+
17
+ schema_row_ids = rows_schema.map {|row_schema| row_schema.id.to_sym}.to_set
18
+
19
+ rows = []
20
+ rows_schema.each do |row_schema|
21
+ row_params = rows_params[row_schema.id.to_sym] || {}
22
+ next unless row_enabled?(row_schema, row_params)
23
+
24
+ items = build_row_items(
25
+ row_schema,
26
+ row_params[:items] || {}
27
+ )
28
+
29
+ rows << StackViewData::Row.new(row_schema, items, row_params[:min_height])
30
+ end
31
+ item.internal.rows = rows
32
+ end
33
+
34
+ private
35
+
36
+ attr_reader :item
37
+
38
+ def build_row_items(row_schema, items_params)
39
+ row_schema.items.each_with_object([]) do |item_schema, items|
40
+ item = ItemBuilder.new(item_schema, row_schema).build(items_params[item_schema.id&.to_sym])
41
+ items << item if item.visible?
42
+ end
43
+ end
44
+
45
+ def row_enabled?(row_schema, row_params)
46
+ if row_params.key?(:display)
47
+ row_params[:display]
48
+ else
49
+ row_schema.display?
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thinreports
4
+ module SectionReport
5
+ module Builder
6
+ module StackViewData
7
+ Row = Struct.new :schema, :items, :min_height
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'build'
4
+ require_relative 'pdf/render'
5
+
6
+ module Thinreports
7
+ module SectionReport
8
+ class Generate
9
+ def initialize
10
+ @pdf = Thinreports::Generator::PDF::Document.new
11
+ end
12
+
13
+ def call(report_params, filename: nil)
14
+ report = Build.new.call(report_params)
15
+
16
+ PDF::Render.new(pdf).call!(report)
17
+
18
+ filename ? pdf.render_file(filename) : pdf.render
19
+ end
20
+
21
+ private
22
+
23
+ attr_reader :pdf
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'renderer/group_renderer'
4
+
5
+ module Thinreports
6
+ module SectionReport
7
+ module PDF
8
+ class Render
9
+ def initialize(pdf)
10
+ @group_renderer = Renderer::GroupRenderer.new(pdf)
11
+ end
12
+
13
+ def call!(report)
14
+ report.groups.each { |group| group_renderer.render(report, group) }
15
+ end
16
+
17
+ private
18
+
19
+ attr_reader :group_renderer
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thinreports
4
+ module SectionReport
5
+ module Renderer
6
+ module DrawItem
7
+ def draw_item(item, expanded_height = 0)
8
+ shape = item.internal
9
+
10
+ if shape.type_of?(Core::Shape::TextBlock::TYPE_NAME)
11
+ computed_height = shape.format.attributes['height']
12
+ computed_height += expanded_height if shape.format.follow_stretch == 'height'
13
+
14
+ if shape.style.finalized_styles['overflow'] == 'expand'
15
+ # When overflow is "expand", the value of the height argument is ignored and the shape is expanded to
16
+ # the bottom of the outer bounding box.
17
+ # That causes a position shift problem if vertical-align is "middle" or "bottom".
18
+ # To solve it, we overwrite the overflow to "truncate" when drawing.
19
+ # To emulate the "expand" behavior in the "truncate" mode,
20
+ # here we pass the greater value of the computed_height and the text height as text block height.
21
+ pdf.draw_shape_tblock(shape, height: [computed_height, calc_text_block_height(shape)].max, overflow: :truncate)
22
+ else
23
+ pdf.draw_shape_tblock(shape, height: computed_height)
24
+ end
25
+ elsif shape.type_of?(Core::Shape::ImageBlock::TYPE_NAME)
26
+ pdf.draw_shape_iblock(shape)
27
+ elsif shape.type_of?('text')
28
+ case shape.format.follow_stretch
29
+ when 'height'
30
+ pdf.draw_shape_text(shape, expanded_height)
31
+ else
32
+ pdf.draw_shape_text(shape)
33
+ end
34
+ elsif shape.type_of?('image')
35
+ pdf.draw_shape_image(shape)
36
+ elsif shape.type_of?('ellipse')
37
+ pdf.draw_shape_ellipse(shape)
38
+ elsif shape.type_of?('rect')
39
+ case shape.format.follow_stretch
40
+ when 'height'
41
+ pdf.draw_shape_rect(shape, expanded_height)
42
+ else
43
+ pdf.draw_shape_rect(shape)
44
+ end
45
+ elsif shape.type_of?('line')
46
+ case shape.format.follow_stretch
47
+ when 'height'
48
+ y1, y2 = shape.format.attributes.values_at('y1', 'y2')
49
+ if y1 < y2
50
+ pdf.draw_shape_line(shape, 0, expanded_height)
51
+ else
52
+ pdf.draw_shape_line(shape, expanded_height, 0)
53
+ end
54
+ when 'y'
55
+ pdf.draw_shape_line(shape, expanded_height, expanded_height)
56
+ else
57
+ pdf.draw_shape_line(shape)
58
+ end
59
+ elsif shape.type_of?(Core::Shape::StackView::TYPE_NAME)
60
+ stack_view_renderer.render(shape)
61
+ else
62
+ raise Thinreports::Errors::UnknownShapeType
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'section_renderer'
4
+
5
+ module Thinreports
6
+ module SectionReport
7
+ module Renderer
8
+ class GroupRenderer
9
+ def initialize(pdf)
10
+ @pdf = pdf
11
+ @section_renderer = Renderer::SectionRenderer.new(pdf)
12
+ end
13
+
14
+ def render(report, group)
15
+ pdf.start_new_page_for_section_report report.schema
16
+ current_page_height = 0
17
+
18
+ max_page_height = pdf.max_content_height
19
+
20
+ group.headers.each do |header|
21
+ section_renderer.render(header)
22
+ current_page_height += section_renderer.section_height(header)
23
+ end
24
+
25
+ group.details.each do |detail|
26
+ if current_page_height + section_renderer.section_height(detail) > max_page_height
27
+ pdf.start_new_page_for_section_report report.schema
28
+ current_page_height = 0
29
+
30
+ group.headers.each do |header|
31
+ if header.schema.every_page?
32
+ section_renderer.render(header)
33
+ current_page_height += section_renderer.section_height(header)
34
+ end
35
+ end
36
+ end
37
+ section_renderer.render(detail)
38
+ current_page_height += section_renderer.section_height(detail)
39
+ end
40
+
41
+ group.footers.each do |footer|
42
+ if current_page_height + section_renderer.section_height(footer) > max_page_height
43
+ pdf.start_new_page_for_section_report report.schema
44
+ current_page_height = 0
45
+ end
46
+ section_renderer.render(footer)
47
+ current_page_height += section_renderer.section_height(footer)
48
+ end
49
+ end
50
+
51
+ private
52
+
53
+ attr_reader :pdf, :section_renderer
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thinreports
4
+ module SectionReport
5
+ module Renderer
6
+ class HeadersRenderer
7
+ def initialize(pdf)
8
+ @pdf = pdf
9
+ @section_renderer = Renderer::SectionRenderer.new(pdf)
10
+ end
11
+
12
+ def render(headers)
13
+ headers.each do |header|
14
+ section_renderer.render(header)
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ attr_reader :pdf, :section_renderer
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thinreports
4
+ module SectionReport
5
+ module Renderer
6
+ module SectionHeight
7
+ LayoutInfo = Struct.new(:shape, :content_height, :top_margin, :bottom_margin)
8
+
9
+ def section_height(section)
10
+ return [section.min_height || 0, section.schema.height].max if !section.schema.auto_stretch? || section.items.empty?
11
+
12
+ item_layouts = section.items.map { |item| item_layout(section, item.internal) }.compact
13
+
14
+ min_bottom_margin = item_layouts.each_with_object([]) do |l, margins|
15
+ margins << l.bottom_margin if l.shape.format.affect_bottom_margin?
16
+ end.min.to_f
17
+
18
+ max_content_bottom = item_layouts.each_with_object([]) do |l, bottoms|
19
+ bottoms << l.top_margin + l.content_height if l.shape.format.affect_bottom_margin?
20
+ end.max.to_f
21
+
22
+ [section.min_height || 0, max_content_bottom + min_bottom_margin].max
23
+ end
24
+
25
+ def calc_float_content_bottom(section)
26
+ item_layouts = section.items.map { |item| item_layout(section, item.internal) }.compact
27
+ item_layouts
28
+ .map { |l| l.top_margin + l.content_height }
29
+ .max.to_f
30
+ end
31
+
32
+ def item_layout(section, shape)
33
+ if shape.type_of?(Core::Shape::TextBlock::TYPE_NAME)
34
+ text_layout(section, shape)
35
+ elsif shape.type_of?(Core::Shape::StackView::TYPE_NAME)
36
+ stack_view_layout(section, shape)
37
+ elsif shape.type_of?(Core::Shape::ImageBlock::TYPE_NAME)
38
+ image_block_layout(section, shape)
39
+ elsif shape.type_of?('ellipse')
40
+ cy, ry = shape.format.attributes.values_at('cy', 'ry')
41
+ static_layout(section, shape, cy - ry, ry * 2)
42
+ elsif shape.type_of?('line')
43
+ y1, y2 = shape.format.attributes.values_at('y1', 'y2')
44
+ static_layout(section, shape, [y1, y2].min, (y2 - y1).abs)
45
+ else
46
+ y, height = shape.format.attributes.values_at('y', 'height')
47
+ raise ArgumentError.new("Unknown layout for #{shape}") if height == nil || y == nil
48
+ static_layout(section, shape, y, height)
49
+ end
50
+ end
51
+
52
+ def static_layout(section, shape, y, height)
53
+ LayoutInfo.new(shape, height, y, section.schema.height - height - y)
54
+ end
55
+
56
+ def image_block_layout(section, shape)
57
+ y, height = shape.format.attributes.values_at('y', 'height')
58
+ if shape.style.finalized_styles['position-y'] == 'top'
59
+ dimensions = pdf.shape_iblock_dimenions(shape)
60
+ content_height = dimensions ? dimensions[1] : 0
61
+
62
+ LayoutInfo.new(shape, content_height, y, section.schema.height - height - y)
63
+ else
64
+ static_layout(section, shape, y, height)
65
+ end
66
+ end
67
+
68
+ def calc_text_block_height(shape)
69
+ height = 0
70
+
71
+ pdf.draw_shape_tblock(shape) do |array, options|
72
+ modified_options = options.merge(at: [0, 10_000], height: 10_000)
73
+ height = pdf.pdf.height_of_formatted(array, modified_options)
74
+ end
75
+ height
76
+ end
77
+
78
+ def text_layout(section, shape)
79
+ y, schema_height = shape.format.attributes.values_at('y', 'height')
80
+
81
+ content_height = if shape.style.finalized_styles['overflow'] == 'expand'
82
+ [schema_height, calc_text_block_height(shape)].max
83
+ else
84
+ schema_height
85
+ end
86
+
87
+ LayoutInfo.new(shape, content_height, y, section.schema.height - schema_height - y)
88
+ end
89
+
90
+ def stack_view_layout(section, shape)
91
+ schema_height = 0
92
+ shape.format.rows.each {|row| schema_height += row.attributes['height']}
93
+
94
+ y = shape.format.attributes['y']
95
+ LayoutInfo.new(shape, stack_view_renderer.section_height(shape), y, section.schema.height - schema_height - y)
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'stack_view_renderer'
4
+ require_relative 'section_height'
5
+ require_relative 'draw_item'
6
+
7
+ module Thinreports
8
+ module SectionReport
9
+ module Renderer
10
+ class SectionRenderer
11
+ include SectionHeight
12
+ include DrawItem
13
+
14
+ def initialize(pdf)
15
+ @pdf = pdf
16
+ end
17
+
18
+ def render(section)
19
+ doc = pdf.pdf
20
+
21
+ actual_height = section_height(section)
22
+ doc.bounding_box([0, doc.cursor], width: doc.bounds.width, height: actual_height) do
23
+ section.items.each do |item|
24
+ draw_item(item, (actual_height - section.schema.height))
25
+ end
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ attr_reader :pdf
32
+
33
+ def stack_view_renderer
34
+ @stack_view_renderer ||= Renderer::StackViewRenderer.new(pdf)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'stack_view_row_renderer'
4
+
5
+ module Thinreports
6
+ module SectionReport
7
+ module Renderer
8
+ class StackViewRenderer
9
+ def initialize(pdf)
10
+ @pdf = pdf
11
+ @row_renderer = Renderer::StackViewRowRenderer.new(pdf)
12
+ end
13
+
14
+ RowLayout = Struct.new(:row, :height, :top)
15
+
16
+ def section_height(shape)
17
+ row_layouts = build_row_layouts(shape.rows)
18
+
19
+ total_row_height = row_layouts.sum(0, &:height)
20
+ float_content_bottom = row_layouts
21
+ .map { |l| row_renderer.calc_float_content_bottom(l.row) + l.top }
22
+ .max.to_f
23
+
24
+ [total_row_height, float_content_bottom].max
25
+ end
26
+
27
+ def render(shape)
28
+ doc = pdf.pdf
29
+
30
+ x, y, w = shape.format.attributes.values_at('x', 'y', 'width')
31
+ doc.bounding_box([x, doc.bounds.height - y], width: w, height: section_height(shape)) do
32
+ shape.rows.each do |row|
33
+ row_renderer.render(row)
34
+ end
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ attr_reader :pdf, :row_renderer
41
+
42
+ def build_row_layouts(rows)
43
+ row_layouts = rows.map { |row| RowLayout.new(row, row_renderer.section_height(row)) }
44
+
45
+ row_layouts.inject(0) do |top, row_layout|
46
+ row_layout.top = top
47
+ top + row_layout.height
48
+ end
49
+
50
+ row_layouts
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end