blob: e26ff3ed67b120928d860fc04ee4ece722db459f [file] [log] [blame] [raw]
package li.cil.oc.client.gui
import java.io.InputStream
import java.util
import com.google.common.base.Charsets
import li.cil.oc.Settings
import li.cil.oc.client.Textures
import li.cil.oc.util.PseudoMarkdown
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.Gui
import net.minecraft.client.gui.GuiScreen
import net.minecraft.client.gui.ScaledResolution
import net.minecraft.util.ResourceLocation
import org.lwjgl.input.Mouse
import scala.collection.convert.WrapAsJava._
import scala.collection.mutable
import scala.io.Source
class Manual extends GuiScreen {
var guiLeft = 0
var guiTop = 0
var xSize = 0
var ySize = 0
var offset = 0
var document = Iterable.empty[PseudoMarkdown.Segment]
var documentHeight = 0
var history = mutable.Stack("index.md")
var hoveredLink = None: Option[String]
final val documentMaxWidth = 230
final val documentMaxHeight = 176
final val scrollPosX = 244
final val scrollPosY = 6
final val scrollHeight = 180
def add[T](list: util.List[T], value: Any) = list.add(value.asInstanceOf[T])
protected var scrollButton: ImageButton = _
def loadPage(path: String, seen: List[String] = List.empty): Iterator[String] = {
if (seen.contains(path)) return Iterator("Redirection loop: ") ++ seen.iterator ++ Iterator(path)
val location = new ResourceLocation(Settings.resourceDomain, if (path.startsWith("/")) path else "doc/" + path)
var is: InputStream = null
try {
val resource = Minecraft.getMinecraft.getResourceManager.getResource(location)
is = resource.getInputStream
// Force resolving immediately via toArray, otherwise we return a read
// iterator on a closed input stream (because of the finally).
val lines = Source.fromInputStream(is)(Charsets.UTF_8).getLines().toArray
lines.headOption match {
case Some(line) if line.toLowerCase.startsWith("#redirect ") => loadPage(line.substring("#redirect ".length), seen :+ path)
case _ => lines.iterator
}
}
catch {
case t: Throwable =>
Iterator(s"Failed loading page '$path':") ++ t.toString.lines
}
finally {
Option(is).foreach(_.close())
}
}
def refreshPage(): Unit = {
document = PseudoMarkdown.parse(loadPage(history.top))
documentHeight = PseudoMarkdown.height(document, documentMaxWidth, fontRendererObj)
scrollTo(offset)
}
def pushPage(path: String): Unit = {
history.push(path)
scrollTo(0)
refreshPage()
}
def popPage(): Unit = {
if (history.size > 1) {
history.pop()
scrollTo(0)
refreshPage()
}
else {
Minecraft.getMinecraft.thePlayer.closeScreenNoPacket()
}
}
override def doesGuiPauseGame = false
override def initGui(): Unit = {
super.initGui()
val mc = Minecraft.getMinecraft
val screenSize = new ScaledResolution(mc, mc.displayWidth, mc.displayHeight)
val guiSize = new ScaledResolution(mc, 256, 192)
val (midX, midY) = (screenSize.getScaledWidth / 2, screenSize.getScaledHeight / 2)
guiLeft = midX - guiSize.getScaledWidth / 2
guiTop = midY - guiSize.getScaledHeight / 2
xSize = guiSize.getScaledWidth
ySize = guiSize.getScaledHeight
scrollButton = new ImageButton(1, guiLeft + scrollPosX, guiTop + scrollPosY, 6, 13, Textures.guiButtonScroll)
add(buttonList, scrollButton)
refreshPage()
}
override def drawScreen(mouseX: Int, mouseY: Int, dt: Float): Unit = {
mc.renderEngine.bindTexture(Textures.guiManual)
Gui.func_146110_a(guiLeft, guiTop, 0, 0, xSize, ySize, 256, 192)
super.drawScreen(mouseX, mouseY, dt)
PseudoMarkdown.render(document, guiLeft + 8, guiTop + 8, documentMaxWidth, documentMaxHeight, offset, fontRendererObj, mouseX, mouseY) match {
case Some(segment) =>
segment.tooltip match {
case Some(text) if text.nonEmpty => drawHoveringText(seqAsJavaList(text.lines.toSeq), mouseX, mouseY, fontRendererObj)
case _ =>
}
hoveredLink = segment.link
case _ => hoveredLink = None
}
}
override def handleMouseInput(): Unit = {
super.handleMouseInput()
if (Mouse.hasWheel && Mouse.getEventDWheel != 0) {
if (math.signum(Mouse.getEventDWheel) < 0) scrollDown()
else scrollUp()
}
}
override def mouseClicked(mouseX: Int, mouseY: Int, button: Int): Unit = {
super.mouseClicked(mouseX, mouseY, button)
if (button == 0) {
// Left click, did we hit a link?
hoveredLink.foreach(link => pushPage(link))
}
else if (button == 1) {
// Right mouseclick = back.
popPage()
}
}
private def scrollUp() = scrollTo(offset - PseudoMarkdown.lineHeight(fontRendererObj) * 3)
private def scrollDown() = scrollTo(offset + PseudoMarkdown.lineHeight(fontRendererObj) * 3)
private def scrollTo(row: Int): Unit = {
val maxOffset = documentHeight - documentMaxHeight
offset = math.max(0, math.min(maxOffset, row))
val yMin = guiTop + scrollPosY
if (maxOffset > 0) {
scrollButton.yPosition = yMin + (scrollHeight - 13) * offset / maxOffset
}
else {
scrollButton.yPosition = yMin
}
}
}