diff --git a/docs/assets/examples/textgrid/v2/main.go b/docs/assets/examples/textgrid/v2/main.go index e8843198..1cf4b929 100644 --- a/docs/assets/examples/textgrid/v2/main.go +++ b/docs/assets/examples/textgrid/v2/main.go @@ -104,5 +104,9 @@ func GetMaroto() core.Maroto { m.AddAutoRow( text.NewCol(12, longText+" "+longText+" "+longText, props.Text{Left: 3, Right: 3, Align: align.Justify, BreakLineStrategy: breakline.EmptySpaceStrategy}), ) + + m.AddAutoRow( + text.NewCol(12, longText+" "+longText+" "+longText, props.Text{VerticalPadding: 10, Left: 3, Right: 3, Align: align.Justify, BreakLineStrategy: breakline.EmptySpaceStrategy}), + ) return m } diff --git a/docs/assets/pdf/textgridv2.pdf b/docs/assets/pdf/textgridv2.pdf index aaedff8d..243bebd9 100644 Binary files a/docs/assets/pdf/textgridv2.pdf and b/docs/assets/pdf/textgridv2.pdf differ diff --git a/docs/assets/text/textgridv2.txt b/docs/assets/text/textgridv2.txt index f023cf2e..72204d05 100644 --- a/docs/assets/text/textgridv2.txt +++ b/docs/assets/text/textgridv2.txt @@ -1,4 +1,4 @@ -generate -> avg: 4.97ms, executions: [4.97ms] -add_row -> avg: 325.33ns, executions: [946.00ns, 211.00ns, 103.00ns, 91.00ns, 92.00ns, 509.00ns] -add_rows -> avg: 76.50ns, executions: [127.00ns, 85.00ns, 41.00ns, 87.00ns, 36.00ns, 83.00ns] -file_size -> 28.15Kb +generate -> avg: 36.66ms, executions: [36.66ms] +add_row -> avg: 1401.00ns, executions: [3.05μs, 0.88μs, 0.61μs, 0.58μs, 0.66μs, 2.62μs] +add_rows -> avg: 368.83ns, executions: [511.00ns, 430.00ns, 190.00ns, 441.00ns, 130.00ns, 511.00ns] +file_size -> 30.68Kb diff --git a/internal/providers/gofpdf/provider.go b/internal/providers/gofpdf/provider.go index 50bd37a6..1075b2af 100644 --- a/internal/providers/gofpdf/provider.go +++ b/internal/providers/gofpdf/provider.go @@ -54,7 +54,7 @@ func (g *provider) GetLinesQuantity(text string, textProp *props.Text, colWidth return g.text.GetLinesQuantity(text, textProp, colWidth) } -func (g *provider) GetTextHeight(prop *props.Font) float64 { +func (g *provider) GetFontHeight(prop *props.Font) float64 { return g.font.GetHeight(prop.Family, prop.Style, prop.Size) } diff --git a/internal/providers/gofpdf/provider_test.go b/internal/providers/gofpdf/provider_test.go index 2fd5b1c4..7fddd0a1 100644 --- a/internal/providers/gofpdf/provider_test.go +++ b/internal/providers/gofpdf/provider_test.go @@ -71,7 +71,7 @@ func TestProvider_GetTextHeight(t *testing.T) { sut := gofpdf.New(dep) // Act - fontHeight := sut.GetTextHeight(&prop) + fontHeight := sut.GetFontHeight(&prop) // Assert font.AssertNumberOfCalls(t, "GetHeight", 1) diff --git a/mocks/Provider.go b/mocks/Provider.go index c3c65807..dd7b2bf4 100644 --- a/mocks/Provider.go +++ b/mocks/Provider.go @@ -664,96 +664,96 @@ func (_c *Provider_GetDimensionsByQrCode_Call) RunAndReturn(run func(string) (*e return _c } -// GetLinesQuantity provides a mock function with given fields: text, textProp, colWidth -func (_m *Provider) GetLinesQuantity(text string, textProp *props.Text, colWidth float64) int { - ret := _m.Called(text, textProp, colWidth) +// GetFontHeight provides a mock function with given fields: prop +func (_m *Provider) GetFontHeight(prop *props.Font) float64 { + ret := _m.Called(prop) if len(ret) == 0 { - panic("no return value specified for GetLinesQuantity") + panic("no return value specified for GetFontHeight") } - var r0 int - if rf, ok := ret.Get(0).(func(string, *props.Text, float64) int); ok { - r0 = rf(text, textProp, colWidth) + var r0 float64 + if rf, ok := ret.Get(0).(func(*props.Font) float64); ok { + r0 = rf(prop) } else { - r0 = ret.Get(0).(int) + r0 = ret.Get(0).(float64) } return r0 } -// Provider_GetLinesQuantity_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetLinesQuantity' -type Provider_GetLinesQuantity_Call struct { +// Provider_GetFontHeight_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetFontHeight' +type Provider_GetFontHeight_Call struct { *mock.Call } -// GetLinesQuantity is a helper method to define mock.On call -// - text string -// - textProp *props.Text -// - colWidth float64 -func (_e *Provider_Expecter) GetLinesQuantity(text interface{}, textProp interface{}, colWidth interface{}) *Provider_GetLinesQuantity_Call { - return &Provider_GetLinesQuantity_Call{Call: _e.mock.On("GetLinesQuantity", text, textProp, colWidth)} +// GetFontHeight is a helper method to define mock.On call +// - prop *props.Font +func (_e *Provider_Expecter) GetFontHeight(prop interface{}) *Provider_GetFontHeight_Call { + return &Provider_GetFontHeight_Call{Call: _e.mock.On("GetFontHeight", prop)} } -func (_c *Provider_GetLinesQuantity_Call) Run(run func(text string, textProp *props.Text, colWidth float64)) *Provider_GetLinesQuantity_Call { +func (_c *Provider_GetFontHeight_Call) Run(run func(prop *props.Font)) *Provider_GetFontHeight_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string), args[1].(*props.Text), args[2].(float64)) + run(args[0].(*props.Font)) }) return _c } -func (_c *Provider_GetLinesQuantity_Call) Return(_a0 int) *Provider_GetLinesQuantity_Call { +func (_c *Provider_GetFontHeight_Call) Return(_a0 float64) *Provider_GetFontHeight_Call { _c.Call.Return(_a0) return _c } -func (_c *Provider_GetLinesQuantity_Call) RunAndReturn(run func(string, *props.Text, float64) int) *Provider_GetLinesQuantity_Call { +func (_c *Provider_GetFontHeight_Call) RunAndReturn(run func(*props.Font) float64) *Provider_GetFontHeight_Call { _c.Call.Return(run) return _c } -// GetTextHeight provides a mock function with given fields: prop -func (_m *Provider) GetTextHeight(prop *props.Font) float64 { - ret := _m.Called(prop) +// GetLinesQuantity provides a mock function with given fields: text, textProp, colWidth +func (_m *Provider) GetLinesQuantity(text string, textProp *props.Text, colWidth float64) int { + ret := _m.Called(text, textProp, colWidth) if len(ret) == 0 { - panic("no return value specified for GetTextHeight") + panic("no return value specified for GetLinesQuantity") } - var r0 float64 - if rf, ok := ret.Get(0).(func(*props.Font) float64); ok { - r0 = rf(prop) + var r0 int + if rf, ok := ret.Get(0).(func(string, *props.Text, float64) int); ok { + r0 = rf(text, textProp, colWidth) } else { - r0 = ret.Get(0).(float64) + r0 = ret.Get(0).(int) } return r0 } -// Provider_GetTextHeight_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetTextHeight' -type Provider_GetTextHeight_Call struct { +// Provider_GetLinesQuantity_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetLinesQuantity' +type Provider_GetLinesQuantity_Call struct { *mock.Call } -// GetTextHeight is a helper method to define mock.On call -// - prop *props.Font -func (_e *Provider_Expecter) GetTextHeight(prop interface{}) *Provider_GetTextHeight_Call { - return &Provider_GetTextHeight_Call{Call: _e.mock.On("GetTextHeight", prop)} +// GetLinesQuantity is a helper method to define mock.On call +// - text string +// - textProp *props.Text +// - colWidth float64 +func (_e *Provider_Expecter) GetLinesQuantity(text interface{}, textProp interface{}, colWidth interface{}) *Provider_GetLinesQuantity_Call { + return &Provider_GetLinesQuantity_Call{Call: _e.mock.On("GetLinesQuantity", text, textProp, colWidth)} } -func (_c *Provider_GetTextHeight_Call) Run(run func(prop *props.Font)) *Provider_GetTextHeight_Call { +func (_c *Provider_GetLinesQuantity_Call) Run(run func(text string, textProp *props.Text, colWidth float64)) *Provider_GetLinesQuantity_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*props.Font)) + run(args[0].(string), args[1].(*props.Text), args[2].(float64)) }) return _c } -func (_c *Provider_GetTextHeight_Call) Return(_a0 float64) *Provider_GetTextHeight_Call { +func (_c *Provider_GetLinesQuantity_Call) Return(_a0 int) *Provider_GetLinesQuantity_Call { _c.Call.Return(_a0) return _c } -func (_c *Provider_GetTextHeight_Call) RunAndReturn(run func(*props.Font) float64) *Provider_GetTextHeight_Call { +func (_c *Provider_GetLinesQuantity_Call) RunAndReturn(run func(string, *props.Text, float64) int) *Provider_GetLinesQuantity_Call { _c.Call.Return(run) return _c } diff --git a/pkg/components/signature/signature.go b/pkg/components/signature/signature.go index 98d8fe15..f8e3486d 100644 --- a/pkg/components/signature/signature.go +++ b/pkg/components/signature/signature.go @@ -55,7 +55,7 @@ func NewAutoRow(value string, ps ...props.Signature) core.Row { // Render renders a Signature into a PDF context. func (s *Signature) Render(provider core.Provider, cell *entity.Cell) { - fontSize := provider.GetTextHeight(s.prop.ToFontProp()) * s.prop.SafePadding + fontSize := provider.GetFontHeight(s.prop.ToFontProp()) * s.prop.SafePadding textProp := s.prop.ToTextProp(align.Center, cell.Height-fontSize, 0) @@ -78,7 +78,7 @@ func (s *Signature) GetStructure() *node.Node[core.Structure] { // GetHeight returns the height that the signature will have in the PDF func (s *Signature) GetHeight(provider core.Provider, cell *entity.Cell) float64 { - return s.prop.LineThickness + provider.GetTextHeight(s.prop.ToFontProp())*s.prop.SafePadding + return s.prop.LineThickness + provider.GetFontHeight(s.prop.ToFontProp())*s.prop.SafePadding } // SetConfig sets the config. diff --git a/pkg/components/signature/signature_test.go b/pkg/components/signature/signature_test.go index ec6e1447..74028c42 100644 --- a/pkg/components/signature/signature_test.go +++ b/pkg/components/signature/signature_test.go @@ -90,7 +90,7 @@ func TestSignature_Render(t *testing.T) { provider := mocks.NewProvider(t) provider.On("AddText", mock.Anything, mock.Anything, mock.Anything).Return(10.0) - provider.On("GetTextHeight", mock.Anything).Return(10.0) + provider.On("GetFontHeight", mock.Anything).Return(10.0) provider.On("AddLine", mock.Anything, mock.Anything) // Act @@ -98,7 +98,7 @@ func TestSignature_Render(t *testing.T) { // Assert provider.AssertNumberOfCalls(t, "AddText", 1) - provider.AssertNumberOfCalls(t, "GetTextHeight", 1) + provider.AssertNumberOfCalls(t, "GetFontHeight", 1) provider.AssertNumberOfCalls(t, "AddLine", 1) }) } @@ -129,7 +129,7 @@ func TestSignature_GetHeight(t *testing.T) { }) provider := mocks.NewProvider(t) - provider.EXPECT().GetTextHeight(&font).Return(5.0) + provider.EXPECT().GetFontHeight(&font).Return(5.0) // Act height := sut.GetHeight(provider, &cell) diff --git a/pkg/components/text/text.go b/pkg/components/text/text.go index a8d2393e..023bc172 100644 --- a/pkg/components/text/text.go +++ b/pkg/components/text/text.go @@ -63,9 +63,10 @@ func (t *Text) GetStructure() *node.Node[core.Structure] { // GetHeight returns the height that the text will have in the PDF func (t *Text) GetHeight(provider core.Provider, cell *entity.Cell) float64 { - lines := provider.GetLinesQuantity(t.value, &t.prop, cell.Width-t.prop.Left-t.prop.Right) - height := provider.GetTextHeight(&props.Font{Family: t.prop.Family, Style: t.prop.Style, Size: t.prop.Size, Color: t.prop.Color}) - return (float64(lines) * height) + t.prop.Top + amountLines := provider.GetLinesQuantity(t.value, &t.prop, cell.Width-t.prop.Left-t.prop.Right) + fontHeight := provider.GetFontHeight(&props.Font{Family: t.prop.Family, Style: t.prop.Style, Size: t.prop.Size, Color: t.prop.Color}) + textHeight := float64(amountLines)*fontHeight + float64(amountLines-1)*t.prop.VerticalPadding + return textHeight + t.prop.Top } // SetConfig sets the config. diff --git a/pkg/components/text/text_test.go b/pkg/components/text/text_test.go index 40b1a05e..d66adaac 100644 --- a/pkg/components/text/text_test.go +++ b/pkg/components/text/text_test.go @@ -115,19 +115,54 @@ func TestText_SetConfig(t *testing.T) { } func TestText_GetHeight(t *testing.T) { - t.Run("When text has a height of 22, should return 22", func(t *testing.T) { + t.Run("When top margin is sent, should increment row height with top margin", func(t *testing.T) { cell := fixture.CellEntity() - textProp := fixture.TextProp() - font := props.Font{Family: textProp.Family, Style: textProp.Style, Size: textProp.Size, Color: textProp.Color} + font := fixture.FontProp() + textProp := props.Text{Top: 10} + textProp.MakeValid(&font) sut := text.New("text", textProp) provider := mocks.NewProvider(t) - provider.EXPECT().GetLinesQuantity("text", &textProp, 97.0).Return(5.0) - provider.EXPECT().GetTextHeight(&font).Return(2.0) + provider.EXPECT().GetLinesQuantity("text", &textProp, 100.0).Return(5.0) + provider.EXPECT().GetFontHeight(&font).Return(2.0) // Act height := sut.GetHeight(provider, &cell) - assert.Equal(t, 22.0, height) + assert.Equal(t, 20.0, height) + }) + + t.Run("When vertical padding is sent, should increment row height with vertical padding", func(t *testing.T) { + cell := fixture.CellEntity() + font := fixture.FontProp() + textProp := props.Text{VerticalPadding: 5} + textProp.MakeValid(&font) + + sut := text.New("text", textProp) + + provider := mocks.NewProvider(t) + provider.EXPECT().GetLinesQuantity("text", &textProp, 100.0).Return(5.0) + provider.EXPECT().GetFontHeight(&font).Return(2.0) + + // Act + height := sut.GetHeight(provider, &cell) + assert.Equal(t, 30.0, height) + }) + + t.Run("When font has a height of 2, should return 10", func(t *testing.T) { + cell := fixture.CellEntity() + font := fixture.FontProp() + textProp := props.Text{} + textProp.MakeValid(&font) + + sut := text.New("text", textProp) + + provider := mocks.NewProvider(t) + provider.EXPECT().GetLinesQuantity("text", &textProp, 100.0).Return(5.0) + provider.EXPECT().GetFontHeight(&font).Return(2.0) + + // Act + height := sut.GetHeight(provider, &cell) + assert.Equal(t, 10.0, height) }) } diff --git a/pkg/core/provider.go b/pkg/core/provider.go index 8354f6d6..72ce633b 100644 --- a/pkg/core/provider.go +++ b/pkg/core/provider.go @@ -15,7 +15,7 @@ type Provider interface { // Features AddLine(cell *entity.Cell, prop *props.Line) AddText(text string, cell *entity.Cell, prop *props.Text) - GetTextHeight(prop *props.Font) float64 + GetFontHeight(prop *props.Font) float64 GetLinesQuantity(text string, textProp *props.Text, colWidth float64) int AddMatrixCode(code string, cell *entity.Cell, prop *props.Rect) AddQrCode(code string, cell *entity.Cell, rect *props.Rect) diff --git a/test/maroto/examples/textgrid.json b/test/maroto/examples/textgrid.json index c17468bc..2b41bfbc 100755 --- a/test/maroto/examples/textgrid.json +++ b/test/maroto/examples/textgrid.json @@ -648,7 +648,33 @@ ] }, { - "value": 169.6641666666667, + "value": 30.583333333333336, + "type": "row", + "nodes": [ + { + "value": 12, + "type": "col", + "nodes": [ + { + "value": "This is a longer sentence that will be broken into multiple lines as it does not fit into the column otherwise. This is a longer sentence that will be broken into multiple lines as it does not fit into the column otherwise. This is a longer sentence that will be broken into multiple lines as it does not fit into the column otherwise.", + "type": "text", + "details": { + "prop_align": "J", + "prop_breakline_strategy": "empty_space_strategy", + "prop_color": "RGB(0, 0, 0)", + "prop_font_family": "arial", + "prop_font_size": 10, + "prop_left": 3, + "prop_right": 3, + "prop_vertical_padding": 10 + } + } + ] + } + ] + }, + { + "value": 139.08083333333335, "type": "row", "nodes": [ {