mirror of
https://github.com/unidoc/unipdf.git
synced 2025-04-24 13:48:49 +08:00
Merge branch 'development' of https://github.com/unidoc/unipdf into development
This commit is contained in:
commit
1a6fda031b
@ -112,7 +112,7 @@ func (div *Division) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext,
|
||||
ctx.X += div.margins.left
|
||||
ctx.Y += div.margins.top
|
||||
ctx.Width -= div.margins.left + div.margins.right
|
||||
ctx.Height -= div.margins.top
|
||||
ctx.Height -= div.margins.top + div.margins.bottom
|
||||
}
|
||||
|
||||
// Set the inline mode of the division to the context.
|
||||
|
@ -5,19 +5,29 @@
|
||||
|
||||
package creator
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// InvoiceAddress contains contact information that can be displayed
|
||||
// in an invoice. It is used for the seller and buyer information in the
|
||||
// invoice template.
|
||||
type InvoiceAddress struct {
|
||||
Heading string
|
||||
Name string
|
||||
Street string
|
||||
Street2 string
|
||||
Zip string
|
||||
City string
|
||||
State string
|
||||
Country string
|
||||
Phone string
|
||||
Email string
|
||||
|
||||
// Separator defines the separator between different address components,
|
||||
// such as the city, state and zip code. It defaults to ", " when the
|
||||
// field is an empty string.
|
||||
Separator string
|
||||
}
|
||||
|
||||
// InvoiceCellProps holds all style properties for an invoice cell.
|
||||
@ -52,6 +62,7 @@ type Invoice struct {
|
||||
// Invoice addresses.
|
||||
buyerAddress *InvoiceAddress
|
||||
sellerAddress *InvoiceAddress
|
||||
addrSeparator string
|
||||
|
||||
// Invoice information.
|
||||
number [2]*InvoiceCell
|
||||
@ -101,14 +112,22 @@ func newInvoice(defaultStyle, headingStyle TextStyle) *Invoice {
|
||||
title: "INVOICE",
|
||||
|
||||
// Addresses.
|
||||
sellerAddress: &InvoiceAddress{},
|
||||
buyerAddress: &InvoiceAddress{},
|
||||
addrSeparator: ", ",
|
||||
|
||||
// Styles.
|
||||
defaultStyle: defaultStyle,
|
||||
headingStyle: headingStyle,
|
||||
}
|
||||
|
||||
// Addresses.
|
||||
i.sellerAddress = &InvoiceAddress{
|
||||
Separator: i.addrSeparator,
|
||||
}
|
||||
i.buyerAddress = &InvoiceAddress{
|
||||
Heading: "Bill to",
|
||||
Separator: i.addrSeparator,
|
||||
}
|
||||
|
||||
// Default colors.
|
||||
lightGrey := ColorRGBFrom8bit(245, 245, 245)
|
||||
mediumGrey := ColorRGBFrom8bit(155, 155, 155)
|
||||
@ -158,7 +177,7 @@ func newInvoice(defaultStyle, headingStyle TextStyle) *Invoice {
|
||||
}
|
||||
|
||||
i.dueDate = [2]*InvoiceCell{
|
||||
i.newCell("Date", i.infoProps),
|
||||
i.newCell("Due Date", i.infoProps),
|
||||
i.newCell("", i.infoProps),
|
||||
}
|
||||
|
||||
@ -536,14 +555,14 @@ func (i *Invoice) setCellBorder(cell *TableCell, invoiceCell *InvoiceCell) {
|
||||
cell.SetBorderColor(invoiceCell.BorderColor)
|
||||
}
|
||||
|
||||
func (i *Invoice) drawAddress(title, name string, addr *InvoiceAddress) []*StyledParagraph {
|
||||
func (i *Invoice) drawAddress(addr *InvoiceAddress) []*StyledParagraph {
|
||||
var paragraphs []*StyledParagraph
|
||||
|
||||
// Address title.
|
||||
if title != "" {
|
||||
if addr.Heading != "" {
|
||||
titleParagraph := newStyledParagraph(i.addressHeadingStyle)
|
||||
titleParagraph.SetMargins(0, 0, 0, 7)
|
||||
titleParagraph.Append(title)
|
||||
titleParagraph.Append(addr.Heading)
|
||||
|
||||
paragraphs = append(paragraphs, titleParagraph)
|
||||
}
|
||||
@ -552,23 +571,36 @@ func (i *Invoice) drawAddress(title, name string, addr *InvoiceAddress) []*Style
|
||||
addressParagraph := newStyledParagraph(i.addressStyle)
|
||||
addressParagraph.SetLineHeight(1.2)
|
||||
|
||||
city := addr.City
|
||||
if addr.Zip != "" {
|
||||
if city != "" {
|
||||
city += ", "
|
||||
}
|
||||
|
||||
city += addr.Zip
|
||||
separator := addr.Separator
|
||||
if separator == "" {
|
||||
separator = i.addrSeparator
|
||||
}
|
||||
|
||||
if name != "" {
|
||||
locality := addr.City
|
||||
if addr.State != "" {
|
||||
if locality != "" {
|
||||
locality += separator
|
||||
}
|
||||
locality += addr.State
|
||||
}
|
||||
if addr.Zip != "" {
|
||||
if locality != "" {
|
||||
locality += separator
|
||||
}
|
||||
locality += addr.Zip
|
||||
}
|
||||
|
||||
if addr.Name != "" {
|
||||
addressParagraph.Append(addr.Name + "\n")
|
||||
}
|
||||
if addr.Street != "" {
|
||||
addressParagraph.Append(addr.Street + "\n")
|
||||
}
|
||||
if city != "" {
|
||||
addressParagraph.Append(city + "\n")
|
||||
if addr.Street2 != "" {
|
||||
addressParagraph.Append(addr.Street2 + "\n")
|
||||
}
|
||||
if locality != "" {
|
||||
addressParagraph.Append(locality + "\n")
|
||||
}
|
||||
if addr.Country != "" {
|
||||
addressParagraph.Append(addr.Country + "\n")
|
||||
@ -727,10 +759,9 @@ func (i *Invoice) generateInformationBlocks(ctx DrawContext) ([]*Block, DrawCont
|
||||
separatorParagraph := newStyledParagraph(i.defaultStyle)
|
||||
separatorParagraph.SetMargins(0, 0, 0, 20)
|
||||
|
||||
addrParagraphs := i.drawAddress(i.sellerAddress.Name, "", i.sellerAddress)
|
||||
addrParagraphs := i.drawAddress(i.sellerAddress)
|
||||
addrParagraphs = append(addrParagraphs, separatorParagraph)
|
||||
addrParagraphs = append(addrParagraphs,
|
||||
i.drawAddress("Bill to", i.buyerAddress.Name, i.buyerAddress)...)
|
||||
addrParagraphs = append(addrParagraphs, i.drawAddress(i.buyerAddress)...)
|
||||
|
||||
addrDivision := newDivision()
|
||||
for _, addrParagraph := range addrParagraphs {
|
||||
|
@ -30,7 +30,7 @@ func TestInvoiceSimple(t *testing.T) {
|
||||
|
||||
// Set invoice addresses.
|
||||
invoice.SetSellerAddress(&InvoiceAddress{
|
||||
Name: "John Doe",
|
||||
Heading: "John Doe",
|
||||
Street: "8 Elm Street",
|
||||
City: "Cambridge",
|
||||
Zip: "CB14DH",
|
||||
@ -40,6 +40,7 @@ func TestInvoiceSimple(t *testing.T) {
|
||||
})
|
||||
|
||||
invoice.SetBuyerAddress(&InvoiceAddress{
|
||||
Heading: "Bill to",
|
||||
Name: "Jane Doe",
|
||||
Street: "9 Elm Street",
|
||||
City: "London",
|
||||
@ -127,7 +128,7 @@ func TestInvoiceAdvanced(t *testing.T) {
|
||||
|
||||
// Set invoice addresses.
|
||||
invoice.SetSellerAddress(&InvoiceAddress{
|
||||
Name: "John Doe",
|
||||
Heading: "JOHN DOE",
|
||||
Street: "8 Elm Street",
|
||||
City: "Cambridge",
|
||||
Zip: "CB14DH",
|
||||
@ -137,13 +138,17 @@ func TestInvoiceAdvanced(t *testing.T) {
|
||||
})
|
||||
|
||||
invoice.SetBuyerAddress(&InvoiceAddress{
|
||||
Name: "Jane Doe",
|
||||
Street: "9 Elm Street",
|
||||
City: "London",
|
||||
Zip: "LB15FH",
|
||||
Country: "United Kingdom",
|
||||
Phone: "xxx-xxx-xxxx",
|
||||
Email: "janedoe@email.com",
|
||||
Heading: "JANE DOE",
|
||||
Name: "Jane Doe and Associates",
|
||||
Street: "Suite #134569",
|
||||
Street2: "1960 W CHELSEA AVE STE 2006R",
|
||||
City: "ALLENTOWN",
|
||||
State: "PA",
|
||||
Zip: "18104",
|
||||
Country: "United States",
|
||||
Phone: "xxx-xxx-xxxx",
|
||||
Email: "janedoe@email.com",
|
||||
Separator: " ",
|
||||
})
|
||||
|
||||
// Customize address styles.
|
||||
@ -198,9 +203,12 @@ func TestInvoiceAdvanced(t *testing.T) {
|
||||
invoice.SetTotal("$85.00")
|
||||
|
||||
// Set invoice content sections.
|
||||
invoice.SetNotes("Notes", "Thank you for your business.")
|
||||
invoice.SetTerms("Terms and conditions", "Full refund for 60 days after purchase.")
|
||||
invoice.AddSection("Custom section", "This is a custom section.")
|
||||
invoice.SetNotes("NOTES", "Thank you for your business.")
|
||||
invoice.SetTerms("I. TERMS OF PAYMENT", "Net 30 days on all invoices. In addition, Buyer shall pay all sales, use, customs, excise or other taxes presently or hereafter payable in regards to this transaction, and Buyer shall reimburse Seller for any such taxes or charges paid by the Seller.\nSeller shall have the continuing right to approve Buyer’s credit. Seller may at any time demand advance payment, additional security or guarantee of prompt payment. If Buyer refuses to give the payment, security or guarantee demanded, Seller may terminate the Agreement, refuse to deliver any undelivered goods and Buyer shall immediately become liable to Seller for the unpaid price of all goods delivered & for damages as provided in Paragraph V below. Buyer agrees to pay Seller cost of collection of overdue invoices, including reasonable attorney’s fees incurred by Seller in collecting said sums. F.O.B. point shall be point of SHIP TO on face hereof.")
|
||||
invoice.AddSection("II. DELIVERY, TOLERANCES, WEIGHT", "Upon due tender of goods for delivery at the F.O.B. point all risk of loss or damage and other incident of ownership pass to Buyer, but Seller retains a security interest in the goods until purchase price is paid. All deliveries are subject to weight at shipping point which shall govern.")
|
||||
invoice.AddSection("III. WARRANTIES", "Seller warrants that goods sold hereunder are merchantable UNLESS manufactured in conformance with Buyer’s particular specification, and that Seller conveys good title thereto. IN NO EVENT WILL SELLER BE LIABLE FOR CONSEQUENTIAL DAMAGES EVEN IF CUSTOMER HAS NOT BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. EXCEPT FOR THE EXPRESS WARRANTY STATED IN THIS PARAGRAPH IV, SELLER GRANTS NO WARRANTIES, EITHER EXPRESS OR IMPLIED HEREIN, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND THIS STATED EXPRESS WARRANTY IS IN LIEU OF ALL LIABILITIES OR OBLIGATIONS OF SELLER FOR DAMAGES INCLUDING BUT NOT LIMITED TO, CONSEQUENTIAL DAMAGES OCCURRING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF ANY GOODS SOLD HEREUNDER. Seller specifically does not warrant the accuracy of sufficiency of any advice or recommendations given to Buyer in connection with the sale of goods hereunder.")
|
||||
invoice.AddSection("IV. FORCE MAJEURE", "Seller shall not be liable for any damages resulting from: any delay or failure of performance arising from any cause not reasonably within Seller’s control; accidents to, breakdowns or mechanical failure of machinery or equipment, however caused; strikes or other labor troubles, shortage of labor, transportation, raw materials, energy sources, or failure of ususal means of supply; fire; flood; war, declared or undeclared; insurrection; riots; acts of God or the public enemy; or priorities, allocations or limitations or other acts required or requested by Federal, State or local governments or any of their sub-divisions, bureaus or agencies. Seller may, at its option, cancel this Agreement or delay performance hereunder for any period reasonably necessary due to any of the foregoing, during which time this Agreement shall remain in full force and effect. Seller shall have the further right to then allocate its available goods between its own uses and its customers in such manner as Seller may consider equitable.")
|
||||
invoice.AddSection("V. PATENT INDEMNITY", "Seller shall defend and hold Buyer harmless for any action against Seller based in a claim that Buyer’s sale or use of goods normally offered for sale by Seller, supplied by Seller hereunder, and while in the form, state or conditions supplies constitutes infringement of any United States letters patent; provided Seller shall receive prompt written notice of the claim or action, and Buyer shall give Seller authority, information and assistance at Seller’s expense. Buyer shall defend and hold Seller harmless for any action against Seller or its suppliers based in a claim that the manufacture or sale of goods hereunder constitutes infringement of any United States letters patent, if such goods were manufactured pursuant to Buyer’s designs, specifications and /or formulae, and were not normally offered for sale by Seller; provided Buyer shall receive prompt written notice of the claim or action and Seller shall give Buyer authority, information and assistance at Buyer’s expense. Buyer and Seller agree that the foregoing constitutes the parties’ entire liability for claims or actions based on patent infringement.")
|
||||
|
||||
// Customize note styles.
|
||||
noteStyle := invoice.NoteStyle()
|
||||
|
@ -507,7 +507,7 @@ func (p *StyledParagraph) wrapText() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GeneratePageBlocks generates the page blocks. Multiple blocks are generated
|
||||
// GeneratePageBlocks generates the page blocks. Multiple blocks are generated
|
||||
// if the contents wrap over multiple pages. Implements the Drawable interface.
|
||||
func (p *StyledParagraph) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext, error) {
|
||||
origContext := ctx
|
||||
@ -523,29 +523,9 @@ func (p *StyledParagraph) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawCon
|
||||
|
||||
// Use available space.
|
||||
p.SetWidth(ctx.Width)
|
||||
|
||||
if p.Height() > ctx.Height {
|
||||
// Goes out of the bounds. Write on a new template instead and create a new context at upper
|
||||
// left corner.
|
||||
// TODO: Handle case when Paragraph is larger than the Page...
|
||||
// Should be fine if we just break on the paragraph, i.e. splitting it up over 2+ pages
|
||||
|
||||
blocks = append(blocks, blk)
|
||||
blk = NewBlock(ctx.PageWidth, ctx.PageHeight)
|
||||
|
||||
// New Page.
|
||||
ctx.Page++
|
||||
newContext := ctx
|
||||
newContext.Y = ctx.Margins.top // + p.Margins.top
|
||||
newContext.X = ctx.Margins.left + p.margins.left
|
||||
newContext.Height = ctx.PageHeight - ctx.Margins.top - ctx.Margins.bottom - p.margins.bottom
|
||||
newContext.Width = ctx.PageWidth - ctx.Margins.left - ctx.Margins.right - p.margins.left - p.margins.right
|
||||
ctx = newContext
|
||||
}
|
||||
} else {
|
||||
// Absolute.
|
||||
// Absolute. Use necessary space.
|
||||
if int(p.wrapWidth) <= 0 {
|
||||
// Use necessary space.
|
||||
p.SetWidth(p.getTextWidth())
|
||||
}
|
||||
ctx.X = p.xPos
|
||||
@ -556,14 +536,40 @@ func (p *StyledParagraph) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawCon
|
||||
p.beforeRender(p, ctx)
|
||||
}
|
||||
|
||||
// Place the Paragraph on the template at position (x,y) based on the ctx.
|
||||
ctx, err := drawStyledParagraphOnBlock(blk, p, ctx)
|
||||
if err != nil {
|
||||
common.Log.Debug("ERROR: %v", err)
|
||||
// Wrap paragraph chunks into lines, based on the available context width.
|
||||
if err := p.wrapText(); err != nil {
|
||||
return nil, ctx, err
|
||||
}
|
||||
|
||||
blocks = append(blocks, blk)
|
||||
// Draw paragraph blocks.
|
||||
lines := p.lines
|
||||
for {
|
||||
// Draw paragraph on block.
|
||||
newCtx, remaining, err := drawStyledParagraphOnBlock(blk, p, lines, ctx)
|
||||
if err != nil {
|
||||
common.Log.Debug("ERROR: %v", err)
|
||||
return nil, ctx, err
|
||||
}
|
||||
ctx = newCtx
|
||||
blocks = append(blocks, blk)
|
||||
|
||||
// If the current block height was not sufficient for all the paragraph
|
||||
// lines, create a new block to draw the remaining lines on.
|
||||
if lines = remaining; len(remaining) == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
// Create new page block.
|
||||
blk = NewBlock(ctx.PageWidth, ctx.PageHeight)
|
||||
ctx.Page++
|
||||
newCtx = ctx
|
||||
newCtx.Y = ctx.Margins.top
|
||||
newCtx.X = ctx.Margins.left + p.margins.left
|
||||
newCtx.Height = ctx.PageHeight - ctx.Margins.top - ctx.Margins.bottom - p.margins.bottom
|
||||
newCtx.Width = ctx.PageWidth - ctx.Margins.left - ctx.Margins.right - p.margins.left - p.margins.right
|
||||
ctx = newCtx
|
||||
}
|
||||
|
||||
if p.positioning.isRelative() {
|
||||
ctx.X -= p.margins.left // Move back.
|
||||
ctx.Width = origContext.Width
|
||||
@ -574,7 +580,7 @@ func (p *StyledParagraph) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawCon
|
||||
}
|
||||
|
||||
// Draw block on specified location on Page, adding to the content stream.
|
||||
func drawStyledParagraphOnBlock(blk *Block, p *StyledParagraph, ctx DrawContext) (DrawContext, error) {
|
||||
func drawStyledParagraphOnBlock(blk *Block, p *StyledParagraph, lines [][]*TextChunk, ctx DrawContext) (DrawContext, [][]*TextChunk, error) {
|
||||
// Find first free index for the font resources of the paragraph.
|
||||
num := 1
|
||||
fontName := core.PdfObjectName(fmt.Sprintf("Font%d", num))
|
||||
@ -586,40 +592,51 @@ func drawStyledParagraphOnBlock(blk *Block, p *StyledParagraph, ctx DrawContext)
|
||||
// Add default font to the page resources.
|
||||
err := blk.resources.SetFontByName(fontName, p.defaultStyle.Font.ToPdfObject())
|
||||
if err != nil {
|
||||
return ctx, err
|
||||
return ctx, nil, err
|
||||
}
|
||||
num++
|
||||
|
||||
defaultFontName := fontName
|
||||
defaultFontSize := p.defaultStyle.FontSize
|
||||
|
||||
// Wrap the text into lines.
|
||||
p.wrapText()
|
||||
|
||||
// Add the fonts of all chunks to the page resources.
|
||||
relativePos := p.positioning.isRelative()
|
||||
var fonts [][]core.PdfObjectName
|
||||
|
||||
var yOffset float64
|
||||
for i, line := range p.lines {
|
||||
var nextBlockLines [][]*TextChunk
|
||||
var totalHeight float64
|
||||
for i, line := range lines {
|
||||
var fontLine []core.PdfObjectName
|
||||
|
||||
var height float64
|
||||
for _, chunk := range line {
|
||||
style := chunk.Style
|
||||
if i == 0 && style.FontSize > yOffset {
|
||||
yOffset = style.FontSize
|
||||
}
|
||||
if style.FontSize > height {
|
||||
height = style.FontSize
|
||||
}
|
||||
|
||||
fontName = core.PdfObjectName(fmt.Sprintf("Font%d", num))
|
||||
|
||||
err := blk.resources.SetFontByName(fontName, style.Font.ToPdfObject())
|
||||
if err != nil {
|
||||
return ctx, err
|
||||
return ctx, nil, err
|
||||
}
|
||||
|
||||
fontLine = append(fontLine, fontName)
|
||||
num++
|
||||
}
|
||||
|
||||
// Check if line fits on the current block.
|
||||
height *= p.lineHeight
|
||||
if relativePos && totalHeight+height > ctx.Height {
|
||||
nextBlockLines = lines[i:]
|
||||
lines = lines[:i]
|
||||
break
|
||||
}
|
||||
|
||||
totalHeight += height
|
||||
fonts = append(fonts, fontLine)
|
||||
}
|
||||
|
||||
@ -637,7 +654,7 @@ func drawStyledParagraphOnBlock(blk *Block, p *StyledParagraph, ctx DrawContext)
|
||||
cc.Add_BT()
|
||||
|
||||
currY := yPos
|
||||
for idx, line := range p.lines {
|
||||
for idx, line := range lines {
|
||||
currX := ctx.X
|
||||
|
||||
if idx != 0 {
|
||||
@ -645,7 +662,7 @@ func drawStyledParagraphOnBlock(blk *Block, p *StyledParagraph, ctx DrawContext)
|
||||
cc.Add_Tstar()
|
||||
}
|
||||
|
||||
isLastLine := idx == len(p.lines)-1
|
||||
isLastLine := idx == len(lines)-1
|
||||
|
||||
// Get width of the line (excluding spaces).
|
||||
var (
|
||||
@ -665,7 +682,7 @@ func drawStyledParagraphOnBlock(blk *Block, p *StyledParagraph, ctx DrawContext)
|
||||
|
||||
spaceMetrics, found := style.Font.GetRuneMetrics(' ')
|
||||
if !found {
|
||||
return ctx, errors.New("the font does not have a space glyph")
|
||||
return ctx, nil, errors.New("the font does not have a space glyph")
|
||||
}
|
||||
|
||||
var chunkSpaces uint
|
||||
@ -683,7 +700,7 @@ func drawStyledParagraphOnBlock(blk *Block, p *StyledParagraph, ctx DrawContext)
|
||||
metrics, found := style.Font.GetRuneMetrics(r)
|
||||
if !found {
|
||||
common.Log.Debug("Unsupported rune %v in font\n", r)
|
||||
return ctx, errors.New("unsupported text glyph")
|
||||
return ctx, nil, errors.New("unsupported text glyph")
|
||||
}
|
||||
|
||||
chunkWidth += style.FontSize * metrics.Wx
|
||||
@ -750,7 +767,7 @@ func drawStyledParagraphOnBlock(blk *Block, p *StyledParagraph, ctx DrawContext)
|
||||
if p.alignment != TextAlignmentJustify || isLastLine {
|
||||
spaceMetrics, found := style.Font.GetRuneMetrics(' ')
|
||||
if !found {
|
||||
return ctx, errors.New("the font does not have a space glyph")
|
||||
return ctx, nil, errors.New("the font does not have a space glyph")
|
||||
}
|
||||
|
||||
fontName = fonts[idx][k]
|
||||
@ -870,8 +887,8 @@ func drawStyledParagraphOnBlock(blk *Block, p *StyledParagraph, ctx DrawContext)
|
||||
|
||||
blk.addContents(ops)
|
||||
|
||||
if p.positioning.isRelative() {
|
||||
pHeight := p.Height() + p.margins.bottom
|
||||
if relativePos {
|
||||
pHeight := totalHeight + p.margins.bottom
|
||||
ctx.Y += pHeight
|
||||
ctx.Height -= pHeight
|
||||
|
||||
@ -881,5 +898,5 @@ func drawStyledParagraphOnBlock(blk *Block, p *StyledParagraph, ctx DrawContext)
|
||||
}
|
||||
}
|
||||
|
||||
return ctx, nil
|
||||
return ctx, nextBlockLines, nil
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
@ -373,21 +373,20 @@ func (table *Table) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext,
|
||||
case *Division:
|
||||
div := t
|
||||
|
||||
ctx := DrawContext{
|
||||
X: xrel,
|
||||
Y: yrel,
|
||||
Width: w,
|
||||
}
|
||||
c := ctx
|
||||
c.X = xrel
|
||||
c.Y = yrel
|
||||
c.Width = w
|
||||
|
||||
// Mock call to generate page blocks.
|
||||
divBlocks, updCtx, err := div.GeneratePageBlocks(ctx)
|
||||
divBlocks, _, err := div.GeneratePageBlocks(c)
|
||||
if err != nil {
|
||||
return nil, ctx, err
|
||||
}
|
||||
|
||||
if len(divBlocks) > 1 {
|
||||
// Wraps across page, make cell reach all the way to bottom of current page.
|
||||
newh := ctx.Height - h
|
||||
newh := c.Height - h
|
||||
if newh > h {
|
||||
diffh := newh - h
|
||||
// Add diff to last row.
|
||||
@ -395,10 +394,8 @@ func (table *Table) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext,
|
||||
}
|
||||
}
|
||||
|
||||
newh := div.Height() + div.margins.top + div.margins.bottom
|
||||
_ = updCtx
|
||||
|
||||
// Get available width and height.
|
||||
newh := div.Height() + div.margins.top + div.margins.bottom
|
||||
if newh > h {
|
||||
diffh := newh - h
|
||||
// Add diff to last row.
|
||||
@ -604,6 +601,7 @@ func (table *Table) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext,
|
||||
}
|
||||
|
||||
ctx.Y += h
|
||||
ctx.Height -= h
|
||||
|
||||
// Resume previous state after headers have been rendered.
|
||||
if drawingHeaders && cellIdx+1 > endHeaderCell {
|
||||
@ -629,6 +627,7 @@ func (table *Table) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext,
|
||||
ctx.Width = origCtx.Width
|
||||
// Add the bottom margin.
|
||||
ctx.Y += table.margins.bottom
|
||||
ctx.Height -= table.margins.bottom
|
||||
|
||||
return blocks, ctx, nil
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user