mirror of
https://github.com/unidoc/unipdf.git
synced 2025-05-01 22:17:29 +08:00
Merge pull request #360 from adrg/creator-chapter-hierarchy
Creator chapter hierarchy
This commit is contained in:
commit
0dc0219e8f
@ -17,14 +17,21 @@ import (
|
||||
// Chapter is used to arrange multiple drawables (paragraphs, images, etc) into a single section.
|
||||
// The concept is the same as a book or a report chapter.
|
||||
type Chapter struct {
|
||||
number int
|
||||
title string
|
||||
// The number of the chapter.
|
||||
number int
|
||||
|
||||
// The title of the chapter.
|
||||
title string
|
||||
|
||||
// The heading paragraph of the chapter.
|
||||
heading *Paragraph
|
||||
|
||||
subchapters int
|
||||
|
||||
// The content components of the chapter.
|
||||
contents []Drawable
|
||||
|
||||
// The number of subchapters the chapter has.
|
||||
subchapters int
|
||||
|
||||
// Show chapter numbering
|
||||
showNumbering bool
|
||||
|
||||
@ -40,6 +47,9 @@ type Chapter struct {
|
||||
// Margins to be applied around the block when drawing on Page.
|
||||
margins margins
|
||||
|
||||
// Reference to the parent chapter the current chapter belongs to.
|
||||
parent *Chapter
|
||||
|
||||
// Reference to the TOC of the creator.
|
||||
toc *TOC
|
||||
|
||||
@ -48,36 +58,53 @@ type Chapter struct {
|
||||
|
||||
// The item of the chapter in the outline.
|
||||
outlineItem *model.OutlineItem
|
||||
|
||||
// The level of the chapter in the chapters hierarchy.
|
||||
level uint
|
||||
}
|
||||
|
||||
// newChapter creates a new chapter with the specified title as the heading.
|
||||
func newChapter(toc *TOC, outline *model.Outline, title string, number int, style TextStyle) *Chapter {
|
||||
p := newParagraph(fmt.Sprintf("%d. %s", number, title), style)
|
||||
p.SetFont(style.Font)
|
||||
p.SetFontSize(16)
|
||||
func newChapter(parent *Chapter, toc *TOC, outline *model.Outline, title string, number int, style TextStyle) *Chapter {
|
||||
var level uint = 1
|
||||
if parent != nil {
|
||||
level = parent.level + 1
|
||||
}
|
||||
|
||||
return &Chapter{
|
||||
chapter := &Chapter{
|
||||
number: number,
|
||||
title: title,
|
||||
showNumbering: true,
|
||||
includeInTOC: true,
|
||||
parent: parent,
|
||||
toc: toc,
|
||||
outline: outline,
|
||||
heading: p,
|
||||
contents: []Drawable{},
|
||||
level: level,
|
||||
}
|
||||
|
||||
p := newParagraph(chapter.headingText(), style)
|
||||
p.SetFont(style.Font)
|
||||
p.SetFontSize(style.FontSize)
|
||||
|
||||
chapter.heading = p
|
||||
return chapter
|
||||
}
|
||||
|
||||
// NewSubchapter creates a new child chapter with the specified title.
|
||||
func (chap *Chapter) NewSubchapter(title string) *Chapter {
|
||||
style := newTextStyle(chap.heading.textFont)
|
||||
style.FontSize = 14
|
||||
|
||||
chap.subchapters++
|
||||
subchapter := newChapter(chap, chap.toc, chap.outline, title, chap.subchapters, style)
|
||||
chap.Add(subchapter)
|
||||
|
||||
return subchapter
|
||||
}
|
||||
|
||||
// SetShowNumbering sets a flag to indicate whether or not to show chapter numbers as part of title.
|
||||
func (chap *Chapter) SetShowNumbering(show bool) {
|
||||
if show {
|
||||
heading := fmt.Sprintf("%d. %s", chap.number, chap.title)
|
||||
chap.heading.SetText(heading)
|
||||
} else {
|
||||
heading := fmt.Sprintf("%s", chap.title)
|
||||
chap.heading.SetText(heading)
|
||||
}
|
||||
chap.showNumbering = show
|
||||
chap.heading.SetText(chap.headingText())
|
||||
}
|
||||
|
||||
// SetIncludeInTOC sets a flag to indicate whether or not to include in tOC.
|
||||
@ -112,10 +139,7 @@ func (chap *Chapter) Add(d Drawable) error {
|
||||
}
|
||||
|
||||
switch d.(type) {
|
||||
case *Chapter:
|
||||
common.Log.Debug("ERROR: Cannot add chapter to a chapter")
|
||||
return errors.New("type check error")
|
||||
case *Paragraph, *Image, *Block, *Subchapter, *Table, *PageBreak:
|
||||
case *Paragraph, *Image, *Block, *Table, *PageBreak, *Chapter:
|
||||
chap.contents = append(chap.contents, d)
|
||||
default:
|
||||
common.Log.Debug("Unsupported: %T", d)
|
||||
@ -125,6 +149,36 @@ func (chap *Chapter) Add(d Drawable) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// headingNumber returns the chapter heading number based on the chapter
|
||||
// hierarchy and the showNumbering property.
|
||||
func (chap *Chapter) headingNumber() string {
|
||||
var chapNumber string
|
||||
if chap.showNumbering {
|
||||
if chap.number != 0 {
|
||||
chapNumber = strconv.Itoa(chap.number) + "."
|
||||
}
|
||||
|
||||
if chap.parent != nil {
|
||||
parentChapNumber := chap.parent.headingNumber()
|
||||
if parentChapNumber != "" {
|
||||
chapNumber = parentChapNumber + chapNumber
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return chapNumber
|
||||
}
|
||||
|
||||
// headingText returns the chapter heading text content.
|
||||
func (chap *Chapter) headingText() string {
|
||||
heading := chap.title
|
||||
if chapNumber := chap.headingNumber(); chapNumber != "" {
|
||||
heading = fmt.Sprintf("%s %s", chapNumber, heading)
|
||||
}
|
||||
|
||||
return heading
|
||||
}
|
||||
|
||||
// GeneratePageBlocks generate the Page blocks. Multiple blocks are generated if the contents wrap
|
||||
// over multiple pages.
|
||||
func (chap *Chapter) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext, error) {
|
||||
@ -138,37 +192,25 @@ func (chap *Chapter) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext,
|
||||
ctx.Height -= chap.margins.top
|
||||
}
|
||||
|
||||
origX := ctx.X
|
||||
origY := ctx.Y
|
||||
|
||||
blocks, ctx, err := chap.heading.GeneratePageBlocks(ctx)
|
||||
blocks, c, err := chap.heading.GeneratePageBlocks(ctx)
|
||||
if err != nil {
|
||||
return blocks, ctx, err
|
||||
}
|
||||
if len(blocks) > 1 {
|
||||
ctx.Page++ // Did not fit, moved to new Page block.
|
||||
}
|
||||
ctx = c
|
||||
|
||||
// Generate chapter title and number.
|
||||
chapTitle := chap.title
|
||||
var chapNumber string
|
||||
posX := ctx.X
|
||||
posY := ctx.Y - chap.heading.Height()
|
||||
page := int64(ctx.Page)
|
||||
|
||||
if chap.showNumbering {
|
||||
if chap.number != 0 {
|
||||
chapNumber = strconv.Itoa(chap.number) + "."
|
||||
}
|
||||
}
|
||||
|
||||
if chapNumber != "" {
|
||||
chapTitle = fmt.Sprintf("%s %s", chapNumber, chapTitle)
|
||||
}
|
||||
chapNumber := chap.headingNumber()
|
||||
chapTitle := chap.headingText()
|
||||
|
||||
// Add to TOC.
|
||||
if chap.includeInTOC {
|
||||
line := chap.toc.Add(chapNumber, chap.title, strconv.FormatInt(page, 10), 1)
|
||||
line := chap.toc.Add(chapNumber, chap.title, strconv.FormatInt(page, 10), chap.level)
|
||||
if chap.toc.showLinks {
|
||||
line.SetLink(page, origX, origY)
|
||||
line.SetLink(page, posX, posY)
|
||||
}
|
||||
}
|
||||
|
||||
@ -176,14 +218,19 @@ func (chap *Chapter) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext,
|
||||
if chap.outlineItem == nil {
|
||||
chap.outlineItem = model.NewOutlineItem(
|
||||
chapTitle,
|
||||
model.NewOutlineDest(page-1, origX, origY),
|
||||
model.NewOutlineDest(page-1, posX, posY),
|
||||
)
|
||||
chap.outline.Add(chap.outlineItem)
|
||||
|
||||
if chap.parent != nil {
|
||||
chap.parent.outlineItem.Add(chap.outlineItem)
|
||||
} else {
|
||||
chap.outline.Add(chap.outlineItem)
|
||||
}
|
||||
} else {
|
||||
outlineDest := &chap.outlineItem.Dest
|
||||
outlineDest.Page = page - 1
|
||||
outlineDest.X = origX
|
||||
outlineDest.Y = origY
|
||||
outlineDest.X = posX
|
||||
outlineDest.Y = posY
|
||||
}
|
||||
|
||||
for _, d := range chap.contents {
|
||||
|
@ -714,13 +714,10 @@ func (c *Creator) NewStyledTOCLine(number, title, page TextChunk, level uint, st
|
||||
// NewChapter creates a new chapter with the specified title as the heading.
|
||||
func (c *Creator) NewChapter(title string) *Chapter {
|
||||
c.chapters++
|
||||
return newChapter(c.toc, c.outline, title, c.chapters, c.NewTextStyle())
|
||||
}
|
||||
style := c.NewTextStyle()
|
||||
style.FontSize = 16
|
||||
|
||||
// NewSubchapter creates a new Subchapter under Chapter ch with specified title.
|
||||
// All other parameters are set to their defaults.
|
||||
func (c *Creator) NewSubchapter(ch *Chapter, title string) *Subchapter {
|
||||
return newSubchapter(ch, title, c.NewTextStyle())
|
||||
return newChapter(nil, c.toc, c.outline, title, c.chapters, style)
|
||||
}
|
||||
|
||||
// NewInvoice returns an instance of an empty invoice.
|
||||
|
@ -793,7 +793,7 @@ func TestSubchaptersSimple(t *testing.T) {
|
||||
|
||||
// Add chapters.
|
||||
ch1 := c.NewChapter("Introduction")
|
||||
subchap1 := c.NewSubchapter(ch1, "The fundamentals of the mastery of the most genious experiment of all times in modern world history. The story of the maker and the maker bot and the genius cow.")
|
||||
subchap1 := ch1.NewSubchapter("The fundamentals of the mastery of the most genious experiment of all times in modern world history. The story of the maker and the maker bot and the genius cow.")
|
||||
subchap1.SetMargins(0, 0, 5, 0)
|
||||
|
||||
//subCh1 := NewSubchapter(ch1, "Workflow")
|
||||
@ -809,19 +809,19 @@ func TestSubchaptersSimple(t *testing.T) {
|
||||
subchap1.Add(p)
|
||||
}
|
||||
|
||||
subchap2 := c.NewSubchapter(ch1, "Mechanism")
|
||||
subchap2 := ch1.NewSubchapter("Mechanism")
|
||||
subchap2.SetMargins(0, 0, 5, 0)
|
||||
for j := 0; j < 1; j++ {
|
||||
subchap2.Add(p)
|
||||
}
|
||||
|
||||
subchap3 := c.NewSubchapter(ch1, "Discussion")
|
||||
subchap3 := ch1.NewSubchapter("Discussion")
|
||||
subchap3.SetMargins(0, 0, 5, 0)
|
||||
for j := 0; j < 1; j++ {
|
||||
subchap3.Add(p)
|
||||
}
|
||||
|
||||
subchap4 := c.NewSubchapter(ch1, "Conclusion")
|
||||
subchap4 := ch1.NewSubchapter("Conclusion")
|
||||
subchap4.SetMargins(0, 0, 5, 0)
|
||||
for j := 0; j < 1; j++ {
|
||||
subchap4.Add(p)
|
||||
@ -895,11 +895,9 @@ func TestSubchapters(t *testing.T) {
|
||||
|
||||
// Add chapters.
|
||||
ch1 := c.NewChapter("Introduction")
|
||||
subchap1 := c.NewSubchapter(ch1, "The fundamentals")
|
||||
subchap1 := ch1.NewSubchapter("The fundamentals")
|
||||
subchap1.SetMargins(0, 0, 5, 0)
|
||||
|
||||
//subCh1 := NewSubchapter(ch1, "Workflow")
|
||||
|
||||
p := c.NewParagraph("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt " +
|
||||
"ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut " +
|
||||
"aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore " +
|
||||
@ -911,19 +909,28 @@ func TestSubchapters(t *testing.T) {
|
||||
subchap1.Add(p)
|
||||
}
|
||||
|
||||
subchap2 := c.NewSubchapter(ch1, "Mechanism")
|
||||
subchap2 := ch1.NewSubchapter("Mechanism")
|
||||
subchap2.SetMargins(0, 0, 5, 0)
|
||||
for j := 0; j < 15; j++ {
|
||||
subchap2.Add(p)
|
||||
}
|
||||
|
||||
subchap3 := c.NewSubchapter(ch1, "Discussion")
|
||||
subchap3 := ch1.NewSubchapter("Discussion")
|
||||
subchap3.SetMargins(0, 0, 5, 0)
|
||||
for j := 0; j < 19; j++ {
|
||||
subchap3.Add(p)
|
||||
}
|
||||
|
||||
subchap4 := c.NewSubchapter(ch1, "Conclusion")
|
||||
// Create multi-level subchapters.
|
||||
subchap := subchap3
|
||||
for i := 0; i < 5; i++ {
|
||||
subchap = subchap.NewSubchapter(fmt.Sprintf("Discussion %d", i+1))
|
||||
for j := 0; j < 5; j++ {
|
||||
subchap.Add(p)
|
||||
}
|
||||
}
|
||||
|
||||
subchap4 := ch1.NewSubchapter("Conclusion")
|
||||
subchap4.SetMargins(0, 0, 5, 0)
|
||||
for j := 0; j < 23; j++ {
|
||||
subchap4.Add(p)
|
||||
@ -1808,7 +1815,7 @@ func TestTableInSubchapter(t *testing.T) {
|
||||
ch.GetHeading().SetFontSize(18)
|
||||
ch.GetHeading().SetColor(ColorRGBFrom8bit(72, 86, 95))
|
||||
|
||||
sc := c.NewSubchapter(ch, "Issuer details")
|
||||
sc := ch.NewSubchapter("Issuer details")
|
||||
sc.SetMargins(0, 0, 5, 0)
|
||||
sc.GetHeading().SetFont(fontRegular)
|
||||
sc.GetHeading().SetFontSize(18)
|
||||
@ -1862,7 +1869,7 @@ func TestTableInSubchapter(t *testing.T) {
|
||||
|
||||
ch.Add(issuerTable)
|
||||
|
||||
sc = c.NewSubchapter(ch, "My Statement")
|
||||
sc = ch.NewSubchapter("My Statement")
|
||||
//sc.SetMargins(0, 0, 5, 0)
|
||||
sc.GetHeading().SetFont(fontRegular)
|
||||
sc.GetHeading().SetFontSize(18)
|
||||
@ -2381,7 +2388,7 @@ func TestCombineDuplicateDirectObjects(t *testing.T) {
|
||||
c.AddTOC = true
|
||||
|
||||
ch1 := c.NewChapter("Introduction")
|
||||
subchap1 := c.NewSubchapter(ch1, "The fundamentals")
|
||||
subchap1 := ch1.NewSubchapter("The fundamentals")
|
||||
subchap1.SetMargins(0, 0, 5, 0)
|
||||
|
||||
//subCh1 := NewSubchapter(ch1, "Workflow")
|
||||
@ -2398,19 +2405,19 @@ func TestCombineDuplicateDirectObjects(t *testing.T) {
|
||||
subchap1.Add(p)
|
||||
}
|
||||
|
||||
subchap2 := c.NewSubchapter(ch1, "Mechanism")
|
||||
subchap2 := ch1.NewSubchapter("Mechanism")
|
||||
subchap2.SetMargins(0, 0, 5, 0)
|
||||
for j := 0; j < 3; j++ {
|
||||
subchap2.Add(p)
|
||||
}
|
||||
|
||||
subchap3 := c.NewSubchapter(ch1, "Discussion")
|
||||
subchap3 := ch1.NewSubchapter("Discussion")
|
||||
subchap3.SetMargins(0, 0, 5, 0)
|
||||
for j := 0; j < 4; j++ {
|
||||
subchap3.Add(p)
|
||||
}
|
||||
|
||||
subchap4 := c.NewSubchapter(ch1, "Conclusion")
|
||||
subchap4 := ch1.NewSubchapter("Conclusion")
|
||||
subchap4.SetMargins(0, 0, 5, 0)
|
||||
for j := 0; j < 3; j++ {
|
||||
subchap4.Add(p)
|
||||
@ -2588,7 +2595,7 @@ func TestCombineIdenticalIndirectObjects(t *testing.T) {
|
||||
c.AddTOC = true
|
||||
|
||||
ch1 := c.NewChapter("Introduction")
|
||||
subchap1 := c.NewSubchapter(ch1, "The fundamentals")
|
||||
subchap1 := ch1.NewSubchapter("The fundamentals")
|
||||
subchap1.SetMargins(0, 0, 5, 0)
|
||||
|
||||
//subCh1 := NewSubchapter(ch1, "Workflow")
|
||||
@ -2604,19 +2611,19 @@ func TestCombineIdenticalIndirectObjects(t *testing.T) {
|
||||
subchap1.Add(p)
|
||||
}
|
||||
|
||||
subchap2 := c.NewSubchapter(ch1, "Mechanism")
|
||||
subchap2 := ch1.NewSubchapter("Mechanism")
|
||||
subchap2.SetMargins(0, 0, 5, 0)
|
||||
for j := 0; j < 15; j++ {
|
||||
subchap2.Add(p)
|
||||
}
|
||||
|
||||
subchap3 := c.NewSubchapter(ch1, "Discussion")
|
||||
subchap3 := ch1.NewSubchapter("Discussion")
|
||||
subchap3.SetMargins(0, 0, 5, 0)
|
||||
for j := 0; j < 19; j++ {
|
||||
subchap3.Add(p)
|
||||
}
|
||||
|
||||
subchap4 := c.NewSubchapter(ch1, "Conclusion")
|
||||
subchap4 := ch1.NewSubchapter("Conclusion")
|
||||
subchap4.SetMargins(0, 0, 5, 0)
|
||||
for j := 0; j < 23; j++ {
|
||||
subchap4.Add(p)
|
||||
@ -2781,7 +2788,7 @@ func TestAllOptimizations(t *testing.T) {
|
||||
c.AddTOC = true
|
||||
|
||||
ch1 := c.NewChapter("Introduction")
|
||||
subchap1 := c.NewSubchapter(ch1, "The fundamentals")
|
||||
subchap1 := ch1.NewSubchapter("The fundamentals")
|
||||
subchap1.SetMargins(0, 0, 5, 0)
|
||||
|
||||
//subCh1 := NewSubchapter(ch1, "Workflow")
|
||||
@ -2797,19 +2804,19 @@ func TestAllOptimizations(t *testing.T) {
|
||||
subchap1.Add(p)
|
||||
}
|
||||
|
||||
subchap2 := c.NewSubchapter(ch1, "Mechanism")
|
||||
subchap2 := ch1.NewSubchapter("Mechanism")
|
||||
subchap2.SetMargins(0, 0, 5, 0)
|
||||
for j := 0; j < 15; j++ {
|
||||
subchap2.Add(p)
|
||||
}
|
||||
|
||||
subchap3 := c.NewSubchapter(ch1, "Discussion")
|
||||
subchap3 := ch1.NewSubchapter("Discussion")
|
||||
subchap3.SetMargins(0, 0, 5, 0)
|
||||
for j := 0; j < 19; j++ {
|
||||
subchap3.Add(p)
|
||||
}
|
||||
|
||||
subchap4 := c.NewSubchapter(ch1, "Conclusion")
|
||||
subchap4 := ch1.NewSubchapter("Conclusion")
|
||||
subchap4.SetMargins(0, 0, 5, 0)
|
||||
for j := 0; j < 23; j++ {
|
||||
subchap4.Add(p)
|
||||
|
@ -1,233 +0,0 @@
|
||||
/*
|
||||
* 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 (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/unidoc/unidoc/common"
|
||||
"github.com/unidoc/unidoc/pdf/model"
|
||||
)
|
||||
|
||||
// Subchapter simply represents a sub chapter pertaining to a specific Chapter. It can contain
|
||||
// multiple Drawables, just like a chapter.
|
||||
type Subchapter struct {
|
||||
subchapterNum int
|
||||
title string
|
||||
heading *Paragraph
|
||||
|
||||
contents []Drawable
|
||||
|
||||
// Show chapter numbering
|
||||
showNumbering bool
|
||||
|
||||
// Include in TOC.
|
||||
includeInTOC bool
|
||||
|
||||
// Positioning: relative / absolute.
|
||||
positioning positioning
|
||||
|
||||
// Absolute coordinates (when in absolute mode).
|
||||
xPos, yPos float64
|
||||
|
||||
// Margins to be applied around the block when drawing on Page.
|
||||
margins margins
|
||||
|
||||
// Reference to the creator's TOC.
|
||||
toc *TOC
|
||||
|
||||
// Reference to the chapter the subchapter belongs to.
|
||||
chapter *Chapter
|
||||
|
||||
// Reference to the outline of the creator.
|
||||
outline *model.Outline
|
||||
|
||||
// The item of the subchapter in the outline.
|
||||
outlineItem *model.OutlineItem
|
||||
}
|
||||
|
||||
// newSubchapter creates a new Subchapter under Chapter ch with specified title.
|
||||
// All other parameters are set to their defaults.
|
||||
func newSubchapter(ch *Chapter, title string, style TextStyle) *Subchapter {
|
||||
ch.subchapters++
|
||||
|
||||
p := newParagraph(fmt.Sprintf("%d.%d %s", ch.number, ch.subchapters, title), style)
|
||||
p.SetFont(style.Font) // bold?
|
||||
p.SetFontSize(14)
|
||||
|
||||
subchapter := &Subchapter{
|
||||
subchapterNum: ch.subchapters,
|
||||
title: title,
|
||||
showNumbering: true,
|
||||
includeInTOC: true,
|
||||
heading: p,
|
||||
contents: []Drawable{},
|
||||
chapter: ch,
|
||||
toc: ch.toc,
|
||||
outline: ch.outline,
|
||||
}
|
||||
|
||||
// Add subchapter to chapter.
|
||||
ch.Add(subchapter)
|
||||
|
||||
return subchapter
|
||||
}
|
||||
|
||||
// SetShowNumbering sets a flag to indicate whether or not to show chapter numbers as part of title.
|
||||
func (subchap *Subchapter) SetShowNumbering(show bool) {
|
||||
if show {
|
||||
heading := fmt.Sprintf("%d.%d. %s", subchap.chapter.number, subchap.subchapterNum, subchap.title)
|
||||
subchap.heading.SetText(heading)
|
||||
} else {
|
||||
heading := fmt.Sprintf("%s", subchap.title)
|
||||
subchap.heading.SetText(heading)
|
||||
}
|
||||
subchap.showNumbering = show
|
||||
}
|
||||
|
||||
// SetIncludeInTOC sets a flag to indicate whether or not to include in the table of contents.
|
||||
func (subchap *Subchapter) SetIncludeInTOC(includeInTOC bool) {
|
||||
subchap.includeInTOC = includeInTOC
|
||||
}
|
||||
|
||||
// GetHeading returns the Subchapter's heading Paragraph to address style (font type, size, etc).
|
||||
func (subchap *Subchapter) GetHeading() *Paragraph {
|
||||
return subchap.heading
|
||||
}
|
||||
|
||||
// Set absolute coordinates.
|
||||
/*
|
||||
func (subchap *subchapter) SetPos(x, y float64) {
|
||||
subchap.positioning = positionAbsolute
|
||||
subchap.xPos = x
|
||||
subchap.yPos = y
|
||||
}
|
||||
*/
|
||||
|
||||
// SetMargins sets the Subchapter's margins (left, right, top, bottom).
|
||||
// These margins are typically not needed as the Creator's page margins are used preferably.
|
||||
func (subchap *Subchapter) SetMargins(left, right, top, bottom float64) {
|
||||
subchap.margins.left = left
|
||||
subchap.margins.right = right
|
||||
subchap.margins.top = top
|
||||
subchap.margins.bottom = bottom
|
||||
}
|
||||
|
||||
// GetMargins returns the Subchapter's margins: left, right, top, bottom.
|
||||
func (subchap *Subchapter) GetMargins() (float64, float64, float64, float64) {
|
||||
return subchap.margins.left, subchap.margins.right, subchap.margins.top, subchap.margins.bottom
|
||||
}
|
||||
|
||||
// Add adds a new Drawable to the chapter.
|
||||
// The currently supported Drawables are: *Paragraph, *Image, *Block, *Table.
|
||||
func (subchap *Subchapter) Add(d Drawable) {
|
||||
switch d.(type) {
|
||||
case *Chapter, *Subchapter:
|
||||
common.Log.Debug("Error: Cannot add chapter or subchapter to a subchapter")
|
||||
case *Paragraph, *Image, *Block, *Table, *PageBreak:
|
||||
subchap.contents = append(subchap.contents, d)
|
||||
default:
|
||||
common.Log.Debug("Unsupported: %T", d)
|
||||
}
|
||||
}
|
||||
|
||||
// GeneratePageBlocks generates the page blocks. Multiple blocks are generated if the contents wrap
|
||||
// over multiple pages. Implements the Drawable interface.
|
||||
func (subchap *Subchapter) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext, error) {
|
||||
origCtx := ctx
|
||||
|
||||
if subchap.positioning.isRelative() {
|
||||
// Update context.
|
||||
ctx.X += subchap.margins.left
|
||||
ctx.Y += subchap.margins.top
|
||||
ctx.Width -= subchap.margins.left + subchap.margins.right
|
||||
ctx.Height -= subchap.margins.top
|
||||
}
|
||||
|
||||
origX := ctx.X
|
||||
origY := ctx.Y
|
||||
|
||||
blocks, ctx, err := subchap.heading.GeneratePageBlocks(ctx)
|
||||
if err != nil {
|
||||
return blocks, ctx, err
|
||||
}
|
||||
if len(blocks) > 1 {
|
||||
ctx.Page++ // did not fit - moved to next Page.
|
||||
}
|
||||
|
||||
// Generate subchapter title and number.
|
||||
subchapTitle := subchap.title
|
||||
var subchapNumber string
|
||||
page := int64(ctx.Page)
|
||||
|
||||
if subchap.showNumbering {
|
||||
if subchap.chapter.number != 0 {
|
||||
subchapNumber = strconv.Itoa(subchap.chapter.number)
|
||||
}
|
||||
if subchap.subchapterNum != 0 {
|
||||
if subchapNumber != "" {
|
||||
subchapNumber += "."
|
||||
}
|
||||
|
||||
subchapNumber += strconv.Itoa(subchap.subchapterNum) + "."
|
||||
}
|
||||
}
|
||||
|
||||
if subchapNumber != "" {
|
||||
subchapTitle = fmt.Sprintf("%s %s", subchapNumber, subchapTitle)
|
||||
}
|
||||
|
||||
// Add to TOC.
|
||||
if subchap.includeInTOC {
|
||||
line := subchap.toc.Add(subchapNumber, subchap.title, strconv.FormatInt(page, 10), 2)
|
||||
if subchap.toc.showLinks {
|
||||
line.SetLink(page, origX, origY)
|
||||
}
|
||||
}
|
||||
|
||||
// Add to outline.
|
||||
if subchap.outlineItem == nil {
|
||||
subchap.outlineItem = model.NewOutlineItem(
|
||||
subchapTitle,
|
||||
model.NewOutlineDest(page-1, origX, origY),
|
||||
)
|
||||
subchap.chapter.outlineItem.Add(subchap.outlineItem)
|
||||
} else {
|
||||
outlineDest := &subchap.outlineItem.Dest
|
||||
outlineDest.Page = page - 1
|
||||
outlineDest.X = origX
|
||||
outlineDest.Y = origY
|
||||
}
|
||||
|
||||
for _, d := range subchap.contents {
|
||||
newBlocks, c, err := d.GeneratePageBlocks(ctx)
|
||||
if err != nil {
|
||||
return blocks, ctx, err
|
||||
}
|
||||
if len(newBlocks) < 1 {
|
||||
continue
|
||||
}
|
||||
|
||||
// The first block is always appended to the last..
|
||||
blocks[len(blocks)-1].mergeBlocks(newBlocks[0])
|
||||
blocks = append(blocks, newBlocks[1:]...)
|
||||
|
||||
ctx = c
|
||||
}
|
||||
|
||||
if subchap.positioning.isRelative() {
|
||||
// Move back X to same start of line.
|
||||
ctx.X = origCtx.X
|
||||
}
|
||||
|
||||
if subchap.positioning.isAbsolute() {
|
||||
// If absolute: return original context.
|
||||
return blocks, origCtx, nil
|
||||
}
|
||||
|
||||
return blocks, ctx, nil
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user