Skip to content

Commit

Permalink
Add support for vertical alignment of styled paragraphs inside table…
Browse files Browse the repository at this point in the history
… cells (#69)
  • Loading branch information
adrg authored and gunnsth committed Jun 2, 2019
1 parent 7f4e3b8 commit 1dcde7d
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 4 deletions.
43 changes: 43 additions & 0 deletions creator/styled_paragraph.go
Expand Up @@ -226,6 +226,49 @@ func (p *StyledParagraph) Height() float64 {
return height
}

// getLineHeight returns both the capheight and the font size based height of
// the line with the specified index.
func (p *StyledParagraph) getLineHeight(idx int) (capHeight, height float64) {
if p.lines == nil || len(p.lines) == 0 {
p.wrapText()
}
if idx < 0 || idx > len(p.lines)-1 {
common.Log.Debug("ERROR: invalid paragraph line index %d. Returning 0, 0", idx)
return 0, 0
}

line := p.lines[idx]
for _, chunk := range line {
descriptor, err := chunk.Style.Font.GetFontDescriptor()
if err != nil {
common.Log.Debug("ERROR: Unable to get font descriptor")
}

var fontCapHeight float64
if descriptor != nil {
if fontCapHeight, err = descriptor.GetCapHeight(); err != nil {
common.Log.Debug("ERROR: Unable to get font CapHeight: %v", err)
}
}
if int(fontCapHeight) <= 0 {
common.Log.Debug("WARN: CapHeight not available - setting to 1000")
fontCapHeight = 1000
}

h := fontCapHeight / 1000.0 * chunk.Style.FontSize * p.lineHeight
if h > capHeight {
capHeight = h
}

h = p.lineHeight * chunk.Style.FontSize
if h > height {
height = h
}
}

return capHeight, height
}

// getTextWidth calculates the text width as if all in one line (not taking
// wrapping into account).
func (p *StyledParagraph) getTextWidth() float64 {
Expand Down
63 changes: 63 additions & 0 deletions creator/styled_paragraph_test.go
Expand Up @@ -798,3 +798,66 @@ func TestStyledLinkRotation(t *testing.T) {
t.Fatalf("Fail: %v\n", err)
}
}

func TestStyledParagraphTableVerticalAlignment(t *testing.T) {
c := New()

fontRegular := newStandard14Font(t, model.CourierName)

createTable := func(c *Creator, text string, align CellVerticalAlignment, fontSize float64) {
textStyle := c.NewTextStyle()
textStyle.Font = fontRegular
textStyle.FontSize = fontSize

table := c.NewTable(1)
table.SetMargins(0, 0, 5, 5)

cell := table.NewCell()
sp := c.NewStyledParagraph()
textChunk := sp.Append(text)
textChunk.Style = textStyle

cell.SetVerticalAlignment(align)
cell.SetContent(sp)
cell.SetBorder(CellBorderSideAll, CellBorderStyleSingle, 1)

if err := c.Draw(table); err != nil {
t.Fatalf("Error drawing: %v", err)
}
}

chunks := []string{
"TR",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Lacus viverra vitae congue eu consequat. Cras adipiscing enim eu turpis. Lectus magna fringilla urna porttitor. Condimentum id venenatis a condimentum. Quis ipsum suspendisse ultrices gravida dictum fusce. In fermentum posuere urna nec tincidunt.",
}

alignments := []struct {
Label string
Alignment CellVerticalAlignment
}{
{"Top alignment", CellVerticalAlignmentTop},
{"Middle alignment", CellVerticalAlignmentMiddle},
{"Bottom alignment", CellVerticalAlignmentBottom},
}

for _, chunk := range chunks {
for _, alignment := range alignments {
c.NewPage()

sp := c.NewStyledParagraph()
sp.Append(alignment.Label).Style.FontSize = 16
sp.SetMargins(0, 0, 0, 5)

if err := c.Draw(sp); err != nil {
t.Fatalf("Error drawing: %v", err)
}

for i := 4; i <= 20; i += 2 {
createTable(c, chunk, alignment.Alignment, float64(i))
}
}
}

// Write output file.
testWriteAndRender(t, c, "styled_paragraph_table_vertical_align.pdf")
}
33 changes: 29 additions & 4 deletions creator/table.go
Expand Up @@ -516,8 +516,10 @@ func (table *Table) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext,
}

if cell.content != nil {
// content width.
cw := cell.content.Width()
cw := cell.content.Width() // content width.
ch := cell.content.Height() // content height.
vertOffset := 0.0

switch t := cell.content.(type) {
case *Paragraph:
if t.enableWrap {
Expand All @@ -527,6 +529,26 @@ func (table *Table) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext,
if t.enableWrap {
cw = t.getMaxLineWidth() / 1000.0
}

// Calculate the height of the paragraph.
lineCapHeight, lineHeight := t.getLineHeight(0)
if len(t.lines) == 1 {
ch = lineCapHeight
} else {
ch = ch - lineHeight + lineCapHeight
}

// Account for the top offset the paragraph adds.
vertOffset = lineCapHeight - t.defaultStyle.FontSize*t.lineHeight

switch cell.verticalAlignment {
case CellVerticalAlignmentTop:
// Add a bit of space from the top border of the cell.
vertOffset += lineCapHeight * 0.5
case CellVerticalAlignmentBottom:
// Add a bit of space from the bottom border of the cell.
vertOffset -= lineCapHeight * 0.5
}
case *Table:
cw = w
case *List:
Expand All @@ -553,8 +575,9 @@ func (table *Table) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext,
}
}

ctx.Y += vertOffset

// Account for vertical alignment.
ch := cell.content.Height() // content height.
switch cell.verticalAlignment {
case CellVerticalAlignmentTop:
// Default: do nothing.
Expand All @@ -567,14 +590,16 @@ func (table *Table) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext,
case CellVerticalAlignmentBottom:
if h > ch {
ctx.Y = ctx.Y + h - ch
ctx.Height = ch
ctx.Height = h
}
}

err := block.DrawWithContext(cell.content, ctx)
if err != nil {
common.Log.Debug("ERROR: %v", err)
}

ctx.Y -= vertOffset
}

ctx.Y += h
Expand Down

0 comments on commit 1dcde7d

Please sign in to comment.