feat: highlight the current book's column in the TOC (Closes #6)
Add TocConfig with highlightColumn field to BookConfig. TocRenderer now applies a light gray background shading to the designated column header and data cells, making it easy to visually distinguish the current book's page numbers from reference book columns. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit was merged in pull request #10.
This commit is contained in:
@@ -8,7 +8,12 @@ data class BookConfig(
|
||||
val images: ImagesConfig = ImagesConfig(),
|
||||
val referenceBooks: List<ReferenceBook> = emptyList(),
|
||||
val output: OutputConfig = OutputConfig(),
|
||||
val foreword: ForewordConfig? = null
|
||||
val foreword: ForewordConfig? = null,
|
||||
val toc: TocConfig = TocConfig()
|
||||
)
|
||||
|
||||
data class TocConfig(
|
||||
val highlightColumn: String? = null // abbreviation of the column to highlight (e.g. "CL")
|
||||
)
|
||||
|
||||
data class ForewordConfig(
|
||||
|
||||
@@ -192,6 +192,28 @@ class ConfigParserTest {
|
||||
config.foreword.shouldBeNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `parse config with toc highlight column`() {
|
||||
val yaml = """
|
||||
book:
|
||||
title: "Test"
|
||||
toc:
|
||||
highlight_column: "CL"
|
||||
""".trimIndent()
|
||||
val config = ConfigParser.parse(yaml)
|
||||
config.toc.highlightColumn shouldBe "CL"
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `parse config without toc section uses defaults`() {
|
||||
val yaml = """
|
||||
book:
|
||||
title: "Test"
|
||||
""".trimIndent()
|
||||
val config = ConfigParser.parse(yaml)
|
||||
config.toc.highlightColumn.shouldBeNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `parse config ignores unknown properties`() {
|
||||
val yaml = """
|
||||
|
||||
@@ -3,11 +3,15 @@ package de.pfadfinder.songbook.renderer.pdf
|
||||
import com.lowagie.text.*
|
||||
import com.lowagie.text.pdf.*
|
||||
import de.pfadfinder.songbook.model.*
|
||||
import java.awt.Color
|
||||
|
||||
class TocRenderer(
|
||||
private val fontMetrics: PdfFontMetrics,
|
||||
private val config: BookConfig
|
||||
) {
|
||||
// Light gray background for the highlighted column
|
||||
private val highlightColor = Color(220, 220, 220)
|
||||
|
||||
fun render(document: Document, writer: PdfWriter, tocEntries: List<TocEntry>) {
|
||||
val tocFont = fontMetrics.getBaseFont(config.fonts.toc)
|
||||
val tocBoldFont = fontMetrics.getBaseFontBold(config.fonts.toc)
|
||||
@@ -35,12 +39,25 @@ class TocRenderer(
|
||||
}
|
||||
table.setWidths(widths)
|
||||
|
||||
// Determine which column index should be highlighted
|
||||
val highlightAbbrev = config.toc.highlightColumn
|
||||
val highlightColumnIndex: Int? = if (highlightAbbrev != null) {
|
||||
// Check "Seite" (page) column first - the current book's page number column
|
||||
if (highlightAbbrev == "Seite") {
|
||||
1
|
||||
} else {
|
||||
val refIndex = refBooks.indexOfFirst { it.abbreviation == highlightAbbrev }
|
||||
if (refIndex >= 0) 2 + refIndex else null
|
||||
}
|
||||
} else null
|
||||
|
||||
// Header row
|
||||
val headerFont = Font(tocBoldFont, fontSize, Font.BOLD)
|
||||
table.addCell(headerCell("Titel", headerFont))
|
||||
table.addCell(headerCell("Seite", headerFont))
|
||||
for (book in refBooks) {
|
||||
table.addCell(headerCell(book.abbreviation, headerFont))
|
||||
table.addCell(headerCell("Titel", headerFont, isHighlighted = false))
|
||||
table.addCell(headerCell("Seite", headerFont, isHighlighted = highlightColumnIndex == 1))
|
||||
for ((i, book) in refBooks.withIndex()) {
|
||||
val isHighlighted = highlightColumnIndex == 2 + i
|
||||
table.addCell(headerCell(book.abbreviation, headerFont, isHighlighted = isHighlighted))
|
||||
}
|
||||
table.headerRows = 1
|
||||
|
||||
@@ -49,31 +66,43 @@ class TocRenderer(
|
||||
val aliasFont = Font(tocFont, fontSize, Font.ITALIC)
|
||||
for (entry in tocEntries.sortedBy { it.title.lowercase() }) {
|
||||
val font = if (entry.isAlias) aliasFont else entryFont
|
||||
table.addCell(entryCell(entry.title, font))
|
||||
table.addCell(entryCell(entry.pageNumber.toString(), entryFont, Element.ALIGN_RIGHT))
|
||||
for (book in refBooks) {
|
||||
table.addCell(entryCell(entry.title, font, isHighlighted = false))
|
||||
table.addCell(entryCell(entry.pageNumber.toString(), entryFont, Element.ALIGN_RIGHT, isHighlighted = highlightColumnIndex == 1))
|
||||
for ((i, book) in refBooks.withIndex()) {
|
||||
val ref = entry.references[book.abbreviation]
|
||||
table.addCell(entryCell(ref?.toString() ?: "", entryFont, Element.ALIGN_RIGHT))
|
||||
val isHighlighted = highlightColumnIndex == 2 + i
|
||||
table.addCell(entryCell(ref?.toString() ?: "", entryFont, Element.ALIGN_RIGHT, isHighlighted = isHighlighted))
|
||||
}
|
||||
}
|
||||
|
||||
document.add(table)
|
||||
}
|
||||
|
||||
private fun headerCell(text: String, font: Font): PdfPCell {
|
||||
private fun headerCell(text: String, font: Font, isHighlighted: Boolean): PdfPCell {
|
||||
val cell = PdfPCell(Phrase(text, font))
|
||||
cell.borderWidth = 0f
|
||||
cell.borderWidthBottom = 0.5f
|
||||
cell.paddingBottom = 4f
|
||||
if (isHighlighted) {
|
||||
cell.backgroundColor = highlightColor
|
||||
}
|
||||
return cell
|
||||
}
|
||||
|
||||
private fun entryCell(text: String, font: Font, alignment: Int = Element.ALIGN_LEFT): PdfPCell {
|
||||
private fun entryCell(
|
||||
text: String,
|
||||
font: Font,
|
||||
alignment: Int = Element.ALIGN_LEFT,
|
||||
isHighlighted: Boolean = false
|
||||
): PdfPCell {
|
||||
val cell = PdfPCell(Phrase(text, font))
|
||||
cell.borderWidth = 0f
|
||||
cell.horizontalAlignment = alignment
|
||||
cell.paddingTop = 1f
|
||||
cell.paddingBottom = 1f
|
||||
if (isHighlighted) {
|
||||
cell.backgroundColor = highlightColor
|
||||
}
|
||||
return cell
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user