From e6cf9887695417b3e460e6b79fd9c623f016c250 Mon Sep 17 00:00:00 2001 From: Andy Jeffries Date: Fri, 9 Sep 2022 13:23:04 +0100 Subject: [PATCH 1/5] Fresh work on nowrap cells Based almost entirely on: https://github.com/prawnpdf/prawn-table/pull/50 Implements the wrapping, adds no more failures (than the current master fails on 3.0.4 anyway), but adds new tests and documentation. --- lib/prawn/table/cell/text.rb | 14 +++++++++++--- manual/table/nowrap.rb | 18 ++++++++++++++++++ manual/table/table.rb | 1 + spec/cell_spec.rb | 15 +++++++++++++++ 4 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 manual/table/nowrap.rb diff --git a/lib/prawn/table/cell/text.rb b/lib/prawn/table/cell/text.rb index ff28789..48f059b 100644 --- a/lib/prawn/table/cell/text.rb +++ b/lib/prawn/table/cell/text.rb @@ -17,7 +17,7 @@ class Text < Cell TextOptions = [:inline_format, :kerning, :size, :align, :valign, :rotate, :rotate_around, :leading, :single_line, :skip_encoding, - :overflow, :min_font_size] + :overflow, :min_font_size, :nowrap] TextOptions.each do |option| define_method("#{option}=") { |v| @text_options[option] = v } @@ -80,7 +80,7 @@ def set_width_constraints # sure we have enough width to be at least one character wide. This is # a bit of a hack, but it should work well enough. unless defined?(@min_width) && @min_width - min_content_width = [natural_content_width, styled_width_of_single_character].min + min_content_width = nowrap ? natural_content_width : [natural_content_width, styled_width_of_single_character].min @min_width = padding_left + padding_right + min_content_width super end @@ -135,7 +135,15 @@ def text_box(extra_options={}) # def styled_width_of(text) options = @text_options.reject { |k| k == :style } - with_font { @pdf.width_of(text, options) } + + with_font do + @pdf.width_of(text, options) + if text.empty? + 0 + else + text.lines.map { |line| @pdf.width_of(line, options) }.max + end + end end private diff --git a/manual/table/nowrap.rb b/manual/table/nowrap.rb new file mode 100644 index 0000000..261833c --- /dev/null +++ b/manual/table/nowrap.rb @@ -0,0 +1,18 @@ +# encoding: utf-8 +# +# Columns specified as nowrap will always fit on to one line forcing others to +# resize as appropriate. +# +require File.expand_path(File.join(File.dirname(__FILE__), + %w[.. example_helper])) + +filename = File.basename(__FILE__).gsub('.rb', '.pdf') +Prawn::ManualBuilder::Example.generate(filename) do + text "Normal widths:" + table([["Blah " * 10, "Blah " * 10]]) + move_down 20 + + text "Nowrap widths:" + table([[cell(:content => "Blah " * 10, :nowrap => true), "Blah " * 10]]) + move_down 20 +end diff --git a/manual/table/table.rb b/manual/table/table.rb index 779dd29..dea12db 100644 --- a/manual/table/table.rb +++ b/manual/table/table.rb @@ -24,6 +24,7 @@ s.example "cell_borders_and_bg" s.example "cell_border_lines" s.example "cell_text" + s.example "nowrap" s.example "image_cells" s.example "span" s.example "before_rendering_page" diff --git a/spec/cell_spec.rb b/spec/cell_spec.rb index 9a5a0fa..6c6d8fa 100644 --- a/spec/cell_spec.rb +++ b/spec/cell_spec.rb @@ -154,6 +154,21 @@ def cell(options={}) (5 * @pdf.height_of("text")) end + it "should have a width that can fit @content without wrapping" do + c = cell(:content => "text", :padding => 10, :nowrap => true) + min_content_width = c.min_width - c.padding[1] - c.padding[3] + + expect(@pdf.height_of("text", :width => min_content_width)).to eq(@pdf.height_of("text")) + end + + it "should have a width that can fit @content without wrapping even if it's multiline" do + c = cell(:content => "text\nlonger", :padding => 10, :nowrap => true) + min_content_width = c.min_width - c.padding[1] - c.padding[3] + + expect(@pdf.height_of("text\nlonger", :width => min_content_width)).to be < + (3 * @pdf.height_of("text")) + end + it "should defer min_width's evaluation of padding" do c = cell(:content => "text", :padding => 100) c.padding = 0 From d8914647e155f3f3656b110978ba34ba8cfa8dfa Mon Sep 17 00:00:00 2001 From: Andy Jeffries Date: Fri, 9 Sep 2022 15:35:01 +0100 Subject: [PATCH 2/5] Adjust documentation for nowrap to not draw an individual border --- manual/table/nowrap.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manual/table/nowrap.rb b/manual/table/nowrap.rb index 261833c..51dfcc9 100644 --- a/manual/table/nowrap.rb +++ b/manual/table/nowrap.rb @@ -13,6 +13,6 @@ move_down 20 text "Nowrap widths:" - table([[cell(:content => "Blah " * 10, :nowrap => true), "Blah " * 10]]) + table([[make_cell(:content => "Blah " * 12, :nowrap => true), "Blah " * 12]]) move_down 20 end From 543800bb05f59aed8edab4e6d44eaa987055da57 Mon Sep 17 00:00:00 2001 From: Andy Jeffries Date: Mon, 12 Sep 2022 11:32:57 +0100 Subject: [PATCH 3/5] Add whitespace option to nowrap --- lib/prawn/table/cell/text.rb | 8 +++++++- manual/table/nowrap.rb | 13 +++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/lib/prawn/table/cell/text.rb b/lib/prawn/table/cell/text.rb index 48f059b..30a8cbb 100644 --- a/lib/prawn/table/cell/text.rb +++ b/lib/prawn/table/cell/text.rb @@ -48,7 +48,13 @@ def font_style=(style) # from the final width if the text is long. # def natural_content_width - @natural_content_width ||= [styled_width_of(@content), @pdf.bounds.width].min + if nowrap == :whitespace + @natural_content_width ||= [@content.split(/[\s]/).map { |word| styled_width_of(word) }.max, @pdf.bounds.width].min + else + @natural_content_width ||= [styled_width_of(@content), @pdf.bounds.width].min + end + + @natural_content_width end # Returns the natural height of this block of text, wrapped to the diff --git a/manual/table/nowrap.rb b/manual/table/nowrap.rb index 51dfcc9..5e91323 100644 --- a/manual/table/nowrap.rb +++ b/manual/table/nowrap.rb @@ -1,7 +1,8 @@ # encoding: utf-8 # # Columns specified as nowrap will always fit on to one line forcing others to -# resize as appropriate. +# resize as appropriate. If you want to allow wrapping, but ensure it's never +# in the middle of a word use :whitespace as the :nowrap option's value. # require File.expand_path(File.join(File.dirname(__FILE__), %w[.. example_helper])) @@ -13,6 +14,14 @@ move_down 20 text "Nowrap widths:" - table([[make_cell(:content => "Blah " * 12, :nowrap => true), "Blah " * 12]]) + table([[make_cell(:content => "Blah " * 11, :nowrap => true), "Blah " * 12]]) + move_down 20 + + text "Wide content without nowrap:" + table([[("wordword" * 7 + " word" * 4), "word " * 10]]) + move_down 20 + + text "Wide content with whitespace nowrap:" + table([[make_cell(:content => ("wordword" * 7 + " word" * 4), :nowrap => :whitespace), "word " * 10]]) move_down 20 end From efbe3569f9d974f6e7fcfe3e49085638ed007eb0 Mon Sep 17 00:00:00 2001 From: Andy Jeffries Date: Mon, 12 Sep 2022 15:35:44 +0100 Subject: [PATCH 4/5] Don't try to compare nil, if the content is accidentally nil --- lib/prawn/table/cell/text.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/prawn/table/cell/text.rb b/lib/prawn/table/cell/text.rb index 30a8cbb..1b7da36 100644 --- a/lib/prawn/table/cell/text.rb +++ b/lib/prawn/table/cell/text.rb @@ -49,7 +49,7 @@ def font_style=(style) # def natural_content_width if nowrap == :whitespace - @natural_content_width ||= [@content.split(/[\s]/).map { |word| styled_width_of(word) }.max, @pdf.bounds.width].min + @natural_content_width ||= [@content.split(/[\s]/).compact.map { |word| styled_width_of(word) }.max, @pdf.bounds.width].min else @natural_content_width ||= [styled_width_of(@content), @pdf.bounds.width].min end From 0a0886149216a771e2fba98a306554bcc90cae6b Mon Sep 17 00:00:00 2001 From: Andy Jeffries Date: Mon, 12 Sep 2022 15:42:13 +0100 Subject: [PATCH 5/5] Further fix for trying to compare with nil --- lib/prawn/table/cell/text.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/prawn/table/cell/text.rb b/lib/prawn/table/cell/text.rb index 1b7da36..a556695 100644 --- a/lib/prawn/table/cell/text.rb +++ b/lib/prawn/table/cell/text.rb @@ -49,7 +49,7 @@ def font_style=(style) # def natural_content_width if nowrap == :whitespace - @natural_content_width ||= [@content.split(/[\s]/).compact.map { |word| styled_width_of(word) }.max, @pdf.bounds.width].min + @natural_content_width ||= [@content.split(/\s/).compact.map { |word| styled_width_of(word) }.max || 0, @pdf.bounds.width || 0].min else @natural_content_width ||= [styled_width_of(@content), @pdf.bounds.width].min end