diff --git a/src/main/java/com/hbm/qmaw/GuiQMAW.java b/src/main/java/com/hbm/qmaw/GuiQMAW.java index 9e3b37595..1cca980fb 100644 --- a/src/main/java/com/hbm/qmaw/GuiQMAW.java +++ b/src/main/java/com/hbm/qmaw/GuiQMAW.java @@ -3,12 +3,20 @@ package com.hbm.qmaw; import java.util.ArrayList; import java.util.List; +import org.lwjgl.input.Keyboard; +import org.lwjgl.input.Mouse; import org.lwjgl.opengl.GL11; import com.hbm.lib.RefStrings; +import com.hbm.qmaw.components.*; +import cpw.mods.fml.common.FMLCommonHandler; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.client.resources.LanguageManager; +import net.minecraft.item.ItemStack; +import net.minecraft.util.MathHelper; import net.minecraft.util.ResourceLocation; public class GuiQMAW extends GuiScreen { @@ -16,19 +24,128 @@ public class GuiQMAW extends GuiScreen { protected static final ResourceLocation texture = new ResourceLocation(RefStrings.MODID + ":textures/gui/gui_wiki.png"); public String title; - public List lines = new ArrayList(); + public ItemStack icon; + public List> lines = new ArrayList(); - protected int xSize = 192; - protected int ySize = 256; + protected int xSize = 340; + protected int ySize = 224; protected int guiLeft; protected int guiTop; + protected boolean isDragging = false; + protected int scrollProgress = 0; + protected int lastClickX = 0; + protected int lastClickY = 0; + + public static final String EN_US = "en_US"; + public GuiQMAW(QuickManualAndWiki qmaw) { parseQMAW(qmaw); } protected void parseQMAW(QuickManualAndWiki qmaw) { + LanguageManager lang = Minecraft.getMinecraft().getLanguageManager(); + this.title = qmaw.title.get(lang.getCurrentLanguage()); + if(title == null) this.title = qmaw.title.get(EN_US); + if(title == null) this.title = "Missing Localization!"; + + this.icon = qmaw.icon; + + String toParse = qmaw.contents.get(lang.getCurrentLanguage()); + if(toParse == null) toParse = qmaw.contents.get(EN_US); + if(toParse == null) toParse = "Missing Localization!"; + toParse = "" + toParse; // strings are reference types, no? + + int maxLineLength = xSize - 29; + String prevToParse = "" + toParse; + int maxIterations = 1000; + int currentLineWidth = 0; + + while(!toParse.isEmpty() && maxIterations > 0) { + if(this.lines.isEmpty()) this.lines.add(new ArrayList()); + List currentLine = this.lines.get(this.lines.size() - 1); + + toParse = toParse.trim(); + + maxIterations--; + + if(toParse.startsWith("
")) { + toParse = toParse.substring(4); + currentLine = new ArrayList(); + this.lines.add(currentLine); + currentLineWidth = 0; + continue; + } + + // handle links + if(toParse.startsWith("[[")) { + int end = toParse.indexOf("]]"); + if(end != -1) { + String link = toParse.substring(2, end); + toParse = toParse.substring(end + 2); + + int pipe = link.indexOf("|"); + QComponentLink linkComponent; + + if(pipe == -1) { + linkComponent = new QComponentLink(link, link); + } else { + linkComponent = new QComponentLink(link.substring(pipe + 1, link.length()), link.substring(0, pipe)); + } + + // append to current line + int width = linkComponent.getWidth(); + if(width + currentLineWidth <= maxLineLength) { + currentLine.add(linkComponent); + currentLineWidth += width; + // new line + } else { + currentLine = new ArrayList(); + this.lines.add(currentLine); + currentLine.add(linkComponent); + currentLineWidth = width; + } + + prevToParse = "" + toParse; + continue; + } + } + + // handle standard text + int delimit = toParse.length(); + + int spaceIndex = toParse.indexOf(" "); + if(spaceIndex != -1) delimit = Math.min(delimit, spaceIndex); + int linkIndex = toParse.indexOf("[["); + if(linkIndex != -1) delimit = Math.min(delimit, linkIndex); + int brIndex = toParse.indexOf("
"); + if(brIndex != -1) delimit = Math.min(delimit, brIndex); + + if(delimit > 0) { + QComponentText textComponent = new QComponentText(toParse.substring(0, delimit) + (spaceIndex == delimit ? " " : "")); + toParse = toParse.substring(delimit); + + // append to current line + int width = textComponent.getWidth(); + if(width + currentLineWidth <= maxLineLength) { + currentLine.add(textComponent); + currentLineWidth += width; + // new line + } else { + currentLine = new ArrayList(); + this.lines.add(currentLine); + currentLine.add(textComponent); + currentLineWidth = width; + } + + prevToParse = "" + toParse; + continue; + } + + if(toParse.equals(prevToParse)) break; + prevToParse = "" + toParse; + } } @Override @@ -38,19 +155,85 @@ public class GuiQMAW extends GuiScreen { this.guiTop = (this.height - this.ySize) / 2; } + @Override + protected void mouseClicked(int x, int y, int key) { + super.mouseClicked(x, y, key); + + if(key == 0) { + this.lastClickX = x; + this.lastClickY = y; + } + } + + public int getSliderPosition() { + double progress = (double) scrollProgress / (double) (lines.size() - 1); + return 25 + (int) (progress * 180); + } + @Override public void drawScreen(int mouseX, int mouseY, float f) { - this.drawDefaultBackground(); + + if(Mouse.isButtonDown(0) && guiLeft + xSize - 15 <= mouseX && guiLeft + xSize - 15 + 12 > mouseX && guiTop + 25 < mouseY && guiTop + 25 + 191 >= mouseY) { + isDragging = true; + } + + if(!Mouse.isButtonDown(0)) isDragging = false; + + if(isDragging) { + int min = guiTop + 25 + 8; + int max = guiTop + 25 + 191 - 8; + int span = max - min; + + double progress = MathHelper.clamp_double((double) (mouseY - min) / span, 0D, 1D); + this.scrollProgress = MathHelper.clamp_int((int) Math.round((lines.size() - 1) * progress), 0, lines.size() - 1); + } + + handleScroll(); + + //this.drawRect(0, 0, this.width, this.height, 0x80919191); + this.drawRect(0, 0, this.width, this.height, 0xe0000000); + this.drawGuiContainerBackgroundLayer(f, mouseX, mouseY); GL11.glDisable(GL11.GL_LIGHTING); this.drawGuiContainerForegroundLayer(mouseX, mouseY); GL11.glEnable(GL11.GL_LIGHTING); + + this.lastClickX = 0; + this.lastClickY = 0; + } + + protected void handleScroll() { + + if(!Mouse.isButtonDown(0) && !Mouse.isButtonDown(1) && Mouse.next()) { + int scroll = Mouse.getEventDWheel(); + if(scroll > 0 && this.scrollProgress > 0) this.scrollProgress--; + if(scroll < 0 && this.scrollProgress < this.lines.size() - 1) this.scrollProgress++; + } } private void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { - int x = 0; - int y = 0; + int x = 4; + int y = 4; + + if(this.icon != null) { + GL11.glPushMatrix(); + GL11.glEnable(GL11.GL_DEPTH_TEST); + Minecraft mc = Minecraft.getMinecraft(); + GL11.glRotated(180, 1, 0, 0); + RenderHelper.enableStandardItemLighting(); + GL11.glRotated(-180, 1, 0, 0); + itemRender.renderItemAndEffectIntoGUI(this.fontRendererObj, mc.renderEngine, this.icon, guiLeft + x, guiTop + y); + itemRender.renderItemOverlayIntoGUI(this.fontRendererObj, mc.renderEngine, this.icon, guiLeft + x, guiTop + y, null); + RenderHelper.disableStandardItemLighting(); + GL11.glDisable(GL11.GL_DEPTH_TEST); + GL11.glPopMatrix(); + + x += 20; + y += (16 - this.fontRendererObj.FONT_HEIGHT) / 2; + } + + y += 1; this.fontRendererObj.drawString(title, guiLeft + x, guiTop + y, 0xFFFFFF); } @@ -58,6 +241,52 @@ public class GuiQMAW extends GuiScreen { private void drawGuiContainerBackgroundLayer(float f, int mouseX, int mouseY) { GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); Minecraft.getMinecraft().getTextureManager().bindTexture(texture); - drawTexturedModalRect(guiLeft, guiTop, 0, 0, xSize, ySize); + drawTexturedModalRect(guiLeft, guiTop, 0, 0, 170, ySize); + drawTexturedModalRect(guiLeft + 170, guiTop, 22, 0, 170, ySize); + + // scroll bar + drawTexturedModalRect(guiLeft + xSize - 15, guiTop + getSliderPosition(), 192, 0, 12, 16); + + int x = guiLeft + 7; + int y = guiTop + 30; + int lineNum = 0; + + for(List line : lines) { + lineNum++; + + if(lineNum <= this.scrollProgress) continue; + + int maxHeight = 0; + int inset = 0; + + for(ManualElement element : line) { + maxHeight = Math.max(maxHeight, element.getHeight()); + } + + if(y + maxHeight > guiTop + 219) break; + + if(line.isEmpty()) y += this.fontRendererObj.FONT_HEIGHT; + + for(ManualElement element : line) { + int elementX = x + inset; + int elementY = y + (maxHeight - element.getHeight()) / 2; + boolean mouseOver = (elementX <= mouseX && elementX + element.getWidth() > mouseX && elementY < mouseY && elementY + element.getHeight() >= mouseY); + element.render(mouseOver, elementX, elementY, mouseX, mouseY); + if(elementX <= lastClickX && elementX + element.getWidth() > lastClickX && elementY < lastClickY && elementY + element.getHeight() >= lastClickY) + element.onClick(); + inset += element.getWidth(); + } + + y += maxHeight + 2; + } + } + + @Override + protected void keyTyped(char typedChar, int keyCode) { + + if(keyCode == 1 || keyCode == this.mc.gameSettings.keyBindInventory.getKeyCode()) { + this.mc.displayGuiScreen((GuiScreen) null); + this.mc.setIngameFocus(); + } } } diff --git a/src/main/java/com/hbm/qmaw/ManualElement.java b/src/main/java/com/hbm/qmaw/ManualElement.java index f878bf8ae..7d5c640d5 100644 --- a/src/main/java/com/hbm/qmaw/ManualElement.java +++ b/src/main/java/com/hbm/qmaw/ManualElement.java @@ -1,12 +1,9 @@ package com.hbm.qmaw; public abstract class ManualElement { - - public int x; - public int y; public abstract int getWidth(); public abstract int getHeight(); - public abstract void render(boolean isMouseOver, int mouseX, int mouseY); + public abstract void render(boolean isMouseOver, int x, int y, int mouseX, int mouseY); public abstract void onClick(); } diff --git a/src/main/java/com/hbm/qmaw/QMAWLoader.java b/src/main/java/com/hbm/qmaw/QMAWLoader.java index c5bdf391e..55a44851a 100644 --- a/src/main/java/com/hbm/qmaw/QMAWLoader.java +++ b/src/main/java/com/hbm/qmaw/QMAWLoader.java @@ -172,7 +172,9 @@ public class QMAWLoader implements IResourceManagerReloadListener { } /** Extracts all the info from a json file's main object to add a QMAW to the system. Very barebones, only handles name, icon and the localized text. */ - public static void registerJson(String name, JsonObject json) { + public static void registerJson(String file, JsonObject json) { + + String name = json.get("name").getAsString(); QuickManualAndWiki qmaw = new QuickManualAndWiki(name); if(json.has("icon")) { @@ -195,7 +197,7 @@ public class QMAWLoader implements IResourceManagerReloadListener { ItemStack trigger = SerializableRecipe.readItemStack(element.getAsJsonArray()); // items get renamed and removed all the time, so we add some more debug goodness for those cases if(trigger == null || trigger.getItem() == ModItems.nothing) { - MainRegistry.logger.info("[QMAW] Manual " + name + " references nonexistant trigger " + element.toString()); + MainRegistry.logger.info("[QMAW] Manual " + file + " references nonexistant trigger " + element.toString()); } else { QMAWLoader.triggers.put(new ComparableStack(trigger).makeSingular(), qmaw); } diff --git a/src/main/java/com/hbm/qmaw/components/QComponentLink.java b/src/main/java/com/hbm/qmaw/components/QComponentLink.java index 6024deb6f..97402d9fb 100644 --- a/src/main/java/com/hbm/qmaw/components/QComponentLink.java +++ b/src/main/java/com/hbm/qmaw/components/QComponentLink.java @@ -9,10 +9,12 @@ import com.hbm.qmaw.QuickManualAndWiki; import cpw.mods.fml.common.FMLCommonHandler; import net.minecraft.client.Minecraft; +import net.minecraft.client.audio.PositionedSoundRecord; import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.renderer.RenderHelper; import net.minecraft.client.renderer.entity.RenderItem; import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; public class QComponentLink extends ManualElement { @@ -35,6 +37,8 @@ public class QComponentLink extends ManualElement { } else { this.icon = qmaw.icon; } + + this.font = Minecraft.getMinecraft().fontRenderer; } public QComponentLink setColor(int color, int hoverColor) { @@ -45,30 +49,33 @@ public class QComponentLink extends ManualElement { @Override public int getWidth() { - return font.getStringWidth(text) + (icon != null ? 20 : 0); + return font.getStringWidth(text) + (icon != null ? 18 : 0); } @Override public int getHeight() { - return Math.max(font.FONT_HEIGHT, icon != null ? 18 : 0); + return Math.max(font.FONT_HEIGHT, icon != null ? 16 : 0); } @Override - public void render(boolean isMouseOver, int mouseX, int mouseY) { - int x = this.x; - int y = this.y; + public void render(boolean isMouseOver, int x, int y, int mouseX, int mouseY) { if(this.icon != null) { - + + GL11.glPushMatrix(); GL11.glEnable(GL11.GL_DEPTH_TEST); Minecraft mc = Minecraft.getMinecraft(); + GL11.glRotated(180, 1, 0, 0); + RenderHelper.enableStandardItemLighting(); + GL11.glRotated(-180, 1, 0, 0); itemRender.renderItemAndEffectIntoGUI(this.font, mc.renderEngine, this.icon, x, y); itemRender.renderItemOverlayIntoGUI(this.font, mc.renderEngine, this.icon, x, y, null); RenderHelper.disableStandardItemLighting(); GL11.glDisable(GL11.GL_DEPTH_TEST); + GL11.glPopMatrix(); - x += 20; - y += (18 - font.FONT_HEIGHT) / 2; + x += 18; + y += (16 - font.FONT_HEIGHT) / 2; } font.drawString(text, x, y, isMouseOver ? hoverColor : color); @@ -76,6 +83,9 @@ public class QComponentLink extends ManualElement { @Override public void onClick() { QuickManualAndWiki qmaw = QMAWLoader.qmaw.get(link); - if(qmaw != null) FMLCommonHandler.instance().showGuiScreen(new GuiQMAW(qmaw)); + if(qmaw != null) { + Minecraft.getMinecraft().getSoundHandler().playSound(PositionedSoundRecord.func_147674_a(new ResourceLocation("gui.button.press"), 1.0F)); + FMLCommonHandler.instance().showGuiScreen(new GuiQMAW(qmaw)); + } } } diff --git a/src/main/java/com/hbm/qmaw/components/QComponentText.java b/src/main/java/com/hbm/qmaw/components/QComponentText.java index fd06d1150..30fd266b5 100644 --- a/src/main/java/com/hbm/qmaw/components/QComponentText.java +++ b/src/main/java/com/hbm/qmaw/components/QComponentText.java @@ -36,7 +36,7 @@ public class QComponentText extends ManualElement { } @Override - public void render(boolean isMouseOver, int mouseX, int mouseY) { + public void render(boolean isMouseOver, int x, int y, int mouseX, int mouseY) { font.drawString(text, x, y, color); } diff --git a/src/main/resources/assets/hbm/manual/demo.json b/src/main/resources/assets/hbm/manual/demo.json index d64a6de99..96cdeeadd 100644 --- a/src/main/resources/assets/hbm/manual/demo.json +++ b/src/main/resources/assets/hbm/manual/demo.json @@ -3,9 +3,9 @@ "icon": ["hbm:item.gun_light_revolver", 1, 0], "trigger": [["hbm:item.plate_iron"], ["hbm:item.plate_gold"], ["hbm:item.plate_sludge"]], "title": { - "en_US": "TEST PAGE" - } + "en_US": "Demo" + }, "content": { - "en_US": "This is a test page that links to [[Demo|DEMO]].\n\nFormat line break" + "en_US": "Referred to as a collective as \"flux\" in NTM, neutrons are the sole driver of fission and therefore the driver of heat production in an RBMK. Fuel assemblies in fuel rod columns will create neutrons according to a mathematically defined flux function which is described in more detail in Category:RBMK Fuel. Some will spontaneously output neutrons whereas others will only emit them when they receive input neutrons with most fuels requiring some form of input to get started. Neutrons are emitted in every horizontal direction away from the fuel rod and will interact with various types of columns during their travel before eventually being absorbed by something. Neutrons are either emitted as fast moving or slow moving and react best with fuels in either state depending on the properties of the fuel. To convert fast neutrons to slow neutrons, they must pass through a moderator such as graphite which can come in the form of moderated rods or moderator columns. There is no way to make slow neutrons become fast after being moderated. If not properly sealed, neutrons can leak out of the RBMK and cause immense environmental radiation. To prevent this, cover every column in the RBMK that neutrons pass through with an RBMK cover panel and seal off all paths that neutrons take with either solid blocks or a column that absorbs the neutrons fully." } } diff --git a/src/main/resources/assets/hbm/textures/gui/gui_wiki.png b/src/main/resources/assets/hbm/textures/gui/gui_wiki.png index 25d913919..48c92d1c4 100644 Binary files a/src/main/resources/assets/hbm/textures/gui/gui_wiki.png and b/src/main/resources/assets/hbm/textures/gui/gui_wiki.png differ