mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-14 09:46:53 -04:00
Added proper code formatting renderer (using font renderer used for screens). Closes #1054.
Fixed text wrapping, strings without "wrap points" caused an infinite loop.
This commit is contained in:
parent
a1283c9aa2
commit
c7dfddd009
@ -22,7 +22,14 @@ over two* lines. But *this ... no *this is* **_bold italic_** *text*.
|
|||||||
|
|
||||||
`test for code`
|
`test for code`
|
||||||
`that's not code yet`
|
`that's not code yet`
|
||||||
this is some `code` that's inline.
|
`function f(a)`
|
||||||
|
` testingIndent(a)`
|
||||||
|
` do`
|
||||||
|
` lalala()`
|
||||||
|
` end`
|
||||||
|
`end`
|
||||||
|
yeah, line spacing is a bit low, but otherwise too little text fits on one screen.
|
||||||
|
this is some `code` that's inline. then `some more CODE that` line wraps and so on.
|
||||||
|
|
||||||
isn't*.
|
isn't*.
|
||||||
|
|
||||||
@ -35,3 +42,7 @@ And finally, [this is a link!](https://avatars1.githubusercontent.com/u/514903).
|
|||||||

|

|
||||||

|

|
||||||

|

|
||||||
|
|
||||||
|
wrap testing
|
||||||
|
12345678901234567890.1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||||
|
`123456789012345678901234567890.12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890`
|
@ -112,6 +112,33 @@ abstract class TextureFontRenderer {
|
|||||||
RenderState.checkError(getClass.getName + ".drawBuffer: leaving")
|
RenderState.checkError(getClass.getName + ".drawBuffer: leaving")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def drawString(s: String, x: Int, y: Int): Unit = {
|
||||||
|
GL11.glPushMatrix()
|
||||||
|
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS)
|
||||||
|
|
||||||
|
GL11.glTranslatef(x, y, 0)
|
||||||
|
GL11.glScalef(0.5f, 0.5f, 1)
|
||||||
|
GL11.glDepthMask(false)
|
||||||
|
|
||||||
|
for (i <- 0 until textureCount) {
|
||||||
|
bindTexture(i)
|
||||||
|
GL11.glBegin(GL11.GL_QUADS)
|
||||||
|
var tx = 0f
|
||||||
|
for (n <- 0 until s.length) {
|
||||||
|
val ch = s.charAt(n)
|
||||||
|
// Don't render whitespace.
|
||||||
|
if (ch != ' ') {
|
||||||
|
drawChar(tx, 0, ch)
|
||||||
|
}
|
||||||
|
tx += charWidth
|
||||||
|
}
|
||||||
|
GL11.glEnd()
|
||||||
|
}
|
||||||
|
|
||||||
|
GL11.glPopAttrib()
|
||||||
|
GL11.glPopMatrix()
|
||||||
|
}
|
||||||
|
|
||||||
protected def charWidth: Int
|
protected def charWidth: Int
|
||||||
|
|
||||||
protected def charHeight: Int
|
protected def charHeight: Int
|
||||||
|
@ -106,6 +106,8 @@ object Document {
|
|||||||
|
|
||||||
private def HeaderSegment(s: Segment, m: Regex.Match) = new segment.HeaderSegment(s, m.group(2), m.group(1).length)
|
private def HeaderSegment(s: Segment, m: Regex.Match) = new segment.HeaderSegment(s, m.group(2), m.group(1).length)
|
||||||
|
|
||||||
|
private def CodeSegment(s: Segment, m: Regex.Match) = new segment.CodeSegment(s, m.group(2))
|
||||||
|
|
||||||
private def LinkSegment(s: Segment, m: Regex.Match) = new segment.LinkSegment(s, m.group(1), m.group(2))
|
private def LinkSegment(s: Segment, m: Regex.Match) = new segment.LinkSegment(s, m.group(1), m.group(2))
|
||||||
|
|
||||||
private def BoldSegment(s: Segment, m: Regex.Match) = new segment.BoldSegment(s, m.group(2))
|
private def BoldSegment(s: Segment, m: Regex.Match) = new segment.BoldSegment(s, m.group(2))
|
||||||
@ -127,7 +129,7 @@ object Document {
|
|||||||
|
|
||||||
private val segmentTypes = Array(
|
private val segmentTypes = Array(
|
||||||
"""^(#+)\s(.*)""".r -> HeaderSegment _, // headers: # ...
|
"""^(#+)\s(.*)""".r -> HeaderSegment _, // headers: # ...
|
||||||
"""(`)(\S.*?\S|$)\1""".r -> ItalicSegment _, // code: `...`
|
"""(`)(.*?)\1""".r -> CodeSegment _, // code: `...`
|
||||||
"""!\[([^\[]*)\]\(([^\)]+)\)""".r -> ImageSegment _, // images: 
|
"""!\[([^\[]*)\]\(([^\)]+)\)""".r -> ImageSegment _, // images: 
|
||||||
"""\[([^\[]+)\]\(([^\)]+)\)""".r -> LinkSegment _, // links: [...](...)
|
"""\[([^\[]+)\]\(([^\)]+)\)""".r -> LinkSegment _, // links: [...](...)
|
||||||
"""(\*\*|__)(\S.*?\S|$)\1""".r -> BoldSegment _, // bold: **...** | __...__
|
"""(\*\*|__)(\S.*?\S|$)\1""".r -> BoldSegment _, // bold: **...** | __...__
|
||||||
|
@ -0,0 +1,84 @@
|
|||||||
|
package li.cil.oc.client.renderer.markdown.segment
|
||||||
|
|
||||||
|
import li.cil.oc.client.renderer.TextBufferRenderCache
|
||||||
|
import li.cil.oc.client.renderer.markdown.Document
|
||||||
|
import net.minecraft.client.gui.FontRenderer
|
||||||
|
import org.lwjgl.opengl.GL11
|
||||||
|
|
||||||
|
private[markdown] class CodeSegment(protected val parent: Segment, val text: String) extends Segment {
|
||||||
|
override def height(indent: Int, maxWidth: Int, renderer: FontRenderer): Int = {
|
||||||
|
var lines = 0
|
||||||
|
var chars = text
|
||||||
|
var lineChars = maxChars(chars, maxWidth - indent)
|
||||||
|
while (chars.length > lineChars) {
|
||||||
|
lines += 1
|
||||||
|
chars = chars.drop(lineChars).dropWhile(_.isWhitespace)
|
||||||
|
lineChars = maxChars(chars, maxWidth)
|
||||||
|
}
|
||||||
|
lines * Document.lineHeight(renderer)
|
||||||
|
}
|
||||||
|
|
||||||
|
override def width(indent: Int, maxWidth: Int, renderer: FontRenderer): Int = {
|
||||||
|
var currentX = indent
|
||||||
|
var chars = text
|
||||||
|
if (indent == 0) chars = chars.dropWhile(_.isWhitespace)
|
||||||
|
var lineChars = maxChars(chars, maxWidth - indent)
|
||||||
|
while (chars.length > lineChars) {
|
||||||
|
chars = chars.drop(lineChars).dropWhile(_.isWhitespace)
|
||||||
|
lineChars = maxChars(chars, maxWidth)
|
||||||
|
currentX = 0
|
||||||
|
}
|
||||||
|
currentX + stringWidth(chars)
|
||||||
|
}
|
||||||
|
|
||||||
|
override def render(x: Int, y: Int, indent: Int, maxWidth: Int, minY: Int, maxY: Int, renderer: FontRenderer, mouseX: Int, mouseY: Int): Option[InteractiveSegment] = {
|
||||||
|
TextBufferRenderCache.renderer.generateChars(text.toCharArray)
|
||||||
|
|
||||||
|
var currentX = x + indent
|
||||||
|
var currentY = y
|
||||||
|
var chars = text
|
||||||
|
var numChars = maxChars(chars, maxWidth - indent)
|
||||||
|
while (chars.length > 0 && (currentY - y) < maxY) {
|
||||||
|
val part = chars.take(numChars).reverse.dropWhile(_.isWhitespace).reverse
|
||||||
|
GL11.glColor4f(0.75f, 0.8f, 1, 1)
|
||||||
|
TextBufferRenderCache.renderer.drawString(part, currentX, currentY)
|
||||||
|
currentX = x
|
||||||
|
currentY += Document.lineHeight(renderer)
|
||||||
|
chars = chars.drop(numChars).dropWhile(_.isWhitespace)
|
||||||
|
numChars = maxChars(chars, maxWidth)
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
private def drawBox(x: Int, y: Int, width: Int, height: Int): Unit = {
|
||||||
|
GL11.glDisable(GL11.GL_TEXTURE_2D)
|
||||||
|
GL11.glBegin(GL11.GL_QUADS)
|
||||||
|
GL11.glVertex2f(x, y)
|
||||||
|
GL11.glVertex2f(x, y + height)
|
||||||
|
GL11.glVertex2f(x + width, y + height)
|
||||||
|
GL11.glVertex2f(x + width, y)
|
||||||
|
GL11.glEnd()
|
||||||
|
GL11.glEnable(GL11.GL_TEXTURE_2D)
|
||||||
|
}
|
||||||
|
|
||||||
|
private def stringWidth(s: String): Int = s.length * TextBufferRenderCache.renderer.charRenderWidth
|
||||||
|
|
||||||
|
private def maxChars(s: String, maxWidth: Int): Int = {
|
||||||
|
val breaks = Set(' ', '-', '.', '+', '*', '_', '/')
|
||||||
|
var pos = 0
|
||||||
|
var lastBreak = -1
|
||||||
|
while (pos < s.length) {
|
||||||
|
pos += 1
|
||||||
|
val width = stringWidth(s.take(pos))
|
||||||
|
if (width >= maxWidth) {
|
||||||
|
if (lastBreak > 0 || stringWidth(s) <= maxWidth) return lastBreak + 1
|
||||||
|
else return pos - 1
|
||||||
|
}
|
||||||
|
if (pos < s.length && breaks.contains(s.charAt(pos))) lastBreak = pos
|
||||||
|
}
|
||||||
|
pos
|
||||||
|
}
|
||||||
|
|
||||||
|
override def toString: String = s"{CodeSegment: text = $text}"
|
||||||
|
}
|
@ -127,7 +127,10 @@ private[markdown] class TextSegment(protected val parent: Segment, val text: Str
|
|||||||
while (pos < s.length) {
|
while (pos < s.length) {
|
||||||
pos += 1
|
pos += 1
|
||||||
val width = (stringWidth(s.take(pos), renderer) * fontScale).toInt
|
val width = (stringWidth(s.take(pos), renderer) * fontScale).toInt
|
||||||
if (width >= maxWidth) return lastBreak + 1
|
if (width >= maxWidth) {
|
||||||
|
if (lastBreak > 0 || stringWidth(s, renderer) <= maxWidth) return lastBreak + 1
|
||||||
|
else return pos - 1
|
||||||
|
}
|
||||||
if (pos < s.length && breaks.contains(s.charAt(pos))) lastBreak = pos
|
if (pos < s.length && breaks.contains(s.charAt(pos))) lastBreak = pos
|
||||||
}
|
}
|
||||||
pos
|
pos
|
||||||
|
@ -209,7 +209,7 @@ object ModOpenComputers extends ModProxy {
|
|||||||
api.Manual.addProvider("oredict", OreDictImageProvider)
|
api.Manual.addProvider("oredict", OreDictImageProvider)
|
||||||
|
|
||||||
api.Manual.addTab(new ItemStackTabIconRenderer(api.Items.get("case1").createItemStack(1)), "oc:gui.Manual.Blocks", "%LANGUAGE%/block/index.md")
|
api.Manual.addTab(new ItemStackTabIconRenderer(api.Items.get("case1").createItemStack(1)), "oc:gui.Manual.Blocks", "%LANGUAGE%/block/index.md")
|
||||||
api.Manual.addTab(new ItemStackTabIconRenderer(api.Items.get("chip1").createItemStack(1)), "oc:gui.Manual.Items", "%LANGUAGE%/item/index.md")
|
api.Manual.addTab(new ItemStackTabIconRenderer(api.Items.get("cpu1").createItemStack(1)), "oc:gui.Manual.Items", "%LANGUAGE%/item/index.md")
|
||||||
}
|
}
|
||||||
|
|
||||||
private def blacklistHost(host: Class[_], itemNames: String*) {
|
private def blacklistHost(host: Class[_], itemNames: String*) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user