more btex styling

This commit is contained in:
minjaesong
2024-04-28 15:17:08 +09:00
parent 30e9f3e2ef
commit 8a1ff32fa7
6 changed files with 253 additions and 130 deletions

View File

@@ -95,8 +95,9 @@ class BTeXPage(
}
fun render(frameDelta: Float, batch: SpriteBatch, x: Int, y: Int, marginH: Int, marginV: Int) {
batch.color = back
batch.color = back.cpy().also { it.a = 0.93f }
Toolkit.fillArea(batch, x, y, width, height)
batch.color = Color.WHITE
drawCalls.forEach {
it.draw(batch, x + marginH, y + marginV)
}

View File

@@ -74,6 +74,7 @@ object BTeXParser {
private val blockLut = HashMap<String, ItemID>()
private val tagStack = ArrayList<String>() // index zero should be "btex"
private var tagHistory = ArrayList<String>()
private var currentTheme = ""
private var spanColour: String? = null
@@ -97,6 +98,7 @@ object BTeXParser {
private var tocPage: Int? = null
private var hasCover = false
private var coverCol: Color? = null
init {
BTeXHandler::class.declaredFunctions.filter { it.findAnnotation<OpenTag>() != null }.forEach {
@@ -147,6 +149,8 @@ object BTeXParser {
lastTagAtDepth[tagStack.size] = theTag
tagStack.add(theTag)
tagHistory.add(theTag)
val attribs = HashMap<String, String>().also {
it.putAll((0 until attributes.length).map { attributes.getQName(it) to attributes.getValue(it) })
@@ -158,7 +162,7 @@ object BTeXParser {
System.err.println("Unknown tag: $theTag")
else {
try {
it.call(this, this, doc, theTag, uri, attribs, pTagCntAtDepth[tagStack.size])
it.call(this, this, doc, uri, attribs)
}
catch (e: Throwable) {
throw BTeXParsingException("processElem$theTag"+"\n"+e.stackTraceToString())
@@ -178,7 +182,7 @@ object BTeXParser {
elemClosers["closeElem$theTag"].let {
try {
it?.call(this, this, doc, theTag, uri, pTagCntAtDepth[tagStack.size])
it?.call(this, this, doc, uri, pTagCntAtDepth[tagStack.size])
}
catch (e: Throwable) {
throw BTeXParsingException(e.stackTraceToString())
@@ -200,7 +204,7 @@ object BTeXParser {
if (spanColour != oldSpanColour || spanColour != null) {
val col = getSpanColourOrNull().toInternalColourCodeStr()
if (spanColour != null && paragraphBuffer.last() == '\u000E') {
if (spanColour != null && paragraphBuffer.isNotEmpty() && paragraphBuffer.last() == '\u000E') {
paragraphBuffer.deleteAt(paragraphBuffer.lastIndex)
}
@@ -472,7 +476,7 @@ object BTeXParser {
@OpenTag // reflective access is impossible with 'private'
fun processElemBTEXDOC(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>, siblingIndex: Int) {
fun processElemBTEXDOC(handler: BTeXHandler, doc: BTeXDocument, uri: String, attribs: HashMap<String, String>) {
if (handler.btexOpened) {
throw BTeXParsingException("BTEXDOC tag has already opened")
}
@@ -499,7 +503,7 @@ object BTeXParser {
}
@OpenTag // reflective access is impossible with 'private'
fun processElemPAIR(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>, siblingIndex: Int) {
fun processElemPAIR(handler: BTeXHandler, doc: BTeXDocument, uri: String, attribs: HashMap<String, String>) {
if (tagStack.size == 3 && tagStack.getOrNull(1) == "blocklut") {
blockLut[attribs["key"]!!] = attribs["value"]!!
}
@@ -509,86 +513,86 @@ object BTeXParser {
}
@OpenTag // reflective access is impossible with 'private'
fun processElemTITLE(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>, siblingIndex: Int) {
fun processElemTITLE(handler: BTeXHandler, doc: BTeXDocument, uri: String, attribs: HashMap<String, String>) {
handler.paragraphBuffer.clear()
}
@OpenTag // reflective access is impossible with 'private'
fun processElemAUTHOR(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>, siblingIndex: Int) {
fun processElemAUTHOR(handler: BTeXHandler, doc: BTeXDocument, uri: String, attribs: HashMap<String, String>) {
handler.paragraphBuffer.clear()
}
@OpenTag // reflective access is impossible with 'private'
fun processElemEDITION(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>, siblingIndex: Int) {
fun processElemEDITION(handler: BTeXHandler, doc: BTeXDocument, uri: String, attribs: HashMap<String, String>) {
handler.paragraphBuffer.clear()
}
@OpenTag // reflective access is impossible with 'private'
fun processElemEMPH(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>, siblingIndex: Int) {
fun processElemEMPH(handler: BTeXHandler, doc: BTeXDocument, uri: String, attribs: HashMap<String, String>) {
handler.spanColour = ccEmph
}
@OpenTag // reflective access is impossible with 'private'
fun processElemITEMNAME(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>, siblingIndex: Int) {
fun processElemITEMNAME(handler: BTeXHandler, doc: BTeXDocument, uri: String, attribs: HashMap<String, String>) {
handler.spanColour = ccItemName
}
@OpenTag // reflective access is impossible with 'private'
fun processElemTARGETNAME(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>, siblingIndex: Int) {
fun processElemTARGETNAME(handler: BTeXHandler, doc: BTeXDocument, uri: String, attribs: HashMap<String, String>) {
handler.spanColour = ccTargetName
}
@OpenTag // reflective access is impossible with 'private'
fun processElemSPAN(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>, siblingIndex: Int) {
fun processElemSPAN(handler: BTeXHandler, doc: BTeXDocument, uri: String, attribs: HashMap<String, String>) {
handler.spanColour = attribs["colour"] ?: attribs["color"]
}
@CloseTag
fun closeElemTARGETNAME(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, siblingIndex: Int) = closeElemEMPH(handler, doc, theTag, uri, siblingIndex)
fun closeElemTARGETNAME(handler: BTeXHandler, doc: BTeXDocument, uri: String, siblingIndex: Int) = closeElemEMPH(handler, doc, uri, siblingIndex)
@CloseTag
fun closeElemITEMNAME(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, siblingIndex: Int) = closeElemEMPH(handler, doc, theTag, uri, siblingIndex)
fun closeElemITEMNAME(handler: BTeXHandler, doc: BTeXDocument, uri: String, siblingIndex: Int) = closeElemEMPH(handler, doc, uri, siblingIndex)
@CloseTag
fun closeElemEMPH(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, siblingIndex: Int) {
fun closeElemEMPH(handler: BTeXHandler, doc: BTeXDocument, uri: String, siblingIndex: Int) {
handler.spanColour = null
}
@OpenTag // reflective access is impossible with 'private'
fun processElemBTEX(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>, siblingIndex: Int) {
fun processElemBTEX(handler: BTeXHandler, doc: BTeXDocument, uri: String, attribs: HashMap<String, String>) {
handler.paragraphBuffer.append("BTeX")
}
@OpenTag // reflective access is impossible with 'private'
fun processElemCOVER(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>, siblingIndex: Int) {
fun processElemCOVER(handler: BTeXHandler, doc: BTeXDocument, uri: String, attribs: HashMap<String, String>) {
hasCover = true
val hue = (attribs["hue"]?.toFloatOrNull() ?: 28f) * DEG_TO_RAD
val coverCol = OKLch(hue, 0.05f, 0.36f)
val (r, g, b) = coverCol.tosRGB()
doc.addNewPage(Color(r, g, b, 1f))
val coverColLCH = OKLch(hue, 0.05f, 0.36f)
val (r, g, b) = coverColLCH.tosRGB()
coverCol = Color(r, g, b, 1f)
doc.addNewPage(coverCol!!)
// handler.spanColour = "white"
}
@OpenTag // reflective access is impossible with 'private'
fun processElemTOCPAGE(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>, siblingIndex: Int) {
doc.addNewPage()
fun processElemTOCPAGE(handler: BTeXHandler, doc: BTeXDocument, uri: String, attribs: HashMap<String, String>) {
doc.addNewPage() // toc: openright
typesetChapterHeading("Table of Contents", handler, 16)
}
@OpenTag // reflective access is impossible with 'private'
fun processElemINDEXPAGE(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>, siblingIndex: Int) {
fun processElemINDEXPAGE(handler: BTeXHandler, doc: BTeXDocument, uri: String, attribs: HashMap<String, String>) {
doc.addNewPage()
typesetChapterHeading("Index", handler, 16)
}
@OpenTag // reflective access is impossible with 'private'
fun processElemTABLEOFCONTENTS(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>, siblingIndex: Int) {
fun processElemTABLEOFCONTENTS(handler: BTeXHandler, doc: BTeXDocument, uri: String, attribs: HashMap<String, String>) {
tocPage = doc.currentPage
handler.paragraphBuffer.clear()
}
@OpenTag // reflective access is impossible with 'private'
fun processElemTABLEOFINDICES(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>, siblingIndex: Int) {
fun processElemTABLEOFINDICES(handler: BTeXHandler, doc: BTeXDocument, uri: String, attribs: HashMap<String, String>) {
handler.paragraphBuffer.clear()
// prepare contents
@@ -600,16 +604,16 @@ object BTeXParser {
}
@CloseTag
fun closeElemTABLEOFINDICES(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, siblingIndex: Int) {
fun closeElemTABLEOFINDICES(handler: BTeXHandler, doc: BTeXDocument, uri: String, siblingIndex: Int) {
}
@OpenTag // reflective access is impossible with 'private'
fun processElemMANUSCRIPT(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>, siblingIndex: Int) {
fun processElemMANUSCRIPT(handler: BTeXHandler, doc: BTeXDocument, uri: String, attribs: HashMap<String, String>) {
doc.addNewPage()
}
@CloseTag
fun closeElemMANUSCRIPT(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, siblingIndex: Int) {
fun closeElemMANUSCRIPT(handler: BTeXHandler, doc: BTeXDocument, uri: String, siblingIndex: Int) {
// setup pages such that:
// toc: openright (done on processElemTOCPAGE)
// first chapter: openright
@@ -618,7 +622,7 @@ object BTeXParser {
doc.addNewPageAt(cptSectMap.first().pagenum)
cptSectMap.forEach { it.pagenum += 1 }
}
else {
else if (cptSectMap.isNotEmpty()) {
doc.addNewPageAt(cptSectMap.first().pagenum)
doc.addNewPageAt(cptSectMap.first().pagenum)
cptSectMap.forEach { it.pagenum += 2 }
@@ -652,7 +656,7 @@ object BTeXParser {
}
@OpenTag // reflective access is impossible with 'private'
fun processElemINDEX(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>, siblingIndex: Int) {
fun processElemINDEX(handler: BTeXHandler, doc: BTeXDocument, uri: String, attribs: HashMap<String, String>) {
attribs["id"]?.let {
indexMap[it] = doc.currentPage
}
@@ -665,17 +669,17 @@ object BTeXParser {
@OpenTag // reflective access is impossible with 'private'
fun processElemBR(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>, siblingIndex: Int) {
fun processElemBR(handler: BTeXHandler, doc: BTeXDocument, uri: String, attribs: HashMap<String, String>) {
handler.paragraphBuffer.append("\n")
}
@OpenTag // reflective access is impossible with 'private'
fun processElemNEWPAGE(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>, siblingIndex: Int) {
fun processElemNEWPAGE(handler: BTeXHandler, doc: BTeXDocument, uri: String, attribs: HashMap<String, String>) {
doc.addNewPage()
}
@CloseTag // reflective access is impossible with 'private'
fun closeElemFULLPAGEBOX(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, siblingIndex: Int) {
fun closeElemFULLPAGEBOX(handler: BTeXHandler, doc: BTeXDocument, uri: String, siblingIndex: Int) {
doc.currentPageObj.let { page ->
val yStart = page.drawCalls.minOf { it.posY }
val yEnd = page.drawCalls.maxOf { it.posY + it.lineCount * doc.lineHeightInPx }
@@ -702,35 +706,36 @@ object BTeXParser {
}
@OpenTag // reflective access is impossible with 'private'
fun processElemP(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>, siblingIndex: Int) {
fun processElemP(handler: BTeXHandler, doc: BTeXDocument, uri: String, attribs: HashMap<String, String>) {
handler.paragraphBuffer.clear()
}
@CloseTag
fun closeElemCOVER(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, siblingIndex: Int) {
fun closeElemCOVER(handler: BTeXHandler, doc: BTeXDocument, uri: String, siblingIndex: Int) {
handler.spanColour = null
if (hasCover) {
doc.pages[0].drawCalls.forEach {
it.colour = Color.WHITE
}
doc.addNewPage()
}
}
@CloseTag // reflective access is impossible with 'private'
fun closeElemTITLE(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, siblingIndex: Int) {
fun closeElemTITLE(handler: BTeXHandler, doc: BTeXDocument, uri: String, siblingIndex: Int) {
val thePar = handler.paragraphBuffer.toString().trim()
typesetBookTitle(thePar, handler)
handler.paragraphBuffer.clear()
}
@CloseTag // reflective access is impossible with 'private'
fun closeElemAUTHOR(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, siblingIndex: Int) {
fun closeElemAUTHOR(handler: BTeXHandler, doc: BTeXDocument, uri: String, siblingIndex: Int) {
val thePar = handler.paragraphBuffer.toString().trim()
typesetBookAuthor(thePar, handler)
handler.paragraphBuffer.clear()
}
@CloseTag // reflective access is impossible with 'private'
fun closeElemEDITION(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, siblingIndex: Int) {
fun closeElemEDITION(handler: BTeXHandler, doc: BTeXDocument, uri: String, siblingIndex: Int) {
val thePar = handler.paragraphBuffer.toString().trim()
typesetBookAuthor(thePar, handler)
handler.paragraphBuffer.clear()
@@ -738,7 +743,7 @@ object BTeXParser {
@OpenTag // reflective access is impossible with 'private'
fun processElemCHAPTER(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>, siblingIndex: Int) {
fun processElemCHAPTER(handler: BTeXHandler, doc: BTeXDocument, uri: String, attribs: HashMap<String, String>) {
handler.paragraphBuffer.clear()
if (attribs["hide"] == null)
@@ -747,7 +752,7 @@ object BTeXParser {
cptSectStack.add(CptSect("chapter-hidden", attribs["alt"], doc.currentPage))
}
@OpenTag // reflective access is impossible with 'private'
fun processElemSECTION(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>, siblingIndex: Int) {
fun processElemSECTION(handler: BTeXHandler, doc: BTeXDocument, uri: String, attribs: HashMap<String, String>) {
handler.paragraphBuffer.clear()
if (attribs["hide"] == null)
@@ -756,7 +761,7 @@ object BTeXParser {
cptSectStack.add(CptSect("section-hidden", attribs["alt"], doc.currentPage))
}
@CloseTag // reflective access is impossible with 'private'
fun closeElemCHAPTER(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, siblingIndex: Int) {
fun closeElemCHAPTER(handler: BTeXHandler, doc: BTeXDocument, uri: String, siblingIndex: Int) {
// insert new page for second+ chapters
if (siblingIndex > 0) doc.addNewPage()
@@ -770,7 +775,7 @@ object BTeXParser {
handler.paragraphBuffer.clear()
}
@CloseTag // reflective access is impossible with 'private'
fun closeElemSECTION(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, siblingIndex: Int) {
fun closeElemSECTION(handler: BTeXHandler, doc: BTeXDocument, uri: String, siblingIndex: Int) {
// if current line is the last line, proceed to the next page
if (doc.linesPrintedOnPage.last() == doc.pageLines - 1) doc.addNewPage()
@@ -787,17 +792,32 @@ object BTeXParser {
@CloseTag // reflective access is impossible with 'private'
fun closeElemP(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, siblingIndex: Int) {
val thePar = (if (siblingIndex > 1) "\u3000" else "") + handler.paragraphBuffer.toString().trim() // indent the strictly non-first pars
typesetParagraphs(thePar, handler)
fun closeElemP(handler: BTeXHandler, doc: BTeXDocument, uri: String, siblingIndex: Int) {
// if this P is a very first P without chapters, leave two lines before typesetting
val addVirtualChapter = (tagHistory.size > 2 && tagHistory[tagHistory.lastIndex - 1] == "MANUSCRIPT")
val thePar = handler.paragraphBuffer.toString().trim()
val text =
if (siblingIndex > 1) "\u3000$thePar"
else if (addVirtualChapter) "\n\n$thePar"
else thePar
typesetParagraphs(text, handler)
handler.paragraphBuffer.clear()
}
@CloseTag // reflective access is impossible with 'private'
fun closeElemSPAN(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, siblingIndex: Int) {
fun closeElemSPAN(handler: BTeXHandler, doc: BTeXDocument, uri: String, siblingIndex: Int) {
spanColour = null
}
@CloseTag
fun closeElemBTEXDOC(handler: BTeXHandler, doc: BTeXDocument, uri: String, siblingIndex: Int) {
// make sure the last pair ends with paper and end-cover
if (doc.pages.size % 2 == 1) doc.addNewPage()
doc.addNewPage()
}

View File

@@ -16,6 +16,7 @@ import net.torvald.terrarum.btex.BTeXDocument
import net.torvald.terrarum.ceilToInt
import net.torvald.terrarum.gdxClearAndEnableBlend
import net.torvald.terrarum.inUse
import java.io.FileReader
/**
@@ -23,85 +24,9 @@ import net.torvald.terrarum.inUse
*/
class BTeXTest : ApplicationAdapter() {
val csiR = "\u001B[31m"
val csiG = "\u001B[32m"
val csi0 = "\u001B[m"
// val filePath = "btex.xml"
val filePath = "literature/koKR/yisang_nalgae.xml"
val tex = """<btexdoc cover="hardcover" inner="standard" papersize="standard">
<cover hue="230">
<title>The Way to Mastery of Lorem Ipsum<br />Or, How To Write and Publish a Book</title>
<author>Terran Publishing</author>
<edition>Test Edition</edition>
</cover>
<tocpage><tableofcontents /></tocpage>
<manuscript>
<chapter>What Is a Book</chapter>
<p>This example book is designed to give you the example of the Book Language.</p>
<section hide="1">What Really Is a Book</section>
<p>A book is a collection of texts printed in a special way that allows them to be read easily, with
enumerable pages and insertion of other helpful resources, such as illustrations and <a href="btex language">hyperlinks</a>.</p>
<section alt="Recursion">BRB: Bad Recursion BRB: Bad Recursion BRB: Bad Recursion BRB: Bad Recursion BRB: Bad Recursion BRB: Bad Recursion BRB: Bad Recursion BRB: Bad Recursion BRB: Bad Recursion BRB RangeError: stack size exceeded</section>
<p>Noice.</p>
<newpage />
<fullpagebox>
<p>text <emph>emph</emph> and <itemname>item</itemname> on <targetname>target</targetname></p>
</fullpagebox>
<chapter>Writing a Book Using Pen and Papers</chapter>
<p><index id="pen and paper" />If you open a book on a writing table, you will be welcomed with a
toolbar used to put other book elements, such as chapters and sections.</p>
<chapter>Writing a Book Using a Typewriter</chapter>
<p><index id="typewriter" />Typewriters can only write in a single style of font, chapters and
sections are not available.</p>
<chapter>Writing a Book Using a Computer</chapter>
<p>Writing book using a computer requires the use of the Book Typesetting Engine Extended, or <btex />.</p>
<section>Full Control of the Shape</section>
<p><index id="btex language" />With <btex /> you can fully control how your publishing would look like,
from a pile of papers that look like they have been typed out using typewriter, a pile of printouts
that have pictures in it, to a true hardcover book.</p>
<p><index id="cover" />This style is controlled using the <code>cover</code> attribute on the root tag,
with following values: <code>typewriter</code>, <code>printout</code> and <code>hardcover</code>.</p>
<p>Typewriter and Printout are considered not-bound and readers will only see one page at a time,
while Hardcover is considered bound and two pages are presented to the readers.</p>
</manuscript>
<indexpage><tableofindices /></indexpage>
</btexdoc>
"""
private lateinit var document: BTeXDocument
private lateinit var batch: FlippingSpriteBatch
@@ -118,7 +43,7 @@ class BTeXTest : ApplicationAdapter() {
bg = TextureRegion(Texture(Gdx.files.internal("test_assets/real_bg_with_guides.png")))
document = BTeXParser.invoke(tex)
document = BTeXParser.invoke(Gdx.files.internal("./assets/mods/basegame/books/$filePath"))
}
private var scroll = 0