2018-09-30 19:06:08 +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 "github.com/unidoc/unidoc/pdf/model/fonts"
|
|
|
|
|
2018-10-01 21:53:32 +03:00
|
|
|
// TOC represents a table of contents component.
|
|
|
|
// It consists of a paragraph heading and a collection of
|
|
|
|
// table of contents lines.
|
2018-09-30 19:06:08 +03:00
|
|
|
type TOC struct {
|
|
|
|
// The heading of the table of contents.
|
|
|
|
heading *StyledParagraph
|
|
|
|
|
|
|
|
// The lines of the table of contents.
|
|
|
|
lines []*TOCLine
|
|
|
|
|
2018-09-30 19:53:06 +03:00
|
|
|
// The style of the number part of new TOC lines.
|
2018-09-30 19:06:08 +03:00
|
|
|
lineNumberStyle TextStyle
|
|
|
|
|
2018-09-30 19:53:06 +03:00
|
|
|
// The style of the title part of new TOC lines.
|
2018-09-30 19:06:08 +03:00
|
|
|
lineTitleStyle TextStyle
|
|
|
|
|
2018-09-30 19:53:06 +03:00
|
|
|
// The style of the separator part of new TOC lines.
|
2018-09-30 19:06:08 +03:00
|
|
|
lineSeparatorStyle TextStyle
|
|
|
|
|
2018-09-30 19:53:06 +03:00
|
|
|
// The style of the page part of new TOC lines.
|
2018-09-30 19:06:08 +03:00
|
|
|
linePageStyle TextStyle
|
2018-09-30 19:26:11 +03:00
|
|
|
|
2018-09-30 19:53:06 +03:00
|
|
|
// The separator for new TOC lines.
|
|
|
|
lineSeparator string
|
|
|
|
|
|
|
|
// The amount of space an indentation level occupies in a TOC line.
|
|
|
|
lineLevelOffset float64
|
|
|
|
|
|
|
|
// The margins of new TOC lines.
|
|
|
|
lineMargins margins
|
|
|
|
|
2018-09-30 19:26:11 +03:00
|
|
|
// Positioning: relative/absolute.
|
|
|
|
positioning positioning
|
2018-09-30 19:06:08 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewTOC creates a new table of contents.
|
|
|
|
func NewTOC(title string) *TOC {
|
|
|
|
headingStyle := NewTextStyle()
|
|
|
|
headingStyle.Font = fonts.NewFontHelveticaBold()
|
|
|
|
headingStyle.FontSize = 14
|
|
|
|
|
|
|
|
heading := NewStyledParagraph(title, headingStyle)
|
|
|
|
heading.SetEnableWrap(true)
|
|
|
|
heading.SetTextAlignment(TextAlignmentLeft)
|
|
|
|
heading.SetMargins(0, 0, 0, 5)
|
|
|
|
|
|
|
|
lineStyle := NewTextStyle()
|
|
|
|
|
|
|
|
return &TOC{
|
|
|
|
heading: heading,
|
|
|
|
lines: []*TOCLine{},
|
|
|
|
lineNumberStyle: lineStyle,
|
|
|
|
lineTitleStyle: lineStyle,
|
|
|
|
lineSeparatorStyle: lineStyle,
|
|
|
|
linePageStyle: lineStyle,
|
2018-09-30 19:53:06 +03:00
|
|
|
lineSeparator: ".",
|
|
|
|
lineLevelOffset: 10,
|
|
|
|
lineMargins: margins{0, 0, 2, 2},
|
2018-09-30 19:26:11 +03:00
|
|
|
positioning: positionRelative,
|
2018-09-30 19:06:08 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Heading returns the heading component of the table of contents.
|
|
|
|
func (t *TOC) Heading() *StyledParagraph {
|
|
|
|
return t.heading
|
|
|
|
}
|
|
|
|
|
2018-10-01 21:40:51 +03:00
|
|
|
// SetHeading sets the text and the style of the heading of the TOC component.
|
2018-09-30 19:06:08 +03:00
|
|
|
func (t *TOC) SetHeading(text string, style TextStyle) {
|
|
|
|
t.heading.Reset(text, style)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add adds a new line with the default style to the table of contents.
|
|
|
|
func (t *TOC) Add(number, title, page string, level uint) *TOCLine {
|
|
|
|
tl := t.AddLine(NewStyledTOCLine(
|
|
|
|
TextChunk{
|
|
|
|
Text: number,
|
|
|
|
Style: t.lineNumberStyle,
|
|
|
|
},
|
|
|
|
TextChunk{
|
|
|
|
Text: title,
|
|
|
|
Style: t.lineTitleStyle,
|
|
|
|
},
|
|
|
|
TextChunk{
|
|
|
|
Text: page,
|
|
|
|
Style: t.linePageStyle,
|
|
|
|
},
|
|
|
|
level,
|
|
|
|
))
|
|
|
|
|
2018-09-30 19:53:06 +03:00
|
|
|
if tl == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set line margins.
|
|
|
|
m := &t.lineMargins
|
|
|
|
tl.SetMargins(m.left, m.right, m.top, m.bottom)
|
|
|
|
|
2018-10-01 21:40:51 +03:00
|
|
|
// Set line level offset.
|
2018-09-30 19:53:06 +03:00
|
|
|
tl.SetLevelOffset(t.lineLevelOffset)
|
|
|
|
|
2018-10-01 21:40:51 +03:00
|
|
|
// Set line separator text and style.
|
2018-09-30 19:53:06 +03:00
|
|
|
tl.Separator.Text = t.lineSeparator
|
2018-09-30 19:06:08 +03:00
|
|
|
tl.Separator.Style = t.lineSeparatorStyle
|
2018-09-30 19:53:06 +03:00
|
|
|
|
2018-09-30 19:06:08 +03:00
|
|
|
return tl
|
|
|
|
}
|
|
|
|
|
2018-10-01 21:19:20 +03:00
|
|
|
// AddLine adds a new line with the provided style to the table of contents.
|
2018-09-30 19:06:08 +03:00
|
|
|
func (t *TOC) AddLine(line *TOCLine) *TOCLine {
|
|
|
|
if line == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
t.lines = append(t.lines, line)
|
|
|
|
return line
|
|
|
|
}
|
|
|
|
|
2018-10-01 21:53:32 +03:00
|
|
|
// SetLineSeparator sets the separator for all new lines of the table of contents.
|
2018-09-30 19:06:08 +03:00
|
|
|
func (t *TOC) SetLineSeparator(separator string) {
|
2018-09-30 19:53:06 +03:00
|
|
|
t.lineSeparator = separator
|
2018-09-30 19:06:08 +03:00
|
|
|
}
|
|
|
|
|
2018-10-01 21:53:32 +03:00
|
|
|
// SetLineMargins sets the margins for all new lines of the table of contents.
|
2018-09-30 19:06:08 +03:00
|
|
|
func (t *TOC) SetLineMargins(left, right, top, bottom float64) {
|
2018-10-01 21:40:51 +03:00
|
|
|
m := &t.lineMargins
|
2018-09-30 19:53:06 +03:00
|
|
|
|
2018-10-01 21:40:51 +03:00
|
|
|
m.left = left
|
|
|
|
m.right = right
|
|
|
|
m.top = top
|
|
|
|
m.bottom = bottom
|
2018-09-30 19:06:08 +03:00
|
|
|
}
|
|
|
|
|
2018-10-01 21:53:32 +03:00
|
|
|
// SetLineNumberStyle sets the style for the numbers part of all new lines
|
|
|
|
// of the table of contents.
|
2018-09-30 19:06:08 +03:00
|
|
|
func (t *TOC) SetLineNumberStyle(style TextStyle) {
|
|
|
|
t.lineNumberStyle = style
|
|
|
|
}
|
|
|
|
|
2018-10-01 21:53:32 +03:00
|
|
|
// SetLineTitleStyle sets the style for the title part of all new lines
|
|
|
|
// of the table of contents.
|
2018-09-30 19:06:08 +03:00
|
|
|
func (t *TOC) SetLineTitleStyle(style TextStyle) {
|
|
|
|
t.lineTitleStyle = style
|
|
|
|
}
|
|
|
|
|
2018-10-01 21:53:32 +03:00
|
|
|
// SetLineSeparatorStyle sets the style for the separator part of all new
|
|
|
|
// lines of the table of contents.
|
2018-09-30 19:06:08 +03:00
|
|
|
func (t *TOC) SetLineSeparatorStyle(style TextStyle) {
|
|
|
|
t.lineSeparatorStyle = style
|
|
|
|
}
|
|
|
|
|
2018-10-01 21:53:32 +03:00
|
|
|
// SetLinePageStyle sets the style for the page part of all new lines
|
|
|
|
// of the table of contents.
|
2018-09-30 19:06:08 +03:00
|
|
|
func (t *TOC) SetLinePageStyle(style TextStyle) {
|
|
|
|
t.linePageStyle = style
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetLineLevelOffset sets the amount of space an indentation level occupies
|
2018-10-01 21:53:32 +03:00
|
|
|
// for all new lines of the table of contents.
|
2018-09-30 19:06:08 +03:00
|
|
|
func (t *TOC) SetLineLevelOffset(levelOffset float64) {
|
2018-09-30 19:53:06 +03:00
|
|
|
t.lineLevelOffset = levelOffset
|
2018-09-30 19:06:08 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// GeneratePageBlocks generate the Page blocks. Multiple blocks are generated if the contents wrap over
|
|
|
|
// multiple pages.
|
|
|
|
func (t *TOC) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext, error) {
|
|
|
|
origCtx := ctx
|
|
|
|
|
2018-09-30 19:53:06 +03:00
|
|
|
// Generate heading blocks.
|
2018-09-30 19:06:08 +03:00
|
|
|
blocks, ctx, err := t.heading.GeneratePageBlocks(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return blocks, ctx, err
|
|
|
|
}
|
|
|
|
|
2018-09-30 19:53:06 +03:00
|
|
|
// Generate blocks for the table of contents lines.
|
2018-09-30 19:06:08 +03:00
|
|
|
for _, line := range t.lines {
|
|
|
|
newBlocks, c, err := line.GeneratePageBlocks(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return blocks, ctx, err
|
|
|
|
}
|
|
|
|
if len(newBlocks) < 1 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2018-09-30 19:53:06 +03:00
|
|
|
// The first block is always appended to the last.
|
2018-09-30 19:06:08 +03:00
|
|
|
blocks[len(blocks)-1].mergeBlocks(newBlocks[0])
|
|
|
|
blocks = append(blocks, newBlocks[1:]...)
|
|
|
|
|
|
|
|
ctx = c
|
|
|
|
}
|
|
|
|
|
|
|
|
if t.positioning.isRelative() {
|
|
|
|
// Move back X to same start of line.
|
|
|
|
ctx.X = origCtx.X
|
|
|
|
}
|
|
|
|
|
|
|
|
if t.positioning.isAbsolute() {
|
|
|
|
// If absolute: return original context.
|
|
|
|
return blocks, origCtx, nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return blocks, ctx, nil
|
|
|
|
}
|