mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-12 19:44:05 +09:00
trying to make <a> tag to work
This commit is contained in:
@@ -107,7 +107,7 @@
|
|||||||
<p><index id="manuscript"/><index id="tags"/>This is the part where you actually write your body texts in. The body text can have the following tags:</p>
|
<p><index id="manuscript"/><index id="tags"/>This is the part where you actually write your body texts in. The body text can have the following tags:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><index id="part (tag)"/><code>part</code> — inserts part separation page to your book</li>
|
<li><index id="part (tag)"/><code>part</code> — inserts part separation page to your book</li>
|
||||||
<li><index id="chapter (tag)"/><index id="section (tag)"/><code>chapter</code>, <code>section</code> — inserts a new chapter/section. If an alternative name is required on the Table of Contents, the <code>alt</code> attribute can be used. If the chapter/section needs to be hidden on the Table of Contents, add the <code>hide="1"</code> attribute. If the chapter must start on a new page, see <a href="macro definition">The Macro Definition</a></li>
|
<li><index id="chapter (tag)"/><index id="section (tag)"/><code>chapter</code>, <code>section</code> — inserts a new chapter/section. If an alternative name is required on the Table of Contents, the <code>alt</code> attribute can be used. If the chapter/section needs to be hidden on the Table of Contents, add the <code>hide="1"</code> attribute. If the chapter must start on a new page, see <a href="macro definition">the Macro Definition</a></li>
|
||||||
<li><index id="p (tag)"/><code>p</code> — inserts a new paragraph. The body texts must be written inside this tag. All paragraphs will have a 16-pixel indentation, with the following exceptions: first <code>p</code> of the part/chapter/section; first <code>p</code> after <code>br</code>, <code>newpage</code>, <code>callout</code>, <code>ul</code>, <code>ol</code> or <code>anonbreak</code></li>
|
<li><index id="p (tag)"/><code>p</code> — inserts a new paragraph. The body texts must be written inside this tag. All paragraphs will have a 16-pixel indentation, with the following exceptions: first <code>p</code> of the part/chapter/section; first <code>p</code> after <code>br</code>, <code>newpage</code>, <code>callout</code>, <code>ul</code>, <code>ol</code> or <code>anonbreak</code></li>
|
||||||
<li><index id="span (tag)"/><code>span</code> — allows changing the colour or the style of the texts. The colour must be specified in the <code>colour</code> attribute. Six-digit hex code, three-digit hex code and CSS Colours Level 4 named colours are supported. Note that all the colours will be rounded to the nearest three-digit hex code</li>
|
<li><index id="span (tag)"/><code>span</code> — allows changing the colour or the style of the texts. The colour must be specified in the <code>colour</code> attribute. Six-digit hex code, three-digit hex code and CSS Colours Level 4 named colours are supported. Note that all the colours will be rounded to the nearest three-digit hex code</li>
|
||||||
<li><index id="emph (tag)"/><code>emph</code> — is a special case of the <code>span</code> tag. The resulting text will be <emph>red</emph></li>
|
<li><index id="emph (tag)"/><code>emph</code> — is a special case of the <code>span</code> tag. The resulting text will be <emph>red</emph></li>
|
||||||
@@ -136,7 +136,7 @@
|
|||||||
<li><code>I</code> — use majuscule Roman numerals for the number (I, II, III, …)</li>
|
<li><code>I</code> — use majuscule Roman numerals for the number (I, II, III, …)</li>
|
||||||
<li><code>1</code> — use Arabic numerals (1, 2, 3)</li>
|
<li><code>1</code> — use Arabic numerals (1, 2, 3)</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>By default, parts use majuscule Roman numerals and others use Arabic. Alternative styling for the <code>part</code> and the <code>chapter</code> can be defined using the <a href="macro definition">Macro Definition</a>.</p>
|
<p>By default, parts use majuscule Roman numerals and others use Arabic. Alternative styling for the <code>part</code> and the <code>chapter</code> can be defined using <a href="macro definition">the Macro Definition</a>.</p>
|
||||||
|
|
||||||
|
|
||||||
<section>Paragraph Styling</section>
|
<section>Paragraph Styling</section>
|
||||||
@@ -311,7 +311,7 @@
|
|||||||
notified and will send the mail containing finished books to the player; if the process exits
|
notified and will send the mail containing finished books to the player; if the process exits
|
||||||
with errors, the mail containing details of the errors will be sent instead.</p>
|
with errors, the mail containing details of the errors will be sent instead.</p>
|
||||||
|
|
||||||
<p>For this reason the “printing press” is not exposed to the player, they only get to interact with it
|
<p>For this reason, the “printing press” is not exposed to the player, they only get to interact with it
|
||||||
indirectly through the “publisher” via mail.</p>
|
indirectly through the “publisher” via mail.</p>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -103,7 +103,7 @@
|
|||||||
<p><index id="원고"/><index id="태그 목록"/>원고는 책의 진짜 본문이 담긴 부분을 말한다. 본문에는 다음의 태그를 사용할 수 있다.</p>
|
<p><index id="원고"/><index id="태그 목록"/>원고는 책의 진짜 본문이 담긴 부분을 말한다. 본문에는 다음의 태그를 사용할 수 있다.</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><index id="part (태그)"/><code>part</code> — 원고에 새 부(part)를 추가함</li>
|
<li><index id="part (태그)"/><code>part</code> — 원고에 새 부(part)를 추가함</li>
|
||||||
<li><index id="chapter (태그)"/><index id="section (태그)"/><code>chapter</code>, <code>section</code> — 원고에 새 장(chapter)·절(section)을 추가함. 목차 페이지에는 다른 이름을 표시하고 싶다면 <code>alt</code> 속성을 사용할 수 있음. 목차 페이지에서 숨기고 싶다면 <code>hide="1"</code> 속성을 추가할 것. 장이 새 페이지에서 시작되게 하려면 <a href="macro definition">매크로 정의문</a>을 볼 것</li>
|
<li><index id="chapter (태그)"/><index id="section (태그)"/><code>chapter</code>, <code>section</code> — 원고에 새 장(chapter)·절(section)을 추가함. 목차 페이지에는 다른 이름을 표시하고 싶다면 <code>alt</code> 속성을 사용할 수 있음. 목차 페이지에서 숨기고 싶다면 <code>hide="1"</code> 속성을 추가할 것. 장이 새 페이지에서 시작되게 하려면 <a href="매크로 정의문">매크로 정의문</a>을 볼 것</li>
|
||||||
<li><index id="p (태그)"/><code>p</code> — 새 문단을 삽입함. 본문의 글은 반드시 이 태그 내부에 작성되어야 함. 모든 문단는 16픽셀의 들여쓰기로 조판되나, 다음의 경우 들여쓰기가 적용되지 않음: 부·장·절의 첫 문단, <code>br</code>, <code>newpage</code>, <code>callout</code>, <code>ul</code>, <code>ol</code>, <code>anonbreak</code> 태그 직후의 문단</li>
|
<li><index id="p (태그)"/><code>p</code> — 새 문단을 삽입함. 본문의 글은 반드시 이 태그 내부에 작성되어야 함. 모든 문단는 16픽셀의 들여쓰기로 조판되나, 다음의 경우 들여쓰기가 적용되지 않음: 부·장·절의 첫 문단, <code>br</code>, <code>newpage</code>, <code>callout</code>, <code>ul</code>, <code>ol</code>, <code>anonbreak</code> 태그 직후의 문단</li>
|
||||||
<li><index id="span (태그)"/><code>span</code> — 문구의 색상이나 스타일을 변경함. 색상은 <code>colour</code> 속성에 작성되어야 함. 6자리 헥스코드, 3자리 헥스코드, CSS Colours Level 4에 정의된 색상명을 사용할 수 있음. 모든 색상은 내부적으로 가장 가까운 3자리 헥스코드로 변경됨에 유의할 것</li>
|
<li><index id="span (태그)"/><code>span</code> — 문구의 색상이나 스타일을 변경함. 색상은 <code>colour</code> 속성에 작성되어야 함. 6자리 헥스코드, 3자리 헥스코드, CSS Colours Level 4에 정의된 색상명을 사용할 수 있음. 모든 색상은 내부적으로 가장 가까운 3자리 헥스코드로 변경됨에 유의할 것</li>
|
||||||
<li><index id="emph (태그)"/><code>emph</code> — <code>span</code>의 특수한 경우로, 문구를 <emph>빨간색으로</emph> 인자함</li>
|
<li><index id="emph (태그)"/><code>emph</code> — <code>span</code>의 특수한 경우로, 문구를 <emph>빨간색으로</emph> 인자함</li>
|
||||||
@@ -132,7 +132,7 @@
|
|||||||
<li><code>I</code> — 번호로 로마 숫자 대문자를 사용함 (I, II, III, …)</li>
|
<li><code>I</code> — 번호로 로마 숫자 대문자를 사용함 (I, II, III, …)</li>
|
||||||
<li><code>1</code> — 번호로 아라비아 숫자를 사용함 (1, 2, 3)</li>
|
<li><code>1</code> — 번호로 아라비아 숫자를 사용함 (1, 2, 3)</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>기본값은, 부는 로마 숫자 대문자, 장·절은 아라비아 숫자를 사용한다. 부의 경우 영어로 “Part I”과 같이 찍히고, 이를 “제1절”로 변경하는 등의 심화된 스타일은 <a href="macro definition">매크로 정의문</a>에서 정의할 수 있다.</p>
|
<p>기본값은, 부는 로마 숫자 대문자, 장·절은 아라비아 숫자를 사용한다. 부의 경우 영어로 “Part I”과 같이 찍히고, 이를 “제1절”로 변경하는 등의 심화된 스타일은 <a href="매크로 정의문">매크로 정의문</a>에서 정의할 수 있다.</p>
|
||||||
|
|
||||||
|
|
||||||
<section>문단 스타일</section>
|
<section>문단 스타일</section>
|
||||||
|
|||||||
110
src/net/torvald/btex/BTeXDocViewer.kt
Normal file
110
src/net/torvald/btex/BTeXDocViewer.kt
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
package net.torvald.btex
|
||||||
|
|
||||||
|
import com.badlogic.gdx.graphics.Color
|
||||||
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||||
|
import net.torvald.terrarum.btex.BTeXDocument
|
||||||
|
import net.torvald.terrarum.ceilToInt
|
||||||
|
import net.torvald.terrarum.inUse
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by minjaesong on 2024-05-17.
|
||||||
|
*/
|
||||||
|
class BTeXDocViewer(val doc: BTeXDocument) {
|
||||||
|
|
||||||
|
private val pageGap = 6
|
||||||
|
private var currentPage = 0
|
||||||
|
private val isTome = (doc.context == "tome")
|
||||||
|
|
||||||
|
val pageCount = doc.pageIndices.endInclusive + 1
|
||||||
|
|
||||||
|
fun gotoPage(page: Int) {
|
||||||
|
val page = page.coerceIn(doc.pageIndices)
|
||||||
|
if (isTome)
|
||||||
|
currentPage = (page / 2) * 2
|
||||||
|
else
|
||||||
|
currentPage = page
|
||||||
|
}
|
||||||
|
fun gotoIndex(id: String) {
|
||||||
|
gotoPage(doc.indexTable[id]!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun currentPageStr(): String {
|
||||||
|
// TODO non-tome
|
||||||
|
if (isTome) {
|
||||||
|
return if (currentPage == 0)
|
||||||
|
"1"
|
||||||
|
else
|
||||||
|
"${currentPage}-${currentPage+1}"
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return (currentPage + 1).toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param x top-centre
|
||||||
|
* @param y top-centre
|
||||||
|
*/
|
||||||
|
fun render(batch: SpriteBatch, x: Float, y: Float) {
|
||||||
|
val x1 = if (isTome)
|
||||||
|
x.toInt() - pageGap/2 - doc.pageDimensionWidth
|
||||||
|
else
|
||||||
|
x.toInt() - doc.pageDimensionWidth / 2
|
||||||
|
|
||||||
|
val x2 = if (isTome)
|
||||||
|
x.toInt() + pageGap/2
|
||||||
|
else
|
||||||
|
0
|
||||||
|
|
||||||
|
val y = y.toInt()
|
||||||
|
|
||||||
|
if (doc.isFinalised || doc.fromArchive) {
|
||||||
|
if (isTome) {
|
||||||
|
batch.color = Color.WHITE
|
||||||
|
|
||||||
|
if (currentPage - 1 in doc.pageIndices)
|
||||||
|
doc.render(0f, batch, currentPage - 1, x1, y)
|
||||||
|
if (currentPage in doc.pageIndices)
|
||||||
|
doc.render(0f, batch, currentPage, x2, y)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
batch.color = Color.WHITE
|
||||||
|
|
||||||
|
if (currentPage in doc.pageIndices)
|
||||||
|
doc.render(0f, batch, currentPage, x1, y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun prevPage() {
|
||||||
|
if (isTome) {
|
||||||
|
currentPage = (currentPage - 2).coerceAtLeast(0)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
currentPage = (currentPage - 1).coerceAtLeast(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun nextPage() {
|
||||||
|
if (isTome) {
|
||||||
|
currentPage = (currentPage + 2).coerceAtMost(doc.pageIndices.endInclusive.toFloat().div(2f).ceilToInt().times(2))
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
currentPage = (currentPage + 1).coerceAtLeast(doc.pageIndices.endInclusive)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun gotoFirstPage() {
|
||||||
|
gotoPage(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun gotoLastPage() {
|
||||||
|
if (isTome) {
|
||||||
|
currentPage = doc.pageIndices.endInclusive.toFloat().div(2f).ceilToInt().times(2)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gotoPage(doc.pageIndices.endInclusive)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ import com.badlogic.gdx.graphics.*
|
|||||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||||
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
||||||
import com.badlogic.gdx.utils.Disposable
|
import com.badlogic.gdx.utils.Disposable
|
||||||
|
import net.torvald.btex.BTeXDocViewer
|
||||||
import net.torvald.terrarum.ceilToInt
|
import net.torvald.terrarum.ceilToInt
|
||||||
import net.torvald.terrarum.concurrent.ThreadExecutor
|
import net.torvald.terrarum.concurrent.ThreadExecutor
|
||||||
import net.torvald.terrarum.imagefont.TinyAlphNum
|
import net.torvald.terrarum.imagefont.TinyAlphNum
|
||||||
@@ -55,6 +56,8 @@ class BTeXDocument : Disposable {
|
|||||||
var endOfPageStart = 2147483647
|
var endOfPageStart = 2147483647
|
||||||
var tocPageStart = 2
|
var tocPageStart = 2
|
||||||
|
|
||||||
|
val indexTable = HashMap<String, Int>()
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val DEFAULT_PAGE_BACK = Color(0xe0dfdb_ff.toInt())
|
val DEFAULT_PAGE_BACK = Color(0xe0dfdb_ff.toInt())
|
||||||
// val DEFAULT_PAGE_FORE = Color(0x0a0706_ff)
|
// val DEFAULT_PAGE_FORE = Color(0x0a0706_ff)
|
||||||
@@ -260,12 +263,6 @@ class BTeXDocument : Disposable {
|
|||||||
*
|
*
|
||||||
* `currentLine` *will* be updated automatically.
|
* `currentLine` *will* be updated automatically.
|
||||||
*/
|
*/
|
||||||
fun appendDrawCall(drawCall: BTeXDrawCall) {
|
|
||||||
pages.last().appendDrawCall(drawCall)
|
|
||||||
|
|
||||||
linesPrintedOnPage[linesPrintedOnPage.lastIndex] += drawCall.lineCount
|
|
||||||
}
|
|
||||||
|
|
||||||
fun appendDrawCall(page: BTeXPage, drawCall: BTeXDrawCall) {
|
fun appendDrawCall(page: BTeXPage, drawCall: BTeXDrawCall) {
|
||||||
page.appendDrawCall(drawCall)
|
page.appendDrawCall(drawCall)
|
||||||
|
|
||||||
@@ -273,6 +270,10 @@ class BTeXDocument : Disposable {
|
|||||||
linesPrintedOnPage[pagenum] += drawCall.lineCount
|
linesPrintedOnPage[pagenum] += drawCall.lineCount
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun appendClickable(page: BTeXPage, clickable: BTeXClickable) {
|
||||||
|
page.appendClickable(clickable)
|
||||||
|
}
|
||||||
|
|
||||||
fun render(frameDelta: Float, batch: SpriteBatch, page: Int, x: Int, y: Int) {
|
fun render(frameDelta: Float, batch: SpriteBatch, page: Int, x: Int, y: Int) {
|
||||||
batch.color = Color.WHITE
|
batch.color = Color.WHITE
|
||||||
|
|
||||||
@@ -330,16 +331,26 @@ class BTeXDocument : Disposable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class BTeXClickable(
|
||||||
|
val posX: Int, val posY: Int, val width: Int, val height: Int,
|
||||||
|
val onClick: (BTeXDocViewer) -> Unit,
|
||||||
|
// val onHover: () -> Unit = {}
|
||||||
|
)
|
||||||
|
|
||||||
class BTeXPage(
|
class BTeXPage(
|
||||||
val back: Color,
|
val back: Color,
|
||||||
val width: Int,
|
val width: Int,
|
||||||
val height: Int,
|
val height: Int,
|
||||||
) {
|
) {
|
||||||
internal val drawCalls = ArrayList<BTeXDrawCall>()
|
internal val drawCalls = ArrayList<BTeXDrawCall>()
|
||||||
|
internal val clickableElements = ArrayList<BTeXClickable>()
|
||||||
|
|
||||||
fun appendDrawCall(drawCall: BTeXDrawCall) {
|
fun appendDrawCall(drawCall: BTeXDrawCall) {
|
||||||
if (drawCall.isNotBlank()) drawCalls.add(drawCall)
|
if (drawCall.isNotBlank()) drawCalls.add(drawCall)
|
||||||
}
|
}
|
||||||
|
fun appendClickable(clickable: BTeXClickable) {
|
||||||
|
clickableElements.add(clickable)
|
||||||
|
}
|
||||||
|
|
||||||
private var prerender = false
|
private var prerender = false
|
||||||
|
|
||||||
@@ -357,9 +368,24 @@ class BTeXPage(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun touchDown(viewer: BTeXDocViewer, screenX: Int, screenY: Int, pointer: Int, button: Int) {
|
||||||
|
val pageRelX = screenX - drawX
|
||||||
|
val pageRelY = screenY - drawY
|
||||||
|
// filter clickable elements that are under the cursor
|
||||||
|
clickableElements.filter {
|
||||||
|
pageRelX in it.posX until it.posX+it.width &&
|
||||||
|
pageRelY in it.posY until it.posY+it.height
|
||||||
|
}.forEach { it.onClick(viewer) }
|
||||||
|
}
|
||||||
|
|
||||||
fun isEmpty() = drawCalls.isEmpty()
|
fun isEmpty() = drawCalls.isEmpty()
|
||||||
fun isNotEmpty() = drawCalls.isNotEmpty()
|
fun isNotEmpty() = drawCalls.isNotEmpty()
|
||||||
|
|
||||||
|
private var drawX = 0
|
||||||
|
private var drawY = 0
|
||||||
|
|
||||||
fun renderToPixmap(pixmap: Pixmap, x: Int, y: Int, marginH: Int, marginV: Int) {
|
fun renderToPixmap(pixmap: Pixmap, x: Int, y: Int, marginH: Int, marginV: Int) {
|
||||||
|
drawX = x; drawY = y
|
||||||
drawCalls.sortedBy { if (it.text != null) 16 else 0 }.let { drawCalls ->
|
drawCalls.sortedBy { if (it.text != null) 16 else 0 }.let { drawCalls ->
|
||||||
val backCol = back.cpy().also { it.a = 0.93f }
|
val backCol = back.cpy().also { it.a = 0.93f }
|
||||||
pixmap.setColor(backCol)
|
pixmap.setColor(backCol)
|
||||||
|
|||||||
@@ -12,11 +12,8 @@ import com.jme3.math.FastMath.DEG_TO_RAD
|
|||||||
import net.torvald.colourutil.OKLch
|
import net.torvald.colourutil.OKLch
|
||||||
import net.torvald.colourutil.tosRGB
|
import net.torvald.colourutil.tosRGB
|
||||||
import net.torvald.terrarum.*
|
import net.torvald.terrarum.*
|
||||||
import net.torvald.terrarum.btex.BTeXBatchDrawCall
|
import net.torvald.terrarum.btex.*
|
||||||
import net.torvald.terrarum.btex.BTeXDocument
|
|
||||||
import net.torvald.terrarum.btex.BTeXDocument.Companion.DEFAULT_ORNAMENTS_COL
|
import net.torvald.terrarum.btex.BTeXDocument.Companion.DEFAULT_ORNAMENTS_COL
|
||||||
import net.torvald.terrarum.btex.BTeXDrawCall
|
|
||||||
import net.torvald.terrarum.btex.TypesetDrawCall
|
|
||||||
import net.torvald.terrarum.gameitems.ItemID
|
import net.torvald.terrarum.gameitems.ItemID
|
||||||
import net.torvald.terrarum.langpack.Lang
|
import net.torvald.terrarum.langpack.Lang
|
||||||
import net.torvald.terrarum.ui.Toolkit
|
import net.torvald.terrarum.ui.Toolkit
|
||||||
@@ -88,6 +85,7 @@ object BTeXParser {
|
|||||||
private var tagHistory = ArrayList<String>()
|
private var tagHistory = ArrayList<String>()
|
||||||
|
|
||||||
private var currentHrefId: String? = null // any Unicode string that is not empty
|
private var currentHrefId: String? = null // any Unicode string that is not empty
|
||||||
|
private var oldHrefTarget: String? = null
|
||||||
|
|
||||||
private var currentTheme = ""
|
private var currentTheme = ""
|
||||||
|
|
||||||
@@ -104,6 +102,7 @@ object BTeXParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val objDict = HashMap<String, (BTeXDrawCall) -> BTeXBatchDrawCall>()
|
private val objDict = HashMap<String, (BTeXDrawCall) -> BTeXBatchDrawCall>()
|
||||||
|
private val hrefDict = HashMap<String, String>()
|
||||||
private val objWidthDict = HashMap<String, Int>()
|
private val objWidthDict = HashMap<String, Int>()
|
||||||
|
|
||||||
private var lastTagAtDepth = Array(24) { "" }
|
private var lastTagAtDepth = Array(24) { "" }
|
||||||
@@ -119,7 +118,6 @@ object BTeXParser {
|
|||||||
|
|
||||||
private val cptSectStack = ArrayList<CptSect>()
|
private val cptSectStack = ArrayList<CptSect>()
|
||||||
|
|
||||||
private val indexMap = HashMap<String, Int>() // id to pagenum
|
|
||||||
private val cptSectMap = ArrayList<CptSectInfo>()
|
private val cptSectMap = ArrayList<CptSectInfo>()
|
||||||
private var tocPage: Int? = null
|
private var tocPage: Int? = null
|
||||||
|
|
||||||
@@ -335,10 +333,6 @@ object BTeXParser {
|
|||||||
// printdbg(" End element \t($popped)")
|
// printdbg(" End element \t($popped)")
|
||||||
}
|
}
|
||||||
|
|
||||||
private var oldSpanColour: String? = null
|
|
||||||
private var oldCodeMode = false
|
|
||||||
private var oldHrefMode = false
|
|
||||||
private var oldBucksMode = false
|
|
||||||
private val CODE_TAG_MARGIN = 2
|
private val CODE_TAG_MARGIN = 2
|
||||||
|
|
||||||
private val CODEMODE_BEGIN = "${spacingBlockToString(CODE_TAG_MARGIN)}$ccCode${TerrarumSansBitmap.charsetOverrideCodestyle}"
|
private val CODEMODE_BEGIN = "${spacingBlockToString(CODE_TAG_MARGIN)}$ccCode${TerrarumSansBitmap.charsetOverrideCodestyle}"
|
||||||
@@ -365,12 +359,50 @@ object BTeXParser {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val REGEX_WHITESPACES = Regex("\\s+")
|
||||||
|
|
||||||
override fun characters(ch: CharArray, start: Int, length: Int) {
|
override fun characters(ch: CharArray, start: Int, length: Int) {
|
||||||
var str =
|
var str =
|
||||||
String(ch.sliceArray(start until start + length)).replace('\n', ' ').replace(Regex(" +"), " ")//.trim()
|
String(ch.sliceArray(start until start + length)).replace('\n', ' ').replace(Regex(" +"), " ")//.trim()
|
||||||
|
|
||||||
if (str.isNotEmpty()) {
|
if (str.isNotEmpty()) {
|
||||||
// printdbg("Characters [col:${spanColour}] \t\"$str\"")
|
|
||||||
|
|
||||||
|
// rising/falling edge of the hrefId
|
||||||
|
if (currentHrefId != oldHrefTarget) {
|
||||||
|
// rising edge
|
||||||
|
if (currentHrefId != null) {
|
||||||
|
printdbg("Href IN($currentHrefId) \t\"$str\"")
|
||||||
|
|
||||||
|
// put OBJ on every word, separated by whitespaces
|
||||||
|
// transform the word such that:
|
||||||
|
// word1 word2 -> [OBJ:XXX]word1 [OBJ:YYY]word2
|
||||||
|
str = str.trim().split(" ").map {
|
||||||
|
val wordWidth = getFont().getWidth(it)
|
||||||
|
val btexObjName = "HREF@${makeRandomObjName()}"
|
||||||
|
|
||||||
|
hrefDict[btexObjName] = currentHrefId!!
|
||||||
|
|
||||||
|
objectMarkerWithWidth(btexObjName, 0) + it
|
||||||
|
}.joinToString(" ")
|
||||||
|
|
||||||
|
}
|
||||||
|
// falling edge
|
||||||
|
else {
|
||||||
|
printdbg("Href OUT(null) \t\"$str\"")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// hrefId held high
|
||||||
|
else if (currentHrefId != null) {
|
||||||
|
printdbg("Href($currentHrefId) \t\"$str\"")
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printdbg("String \t\"$str\"")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
oldHrefTarget = currentHrefId
|
||||||
paragraphBuffer.append(str)
|
paragraphBuffer.append(str)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -725,6 +757,9 @@ object BTeXParser {
|
|||||||
@CloseTag
|
@CloseTag
|
||||||
fun closeElemA(handler: BTeXHandler, doc: BTeXDocument, uri: String, siblingIndex: Int) {
|
fun closeElemA(handler: BTeXHandler, doc: BTeXDocument, uri: String, siblingIndex: Int) {
|
||||||
paragraphBuffer.append(HREF_END)
|
paragraphBuffer.append(HREF_END)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
currentHrefId = null
|
currentHrefId = null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -776,8 +811,8 @@ object BTeXParser {
|
|||||||
// prepare contents
|
// prepare contents
|
||||||
val pageWidth = doc.textWidth
|
val pageWidth = doc.textWidth
|
||||||
|
|
||||||
indexMap.keys.toList().sorted().forEach { key ->
|
doc.indexTable.keys.toList().sorted().forEach { key ->
|
||||||
typesetTOCline("", key, indexMap[key]!! - 1, handler)
|
typesetTOCline("", key, doc.indexTable[key]!! - 1, handler)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -792,7 +827,7 @@ object BTeXParser {
|
|||||||
|
|
||||||
@CloseTag
|
@CloseTag
|
||||||
fun closeElemMANUSCRIPT(handler: BTeXHandler, doc: BTeXDocument, uri: String, siblingIndex: Int) {
|
fun closeElemMANUSCRIPT(handler: BTeXHandler, doc: BTeXDocument, uri: String, siblingIndex: Int) {
|
||||||
// if tocPage != null, estimate TOC page size, renumber indexMap and cptSectMap if needed, then typeset the toc
|
// if tocPage != null, estimate TOC page size, renumber doc.indexTable and cptSectMap if needed, then typeset the toc
|
||||||
if (tocPage != null) {
|
if (tocPage != null) {
|
||||||
// estimate the number of TOC pages
|
// estimate the number of TOC pages
|
||||||
// TOC page always takes up a full paper, therefore tocSizeInPages is always multiple of 2
|
// TOC page always takes up a full paper, therefore tocSizeInPages is always multiple of 2
|
||||||
@@ -800,13 +835,13 @@ object BTeXParser {
|
|||||||
if (tocSizeInPages == 0) tocSizeInPages = 2
|
if (tocSizeInPages == 0) tocSizeInPages = 2
|
||||||
if (tocSizeInPages % 2 == 1) tocSizeInPages += 1
|
if (tocSizeInPages % 2 == 1) tocSizeInPages += 1
|
||||||
|
|
||||||
println("TOC number of entries: ${cptSectMap.size}, estimated page count: $tocSizeInPages")
|
// printdbg("TOC number of entries: ${cptSectMap.size}, estimated page count: $tocSizeInPages")
|
||||||
|
|
||||||
// renumber things
|
// renumber things
|
||||||
if (tocSizeInPages > 1) {
|
if (tocSizeInPages > 1) {
|
||||||
val pageDelta = tocSizeInPages - 1
|
val pageDelta = tocSizeInPages - 1
|
||||||
indexMap.keys.forEach {
|
doc.indexTable.keys.forEach {
|
||||||
indexMap[it] = indexMap[it]!! + pageDelta
|
doc.indexTable[it] = doc.indexTable[it]!! + pageDelta
|
||||||
}
|
}
|
||||||
|
|
||||||
cptSectMap.forEach { it.pagenum += pageDelta }
|
cptSectMap.forEach { it.pagenum += pageDelta }
|
||||||
@@ -841,7 +876,7 @@ object BTeXParser {
|
|||||||
@OpenTag // reflective access is impossible with 'private'
|
@OpenTag // reflective access is impossible with 'private'
|
||||||
fun processElemINDEX(handler: BTeXHandler, doc: BTeXDocument, uri: String, attribs: HashMap<String, String>) {
|
fun processElemINDEX(handler: BTeXHandler, doc: BTeXDocument, uri: String, attribs: HashMap<String, String>) {
|
||||||
attribs["id"]?.let {
|
attribs["id"]?.let {
|
||||||
indexMap[it] = doc.currentPage + 1
|
doc.indexTable[it] = doc.currentPage + 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1614,6 +1649,18 @@ object BTeXParser {
|
|||||||
doc.appendDrawCall(doc.pages[pageNum], it); drawCalls.add(it)
|
doc.appendDrawCall(doc.pages[pageNum], it); drawCalls.add(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
val hrefs = parseAndGetHref(textDrawCalls[0], font, handler, posYline, slugs, subset.first, subset.second)
|
||||||
|
hrefs.forEach {
|
||||||
|
// search for:
|
||||||
|
// ..... [OBJ:RSETNFAOON]word setaf
|
||||||
|
// get width of "word"
|
||||||
|
val searchStr = slugs.typesettedSlugs.subList(subset.first, subset.first + subset.second)
|
||||||
|
printdbg("HREF searchStr: ${searchStr.joinToString { it.toReadable() }}")
|
||||||
|
// val clickable = BTeXClickable(it.x, it.y, undefined, doc.lineHeightInPx) { viewer ->
|
||||||
|
// viewer.gotoIndex(it.hrefTarget)
|
||||||
|
// }
|
||||||
|
// doc.appendClickable(doc.pages[pageNum], it)
|
||||||
|
}
|
||||||
|
|
||||||
linesOut += remainder
|
linesOut += remainder
|
||||||
slugHeight -= remainder
|
slugHeight -= remainder
|
||||||
@@ -1634,6 +1681,13 @@ object BTeXParser {
|
|||||||
doc.appendDrawCall(doc.pages[pageNum], it); drawCalls.add(it)
|
doc.appendDrawCall(doc.pages[pageNum], it); drawCalls.add(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// >>> HREF code here!! <<<
|
||||||
|
val hrefs = parseAndGetHref(textDrawCalls[0], font, handler, posYline, slugs, subset.first, subset.second)
|
||||||
|
hrefs.forEach {
|
||||||
|
val searchStr = slugs.typesettedSlugs.subList(subset.first, subset.first + subset.second)
|
||||||
|
printdbg("HREF searchStr: ${searchStr.joinToString { it.toReadable() }}")
|
||||||
|
}
|
||||||
|
// >>> HREF code ends here!! <<<
|
||||||
|
|
||||||
linesOut += remainder
|
linesOut += remainder
|
||||||
slugHeight -= remainder
|
slugHeight -= remainder
|
||||||
@@ -1652,10 +1706,7 @@ object BTeXParser {
|
|||||||
private fun textToDrawCall(handler: BTeXHandler, posYline: Int, slugs: MovableType, lineStart: Int, lineCount: Int): List<BTeXDrawCall> {
|
private fun textToDrawCall(handler: BTeXHandler, posYline: Int, slugs: MovableType, lineStart: Int, lineCount: Int): List<BTeXDrawCall> {
|
||||||
return listOf(
|
return listOf(
|
||||||
BTeXDrawCall(
|
BTeXDrawCall(
|
||||||
doc,
|
doc, 0, posYline * doc.lineHeightInPx, currentTheme,
|
||||||
0,
|
|
||||||
posYline * doc.lineHeightInPx,
|
|
||||||
currentTheme,
|
|
||||||
TypesetDrawCall(slugs, lineStart, lineCount)
|
TypesetDrawCall(slugs, lineStart, lineCount)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -1688,16 +1739,51 @@ object BTeXParser {
|
|||||||
c += 1
|
c += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
val extraDrawCall = BTeXDrawCall(
|
if (!idbuf.startsWith("HREF@")) {
|
||||||
doc,
|
out.add(BTeXDrawCall(
|
||||||
x,
|
doc, x, y, currentTheme,
|
||||||
y,
|
cmd = objDict[idbuf.toString()]?.invoke(textDrawCall)
|
||||||
currentTheme,
|
?: throw NullPointerException("No OBJ with id '$idbuf' exists"),
|
||||||
cmd = objDict[idbuf.toString()]?.invoke(textDrawCall) ?: throw NullPointerException("No OBJ with id '$idbuf' exists"),
|
font = font,
|
||||||
font = font,
|
))
|
||||||
)
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
out.add(extraDrawCall)
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun parseAndGetHref(
|
||||||
|
textDrawCall: BTeXDrawCall,
|
||||||
|
font: TerrarumSansBitmap,
|
||||||
|
handler: BTeXHandler,
|
||||||
|
posYline: Int,
|
||||||
|
slugs: MovableType,
|
||||||
|
lineStart: Int,
|
||||||
|
lineCount: Int
|
||||||
|
): List<_HrefObject> {
|
||||||
|
val out = ArrayList<_HrefObject>()
|
||||||
|
|
||||||
|
slugs.typesettedSlugs.subList(lineStart, lineStart + lineCount).forEachIndexed { lineNumCnt, line ->
|
||||||
|
line.mapIndexed { i, c -> i to c }.filter { it.second == OBJ }.map { it.first }.forEach { xIndex ->
|
||||||
|
val x = font.getWidthNormalised(CodepointSequence(line.subList(0, xIndex)))
|
||||||
|
val y = (posYline + lineNumCnt) * doc.lineHeightInPx
|
||||||
|
|
||||||
|
// get OBJ id
|
||||||
|
val idbuf = StringBuilder()
|
||||||
|
|
||||||
|
var c = xIndex + 1
|
||||||
|
while (true) {
|
||||||
|
val codepoint = line[c]
|
||||||
|
if (codepoint == 0xFFF9F) break
|
||||||
|
idbuf.append(codepointToObjIdChar(codepoint))
|
||||||
|
c += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idbuf.startsWith("HREF@")) {
|
||||||
|
val id = hrefDict[idbuf.toString()]!!
|
||||||
|
out.add(_HrefObject(x, y, id))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1788,6 +1874,7 @@ object BTeXParser {
|
|||||||
doc.addNewPage()
|
doc.addNewPage()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private data class _HrefObject(val x: Int, val y: Int, val hrefTarget: String)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
init {
|
init {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import com.badlogic.gdx.graphics.OrthographicCamera
|
|||||||
import com.badlogic.gdx.graphics.Texture
|
import com.badlogic.gdx.graphics.Texture
|
||||||
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
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.BTeXDocViewer
|
||||||
import net.torvald.btex.BTeXParser
|
import net.torvald.btex.BTeXParser
|
||||||
import net.torvald.terrarum.*
|
import net.torvald.terrarum.*
|
||||||
import net.torvald.terrarum.btex.BTeXDocument
|
import net.torvald.terrarum.btex.BTeXDocument
|
||||||
@@ -94,42 +95,44 @@ class BTeXTest : ApplicationAdapter() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var scroll = 0
|
var init = false
|
||||||
|
private lateinit var viewer: BTeXDocViewer
|
||||||
|
|
||||||
val pageGap = 6
|
private val drawY = 24
|
||||||
|
|
||||||
override fun render() {
|
override fun render() {
|
||||||
Gdx.graphics.setTitle("BTeXTest $EMDASH F: ${Gdx.graphics.framesPerSecond}")
|
Gdx.graphics.setTitle("BTeXTest $EMDASH F: ${Gdx.graphics.framesPerSecond}")
|
||||||
|
|
||||||
gdxClearAndEnableBlend(.063f, .070f, .086f, 1f)
|
gdxClearAndEnableBlend(.063f, .070f, .086f, 1f)
|
||||||
|
|
||||||
|
|
||||||
if (::document.isInitialized) {
|
if (::document.isInitialized) {
|
||||||
if (document.isFinalised || document.fromArchive) {
|
if (!init) {
|
||||||
val drawX = (1280 - (pageGap + document.pageDimensionWidth * 2)) / 2
|
init = true
|
||||||
val drawY = 24
|
viewer = BTeXDocViewer(document)
|
||||||
|
}
|
||||||
|
else {
|
||||||
batch.inUse {
|
batch.inUse {
|
||||||
batch.color = Color.WHITE
|
|
||||||
batch.draw(bg, 0f, 0f)
|
batch.draw(bg, 0f, 0f)
|
||||||
|
viewer.render(batch, 640f, drawY.toFloat())
|
||||||
|
|
||||||
if (scroll - 1 in document.pageIndices)
|
batch.color = Color.WHITE
|
||||||
document.render(0f, batch, scroll - 1, drawX, drawY)
|
val pageText = "${viewer.currentPageStr()}/${viewer.pageCount}"
|
||||||
if (scroll in document.pageIndices)
|
Toolkit.drawTextCentered(
|
||||||
document.render(0f, batch, scroll, drawX + (6 + document.pageDimensionWidth), drawY)
|
batch, TinyAlphNum, pageText,
|
||||||
|
1280, 0, drawY + document.pageDimensionHeight + 12
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// control
|
||||||
if (Gdx.input.isKeyJustPressed(Input.Keys.LEFT))
|
if (Gdx.input.isKeyJustPressed(Input.Keys.LEFT))
|
||||||
scroll = (scroll - 2).coerceAtLeast(0)
|
viewer.prevPage()
|
||||||
else if (Gdx.input.isKeyJustPressed(Input.Keys.RIGHT))
|
else if (Gdx.input.isKeyJustPressed(Input.Keys.RIGHT))
|
||||||
scroll =
|
viewer.nextPage()
|
||||||
(scroll + 2).coerceAtMost(
|
|
||||||
document.pageIndices.endInclusive.toFloat().div(2f).ceilToInt().times(2)
|
|
||||||
)
|
|
||||||
else if (Gdx.input.isKeyJustPressed(Input.Keys.PAGE_UP))
|
else if (Gdx.input.isKeyJustPressed(Input.Keys.PAGE_UP))
|
||||||
scroll = 0
|
viewer.gotoFirstPage()
|
||||||
else if (Gdx.input.isKeyJustPressed(Input.Keys.PAGE_DOWN))
|
else if (Gdx.input.isKeyJustPressed(Input.Keys.PAGE_DOWN))
|
||||||
scroll = document.pageIndices.endInclusive.toFloat().div(2f).ceilToInt().times(2)
|
viewer.gotoLastPage()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user