unipdf/pdf/creator/toc_line.go

187 lines
3.8 KiB
Go
Raw Normal View History

2018-09-27 20:55:58 +03:00
/*
* This file is subject to the terms and conditions defined in
* file 'LICENSE.md', which is part of this source code package.
*/
package creator
import (
"strings"
)
type TOCLine struct {
sp *StyledParagraph
Number TextChunk
Title TextChunk
Page TextChunk
Separator TextChunk
2018-09-27 20:55:58 +03:00
level uint
offset float64
levelOffset float64
2018-09-30 19:06:08 +03:00
// Positioning: relative/absolute.
positioning positioning
2018-09-27 20:55:58 +03:00
}
func NewTOCLine(number, title, page string, level uint) *TOCLine {
style := NewTextStyle()
return NewStyledTOCLine(
TextChunk{
Text: number,
Style: style,
},
TextChunk{
Text: title,
Style: style,
},
TextChunk{
Text: page,
Style: style,
},
2018-09-27 20:55:58 +03:00
level,
)
}
func NewStyledTOCLine(number, title, page TextChunk, level uint) *TOCLine {
style := NewTextStyle()
sp := NewStyledParagraph("", style)
sp.SetEnableWrap(true)
sp.SetTextAlignment(TextAlignmentLeft)
2018-09-30 19:06:08 +03:00
sp.SetMargins(0, 0, 2, 2)
2018-09-27 20:55:58 +03:00
tl := &TOCLine{
sp: sp,
Number: number,
Title: title,
Page: page,
Separator: TextChunk{
2018-09-27 20:55:58 +03:00
Text: ".",
Style: style,
},
offset: 0,
level: level,
levelOffset: 10,
2018-09-27 20:55:58 +03:00
}
sp.margins.left = tl.offset + float64(tl.level-1)*tl.levelOffset
2018-09-27 20:55:58 +03:00
sp.beforeRender = tl.prepareParagraph
return tl
}
func (tl *TOCLine) Level() uint {
return tl.level
}
func (tl *TOCLine) SetLevel(level uint) {
tl.level = level
tl.sp.margins.left = tl.offset + float64(tl.level-1)*tl.levelOffset
}
func (tl *TOCLine) LevelOffset() float64 {
return tl.levelOffset
}
func (tl *TOCLine) SetLevelOffset(levelOffset float64) {
tl.levelOffset = levelOffset
tl.sp.margins.left = tl.offset + float64(tl.level-1)*tl.levelOffset
}
// GetMargins returns the margins of the TOC line: left, right, top, bottom.
func (tl *TOCLine) GetMargins() (float64, float64, float64, float64) {
m := &tl.sp.margins
return tl.offset, m.right, m.top, m.bottom
}
// SetMargins sets the margins TOC line.
func (tl *TOCLine) SetMargins(left, right, top, bottom float64) {
tl.offset = left
m := &tl.sp.margins
m.left = tl.offset + float64(tl.level-1)*tl.levelOffset
m.right = right
m.top = top
m.bottom = bottom
}
2018-09-27 20:55:58 +03:00
func (tl *TOCLine) prepareParagraph(sp *StyledParagraph, ctx DrawContext) {
// Add text chunks to the paragraph
title := tl.Title.Text
if tl.Number.Text != "" {
title = " " + title
2018-09-27 20:55:58 +03:00
}
title += " "
2018-09-27 20:55:58 +03:00
page := tl.Page.Text
if page != "" {
page = " " + page
2018-09-27 20:55:58 +03:00
}
sp.chunks = []TextChunk{
tl.Number,
TextChunk{
Text: title,
Style: tl.Title.Style,
},
TextChunk{
Text: page,
Style: tl.Page.Style,
},
2018-09-27 20:55:58 +03:00
}
2018-09-27 20:55:58 +03:00
sp.SetEncoder(sp.encoder)
sp.wrapText()
// Insert separator
2018-09-27 20:55:58 +03:00
l := len(sp.lines)
if l == 0 {
return
}
availWidth := ctx.Width*1000 - sp.getTextLineWidth(sp.lines[l-1])
sepWidth := sp.getTextLineWidth([]TextChunk{tl.Separator})
2018-09-27 20:55:58 +03:00
sepCount := int(availWidth / sepWidth)
sepText := strings.Repeat(tl.Separator.Text, sepCount)
sepStyle := tl.Separator.Style
2018-09-27 20:55:58 +03:00
sp.Insert(2, sepText, sepStyle)
2018-09-27 20:55:58 +03:00
// Push page numbers to the end of the line
availWidth = availWidth - float64(sepCount)*sepWidth
if availWidth > 500 {
spaceMetrics, found := sepStyle.Font.GetGlyphCharMetrics("space")
2018-09-27 20:55:58 +03:00
if found && availWidth > spaceMetrics.Wx {
spaces := int(availWidth / spaceMetrics.Wx)
if spaces > 0 {
style := sepStyle
2018-09-27 20:55:58 +03:00
style.FontSize = 1
sp.Insert(2, strings.Repeat(" ", spaces), style)
}
}
}
}
func (tl *TOCLine) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext, error) {
origCtx := ctx
blocks, ctx, err := tl.sp.GeneratePageBlocks(ctx)
if err != nil {
return blocks, ctx, err
}
2018-09-30 19:06:08 +03:00
if tl.positioning.isRelative() {
2018-09-27 20:55:58 +03:00
// Move back X to same start of line.
ctx.X = origCtx.X
}
2018-09-30 19:06:08 +03:00
if tl.positioning.isAbsolute() {
2018-09-27 20:55:58 +03:00
// If absolute: return original context.
return blocks, origCtx, nil
}
return blocks, ctx, nil
}