lib/thinreports/generator/pdf/document/graphics/text.rb in thinreports-0.9.1 vs lib/thinreports/generator/pdf/document/graphics/text.rb in thinreports-0.10.0

- old
+ new

@@ -1,161 +1,176 @@ -# coding: utf-8 +# frozen_string_literal: true module Thinreports module Generator + class PDF + module Graphics + # @param [String] content + # @param [Numeric, String] x + # @param [Numeric, String] y + # @param [Numeric, String] w + # @param [Numeric, String] h + # @param [Hash] attrs ({}) + # @option attrs [String] :font + # @option attrs [Numeric, String] :size + # @option attrs [String] :color + # @option attrs [Array<:bold, :italic, :underline, :strikethrough>] + # :styles (nil) + # @option attrs [:left, :center, :right] :align (:left) + # @option attrs [:top, :center, :bottom] :valign (:top) + # @option attrs [Numeric, String] :line_height The total height of an text line. + # @option attrs [Numeric, String] :letter_spacing + # @option attrs [Boolean] :single (false) + # @option attrs [:trancate, :shrink_to_fit, :expand] :overflow (:trancate) + # @option attrs [:none, :break_word] :word_wrap (:none) + def text_box(content, x, y, w, h, attrs = {}) + w, h = s2f(w, h) - module PDF::Graphics - # @param [String] content - # @param [Numeric, String] x - # @param [Numeric, String] y - # @param [Numeric, String] w - # @param [Numeric, String] h - # @param [Hash] attrs ({}) - # @option attrs [String] :font - # @option attrs [Numeric, String] :size - # @option attrs [String] :color - # @option attrs [Array<:bold, :italic, :underline, :strikethrough>] - # :styles (nil) - # @option attrs [:left, :center, :right] :align (:left) - # @option attrs [:top, :center, :bottom] :valign (:top) - # @option attrs [Numeric, String] :line_height The total height of an text line. - # @option attrs [Numeric, String] :letter_spacing - # @option attrs [Boolean] :single (false) - # @option attrs [:trancate, :shrink_to_fit, :expand] :overflow (:trancate) - # @option attrs [:none, :break_word] :word_wrap (:none) - def text_box(content, x, y, w, h, attrs = {}) - w, h = s2f(w, h) - box_attrs = text_box_attrs(x, y, w, h, single: attrs.delete(:single), - overflow: attrs[:overflow]) - # Do not break by word unless :word_wrap is :break_word - content = text_without_line_wrap(content) if attrs[:word_wrap] == :none + box_attrs = text_box_attrs( + x, y, w, h, + single: attrs.delete(:single), + overflow: attrs[:overflow] + ) - with_text_styles(attrs) do |built_attrs, font_styles| - pdf.formatted_text_box([{ text: content, styles: font_styles }], - built_attrs.merge(box_attrs)) + # Do not break by word unless :word_wrap is :break_word + content = text_without_line_wrap(content) if attrs[:word_wrap] == :none + + with_text_styles(attrs) do |built_attrs, font_styles| + pdf.formatted_text_box( + [{ text: content, styles: font_styles }], + built_attrs.merge(box_attrs) + ) + end + # rubocop:disable Lint/HandleExceptions + rescue Prawn::Errors::CannotFit + # Nothing to do. + # + # When the area is too small compared + # with the content and the style of the text. + # (See prawn/core/text/formatted/line_wrap.rb#L185) end - rescue Prawn::Errors::CannotFit - # Nothing to do. - # - # When the area is too small compared - # with the content and the style of the text. - # (See prawn/core/text/formatted/line_wrap.rb#L185) - end - # @see #text_box - def text(content, x, y, w, h, attrs = {}) - # Set the :overflow property to :shirink_to_fit. - text_box(content, x, y, w, h, { overflow: :shirink_to_fit }.merge(attrs)) - end + # @see #text_box + def text(content, x, y, w, h, attrs = {}) + # Set the :overflow property to :shirink_to_fit. + text_box(content, x, y, w, h, { overflow: :shirink_to_fit }.merge(attrs)) + end - private + private - # @param x (see #text_box) - # @param y (see #text_box) - # @param w (see #text_box) - # @param h (see #text_box) - # @param [Hash] states - # @option states [Boolean] :single - # @option states [Symbold] :overflow - # @return [Hash] - def text_box_attrs(x, y, w, h, states = {}) - attrs = {at: pos(x, y), - width: s2f(w)} - if states[:single] - states[:overflow] != :expand ? attrs.merge(single_line: true) : attrs - else - attrs.merge(height: s2f(h)) + # @param x (see #text_box) + # @param y (see #text_box) + # @param w (see #text_box) + # @param h (see #text_box) + # @param [Hash] states + # @option states [Boolean] :single + # @option states [Symbold] :overflow + # @return [Hash] + def text_box_attrs(x, y, w, h, states = {}) + attrs = { + at: pos(x, y), + width: s2f(w) + } + if states[:single] + states[:overflow] != :expand ? attrs.merge(single_line: true) : attrs + else + attrs.merge(height: s2f(h)) + end end - end - # @param attrs (see #text) - # @yield [built_attrs, font_styles] - # @yieldparam [Hash] built_attrs The finalized attributes. - # @yieldparam [Array] font_styles The finalized styles. - def with_text_styles(attrs, &block) - # When no color is given, do not draw. - return unless attrs.key?(:color) && attrs[:color] != 'none' + # @param attrs (see #text) + # @yield [built_attrs, font_styles] + # @yieldparam [Hash] built_attrs The finalized attributes. + # @yieldparam [Array] font_styles The finalized styles. + # rubocop:disable Metrics/AbcSize + def with_text_styles(attrs, &block) + # When no color is given, do not draw. + return unless attrs.key?(:color) && attrs[:color] != 'none' - save_graphics_state + save_graphics_state - fontinfo = {name: attrs.delete(:font).to_s, - color: parse_color(attrs.delete(:color)), - size: s2f(attrs.delete(:size))} + fontinfo = { + name: attrs.delete(:font).to_s, + color: parse_color(attrs.delete(:color)), + size: s2f(attrs.delete(:size)) + } - # Add the specified value to :leading option. - line_height = attrs.delete(:line_height) - if line_height - attrs[:leading] = text_line_leading(s2f(line_height), - name: fontinfo[:name], - size: fontinfo[:size]) - end + # Add the specified value to :leading option. + line_height = attrs.delete(:line_height) + if line_height + attrs[:leading] = text_line_leading( + s2f(line_height), + name: fontinfo[:name], + size: fontinfo[:size] + ) + end - # Set the :character_spacing option. - spacing = attrs.delete(:letter_spacing) - attrs[:character_spacing] = s2f(spacing) if spacing + # Set the :character_spacing option. + spacing = attrs.delete(:letter_spacing) + attrs[:character_spacing] = s2f(spacing) if spacing - # Or... with_font_styles(attrs, fontinfo, &block) - with_font_styles(attrs, fontinfo) do |modified_attrs, styles| - block.call(modified_attrs, styles) + # Or... with_font_styles(attrs, fontinfo, &block) + with_font_styles(attrs, fontinfo) do |modified_attrs, styles| + block.call(modified_attrs, styles) + end + + restore_graphics_state end - restore_graphics_state - end + # @param [Numeric] line_height + # @param [Hash] font + # @option font [String] :name Name of font. + # @option font [Numeric] :size Size of font. + # @return [Numeric] + def text_line_leading(line_height, font) + line_height - pdf.font(font[:name], size: font[:size]).height + end - # @param [Numeric] line_height - # @param [Hash] font - # @option font [String] :name Name of font. - # @option font [Numeric] :size Size of font. - # @return [Numeric] - def text_line_leading(line_height, font) - line_height - pdf.font(font[:name], size: font[:size]).height - end + # @param [String] content + # @return [String] + def text_without_line_wrap(content) + content.gsub(/ /, Prawn::Text::NBSP) + end - # @param [String] content - # @return [String] - def text_without_line_wrap(content) - content.gsub(/ /, Prawn::Text::NBSP) - end + # @param [Hash] attrs + # @param [Hash] font + # @option font [String] :color + # @option font [Numeric] :size + # @option font [String] :name + # @yield [attributes, styles] + # @yieldparam [Hash] modified_attrs + # @yieldparam [Array] styles + # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity + def with_font_styles(attrs, font, &block) + # Building font styles. + styles = attrs.delete(:styles) - # @param [Hash] attrs - # @param [Hash] font - # @option font [String] :color - # @option font [Numeric] :size - # @option font [String] :name - # @yield [attributes, styles] - # @yieldparam [Hash] modified_attrs - # @yieldparam [Array] styles - def with_font_styles(attrs, font, &block) - # Building font styles. - styles = attrs.delete(:styles) - - if styles - manual, styles = styles.partition do |style| - [:bold, :italic].include?(style) && !font_has_style?(font[:name], style) + if styles + manual, styles = styles.partition do |style| + %i[bold italic].include?(style) && !font_has_style?(font[:name], style) + end end - end - # Emulate bold style. - if manual && manual.include?(:bold) - pdf.stroke_color(font[:color]) - pdf.line_width(font[:size] * 0.025) + # Emulate bold style. + if manual && manual.include?(:bold) + pdf.stroke_color(font[:color]) + pdf.line_width(font[:size] * 0.025) - # Change rendering mode to :fill_stroke. - attrs[:mode] = :fill_stroke - end + # Change rendering mode to :fill_stroke. + attrs[:mode] = :fill_stroke + end - # Emulate italic style. - if manual && manual.include?(:italic) - # FIXME - # pdf.transformation_matrix(1, 0, 0.26, 1, 0, 0) - end + # Emulate italic style. + if manual && manual.include?(:italic) + # FIXME + # pdf.transformation_matrix(1, 0, 0.26, 1, 0, 0) + end - pdf.font(font[:name], size: font[:size]) do - pdf.fill_color(font[:color]) - block.call(attrs, styles || []) + pdf.font(font[:name], size: font[:size]) do + pdf.fill_color(font[:color]) + block.call(attrs, styles || []) + end end end - end - end end