btex chapter and section styling

This commit is contained in:
minjaesong
2024-04-26 02:58:59 +09:00
parent 40be60865b
commit 6de340bde6
6 changed files with 163 additions and 82 deletions

View File

@@ -18,7 +18,7 @@
<section>What Really Is a Book</section> <section>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 <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 hyperlinks.</p> enumerable pages and insertion of other helpful resources, such as illustrations and <a href="btex language">hyperlinks</a>.</p>
<newpage /> <newpage />
@@ -34,33 +34,33 @@
<chapter>Writing Book Using Pen and Papers</chapter> <chapter>Writing 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 <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, sections.</p> toolbar used to put other book elements, such as chapters and sections.</p>
<chapter>Writing Book Using Typewriter</chapter> <chapter>Writing Book Using a Typewriter</chapter>
<p><index id="typewriter" />Typewriters can only write single style of font, therefore chapters and <p><index id="typewriter" />Typewriters can only write in a single style of font, chapters and
sections are not available.</p> sections are not available.</p>
<chapter>Writing Book using Computer</chapter> <chapter>Writing Book Using a Computer</chapter>
<p>Writing book using a computer requires a use of the Book Typesetting Engine Extended, or <btex /></p> <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> <section>Full Control of the Shape</section>
<p><index id="btex language" />With <btex /> you can fully control how your publishing would look like, <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 papers but a from a pile of papers that look like they have been typed out using typewriter, a pile of papers but a
fully-featured printouts that have illustrations in it, to a fully-featured hardcover book.</p> fully-featured printouts that have illustrations 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, <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>, <code>hardcover</code></p> 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, <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> while Hardcover is considered bound and two pages are presented to the readers.</p>
</manuscript> </manuscript>

Binary file not shown.

View File

@@ -5,6 +5,7 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch
import com.badlogic.gdx.graphics.g2d.TextureRegion import com.badlogic.gdx.graphics.g2d.TextureRegion
import net.torvald.terrarum.ui.Toolkit import net.torvald.terrarum.ui.Toolkit
import net.torvald.terrarumsansbitmap.MovableType import net.torvald.terrarumsansbitmap.MovableType
import net.torvald.terrarumsansbitmap.gdx.CodepointSequence
/** /**
* Created by minjaesong on 2023-10-28. * Created by minjaesong on 2023-10-28.
@@ -15,9 +16,9 @@ class BTeXDocument {
var inner = "standard" var inner = "standard"
var papersize = "standard" var papersize = "standard"
var textWidth = 450 var textWidth = 480
var lineHeightInPx = 24 var lineHeightInPx = 24
var pageLines = 24 var pageLines = 20
var textHeight = pageLines * lineHeightInPx var textHeight = pageLines * lineHeightInPx
val pageMarginH = 15 val pageMarginH = 15
@@ -38,6 +39,9 @@ class BTeXDocument {
val currentPage: Int val currentPage: Int
get() = pages.size - 1 get() = pages.size - 1
val currentPageObj: BTeXPage
get() = pages[currentPage]
val pageIndices: IntRange val pageIndices: IntRange
get() = pages.indices get() = pages.indices
@@ -72,7 +76,7 @@ class BTeXPage(
private val drawCalls = ArrayList<BTeXDrawCall>() private val drawCalls = ArrayList<BTeXDrawCall>()
fun appendDrawCall(drawCall: BTeXDrawCall) { fun appendDrawCall(drawCall: BTeXDrawCall) {
drawCalls.add(drawCall) if (drawCall.isNotBlank()) drawCalls.add(drawCall)
} }
fun render(frameDelta: Float, batch: SpriteBatch, x: Int, y: Int, marginH: Int, marginV: Int) { fun render(frameDelta: Float, batch: SpriteBatch, x: Int, y: Int, marginH: Int, marginV: Int) {
@@ -82,6 +86,9 @@ class BTeXPage(
it.draw(batch, x + marginH, y + marginV) it.draw(batch, x + marginH, y + marginV)
} }
} }
fun isEmpty() = drawCalls.isEmpty()
fun isNotEmpty() = drawCalls.isNotEmpty()
} }
interface BTeXTextDrawCall { interface BTeXTextDrawCall {
@@ -103,8 +110,8 @@ data class MovableTypeDrawCall(val movableType: MovableType, override val rowSta
}*/ }*/
class BTeXDrawCall( class BTeXDrawCall(
val posX: Int, // position relative to the page start (excluding page margin) var posX: Int, // position relative to the page start (excluding page margin)
val posY: Int, // position relative to the page start (excluding page margin) var posY: Int, // position relative to the page start (excluding page margin)
val theme: String, val theme: String,
val colour: Color, val colour: Color,
val text: BTeXTextDrawCall? = null, val text: BTeXTextDrawCall? = null,
@@ -132,11 +139,25 @@ class BTeXDrawCall(
batch.draw(texture, px, py) batch.draw(texture, px, py)
} }
else throw Error("Text and Texture are both non-null") else throw Error("Text and Texture are both non-null")
extraDrawFun(batch, px, py)
} }
fun isNotBlank(): Boolean {
if (text == null && texture == null) return false
if (text is MovableTypeDrawCall && text.movableType.inputText.isBlank()) return false
// if (text is RaggedLeftDrawCall && text.raggedType.inputText.isBlank()) return false
return true
}
internal var extraDrawFun: (SpriteBatch, Float, Float) -> Unit = { _,_,_ ->}
internal val lineCount = if (text != null) internal val lineCount = if (text != null)
text.rowEnd - text.rowStart text.rowEnd - text.rowStart
else else
TODO() TODO()
companion object {
private fun CodepointSequence.isBlank() = this.all { whitespaces.contains(it) }
private val whitespaces = (listOf(0x00, 0x20, 0x3000, 0xA0, 0xAD) + (0x2000..0x200F) + (0x202A..0x202F) + (0x205F..0x206F) + (0xFFFE0..0xFFFFF)).toHashSet()
}
} }

View File

@@ -2,11 +2,13 @@ package net.torvald.btex
import com.badlogic.gdx.files.FileHandle import com.badlogic.gdx.files.FileHandle
import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import net.torvald.terrarum.App import net.torvald.terrarum.App
import net.torvald.terrarum.btex.BTeXDocument import net.torvald.terrarum.btex.BTeXDocument
import net.torvald.terrarum.btex.BTeXDrawCall import net.torvald.terrarum.btex.BTeXDrawCall
import net.torvald.terrarum.btex.MovableTypeDrawCall import net.torvald.terrarum.btex.MovableTypeDrawCall
import net.torvald.terrarum.gameitems.ItemID import net.torvald.terrarum.gameitems.ItemID
import net.torvald.terrarum.ui.Toolkit
import net.torvald.terrarumsansbitmap.MovableType import net.torvald.terrarumsansbitmap.MovableType
import net.torvald.terrarumsansbitmap.gdx.TerrarumSansBitmap import net.torvald.terrarumsansbitmap.gdx.TerrarumSansBitmap
import org.xml.sax.Attributes import org.xml.sax.Attributes
@@ -75,6 +77,9 @@ object BTeXParser {
private val paragraphBuffer = StringBuilder() private val paragraphBuffer = StringBuilder()
private var lastTagAtDepth = Array(24) { "" }
private var pTagCntAtDepth = IntArray(24)
init { init {
BTeXHandler::class.declaredFunctions.filter { it.findAnnotation<OpenTag>() != null }.forEach { BTeXHandler::class.declaredFunctions.filter { it.findAnnotation<OpenTag>() != null }.forEach {
println("Tag opener: ${it.name}") println("Tag opener: ${it.name}")
@@ -119,6 +124,10 @@ object BTeXParser {
if (tagStack.isNotEmpty() && !textTags.contains(tagStack.last()) && textDecorTags.contains(theTag)) if (tagStack.isNotEmpty() && !textTags.contains(tagStack.last()) && textDecorTags.contains(theTag))
throw IllegalStateException("Text decoration tag '$theTag' used outside of a text tag (tag stack is ${tagStack.joinToString()})") throw IllegalStateException("Text decoration tag '$theTag' used outside of a text tag (tag stack is ${tagStack.joinToString()})")
if (lastTagAtDepth[tagStack.size] != "P") pTagCntAtDepth[tagStack.size] = 0
if (theTag == "P") pTagCntAtDepth[tagStack.size] += 1
lastTagAtDepth[tagStack.size] = theTag
tagStack.add(theTag) tagStack.add(theTag)
val attribs = HashMap<String, String>().also { val attribs = HashMap<String, String>().also {
@@ -131,10 +140,10 @@ object BTeXParser {
System.err.println("Unknown tag: $theTag") System.err.println("Unknown tag: $theTag")
else { else {
try { try {
it.call(this, this, doc, theTag, uri, attribs) it.call(this, this, doc, theTag, uri, attribs, pTagCntAtDepth[tagStack.size])
} }
catch (e: Throwable) { catch (e: Throwable) {
throw BTeXParsingException(e.stackTraceToString()) throw BTeXParsingException("processElem$theTag"+"\n"+e.stackTraceToString())
} }
} }
} }
@@ -143,13 +152,15 @@ object BTeXParser {
} }
override fun endElement(uri: String, localName: String, qName: String) { override fun endElement(uri: String, localName: String, qName: String) {
lastTagAtDepth[tagStack.size] = "xxx"
val popped = tagStack.removeLast() val popped = tagStack.removeLast()
val theTag = qName.uppercase() val theTag = qName.uppercase()
elemClosers["closeElem$theTag"].let { elemClosers["closeElem$theTag"].let {
try { try {
it?.call(this, this, doc, theTag, uri) it?.call(this, this, doc, theTag, uri, pTagCntAtDepth[tagStack.size])
} }
catch (e: Throwable) { catch (e: Throwable) {
throw BTeXParsingException(e.stackTraceToString()) throw BTeXParsingException(e.stackTraceToString())
@@ -396,15 +407,15 @@ object BTeXParser {
) )
private val pageWidthMap = hashMapOf( private val pageWidthMap = hashMapOf(
"standard" to 450 "standard" to 480
) )
private val pageHeightMap = hashMapOf( private val pageHeightMap = hashMapOf(
"standard" to 24 "standard" to 20
) )
@OpenTag // reflective access is impossible with 'private' @OpenTag // reflective access is impossible with 'private'
fun processElemBTEXDOC(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>) { fun processElemBTEXDOC(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>, siblingIndex: Int) {
if (handler.btexOpened) { if (handler.btexOpened) {
throw BTeXParsingException("BTEXDOC tag has already opened") throw BTeXParsingException("BTEXDOC tag has already opened")
} }
@@ -431,7 +442,7 @@ object BTeXParser {
} }
@OpenTag // reflective access is impossible with 'private' @OpenTag // reflective access is impossible with 'private'
fun processElemPAIR(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>) { fun processElemPAIR(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>, siblingIndex: Int) {
if (tagStack.size == 3 && tagStack.getOrNull(1) == "blocklut") { if (tagStack.size == 3 && tagStack.getOrNull(1) == "blocklut") {
blockLut[attribs["key"]!!] = attribs["value"]!! blockLut[attribs["key"]!!] = attribs["value"]!!
} }
@@ -441,35 +452,35 @@ object BTeXParser {
} }
@OpenTag // reflective access is impossible with 'private' @OpenTag // reflective access is impossible with 'private'
fun processElemSPAN(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>) { fun processElemSPAN(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>, siblingIndex: Int) {
attribs["span"]?.let { attribs["span"]?.let {
spanColour = it spanColour = it
} }
} }
@OpenTag // reflective access is impossible with 'private' @OpenTag // reflective access is impossible with 'private'
fun processElemTABLEOFCONTENTS(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>) { fun processElemTABLEOFCONTENTS(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>, siblingIndex: Int) {
// TODO add post-parsing hook to the handler // TODO add post-parsing hook to the handler
} }
@OpenTag // reflective access is impossible with 'private' @OpenTag // reflective access is impossible with 'private'
fun processElemBTEX(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>) { fun processElemBTEX(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>, siblingIndex: Int) {
handler.paragraphBuffer.append("BTeX") handler.paragraphBuffer.append("BTeX")
} }
@OpenTag // reflective access is impossible with 'private' @OpenTag // reflective access is impossible with 'private'
fun processElemCOVER(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>) { fun processElemCOVER(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>, siblingIndex: Int) {
doc.addNewPage(Color(0x6f4a45ff)) doc.addNewPage(Color(0x6f4a45ff))
handler.spanColour = "white" handler.spanColour = "white"
} }
@OpenTag // reflective access is impossible with 'private' @OpenTag // reflective access is impossible with 'private'
fun processElemTOC(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>) { fun processElemTOC(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>, siblingIndex: Int) {
doc.addNewPage() doc.addNewPage()
} }
@OpenTag // reflective access is impossible with 'private' @OpenTag // reflective access is impossible with 'private'
fun processElemMANUSCRIPT(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>) { fun processElemMANUSCRIPT(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>, siblingIndex: Int) {
doc.addNewPage() doc.addNewPage()
} }
@@ -480,48 +491,87 @@ object BTeXParser {
@OpenTag // reflective access is impossible with 'private' @OpenTag // reflective access is impossible with 'private'
fun processElemBR(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>) { fun processElemBR(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>, siblingIndex: Int) {
handler.paragraphBuffer.append("\n") handler.paragraphBuffer.append("\n")
} }
@OpenTag // reflective access is impossible with 'private' @OpenTag // reflective access is impossible with 'private'
fun processElemNEWPAGE(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>) { fun processElemNEWPAGE(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>, siblingIndex: Int) {
doc.addNewPage() doc.addNewPage()
} }
@CloseTag // reflective access is impossible with 'private' @CloseTag // reflective access is impossible with 'private'
fun closeElemFULLPAGEBOX(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String) { fun closeElemFULLPAGEBOX(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, siblingIndex: Int) {
doc.addNewPage() doc.addNewPage()
} }
@OpenTag // reflective access is impossible with 'private' @OpenTag // reflective access is impossible with 'private'
fun processElemP(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>) { fun processElemP(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>, siblingIndex: Int) {
} }
@CloseTag @CloseTag
fun closeElemCOVER(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String) { fun closeElemCOVER(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, siblingIndex: Int) {
handler.spanColour = null handler.spanColour = null
} }
@CloseTag // reflective access is impossible with 'private' @CloseTag // reflective access is impossible with 'private'
fun closeElemTITLE(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String) = closeElemP(handler, doc, theTag, uri) fun closeElemTITLE(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, siblingIndex: Int) = closeElemP(handler, doc, theTag, uri, siblingIndex)
@CloseTag // reflective access is impossible with 'private' @CloseTag // reflective access is impossible with 'private'
fun closeElemAUTHOR(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String) = closeElemP(handler, doc, theTag, uri) fun closeElemAUTHOR(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, siblingIndex: Int) = closeElemP(handler, doc, theTag, uri, siblingIndex)
@CloseTag // reflective access is impossible with 'private' @CloseTag // reflective access is impossible with 'private'
fun closeElemEDITION(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String) = closeElemP(handler, doc, theTag, uri) fun closeElemEDITION(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, siblingIndex: Int) = closeElemP(handler, doc, theTag, uri, siblingIndex)
@CloseTag // reflective access is impossible with 'private' @CloseTag // reflective access is impossible with 'private'
fun closeElemCHAPTER(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String) = closeElemP(handler, doc, theTag, uri) fun closeElemCHAPTER(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, siblingIndex: Int) {
val indent = 16
val thePar = "\n" + handler.paragraphBuffer.toString().trim()
typesetParagraphs(thePar, handler, doc.textWidth - indent).also {
// add indents and adjust text y pos
it.forEach {
it.posX += indent
it.posY -= doc.lineHeightInPx / 2
}
// add ornamental column on the left
it.forEach {
it.extraDrawFun = { batch, x, y ->
Toolkit.fillArea(batch, x - (indent - 2), y + doc.lineHeightInPx, 6f, (it.lineCount - 1).coerceAtLeast(1) * doc.lineHeightInPx.toFloat())
}
}
}
handler.paragraphBuffer.clear()
}
@CloseTag // reflective access is impossible with 'private' @CloseTag // reflective access is impossible with 'private'
fun closeElemSECTION(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String) = closeElemP(handler, doc, theTag, uri) fun closeElemSECTION(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, siblingIndex: Int) {
val indent = 8
val thePar = "\n" + handler.paragraphBuffer.toString().trim()
typesetParagraphs(thePar, handler, doc.textWidth - indent).also {
// add indents and adjust text y pos
it.forEach {
it.posX += indent
it.posY -= doc.lineHeightInPx / 2
}
}
handler.paragraphBuffer.clear()
}
@CloseTag // reflective access is impossible with 'private' @CloseTag // reflective access is impossible with 'private'
fun closeElemP(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String) { fun closeElemP(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, siblingIndex: Int) {
val thePar = handler.paragraphBuffer.toString().trim() + "\n" val thePar = (if (siblingIndex > 1) "\u3000" else "") + handler.paragraphBuffer.toString().trim() // indent the strictly non-first pars
printdbg("Par: '$thePar'") typesetParagraphs(thePar, handler)
handler.paragraphBuffer.clear()
}
@CloseTag // reflective access is impossible with 'private'
fun closeElemSPAN(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, siblingIndex: Int) {
spanColour = null
}
private fun typesetParagraphs(thePar: String, handler: BTeXHandler, width: Int = doc.textWidth): List<BTeXDrawCall> {
val font = getFont() val font = getFont()
val slugs = MovableType(font, thePar, doc.textWidth) val slugs = MovableType(font, thePar, width)
val drawCalls = ArrayList<BTeXDrawCall>()
var remainder = doc.pageLines - doc.currentLine var remainder = doc.pageLines - doc.currentLine
var slugHeight = slugs.height var slugHeight = slugs.height
@@ -540,7 +590,7 @@ object BTeXParser {
MovableTypeDrawCall(slugs, subset.first, subset.second) MovableTypeDrawCall(slugs, subset.first, subset.second)
) )
doc.appendDrawCall(drawCall) doc.appendDrawCall(drawCall); drawCalls.add(drawCall)
linesOut += remainder linesOut += remainder
slugHeight -= remainder slugHeight -= remainder
@@ -561,7 +611,7 @@ object BTeXParser {
MovableTypeDrawCall(slugs, subset.first, subset.second) MovableTypeDrawCall(slugs, subset.first, subset.second)
) )
doc.appendDrawCall(drawCall) doc.appendDrawCall(drawCall); drawCalls.add(drawCall)
linesOut += remainder linesOut += remainder
slugHeight -= remainder slugHeight -= remainder
@@ -571,19 +621,10 @@ object BTeXParser {
} }
} }
handler.paragraphBuffer.clear() // if typesetting the paragraph leaves the first line of new page empty, move the "row cursor" back up
} if (doc.currentLine == 1 && doc.currentPageObj.isEmpty()) doc.currentLine = 0 // '\n' adds empty draw call to the page, which makes isEmpty() to return false
@OpenTag // reflective access is impossible with 'private' return drawCalls
fun processElemARST(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String, attribs: HashMap<String, String>) {
}
@CloseTag // reflective access is impossible with 'private'
fun closeElemSPAN(handler: BTeXHandler, doc: BTeXDocument, theTag: String, uri: String) {
spanColour = null
} }
} }

View File

@@ -5,7 +5,10 @@ import com.badlogic.gdx.Gdx
import com.badlogic.gdx.Input import com.badlogic.gdx.Input
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.OrthographicCamera import com.badlogic.gdx.graphics.OrthographicCamera
import com.badlogic.gdx.graphics.Texture
import com.badlogic.gdx.graphics.g2d.TextureRegion
import com.badlogic.gdx.graphics.glutils.ShaderProgram import com.badlogic.gdx.graphics.glutils.ShaderProgram
import net.torvald.btex.BTeXParser import net.torvald.btex.BTeXParser
import net.torvald.terrarum.FlippingSpriteBatch import net.torvald.terrarum.FlippingSpriteBatch
@@ -34,9 +37,9 @@ class BTeXTest : ApplicationAdapter() {
<toc><tableofcontents /></toc> <toc><tableofcontents /></toc>
<manuscript> <manuscript>
<chapter>What Is a Book</chapter> <chapter>What Is a Book</chapter>
<p>This example book is designed to give you the example of the Book Language.</p> <p>This example book is designed to give you the example of the Book Language.</p>
@@ -44,49 +47,49 @@ class BTeXTest : ApplicationAdapter() {
<section>What Really Is a Book</section> <section>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 <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 hyperlinks.</p> enumerable pages and insertion of other helpful resources, such as illustrations and <a href="btex language">hyperlinks</a>.</p>
<newpage /> <newpage />
<!--<fullpagebox> <fullpagebox>
<p><span colour="grey"> <p><span colour="grey">
this page is intentionally left blank this page is intentionally left blank
</span></p> </span></p>
</fullpagebox>--> </fullpagebox>
<chapter>Writing Book Using Pen and Papers</chapter> <chapter>Writing 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 <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, sections.</p> toolbar used to put other book elements, such as chapters and sections.</p>
<chapter>Writing Book Using Typewriter</chapter>
<p><index id="typewriter" />Typewriters can only write single style of font, therefore chapters and
<chapter>Writing 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> sections are not available.</p>
<chapter>Writing Book using Computer</chapter>
<p>Writing book using a computer requires a use of the Book Typesetting Engine Extended, or <btex /></p>
<chapter>Writing 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> <section>Full Control of the Shape</section>
<p><index id="btex language" />With <btex /> you can fully control how your publishing would look like, <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 papers but a from a pile of papers that look like they have been typed out using typewriter, a pile of papers but a
fully-featured printouts that have illustrations in it, to a fully-featured hardcover book.</p> fully-featured printouts that have illustrations 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, <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>, <code>hardcover</code></p> 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, <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> while Hardcover is considered bound and two pages are presented to the readers.</p>
</manuscript> </manuscript>
@@ -94,12 +97,16 @@ class BTeXTest : ApplicationAdapter() {
<indexpage><tableofindices /></indexpage> <indexpage><tableofindices /></indexpage>
</btexdoc> </btexdoc>
""" """
private lateinit var document: BTeXDocument private lateinit var document: BTeXDocument
private lateinit var batch: FlippingSpriteBatch private lateinit var batch: FlippingSpriteBatch
private lateinit var camera: OrthographicCamera private lateinit var camera: OrthographicCamera
private lateinit var bg: TextureRegion
override fun create() { override fun create() {
batch = FlippingSpriteBatch(1000) batch = FlippingSpriteBatch(1000)
camera = OrthographicCamera(1280f, 720f) camera = OrthographicCamera(1280f, 720f)
@@ -107,20 +114,29 @@ class BTeXTest : ApplicationAdapter() {
camera.update() camera.update()
batch.projectionMatrix = camera.combined batch.projectionMatrix = camera.combined
bg = TextureRegion(Texture(Gdx.files.internal("test_assets/Screenshot-1714034883660.png")))
document = BTeXParser.invoke(tex) document = BTeXParser.invoke(tex)
} }
private var scroll = 0 private var scroll = 0
val pageGap = 6
override fun render() { override fun render() {
gdxClearAndEnableBlend(.063f, .070f, .086f, 1f) gdxClearAndEnableBlend(.063f, .070f, .086f, 1f)
val drawX = (1280 - (pageGap + document.pageWidth*2)) / 2
val drawY = 100
batch.inUse { batch.inUse {
batch.color = Color.WHITE
batch.draw(bg, 0f, 0f)
if (scroll - 1 in document.pageIndices) if (scroll - 1 in document.pageIndices)
document.render(0f, batch, scroll - 1, 12, 12) document.render(0f, batch, scroll - 1, drawX, drawY)
if (scroll in document.pageIndices) if (scroll in document.pageIndices)
document.render(0f, batch, scroll, 12 + (6 + document.pageWidth), 12) document.render(0f, batch, scroll, drawX + (6 + document.pageWidth), drawY)
} }

Binary file not shown.