blob: 52e513a028d8a4014e4ba9c2c77aa5138c8dabde [file] [log] [blame] [raw]
package li.cil.oc.client.gui
import java.util
import li.cil.oc.Localization
import li.cil.oc.api
import li.cil.oc.client.Textures
import li.cil.oc.client.renderer.markdown.Document
import li.cil.oc.client.renderer.markdown.segment.InteractiveSegment
import li.cil.oc.client.renderer.markdown.segment.Segment
import li.cil.oc.client.{Manual => ManualAPI}
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.Gui
import net.minecraft.client.gui.GuiButton
import net.minecraft.client.gui.GuiScreen
import net.minecraft.client.gui.ScaledResolution
import org.lwjgl.input.Mouse
import org.lwjgl.opengl.GL11
import scala.collection.convert.WrapAsJava._
import scala.collection.convert.WrapAsScala._
class Manual extends GuiScreen {
final val documentMaxWidth = 230
final val documentMaxHeight = 176
final val scrollPosX = 244
final val scrollPosY = 6
final val scrollWidth = 6
final val scrollHeight = 180
final val tabPosX = -23
final val tabPosY = 7
final val tabWidth = 23
final val tabHeight = 26
final val maxTabsPerSide = 7
var guiLeft = 0
var guiTop = 0
var xSize = 0
var ySize = 0
var isDragging = false
var document: Segment = null
var documentHeight = 0
var currentSegment = None: Option[InteractiveSegment]
protected var scrollButton: ImageButton = _
private def canScroll = maxOffset > 0
def offset = ManualAPI.history.top.offset
def maxOffset = documentHeight - documentMaxHeight
def add[T](list: util.List[T], value: Any) = list.add(value.asInstanceOf[T])
def resolveLink(path: String, current: String): String =
if (path.startsWith("/")) path
else {
val splitAt = current.lastIndexOf('/')
if (splitAt >= 0) current.splitAt(splitAt)._1 + "/" + path
else path
}
def refreshPage(): Unit = {
val content = Option(api.Manual.contentFor(ManualAPI.history.top.path)).
getOrElse(asJavaIterable(Iterable("Document not found: " + ManualAPI.history.top.path)))
document = Document.parse(content)
documentHeight = Document.height(document, documentMaxWidth, fontRendererObj)
scrollTo(offset)
}
def pushPage(path: String): Unit = {
if (path != ManualAPI.history.top.path) {
ManualAPI.history.push(new ManualAPI.History(path))
refreshPage()
}
}
def popPage(): Unit = {
if (ManualAPI.history.size > 1) {
ManualAPI.history.pop()
refreshPage()
}
else {
Minecraft.getMinecraft.thePlayer.closeScreen()
}
}
override def doesGuiPauseGame = false
override def actionPerformed(button: GuiButton): Unit = {
if (button.id >= 0 && button.id < ManualAPI.tabs.length) {
api.Manual.navigate(ManualAPI.tabs(button.id).path)
}
}
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
for ((tab, i) <- ManualAPI.tabs.zipWithIndex if i < maxTabsPerSide) {
val x = guiLeft + tabPosX
val y = guiTop + tabPosY + i * (tabHeight - 1)
add(buttonList, new ImageButton(i, x, y, tabWidth, tabHeight, Textures.guiManualTab))
}
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)
scrollButton.enabled = canScroll
scrollButton.hoverOverride = isDragging
super.drawScreen(mouseX, mouseY, dt)
for ((tab, i) <- ManualAPI.tabs.zipWithIndex if i < maxTabsPerSide) {
val button = buttonList.get(i).asInstanceOf[ImageButton]
GL11.glPushMatrix()
GL11.glTranslated(button.xPosition + 5, button.yPosition + 5, zLevel)
tab.renderer.render()
GL11.glPopMatrix()
}
currentSegment = Document.render(document, guiLeft + 8, guiTop + 8, documentMaxWidth, documentMaxHeight, offset, fontRendererObj, mouseX, mouseY)
if (!isDragging) currentSegment match {
case Some(segment) =>
segment.tooltip match {
case Some(text) if text.nonEmpty => drawHoveringText(seqAsJavaList(Localization.localizeImmediately(text).lines.toSeq), mouseX, mouseY, fontRendererObj)
case _ =>
}
case _ =>
}
if (!isDragging) for ((tab, i) <- ManualAPI.tabs.zipWithIndex if i < maxTabsPerSide) {
val button = buttonList.get(i).asInstanceOf[ImageButton]
if (mouseX > button.xPosition && mouseX < button.xPosition + tabWidth && mouseY > button.yPosition && mouseY < button.yPosition + tabHeight) tab.tooltip.foreach(text => {
drawHoveringText(seqAsJavaList(Localization.localizeImmediately(text).lines.toSeq), mouseX, mouseY, fontRendererObj)
})
}
if (isCoordinateOverScrollBar(mouseX - guiLeft, mouseY - guiTop) || isDragging) {
drawHoveringText(seqAsJavaList(Seq(s"${100 * offset / maxOffset}%")), guiLeft + scrollPosX + scrollWidth, scrollButton.yPosition + scrollButton.height + 1, fontRendererObj)
}
}
override def keyTyped(char: Char, code: Int): Unit = {
if (code == mc.gameSettings.keyBindJump.getKeyCode) {
popPage()
}
else if (code == mc.gameSettings.keyBindInventory.getKeyCode) {
mc.thePlayer.closeScreen()
}
else super.keyTyped(char, code)
}
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 (canScroll && button == 0 && isCoordinateOverScrollBar(mouseX - guiLeft, mouseY - guiTop)) {
isDragging = true
scrollMouse(mouseY)
}
else if (button == 0) currentSegment.foreach(_.onMouseClick(mouseX, mouseY))
else if (button == 1) popPage()
}
override protected def mouseClickMove(mouseX: Int, mouseY: Int, lastButtonClicked: Int, timeSinceMouseClick: Long) {
super.mouseClickMove(mouseX, mouseY, lastButtonClicked, timeSinceMouseClick)
if (isDragging) {
scrollMouse(mouseY)
}
}
override protected def mouseMovedOrUp(mouseX: Int, mouseY: Int, button: Int) {
super.mouseMovedOrUp(mouseX, mouseY, button)
if (button == 0) {
isDragging = false
}
}
private def scrollMouse(mouseY: Int) {
scrollTo(math.round((mouseY - guiTop - scrollPosY - 6.5) * maxOffset / (scrollHeight - 13.0)).toInt)
}
private def scrollUp() = scrollTo(offset - Document.lineHeight(fontRendererObj) * 3)
private def scrollDown() = scrollTo(offset + Document.lineHeight(fontRendererObj) * 3)
private def scrollTo(row: Int): Unit = {
ManualAPI.history.top.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
}
}
private def isCoordinateOverScrollBar(x: Int, y: Int) =
x > scrollPosX && x < scrollPosX + scrollWidth &&
y >= scrollPosY && y < scrollPosY + scrollHeight
}