package slimeknights.tconstruct.tools.common.client.module; import com.google.common.collect.Lists; import gnu.trove.list.TIntList; import gnu.trove.list.linked.TIntLinkedList; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.inventory.Container; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.MathHelper; import net.minecraft.util.text.TextFormatting; import java.util.List; import java.util.ListIterator; import slimeknights.mantle.client.gui.GuiElement; import slimeknights.mantle.client.gui.GuiElementScalable; import slimeknights.mantle.client.gui.GuiModule; import slimeknights.mantle.client.gui.GuiMultiModule; import slimeknights.mantle.client.gui.GuiWidgetSlider; import slimeknights.mantle.util.LocUtils; import slimeknights.tconstruct.common.ClientProxy; import slimeknights.tconstruct.library.Util; public class GuiInfoPanel extends GuiModule { private static int resW = 118; private static int resH = 75; private static ResourceLocation BACKGROUND = Util.getResource("textures/gui/panel.png"); private static GuiElement topLeft = new GuiElement(0,0, 4, 4, 256,256); private static GuiElement topRight = new GuiElement(resW+4,0, 4, 4); private static GuiElement botLeft = new GuiElement(0, resH+4, 4, 4); private static GuiElement botRight = new GuiElement(resW+4, resH+4, 4, 4); private static GuiElementScalable top = new GuiElementScalable(4, 0, resW, 4); private static GuiElementScalable bot = new GuiElementScalable(4, 4 + resH, resW, 4); private static GuiElementScalable left = new GuiElementScalable(0, 4, 4, resH); private static GuiElementScalable right = new GuiElementScalable(4 + resW, 4, 4, resH); private static GuiElementScalable background = new GuiElementScalable(4,4, resW, resH); private static GuiElement sliderNormal = new GuiElement(0, 83, 3, 5); private static GuiElement sliderHover = sliderNormal.shift(sliderNormal.w, 0); private static GuiElementScalable sliderBar = new GuiElementScalable(0, 88, 3, 8); private static GuiElement sliderTop = new GuiElement(3, 88, 3, 4); private static GuiElement sliderBot = new GuiElement(3, 92, 3, 4); private GuiWidgetBorder border = new GuiWidgetBorder(); private FontRenderer fontRenderer = ClientProxy.fontRenderer; private GuiWidgetSlider slider = new GuiWidgetSlider(sliderNormal, sliderHover, sliderHover, sliderTop, sliderBot, sliderBar); protected String caption; protected List<String> text; protected List<String> tooltips; private TIntList tooltipLines = new TIntLinkedList(); public float textScale = 1.0f; public GuiInfoPanel(GuiMultiModule parent, Container container) { super(parent, container, true, false); border.borderTop = top; border.borderBottom = bot; border.borderLeft = left; border.borderRight = right; border.cornerTopLeft = topLeft; border.cornerTopRight = topRight; border.cornerBottomLeft = botLeft; border.cornerBottomRight = botRight; this.xSize = resW + 8; this.ySize = resH + 8; caption = "Caption"; text = Lists.newLinkedList(); fontRendererObj = fontRenderer; } @Override public void setWorldAndResolution(Minecraft mc, int width, int height) { super.setWorldAndResolution(mc, width, height); fontRendererObj = fontRenderer; } @Override public void updatePosition(int parentX, int parentY, int parentSizeX, int parentSizeY) { super.updatePosition(parentX, parentY, parentSizeX, parentSizeY); border.setPosition(guiLeft, guiTop); border.setSize(xSize, ySize); slider.setPosition(guiRight() - border.w - 2, guiTop + border.h + 12); slider.setSize(this.ySize - border.h * 2 - 2 - 12); updateSliderParameters(); } public void setCaption(String caption) { this.caption = caption; updateSliderParameters(); } public void setText(String... text) { setText(Lists.newArrayList(text), null); } public void setText(List<String> text) { setText(text, null); } public void setText(List<String> text, List<String> tooltips) { // convert \n in localized text to actual newlines if(text != null) { text = Lists.newArrayList(text); for(int i = 0; i < text.size(); i++) { text.set(i, LocUtils.convertNewlines(text.get(i))); } } this.text = text; updateSliderParameters(); setTooltips(tooltips); } protected void setTooltips(List<String> tooltips) { // convert \n in localized text to actual newlines if(tooltips != null) { for(int i = 0; i < tooltips.size(); i++) { tooltips.set(i, LocUtils.convertNewlines(tooltips.get(i))); } } this.tooltips = tooltips; } public boolean hasCaption() { return caption != null && !caption.isEmpty(); } public boolean hasTooltips() { return tooltips != null && !tooltips.isEmpty(); } public int calcNeededHeight() { int neededHeight = 0; if(hasCaption()) { neededHeight += fontRenderer.FONT_HEIGHT; neededHeight += 3; } neededHeight += (fontRenderer.FONT_HEIGHT + 0.5f) * getTotalLines().size(); return neededHeight; } protected void updateSliderParameters() { // we assume slider not shown slider.hide(); int h = ySize - 2 * 5; // we use 5 as border thickness // check if we can display all lines if(calcNeededHeight() <= h) // can display all, stay hidden { return; } // we need the slider slider.show(); // check how many lines we can show int neededHeight = calcNeededHeight(); // recalc because width changed due to slider int hiddenRows = (neededHeight - h) / fontRenderer.FONT_HEIGHT; if((neededHeight - h) % fontRenderer.FONT_HEIGHT > 0) { hiddenRows++; } slider.setSliderParameters(0, hiddenRows, 1); } protected List<String> getTotalLines() { int w = xSize - border.w * 2 + 2; if(!slider.isHidden()) { w -= slider.width + 3; } w = (int) ((float) w / textScale); List<String> lines = Lists.newLinkedList(); tooltipLines.clear(); for(String line : text) { tooltipLines.add(lines.size()); // empty line if(line == null || line.isEmpty()) { lines.add(""); continue; } lines.addAll(fontRenderer.listFormattedStringToWidth(line, w)); } return lines; } public GuiInfoPanel wood() { shift(resW + 8, 0); shiftSlider(6, 0); return this; } public GuiInfoPanel metal() { shift(resW + 8, resH + 8); shiftSlider(12, 0); return this; } private void shift(int xd, int yd) { border.borderTop = top.shift(xd, yd); border.borderBottom = bot.shift(xd, yd); border.borderLeft = left.shift(xd, yd); border.borderRight = right.shift(xd, yd); border.cornerTopLeft = topLeft.shift(xd, yd); border.cornerTopRight = topRight.shift(xd, yd); border.cornerBottomLeft = botLeft.shift(xd, yd); border.cornerBottomRight = botRight.shift(xd, yd); } private void shiftSlider(int xd, int yd) { slider = new GuiWidgetSlider(sliderNormal.shift(xd, yd), sliderHover.shift(xd, yd), sliderHover.shift(xd, yd), sliderTop.shift(xd, yd), sliderBot.shift(xd, yd), sliderBar.shift(xd, yd)); } @Override protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { if(tooltips == null) { return; } if(mouseX < guiLeft || mouseX > guiRight()) { return; } // floating over tooltip info? if(hasTooltips() && mouseX >= guiRight() - border.w - fontRenderer.getCharWidth('?') / 2 && mouseX < guiRight() && mouseY > guiTop + 5 && mouseY < guiTop + 5 + fontRenderer.FONT_HEIGHT) { int w = MathHelper.clamp(this.width - mouseX - 12, 10, 200); drawHoveringText(fontRenderer.listFormattedStringToWidth(Util.translate("gui.general.hover"), w), mouseX - guiLeft, mouseY - guiTop); } // are we hovering over an entry? float y = 5 + guiTop; if(hasCaption()) { y += fontRenderer.FONT_HEIGHT + 3; } float textHeight = fontRenderer.FONT_HEIGHT * textScale + 0.5f; float lowerBound = (guiTop + ySize - 5) / textScale; // get the index of the currently hovered line int index = -1; ListIterator<String> iter = getTotalLines().listIterator(slider.getValue()); while(iter.hasNext()) { if(y + textHeight > lowerBound) { break; } if(mouseY > y && mouseY <= y + textHeight) { index = iter.nextIndex(); break; } else { iter.next(); } y += textHeight; } // no line hovered if(index < 0) { return; } // get the tooltip index from the hovered line int i = 0; while(tooltipLines.size() > i && index > tooltipLines.get(i)) { i++; } if(i >= tooltips.size() || tooltips.get(i) == null) { return; } int w = MathHelper.clamp(this.width - mouseX - 12, 0, 200); if(w < 100) { mouseX -= 100 - w; w = 100; } List<String> lines = fontRenderer.listFormattedStringToWidth(tooltips.get(i), w); drawHoveringText(lines, mouseX - guiLeft, mouseY - guiTop - lines.size() * fontRenderer.FONT_HEIGHT / 2); } @Override protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY) { this.mc.getTextureManager().bindTexture(BACKGROUND); border.draw(); background.drawScaled(guiLeft + 4, guiTop + 4, xSize - 8, ySize - 8); float y = 5 + guiTop; float x = 5 + guiLeft; int color = 0xfff0f0f0; // info ? in the top right corner if(hasTooltips()) { fontRenderer.drawString("?", guiRight() - border.w - fontRenderer.getCharWidth('?') / 2, guiTop + 5, 0xff5f5f5f, false); } // draw caption if(hasCaption()) { int x2 = xSize / 2; x2 -= fontRenderer.getStringWidth(caption) / 2; fontRenderer.drawStringWithShadow(TextFormatting.UNDERLINE + TextFormatting .getTextWithoutFormattingCodes(caption), guiLeft + x2, y, color); y += fontRenderer.FONT_HEIGHT + 3; } if(text == null || text.size() == 0) { // no text to draw return; } float textHeight = fontRenderer.FONT_HEIGHT * textScale + 0.5f; float lowerBound = (guiTop + ySize - 5) / textScale; GlStateManager.scale(textScale, textScale, 1.0f); x /= textScale; y /= textScale; // render shown lines ListIterator<String> iter = getTotalLines().listIterator(slider.getValue()); while(iter.hasNext()) { if(y + textHeight - 0.5f > lowerBound) { break; } String line = iter.next(); fontRenderer.drawStringWithShadow(line, x, y, color); y += textHeight; } GlStateManager.scale(1f / textScale, 1f / textScale, 1.0f); this.mc.getTextureManager().bindTexture(BACKGROUND); GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); slider.update(mouseX, mouseY, !isMouseOverFullSlot(mouseX, mouseY) && isMouseInModule(mouseX, mouseY)); slider.draw(); } }