mirror of
https://github.com/unidoc/unipdf.git
synced 2025-04-27 13:48:51 +08:00
697 lines
19 KiB
Go
697 lines
19 KiB
Go
/*
|
|
* 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 (
|
|
"errors"
|
|
|
|
"github.com/unidoc/unidoc/common"
|
|
"github.com/unidoc/unidoc/pdf/contentstream/draw"
|
|
"github.com/unidoc/unidoc/pdf/core"
|
|
"github.com/unidoc/unidoc/pdf/model"
|
|
)
|
|
|
|
// Table allows organizing content in an rows X columns matrix, which can spawn across multiple pages.
|
|
type Table struct {
|
|
// Number of rows and columns.
|
|
rows int
|
|
cols int
|
|
|
|
// Current cell. Current cell in the table.
|
|
// For 4x4 table, if in the 2nd row, 3rd column, then
|
|
// curCell = 4+3 = 7
|
|
curCell int
|
|
|
|
// Column width fractions: should add up to 1.
|
|
colWidths []float64
|
|
|
|
// Row heights.
|
|
rowHeights []float64
|
|
|
|
// Default row height.
|
|
defaultRowHeight float64
|
|
|
|
// Content cells.
|
|
cells []*TableCell
|
|
|
|
// 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
|
|
}
|
|
|
|
// NewTable create a new Table with a specified number of columns.
|
|
func NewTable(cols int) *Table {
|
|
t := &Table{}
|
|
t.rows = 0
|
|
t.cols = cols
|
|
|
|
t.curCell = 0
|
|
|
|
// Initialize column widths as all equal.
|
|
t.colWidths = []float64{}
|
|
colWidth := float64(1.0) / float64(cols)
|
|
for i := 0; i < cols; i++ {
|
|
t.colWidths = append(t.colWidths, colWidth)
|
|
}
|
|
|
|
t.rowHeights = []float64{}
|
|
|
|
// Default row height
|
|
// XXX/TODO: Base on contents instead?
|
|
t.defaultRowHeight = 10.0
|
|
|
|
t.cells = []*TableCell{}
|
|
|
|
return t
|
|
}
|
|
|
|
// SetColumnWidths sets the fractional column widths.
|
|
// Each width should be in the range 0-1 and is a fraction of the table width.
|
|
// The number of width inputs must match number of columns, otherwise an error is returned.
|
|
func (table *Table) SetColumnWidths(widths ...float64) error {
|
|
if len(widths) != table.cols {
|
|
common.Log.Debug("Mismatching number of widths and columns")
|
|
return errors.New("Range check error")
|
|
}
|
|
|
|
table.colWidths = widths
|
|
|
|
return nil
|
|
}
|
|
|
|
// Height returns the total height of all rows.
|
|
func (table *Table) Height() float64 {
|
|
sum := float64(0.0)
|
|
for _, h := range table.rowHeights {
|
|
sum += h
|
|
}
|
|
|
|
return sum
|
|
}
|
|
|
|
// SetMargins sets the Table's left, right, top, bottom margins.
|
|
func (table *Table) SetMargins(left, right, top, bottom float64) {
|
|
table.margins.left = left
|
|
table.margins.right = right
|
|
table.margins.top = top
|
|
table.margins.bottom = bottom
|
|
}
|
|
|
|
// GetMargins returns the left, right, top, bottom Margins.
|
|
func (table *Table) GetMargins() (float64, float64, float64, float64) {
|
|
return table.margins.left, table.margins.right, table.margins.top, table.margins.bottom
|
|
}
|
|
|
|
// SetRowHeight sets the height for a specified row.
|
|
func (table *Table) SetRowHeight(row int, h float64) error {
|
|
if row < 1 || row > len(table.rowHeights) {
|
|
return errors.New("Range check error")
|
|
}
|
|
|
|
table.rowHeights[row-1] = h
|
|
return nil
|
|
}
|
|
|
|
// CurRow returns the currently active cell's row number.
|
|
func (table *Table) CurRow() int {
|
|
curRow := (table.curCell-1)/table.cols + 1
|
|
return curRow
|
|
}
|
|
|
|
// CurCol returns the currently active cell's column number.
|
|
func (table *Table) CurCol() int {
|
|
curCol := (table.curCell-1)%(table.cols) + 1
|
|
return curCol
|
|
}
|
|
|
|
// SetPos sets the Table's positioning to absolute mode and specifies the upper-left corner
|
|
// coordinates as (x,y).
|
|
// Note that this is only sensible to use when the table does not wrap over multiple pages.
|
|
// TODO: Should be able to set width too (not just based on context/relative positioning mode).
|
|
func (table *Table) SetPos(x, y float64) {
|
|
table.positioning = positionAbsolute
|
|
table.xPos = x
|
|
table.yPos = y
|
|
}
|
|
|
|
// GeneratePageBlocks generate the page blocks. Multiple blocks are generated if the contents wrap
|
|
// over multiple pages.
|
|
// Implements the Drawable interface.
|
|
func (table *Table) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext, error) {
|
|
blocks := []*Block{}
|
|
block := NewBlock(ctx.PageWidth, ctx.PageHeight)
|
|
|
|
origCtx := ctx
|
|
if table.positioning.isAbsolute() {
|
|
ctx.X = table.xPos
|
|
ctx.Y = table.yPos
|
|
} else {
|
|
// Relative mode: add margins.
|
|
ctx.X += table.margins.left
|
|
ctx.Y += table.margins.top
|
|
ctx.Width -= table.margins.left + table.margins.right
|
|
ctx.Height -= table.margins.bottom + table.margins.top
|
|
}
|
|
tableWidth := ctx.Width
|
|
|
|
// Store table's upper left corner.
|
|
ulX := ctx.X
|
|
ulY := ctx.Y
|
|
|
|
ctx.Height = ctx.PageHeight - ctx.Y - ctx.Margins.bottom
|
|
origHeight := ctx.Height
|
|
|
|
// Start row keeps track of starting row (wraps to 0 on new page).
|
|
startrow := 0
|
|
|
|
// Prepare for drawing: Calculate cell dimensions, row, cell heights.
|
|
for _, cell := range table.cells {
|
|
// Get total width fraction
|
|
wf := float64(0.0)
|
|
for i := 0; i < cell.colspan; i++ {
|
|
wf += table.colWidths[cell.col+i-1]
|
|
}
|
|
// Get x pos relative to table upper left corner.
|
|
xrel := float64(0.0)
|
|
for i := 0; i < cell.col-1; i++ {
|
|
xrel += table.colWidths[i] * tableWidth
|
|
}
|
|
// Get y pos relative to table upper left corner.
|
|
yrel := float64(0.0)
|
|
for i := startrow; i < cell.row-1; i++ {
|
|
yrel += table.rowHeights[i]
|
|
}
|
|
|
|
// Calculate the width out of available width.
|
|
w := wf * tableWidth
|
|
|
|
// Get total height.
|
|
h := float64(0.0)
|
|
for i := 0; i < cell.rowspan; i++ {
|
|
h += table.rowHeights[cell.row+i-1]
|
|
}
|
|
|
|
// For text: Calculate width, height, wrapping within available space if specified.
|
|
switch t := cell.content.(type) {
|
|
case *Paragraph:
|
|
p := t
|
|
if p.enableWrap {
|
|
p.SetWidth(w - cell.indent)
|
|
}
|
|
|
|
newh := p.Height() + p.margins.bottom + p.margins.bottom
|
|
newh += 0.5 * p.fontSize * p.lineHeight // TODO: Make the top margin configurable?
|
|
if newh > h {
|
|
diffh := newh - h
|
|
// Add diff to last row.
|
|
table.rowHeights[cell.row+cell.rowspan-2] += diffh
|
|
}
|
|
case *Image:
|
|
img := t
|
|
newh := img.Height() + img.margins.top + img.margins.bottom
|
|
if newh > h {
|
|
diffh := newh - h
|
|
// Add diff to last row.
|
|
table.rowHeights[cell.row+cell.rowspan-2] += diffh
|
|
}
|
|
case *Division:
|
|
div := t
|
|
|
|
ctx := DrawContext{
|
|
X: xrel,
|
|
Y: yrel,
|
|
Width: w,
|
|
}
|
|
|
|
// Mock call to generate page blocks.
|
|
divBlocks, updCtx, err := div.GeneratePageBlocks(ctx)
|
|
if err != nil {
|
|
return nil, ctx, err
|
|
}
|
|
|
|
if len(divBlocks) > 1 {
|
|
// Wraps across page, make cell reach all the way to bottom of current page.
|
|
newh := ctx.Height - h
|
|
if newh > h {
|
|
diffh := newh - h
|
|
// Add diff to last row.
|
|
table.rowHeights[cell.row+cell.rowspan-2] += diffh
|
|
}
|
|
}
|
|
|
|
newh := div.Height() + div.margins.top + div.margins.bottom
|
|
_ = updCtx
|
|
|
|
// Get available width and height.
|
|
if newh > h {
|
|
diffh := newh - h
|
|
// Add diff to last row.
|
|
table.rowHeights[cell.row+cell.rowspan-2] += diffh
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// Draw cells.
|
|
// row height, cell height
|
|
for _, cell := range table.cells {
|
|
// Get total width fraction
|
|
wf := float64(0.0)
|
|
for i := 0; i < cell.colspan; i++ {
|
|
wf += table.colWidths[cell.col+i-1]
|
|
}
|
|
// Get x pos relative to table upper left corner.
|
|
xrel := float64(0.0)
|
|
for i := 0; i < cell.col-1; i++ {
|
|
xrel += table.colWidths[i] * tableWidth
|
|
}
|
|
// Get y pos relative to table upper left corner.
|
|
yrel := float64(0.0)
|
|
for i := startrow; i < cell.row-1; i++ {
|
|
yrel += table.rowHeights[i]
|
|
}
|
|
|
|
// Calculate the width out of available width.
|
|
w := wf * tableWidth
|
|
|
|
// Get total height.
|
|
h := float64(0.0)
|
|
for i := 0; i < cell.rowspan; i++ {
|
|
h += table.rowHeights[cell.row+i-1]
|
|
}
|
|
|
|
ctx.Height = origHeight - yrel
|
|
|
|
if h > ctx.Height {
|
|
// Go to next page.
|
|
blocks = append(blocks, block)
|
|
block = NewBlock(ctx.PageWidth, ctx.PageHeight)
|
|
ulX = ctx.Margins.left
|
|
ulY = ctx.Margins.top
|
|
ctx.Height = ctx.PageHeight - ctx.Margins.top - ctx.Margins.bottom
|
|
|
|
startrow = cell.row - 1
|
|
yrel = 0
|
|
}
|
|
|
|
// Height should be how much space there is left of the page.
|
|
ctx.Width = w
|
|
ctx.X = ulX + xrel
|
|
ctx.Y = ulY + yrel
|
|
|
|
// Creating border
|
|
border := newBorder(ctx.X, ctx.Y, w, h)
|
|
|
|
if cell.backgroundColor != nil {
|
|
r := cell.backgroundColor.R()
|
|
g := cell.backgroundColor.G()
|
|
b := cell.backgroundColor.B()
|
|
|
|
border.SetFillColor(ColorRGBFromArithmetic(r, g, b))
|
|
}
|
|
|
|
border.LineStyle = cell.borderLineStyle
|
|
|
|
border.styleLeft = cell.borderStyleLeft
|
|
border.styleRight = cell.borderStyleRight
|
|
border.styleTop = cell.borderStyleTop
|
|
border.styleBottom = cell.borderStyleBottom
|
|
|
|
if cell.borderColorLeft != nil {
|
|
border.SetColorLeft(ColorRGBFromArithmetic(cell.borderColorLeft.R(), cell.borderColorLeft.G(), cell.borderColorLeft.B()))
|
|
}
|
|
if cell.borderColorBottom != nil {
|
|
border.SetColorBottom(ColorRGBFromArithmetic(cell.borderColorBottom.R(), cell.borderColorBottom.G(), cell.borderColorBottom.B()))
|
|
}
|
|
if cell.borderColorRight != nil {
|
|
border.SetColorRight(ColorRGBFromArithmetic(cell.borderColorRight.R(), cell.borderColorRight.G(), cell.borderColorRight.B()))
|
|
}
|
|
if cell.borderColorTop != nil {
|
|
border.SetColorTop(ColorRGBFromArithmetic(cell.borderColorTop.R(), cell.borderColorTop.G(), cell.borderColorTop.B()))
|
|
}
|
|
|
|
border.SetWidthBottom(cell.borderWidthBottom)
|
|
border.SetWidthLeft(cell.borderWidthLeft)
|
|
border.SetWidthRight(cell.borderWidthRight)
|
|
border.SetWidthTop(cell.borderWidthTop)
|
|
|
|
err := block.Draw(border)
|
|
if err != nil {
|
|
common.Log.Debug("ERROR: %v", err)
|
|
}
|
|
|
|
if cell.content != nil {
|
|
// Account for horizontal alignment:
|
|
cw := cell.content.Width() // content width.
|
|
switch cell.horizontalAlignment {
|
|
case CellHorizontalAlignmentLeft:
|
|
// Account for indent.
|
|
ctx.X += cell.indent
|
|
ctx.Width -= cell.indent
|
|
case CellHorizontalAlignmentCenter:
|
|
// Difference between available space and content space.
|
|
dw := w - cw
|
|
if dw > 0 {
|
|
ctx.X += dw / 2
|
|
ctx.Width -= dw / 2
|
|
}
|
|
case CellHorizontalAlignmentRight:
|
|
if w > cw {
|
|
ctx.X = ctx.X + w - cw - cell.indent
|
|
ctx.Width = cw
|
|
}
|
|
}
|
|
|
|
// Account for vertical alignment.
|
|
ch := cell.content.Height() // content height.
|
|
switch cell.verticalAlignment {
|
|
case CellVerticalAlignmentTop:
|
|
// Default: do nothing.
|
|
case CellVerticalAlignmentMiddle:
|
|
dh := h - ch
|
|
if dh > 0 {
|
|
ctx.Y += dh / 2
|
|
ctx.Height -= dh / 2
|
|
}
|
|
case CellVerticalAlignmentBottom:
|
|
if h > ch {
|
|
ctx.Y = ctx.Y + h - ch
|
|
ctx.Height = ch
|
|
}
|
|
}
|
|
|
|
err := block.DrawWithContext(cell.content, ctx)
|
|
if err != nil {
|
|
common.Log.Debug("ERROR: %v", err)
|
|
}
|
|
}
|
|
|
|
ctx.Y += h
|
|
}
|
|
blocks = append(blocks, block)
|
|
|
|
if table.positioning.isAbsolute() {
|
|
return blocks, origCtx, nil
|
|
}
|
|
// Relative mode.
|
|
// Move back X after.
|
|
ctx.X = origCtx.X
|
|
// Return original width.
|
|
ctx.Width = origCtx.Width
|
|
// Add the bottom margin.
|
|
ctx.Y += table.margins.bottom
|
|
|
|
return blocks, ctx, nil
|
|
}
|
|
|
|
// CellBorderStyle defines the table cell's border style.
|
|
type CellBorderStyle int
|
|
|
|
// Currently supported table styles are: None (no border) and boxed (line along each side).
|
|
const (
|
|
// No border
|
|
CellBorderStyleNone CellBorderStyle = iota
|
|
|
|
// Borders along all sides (boxed).
|
|
CellBorderStyleSingle
|
|
CellBorderStyleDouble
|
|
)
|
|
|
|
// CellBorderSide defines the table cell's border side.
|
|
type CellBorderSide int
|
|
|
|
const (
|
|
// Left side border.
|
|
CellBorderSideLeft CellBorderSide = iota
|
|
CellBorderSideRight
|
|
CellBorderSideTop
|
|
CellBorderSideBottom
|
|
// Border on all sides.
|
|
CellBorderSideAll
|
|
)
|
|
|
|
// CellHorizontalAlignment defines the table cell's horizontal alignment.
|
|
type CellHorizontalAlignment int
|
|
|
|
// Table cells have three horizontal alignment modes: left, center and right.
|
|
const (
|
|
// Align cell content on the left (with specified indent); unused space on the right.
|
|
CellHorizontalAlignmentLeft CellHorizontalAlignment = iota
|
|
|
|
// Align cell content in the middle (unused space divided equally on the left/right).
|
|
CellHorizontalAlignmentCenter
|
|
|
|
// Align the cell content on the right; unsued space on the left.
|
|
CellHorizontalAlignmentRight
|
|
)
|
|
|
|
// CellVerticalAlignment defines the table cell's vertical alignment.
|
|
type CellVerticalAlignment int
|
|
|
|
// Table cells have three vertical alignment modes: top, middle and bottom.
|
|
const (
|
|
// Align cell content vertically to the top; unused space below.
|
|
CellVerticalAlignmentTop CellVerticalAlignment = iota
|
|
|
|
// Align cell content in the middle; unused space divided equally above and below.
|
|
CellVerticalAlignmentMiddle
|
|
|
|
// Align cell content on the bottom; unused space above.
|
|
CellVerticalAlignmentBottom
|
|
)
|
|
|
|
// TableCell defines a table cell which can contain a Drawable as content.
|
|
type TableCell struct {
|
|
// Background
|
|
backgroundColor *model.PdfColorDeviceRGB
|
|
|
|
borderLineStyle draw.LineStyle
|
|
|
|
// border
|
|
borderStyleLeft CellBorderStyle
|
|
borderColorLeft *model.PdfColorDeviceRGB
|
|
borderWidthLeft float64
|
|
borderStyleBottom CellBorderStyle
|
|
borderColorBottom *model.PdfColorDeviceRGB
|
|
borderWidthBottom float64
|
|
borderStyleRight CellBorderStyle
|
|
borderColorRight *model.PdfColorDeviceRGB
|
|
borderWidthRight float64
|
|
borderStyleTop CellBorderStyle
|
|
borderColorTop *model.PdfColorDeviceRGB
|
|
borderWidthTop float64
|
|
|
|
// The row and column which the cell starts from.
|
|
row, col int
|
|
|
|
// Row, column span.
|
|
rowspan int
|
|
colspan int
|
|
|
|
// Each cell can contain 1 drawable.
|
|
content VectorDrawable
|
|
|
|
// Alignment
|
|
horizontalAlignment CellHorizontalAlignment
|
|
verticalAlignment CellVerticalAlignment
|
|
|
|
// Left indent.
|
|
indent float64
|
|
|
|
// Table reference
|
|
table *Table
|
|
}
|
|
|
|
// NewCell makes a new cell and inserts into the table at current position in the table.
|
|
func (table *Table) NewCell() *TableCell {
|
|
table.curCell++
|
|
|
|
curRow := (table.curCell-1)/table.cols + 1
|
|
for curRow > table.rows {
|
|
table.rows++
|
|
table.rowHeights = append(table.rowHeights, table.defaultRowHeight)
|
|
}
|
|
curCol := (table.curCell-1)%(table.cols) + 1
|
|
|
|
cell := &TableCell{}
|
|
cell.row = curRow
|
|
cell.col = curCol
|
|
|
|
// Default left indent
|
|
cell.indent = 5
|
|
|
|
cell.borderStyleLeft = CellBorderStyleNone
|
|
cell.borderLineStyle = draw.LineStyleSolid
|
|
|
|
// Alignment defaults.
|
|
cell.horizontalAlignment = CellHorizontalAlignmentLeft
|
|
cell.verticalAlignment = CellVerticalAlignmentTop
|
|
|
|
cell.borderWidthLeft = 0
|
|
cell.borderWidthBottom = 0
|
|
cell.borderWidthRight = 0
|
|
cell.borderWidthTop = 0
|
|
|
|
col := ColorBlack
|
|
cell.borderColorLeft = model.NewPdfColorDeviceRGB(col.ToRGB())
|
|
cell.borderColorBottom = model.NewPdfColorDeviceRGB(col.ToRGB())
|
|
cell.borderColorRight = model.NewPdfColorDeviceRGB(col.ToRGB())
|
|
cell.borderColorTop = model.NewPdfColorDeviceRGB(col.ToRGB())
|
|
|
|
cell.rowspan = 1
|
|
cell.colspan = 1
|
|
|
|
table.cells = append(table.cells, cell)
|
|
|
|
// Keep reference to the table.
|
|
cell.table = table
|
|
|
|
return cell
|
|
}
|
|
|
|
// SkipCells skips over a specified number of cells in the table.
|
|
func (table *Table) SkipCells(num int) {
|
|
if num < 0 {
|
|
common.Log.Debug("Table: cannot skip back to previous cells")
|
|
return
|
|
}
|
|
table.curCell += num
|
|
}
|
|
|
|
// SkipRows skips over a specified number of rows in the table.
|
|
func (table *Table) SkipRows(num int) {
|
|
ncells := num*table.cols - 1
|
|
if ncells < 0 {
|
|
common.Log.Debug("Table: cannot skip back to previous cells")
|
|
return
|
|
}
|
|
table.curCell += ncells
|
|
}
|
|
|
|
// SkipOver skips over a specified number of rows and cols.
|
|
func (table *Table) SkipOver(rows, cols int) {
|
|
ncells := rows*table.cols + cols - 1
|
|
if ncells < 0 {
|
|
common.Log.Debug("Table: cannot skip back to previous cells")
|
|
return
|
|
}
|
|
table.curCell += ncells
|
|
}
|
|
|
|
// SetIndent sets the cell's left indent.
|
|
func (cell *TableCell) SetIndent(indent float64) {
|
|
cell.indent = indent
|
|
}
|
|
|
|
// SetHorizontalAlignment sets the cell's horizontal alignment of content.
|
|
// Can be one of:
|
|
// - CellHorizontalAlignmentLeft
|
|
// - CellHorizontalAlignmentCenter
|
|
// - CellHorizontalAlignmentRight
|
|
func (cell *TableCell) SetHorizontalAlignment(halign CellHorizontalAlignment) {
|
|
cell.horizontalAlignment = halign
|
|
}
|
|
|
|
// SetVerticalAlignment set the cell's vertical alignment of content.
|
|
// Can be one of:
|
|
// - CellHorizontalAlignmentTop
|
|
// - CellHorizontalAlignmentMiddle
|
|
// - CellHorizontalAlignmentBottom
|
|
func (cell *TableCell) SetVerticalAlignment(valign CellVerticalAlignment) {
|
|
cell.verticalAlignment = valign
|
|
}
|
|
|
|
// SetBorder sets the cell's border style.
|
|
func (cell *TableCell) SetBorder(side CellBorderSide, style CellBorderStyle, width float64) {
|
|
if style == CellBorderStyleSingle && side == CellBorderSideAll {
|
|
cell.borderStyleLeft = CellBorderStyleSingle
|
|
cell.borderWidthLeft = width
|
|
cell.borderStyleBottom = CellBorderStyleSingle
|
|
cell.borderWidthBottom = width
|
|
cell.borderStyleRight = CellBorderStyleSingle
|
|
cell.borderWidthRight = width
|
|
cell.borderStyleTop = CellBorderStyleSingle
|
|
cell.borderWidthTop = width
|
|
} else if style == CellBorderStyleDouble && side == CellBorderSideAll {
|
|
cell.borderStyleLeft = CellBorderStyleDouble
|
|
cell.borderWidthLeft = width
|
|
cell.borderStyleBottom = CellBorderStyleDouble
|
|
cell.borderWidthBottom = width
|
|
cell.borderStyleRight = CellBorderStyleDouble
|
|
cell.borderWidthRight = width
|
|
cell.borderStyleTop = CellBorderStyleDouble
|
|
cell.borderWidthTop = width
|
|
} else if (style == CellBorderStyleSingle || style == CellBorderStyleDouble) && side == CellBorderSideLeft {
|
|
cell.borderStyleLeft = style
|
|
cell.borderWidthLeft = width
|
|
} else if (style == CellBorderStyleSingle || style == CellBorderStyleDouble) && side == CellBorderSideBottom {
|
|
cell.borderStyleBottom = style
|
|
cell.borderWidthBottom = width
|
|
} else if (style == CellBorderStyleSingle || style == CellBorderStyleDouble) && side == CellBorderSideRight {
|
|
cell.borderStyleRight = style
|
|
cell.borderWidthRight = width
|
|
} else if (style == CellBorderStyleSingle || style == CellBorderStyleDouble) && side == CellBorderSideTop {
|
|
cell.borderStyleTop = style
|
|
cell.borderWidthTop = width
|
|
}
|
|
}
|
|
|
|
// SetBorderColor sets the cell's border color.
|
|
func (cell *TableCell) SetBorderColor(col Color) {
|
|
cell.borderColorLeft = model.NewPdfColorDeviceRGB(col.ToRGB())
|
|
cell.borderColorBottom = model.NewPdfColorDeviceRGB(col.ToRGB())
|
|
cell.borderColorRight = model.NewPdfColorDeviceRGB(col.ToRGB())
|
|
cell.borderColorTop = model.NewPdfColorDeviceRGB(col.ToRGB())
|
|
}
|
|
|
|
// SetBorderLineStyle sets border style (currently dashed or plain).
|
|
func (cell *TableCell) SetBorderLineStyle(style draw.LineStyle) {
|
|
cell.borderLineStyle = style
|
|
}
|
|
|
|
// SetBackgroundColor sets the cell's background color.
|
|
func (cell *TableCell) SetBackgroundColor(col Color) {
|
|
cell.backgroundColor = model.NewPdfColorDeviceRGB(col.ToRGB())
|
|
}
|
|
|
|
// Width returns the cell's width based on the input draw context.
|
|
func (cell *TableCell) Width(ctx DrawContext) float64 {
|
|
fraction := float64(0.0)
|
|
for j := 0; j < cell.colspan; j++ {
|
|
fraction += cell.table.colWidths[cell.col+j-1]
|
|
}
|
|
w := ctx.Width * fraction
|
|
return w
|
|
}
|
|
|
|
// SetContent sets the cell's content. The content is a VectorDrawable, i.e. a Drawable with a known height and width.
|
|
// The currently supported VectorDrawable is: *Paragraph.
|
|
func (cell *TableCell) SetContent(vd VectorDrawable) error {
|
|
switch t := vd.(type) {
|
|
case *Paragraph:
|
|
if t.defaultWrap {
|
|
// Default paragraph settings in table: no wrapping.
|
|
t.enableWrap = false // No wrapping.
|
|
}
|
|
|
|
cell.content = vd
|
|
case *Image:
|
|
cell.content = vd
|
|
case *Division:
|
|
cell.content = vd
|
|
default:
|
|
common.Log.Debug("ERROR: unsupported cell content type %T", vd)
|
|
return core.ErrTypeError
|
|
}
|
|
|
|
return nil
|
|
}
|