Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature/Repeat list heading on new page #472

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 10 additions & 16 deletions cmd/benchmark/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ import (

"github.com/johnfercher/maroto/v2"

"github.com/johnfercher/maroto/v2/pkg/components/list"
"github.com/johnfercher/maroto/v2/pkg/config"
"github.com/johnfercher/maroto/v2/pkg/consts/fontstyle"
"github.com/johnfercher/maroto/v2/pkg/metrics"

"github.com/johnfercher/maroto/v2/pkg/components/code"
"github.com/johnfercher/maroto/v2/pkg/components/col"
"github.com/johnfercher/maroto/v2/pkg/components/image"
"github.com/johnfercher/maroto/v2/pkg/components/list"
"github.com/johnfercher/maroto/v2/pkg/components/row"
"github.com/johnfercher/maroto/v2/pkg/components/signature"
"github.com/johnfercher/maroto/v2/pkg/components/text"
Expand Down Expand Up @@ -68,15 +68,13 @@ func run() *metrics.Time {
m.AddRows(
text.NewRow(20, "Main features", props.Text{Size: 15, Top: 6.5}),
)
myList := list.New(getHeader(), props.List{MinimumRowsBypage: 3}).Add(getObjects(1158)...)

objects := getObjects(1158)
rows, err := list.Build[Object](objects)
err = myList.BuildListWithFixedHeader(m)
if err != nil {
log.Fatal(err.Error())
}

m.AddRows(rows...)

for i := 0; i < 1158; i++ {
m.AddRows(buildCodesRow()...)
m.AddRows(buildImagesRow()...)
Expand Down Expand Up @@ -184,35 +182,31 @@ type Object struct {
Value string
}

func (o Object) GetHeader() core.Row {
func getHeader() core.Row {
return row.New(10).Add(
text.NewCol(4, "Key", props.Text{Style: fontstyle.Bold}),
text.NewCol(8, "Bytes", props.Text{Style: fontstyle.Bold}),
)
}

func (o Object) GetContent(i int) core.Row {
func getContent(i int) core.Row {
r := row.New(5).Add(
text.NewCol(4, o.Key),
text.NewCol(8, o.Value),
text.NewCol(4, fmt.Sprintf("Key: %d", i)),
text.NewCol(8, fmt.Sprintf("Value: %d", i)),
)

if i%2 == 0 {
r.WithStyle(&props.Cell{
BackgroundColor: background,
})
}

return r
}

func getObjects(max int) []Object {
var objects []Object
func getObjects(max int) []core.Row {
var objects []core.Row
for i := 0; i < max; i++ {
objects = append(objects, Object{
Key: fmt.Sprintf("Key: %d", i),
Value: fmt.Sprintf("Bytes: %d", i),
})
objects = append(objects, getContent(i))
}
return objects
}
49 changes: 20 additions & 29 deletions docs/assets/examples/list/v2/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,32 +43,27 @@ func GetMaroto() core.Maroto {
mrt := maroto.New()
m := maroto.NewMetricsDecorator(mrt)

objects := getObjects(100)
rows, err := list.Build[Object](objects)
if err != nil {
log.Fatal(err.Error())
}
myList1 := list.New(GetHeader("header 1"), props.List{MinimumRowsBypage: 3}).Add(GetObjects(120)...)
m.AddRows(myList1.GetRows()...)

m.AddRows(rows...)
return m
}
myList := list.New(GetHeader("header 2"), props.List{MinimumRowsBypage: 5}).Add(GetObjects(100)...)
myList.BuildListWithFixedHeader(m)

type Object struct {
Key string
Value string
return m
}

func (o Object) GetHeader() core.Row {
return row.New(10).Add(
text.NewCol(4, "Key", props.Text{Style: fontstyle.Bold}),
text.NewCol(8, "Bytes", props.Text{Style: fontstyle.Bold}),
)
func GetObjects(max int) []core.Row {
var objects []core.Row
for i := 0; i < max; i++ {
objects = append(objects, GetContent(i))
}
return objects
}

func (o Object) GetContent(i int) core.Row {
r := row.New(5).Add(
text.NewCol(4, o.Key),
text.NewCol(8, o.Value),
func GetContent(i int) core.Row {
r := row.New(4).Add(
text.NewCol(4, fmt.Sprintf("key %d", i)),
text.NewCol(8, fmt.Sprintf("Value %d", i)),
)

if i%2 == 0 {
Expand All @@ -80,13 +75,9 @@ func (o Object) GetContent(i int) core.Row {
return r
}

func getObjects(max int) []Object {
var objects []Object
for i := 0; i < max; i++ {
objects = append(objects, Object{
Key: fmt.Sprintf("Key: %d", i),
Value: fmt.Sprintf("Bytes: %d", i),
})
}
return objects
func GetHeader(name string) core.Row {
return row.New(20).Add(
text.NewCol(4, "Key "+name, props.Text{Style: fontstyle.Bold}),
text.NewCol(8, "value "+name, props.Text{Style: fontstyle.Bold}),
)
}
13 changes: 11 additions & 2 deletions example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,19 @@ func ExampleMaroto_AddRow() {
}

// ExampleMaroto_FitlnCurrentPage demonstrate how to check if the new line fits on the current page
func ExampleMaroto_FitlnCurrentPage() {
func ExampleMaroto_FitsOnCurrentPage() {
m := maroto.New()

m.FitlnCurrentPage(12)
_ = m.FitsOnCurrentPage(text.NewAutoRow("text"))

// Do things and generate
}

// ExampleMaroto_FillPageToAddNew demonstrate how add a new page
func ExampleMaroto_FillPageToAddNew() {
m := maroto.New()

m.FillPageToAddNew()

// Do things and generate
}
Expand Down
88 changes: 49 additions & 39 deletions maroto.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ func New(cfgs ...*entity.Config) core.Maroto {
func (m *Maroto) AddPages(pages ...core.Page) {
for _, page := range pages {
if m.currentHeight != m.headerHeight {
m.fillPageToAddNew()
m.FillPageToAddNew()
m.addHeader()
}
m.addRows(page.GetRows()...)
Expand Down Expand Up @@ -121,11 +121,20 @@ func (m *Maroto) AddAutoRow(cols ...core.Col) core.Row {
return r
}

// FitlnCurrentPage is responsible to validating whether a line fits on
// the current page.
func (m *Maroto) FitlnCurrentPage(heightNewLine float64) bool {
contentSize := m.getRowsHeight(m.rows...) + m.footerHeight + m.headerHeight
return contentSize+heightNewLine < m.config.Dimensions.Height
// FitlnCurrentPage is responsible for validating from a set of rows,
// how many fit on the current page
func (m *Maroto) FitsOnCurrentPage(rows ...core.Row) int {
totalHeight := 0.0
for i, row := range rows {
row.SetConfig(m.config)
rowHeight := row.GetHeight(m.provider, &m.cell)
if fit := m.fitsOnCurrentPage(rowHeight, totalHeight+m.currentHeight); !fit {
return i
}
totalHeight += rowHeight
}

return len(rows)
}

// RegisterHeader is responsible to define a set of rows as a header
Expand Down Expand Up @@ -166,7 +175,7 @@ func (m *Maroto) RegisterFooter(rows ...core.Row) error {
// Generate is responsible to compute the component tree created by
// the usage of all other Maroto methods, and generate the PDF document.
func (m *Maroto) Generate() (core.Document, error) {
m.fillPageToAddNew()
m.FillPageToAddNew()
m.setConfig()

if m.config.GenerationMode == generation.Concurrent {
Expand All @@ -183,7 +192,7 @@ func (m *Maroto) Generate() (core.Document, error) {
// GetStructure is responsible for return the component tree, this is useful
// on unit tests cases.
func (m *Maroto) GetStructure() *node.Node[core.Structure] {
m.fillPageToAddNew()
m.FillPageToAddNew()

str := core.Structure{
Type: "maroto",
Expand All @@ -199,33 +208,59 @@ func (m *Maroto) GetStructure() *node.Node[core.Structure] {
return node
}

// FillPageToAddNew is responsible for adding a new page
func (m *Maroto) FillPageToAddNew() {
space := m.cell.Height - m.currentHeight - m.footerHeight

c := col.New(m.config.MaxGridSize)
spaceRow := row.New(space).Add(c)

m.rows = append(m.rows, spaceRow)
m.rows = append(m.rows, m.footer...)

var p core.Page
if m.config.PageNumber != nil {
p = page.New(*m.config.PageNumber)
} else {
p = page.New()
}

p.SetConfig(m.config)
p.Add(m.rows...)

m.pages = append(m.pages, p)
m.rows = nil
m.currentHeight = 0
}

func (m *Maroto) addRows(rows ...core.Row) {
for _, row := range rows {
m.addRow(row)
}
}

func (m *Maroto) fitsOnCurrentPage(heightNewContent, currentHeight float64) bool {
sumHeight := heightNewContent + currentHeight + m.footerHeight
return sumHeight < m.cell.Height
}

func (m *Maroto) addRow(r core.Row) {
if len(r.GetColumns()) == 0 {
r.Add(col.New())
}

maxHeight := m.cell.Height

r.SetConfig(m.config)
rowHeight := r.GetHeight(m.provider, &m.cell)
sumHeight := rowHeight + m.currentHeight + m.footerHeight

// Row smaller than the remain space on page
if sumHeight < maxHeight {
if m.fitsOnCurrentPage(rowHeight, m.currentHeight) {
m.currentHeight += rowHeight
m.rows = append(m.rows, r)
return
}

// As row will extrapolate page, we will add empty space
// on the page to force a new page
m.fillPageToAddNew()
m.FillPageToAddNew()

m.addHeader()

Expand All @@ -241,31 +276,6 @@ func (m *Maroto) addHeader() {
}
}

func (m *Maroto) fillPageToAddNew() {
space := m.cell.Height - m.currentHeight - m.footerHeight

c := col.New(m.config.MaxGridSize)
spaceRow := row.New(space)
spaceRow.Add(c)

m.rows = append(m.rows, spaceRow)
m.rows = append(m.rows, m.footer...)

var p core.Page
if m.config.PageNumber != nil {
p = page.New(*m.config.PageNumber)
} else {
p = page.New()
}

p.SetConfig(m.config)
p.Add(m.rows...)

m.pages = append(m.pages, p)
m.rows = nil
m.currentHeight = 0
}

func (m *Maroto) setConfig() {
for i, page := range m.pages {
page.SetConfig(m.config)
Expand Down
Loading
Loading