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
|
|
|
|
|
2018-09-28 19:30:46 +03:00
|
|
|
Number TextChunk
|
|
|
|
Title TextChunk
|
|
|
|
Page TextChunk
|
|
|
|
Separator TextChunk
|
2018-09-27 20:55:58 +03:00
|
|
|
|
2018-09-28 19:30:46 +03:00
|
|
|
Level uint
|
|
|
|
LevelOffset float64
|
2018-09-27 20:55:58 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func NewTOCLine(number, title, page string, level uint) *TOCLine {
|
|
|
|
style := NewTextStyle()
|
|
|
|
|
|
|
|
return NewStyledTOCLine(
|
2018-09-28 19:30:46 +03:00
|
|
|
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)
|
|
|
|
|
|
|
|
tl := &TOCLine{
|
|
|
|
sp: sp,
|
2018-09-28 19:30:46 +03:00
|
|
|
Number: number,
|
|
|
|
Title: title,
|
|
|
|
Page: page,
|
|
|
|
Separator: TextChunk{
|
2018-09-27 20:55:58 +03:00
|
|
|
Text: ".",
|
|
|
|
Style: style,
|
|
|
|
},
|
2018-09-28 19:30:46 +03:00
|
|
|
Level: level,
|
|
|
|
LevelOffset: 10,
|
2018-09-27 20:55:58 +03:00
|
|
|
}
|
|
|
|
|
2018-09-28 19:30:46 +03:00
|
|
|
sp.margins.left = float64(tl.Level-1) * tl.LevelOffset
|
2018-09-27 20:55:58 +03:00
|
|
|
sp.beforeRender = tl.prepareParagraph
|
|
|
|
return tl
|
|
|
|
}
|
|
|
|
|
|
|
|
func (tl *TOCLine) prepareParagraph(sp *StyledParagraph, ctx DrawContext) {
|
2018-09-28 19:30:46 +03:00
|
|
|
// Add text chunks to the paragraph
|
|
|
|
title := tl.Title.Text
|
|
|
|
if tl.Number.Text != "" {
|
|
|
|
title = " " + title
|
2018-09-27 20:55:58 +03:00
|
|
|
}
|
2018-09-28 19:30:46 +03:00
|
|
|
title += " "
|
2018-09-27 20:55:58 +03:00
|
|
|
|
2018-09-28 19:30:46 +03:00
|
|
|
page := tl.Page.Text
|
|
|
|
if page != "" {
|
|
|
|
page = " " + page
|
2018-09-27 20:55:58 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
sp.chunks = []TextChunk{
|
2018-09-28 19:30:46 +03:00
|
|
|
tl.Number,
|
|
|
|
TextChunk{
|
|
|
|
Text: title,
|
|
|
|
Style: tl.Title.Style,
|
|
|
|
},
|
|
|
|
TextChunk{
|
|
|
|
Text: page,
|
|
|
|
Style: tl.Page.Style,
|
|
|
|
},
|
2018-09-27 20:55:58 +03:00
|
|
|
}
|
|
|
|
sp.SetEncoder(sp.encoder)
|
|
|
|
sp.wrapText()
|
|
|
|
|
2018-09-28 19:30:46 +03:00
|
|
|
// 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])
|
2018-09-28 19:30:46 +03:00
|
|
|
sepWidth := sp.getTextLineWidth([]TextChunk{tl.Separator})
|
2018-09-27 20:55:58 +03:00
|
|
|
sepCount := int(availWidth / sepWidth)
|
2018-09-28 19:30:46 +03:00
|
|
|
sepText := strings.Repeat(tl.Separator.Text, sepCount)
|
|
|
|
sepStyle := tl.Separator.Style
|
2018-09-27 20:55:58 +03:00
|
|
|
|
2018-09-28 19:30:46 +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 {
|
2018-09-28 19:30:46 +03:00
|
|
|
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 {
|
2018-09-28 19:30:46 +03:00
|
|
|
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
|
|
|
|
}
|
|
|
|
if len(blocks) > 1 {
|
|
|
|
// Did not fit, moved to new Page block.
|
|
|
|
ctx.Page++
|
|
|
|
}
|
|
|
|
|
|
|
|
if tl.sp.positioning.isRelative() {
|
|
|
|
// Move back X to same start of line.
|
|
|
|
ctx.X = origCtx.X
|
|
|
|
}
|
|
|
|
|
|
|
|
if tl.sp.positioning.isAbsolute() {
|
|
|
|
// If absolute: return original context.
|
|
|
|
return blocks, origCtx, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return blocks, ctx, nil
|
|
|
|
}
|