diff --git a/NFe.Danfe.PdfClown/Blocos/TabelaProdutoServicos.cs b/NFe.Danfe.PdfClown/Blocos/TabelaProdutoServicos.cs index 1e27d2660..67557c0d7 100644 --- a/NFe.Danfe.PdfClown/Blocos/TabelaProdutoServicos.cs +++ b/NFe.Danfe.PdfClown/Blocos/TabelaProdutoServicos.cs @@ -34,14 +34,14 @@ public TabelaProdutosServicos(DanfeViewModel viewModel, Estilo estilo) : base(es .ComColuna(3.9F, ac, cabecalho4) .ComColuna(3.5F, ac, "CFOP") .ComColuna(3.25F, ac, "UN") - .ComColuna(6F, ad, "QUANTI.") - .ComColuna(6F, ad, "VALOR", "UNIT.") - .ComColuna(6F, ad, "VALOR", "TOTAL") - .ComColuna(6F, ad, "B CÁLC", "ICMS") - .ComColuna(5, ad, "VALOR", "ICMS") - .ComColuna(5, ad, "VALOR", "IPI") - .ComColuna(3.5F, ad, "ALIQ.", "ICMS") - .ComColuna(3.5F, ad, "ALIQ.", "IPI"); + .ComColunaDeValor(6F, ad, "QUANTI.") + .ComColunaDeValor(6F, ad, "VALOR", "UNIT.") + .ComColunaDeValor(6F, ad, "VALOR", "TOTAL") + .ComColunaDeValor(6F, ad, "B CÁLC", "ICMS") + .ComColunaDeValor(5, ad, "VALOR", "ICMS") + .ComColunaDeValor(5, ad, "VALOR", "IPI") + .ComColunaDeValor(3.5F, ad, "ALIQ.", "ICMS") + .ComColunaDeValor(3.5F, ad, "ALIQ.", "IPI"); } if (ViewModel.Orientacao == Orientacao.Paisagem) { @@ -52,14 +52,14 @@ public TabelaProdutosServicos(DanfeViewModel viewModel, Estilo estilo) : base(es .ComColuna(3.1F, ac, cabecalho4) .ComColuna(3.1F, ac, "CFOP") .ComColuna(3F, ac, "UN") - .ComColuna(5.25F, ad, "QUANTI.") - .ComColuna(5.6F, ad, "VALOR UNIT.") - .ComColuna(5.6F, ad, "VALOR TOTAL") - .ComColuna(5.6F, ad, "B CÁLC ICMS") - .ComColuna(5.6F, ad, "VALOR ICMS") - .ComColuna(5.6F, ad, "VALOR IPI") - .ComColuna(3F, ad, "ALIQ.", "ICMS") - .ComColuna(3F, ad, "ALIQ.", "IPI"); + .ComColunaDeValor(5.25F, ad, "QUANTI.") + .ComColunaDeValor(5.6F, ad, "VALOR UNIT.") + .ComColunaDeValor(5.6F, ad, "VALOR TOTAL") + .ComColunaDeValor(5.6F, ad, "B CÁLC ICMS") + .ComColunaDeValor(5.6F, ad, "VALOR ICMS") + .ComColunaDeValor(5.6F, ad, "VALOR IPI") + .ComColunaDeValor(3F, ad, "ALIQ.", "ICMS") + .ComColunaDeValor(3F, ad, "ALIQ.", "IPI"); } Tabela.AjustarLarguraColunas(); diff --git a/NFe.Danfe.PdfClown/Elementos/Tabela.cs b/NFe.Danfe.PdfClown/Elementos/Tabela.cs index 0b8d6128d..f847c3aae 100644 --- a/NFe.Danfe.PdfClown/Elementos/Tabela.cs +++ b/NFe.Danfe.PdfClown/Elementos/Tabela.cs @@ -41,12 +41,29 @@ public Tabela(Estilo estilo) : base(estilo) FonteCabecalho = estilo.CriarFonteRegular(6F); } + /// + /// Menor corpo de fonte aceito pelo ajuste automático das colunas de valor. Abaixo dele + /// o número deixaria de ser legível no impresso, e o comportamento anterior (quebra de + /// linha) é preservado. + /// + private const float TamanhoMinimoDaCelulaAjustada = 4F; + public Tabela ComColuna(float larguraP, AlinhamentoHorizontal ah, params string[] cabecalho) { Colunas.Add(new TabelaColuna(cabecalho, larguraP, ah)); return this; } + /// + /// Acrescenta uma coluna de valor: o conteúdo é indivisível e, se não couber na célula, + /// encolhe para caber em uma única linha. Ver . + /// + public Tabela ComColunaDeValor(float larguraP, AlinhamentoHorizontal ah, params string[] cabecalho) + { + Colunas.Add(new TabelaColuna(cabecalho, larguraP, ah, ajustarFonteParaCaber: true)); + return this; + } + public void AdicionarLinha(List linha) { if (linha.Count != Colunas.Count) throw new ArgumentException(nameof(linha)); @@ -66,6 +83,37 @@ public void AjustarLarguraColunas() } + /// + /// Fonte de uma célula. Por padrão, a fonte do corpo da tabela. Numa coluna de valor + /// () cujo conteúdo é indivisível — sem + /// espaços — e mais largo que a célula, o corpo da fonte é reduzido o suficiente para o + /// conteúdo caber em uma única linha, respeitando + /// . + /// + /// Coluna da célula. + /// Conteúdo da célula. + /// Largura disponível da célula, em milímetros. + private Fonte FonteDaCelula(TabelaColuna coluna, string valor, float larguraUtil) + { + if (!coluna.AjustarFonteParaCaber || larguraUtil <= 0) return FonteCorpo; + + foreach (var caractere in valor) + { + if (char.IsWhiteSpace(caractere)) return FonteCorpo; + } + + float largura = FonteCorpo.MedirLarguraTexto(valor); + + if (largura <= larguraUtil || largura <= 0) return FonteCorpo; + + // A folga de 0.5% evita que o arredondamento da medição encoste o valor na borda. + float tamanho = FonteCorpo.Tamanho * (larguraUtil / largura) * 0.995F; + + return tamanho < TamanhoMinimoDaCelulaAjustada + ? FonteCorpo + : new Fonte(FonteCorpo.FonteInterna, tamanho); + } + private Boolean DesenharLinha(Gfx gfx) { float x = X; @@ -82,10 +130,11 @@ private Boolean DesenharLinha(Gfx gfx) if (!string.IsNullOrWhiteSpace(v)) { + float larguraUtil = w - 2F * Estilo.PaddingHorizontal; - tb[i] = new TextBlock(v, FonteCorpo) + tb[i] = new TextBlock(v, FonteDaCelula(c, v, larguraUtil)) { - Width = w - 2F * Estilo.PaddingHorizontal, + Width = larguraUtil, X = x + PaddingHorizontal, Y = _DY + PaddingSuperior, AlinhamentoHorizontal = c.AlinhamentoHorizontal diff --git a/NFe.Danfe.PdfClown/Elementos/TabelaColuna.cs b/NFe.Danfe.PdfClown/Elementos/TabelaColuna.cs index cf1f82c81..9a1c5c981 100644 --- a/NFe.Danfe.PdfClown/Elementos/TabelaColuna.cs +++ b/NFe.Danfe.PdfClown/Elementos/TabelaColuna.cs @@ -8,11 +8,19 @@ internal class TabelaColuna public float PorcentagemLargura { get; set; } public AlinhamentoHorizontal AlinhamentoHorizontal { get; private set; } - public TabelaColuna(string[] cabecalho, float porcentagemLargura, AlinhamentoHorizontal alinhamentoHorizontal = AlinhamentoHorizontal.Esquerda) + /// + /// Indica que o conteúdo desta coluna é indivisível — um valor formatado, sem espaços. + /// Quando true, um conteúdo mais largo que a célula é impresso em fonte reduzida + /// em vez de ser quebrado no meio dos caracteres. + /// + public bool AjustarFonteParaCaber { get; private set; } + + public TabelaColuna(string[] cabecalho, float porcentagemLargura, AlinhamentoHorizontal alinhamentoHorizontal = AlinhamentoHorizontal.Esquerda, bool ajustarFonteParaCaber = false) { Cabecalho = cabecalho ?? throw new ArgumentNullException(nameof(cabecalho)); PorcentagemLargura = porcentagemLargura; AlinhamentoHorizontal = alinhamentoHorizontal; + AjustarFonteParaCaber = ajustarFonteParaCaber; } public override string ToString()