diff options
Diffstat (limited to 'src/main/java/gregtech/api/gui/widgets')
14 files changed, 1600 insertions, 0 deletions
diff --git a/src/main/java/gregtech/api/gui/widgets/GT_CoverTickRateButton.java b/src/main/java/gregtech/api/gui/widgets/GT_CoverTickRateButton.java new file mode 100644 index 0000000000..883ffb4079 --- /dev/null +++ b/src/main/java/gregtech/api/gui/widgets/GT_CoverTickRateButton.java @@ -0,0 +1,82 @@ +package gregtech.api.gui.widgets; + +import static gregtech.api.gui.modularui.GT_UITextures.OVERLAY_BUTTON_HOURGLASS; +import static gregtech.common.covers.CoverInfo.MAX_TICK_RATE_ADDITION; + +import java.util.List; + +import net.minecraft.util.StatCollector; + +import org.jetbrains.annotations.NotNull; + +import com.google.common.collect.ImmutableList; +import com.gtnewhorizons.modularui.api.drawable.UITexture; +import com.gtnewhorizons.modularui.api.widget.IWidgetBuilder; +import com.gtnewhorizons.modularui.api.widget.Widget; +import com.gtnewhorizons.modularui.common.widget.ButtonWidget; +import com.gtnewhorizons.modularui.common.widget.FakeSyncWidget; + +import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.common.covers.CoverInfo; + +public class GT_CoverTickRateButton extends ButtonWidget { + + private static final UITexture BACKGROUND = GT_UITextures.BUTTON_COVER_NORMAL.getSubArea(0, 0, 1, 0.5f); + + private final CoverInfo coverInfo; + private int clientTickRate; + private int tickRateAddition; + + public GT_CoverTickRateButton(@NotNull CoverInfo coverInfo, @NotNull IWidgetBuilder<?> builder) { + this.coverInfo = coverInfo; + this.clientTickRate = coverInfo.getTickRate(); + this.tickRateAddition = coverInfo.getTickRateAddition(); + + super.setBackground(BACKGROUND, OVERLAY_BUTTON_HOURGLASS); + super.setOnClick(this::onClick); + super.dynamicTooltip(this::dynamicTooltip); + super.attachSyncer( + new FakeSyncWidget.IntegerSyncer(this.coverInfo::getTickRate, integer -> clientTickRate = integer), + builder, + (widget, aInt) -> notifyTooltipChange()) + .attachSyncer( + new FakeSyncWidget.IntegerSyncer( + this.coverInfo::getTickRateAddition, + integer -> tickRateAddition = integer), + builder); + + } + + private void onClick(@NotNull ClickData clickData, @NotNull Widget widget) { + final int iterations = clickData.ctrl ? 5 : 1; + final boolean isDecreasing = clickData.mouseButton == 1; + + // Do five operations at once if Ctrl is held down. Since the actual increase granted by each invocation can be + // different on each call, just call the method several times rather than trying to do a bunch of weird math. + for (int i = 0; i < iterations; i++) { + coverInfo.adjustTickRateMultiplier(isDecreasing); + } + } + + private List<String> dynamicTooltip() { + final String boundsNotification; + + if (tickRateAddition == 0) { + boundsNotification = StatCollector.translateToLocal("gt.cover.info.button.bounds_notification.minimum"); + } else if (tickRateAddition >= MAX_TICK_RATE_ADDITION - 1) { + // Clamping can make tickRateAddition approach but never actually equal MAX_ADDITION, so we need this + // adjustment. + boundsNotification = StatCollector.translateToLocal("gt.cover.info.button.bounds_notification.maximum"); + } else { + boundsNotification = ""; + } + + return ImmutableList.of( + StatCollector.translateToLocalFormatted( + "gt.cover.info.button.tick_rate.1", + new CoverInfo.ClientTickRateFormatter(clientTickRate), + boundsNotification), + StatCollector.translateToLocal("gt.cover.info.button.tick_rate.2"), + StatCollector.translateToLocal("gt.cover.info.button.tick_rate.3")); + } +} diff --git a/src/main/java/gregtech/api/gui/widgets/GT_GuiCoverTabLine.java b/src/main/java/gregtech/api/gui/widgets/GT_GuiCoverTabLine.java new file mode 100644 index 0000000000..6f4eb0e2c2 --- /dev/null +++ b/src/main/java/gregtech/api/gui/widgets/GT_GuiCoverTabLine.java @@ -0,0 +1,179 @@ +package gregtech.api.gui.widgets; + +import java.awt.Rectangle; +import java.util.List; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.inventory.GuiContainer; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.StatCollector; +import net.minecraftforge.common.util.ForgeDirection; + +import org.lwjgl.opengl.GL11; + +import codechicken.nei.api.API; +import codechicken.nei.api.INEIGuiAdapter; +import gregtech.api.enums.GT_Values; +import gregtech.api.gui.GT_GUIContainerMetaTile_Machine; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.net.GT_Packet_GtTileEntityGuiRequest; +import gregtech.common.GT_Proxy; + +/** + * Let's you access a GregTech IGregTechTileEntity's covers as tabs on the GUI's sides + */ +public class GT_GuiCoverTabLine extends GT_GuiTabLine { + + // Names of the block a cover could be on + private static final String[] SIDES = new String[] { "GT5U.interface.coverTabs.down", "GT5U.interface.coverTabs.up", + "GT5U.interface.coverTabs.north", "GT5U.interface.coverTabs.south", "GT5U.interface.coverTabs.west", + "GT5U.interface.coverTabs.east" }; + + // Not sure if there's a point in JIT translation but that's what this is + private final String[] translatedSides; + private final IGregTechTileEntity tile; + private final int colorization; + + /** + * Let's you access an IGregTechTileEntity's covers as tabs on the GUI's sides + * + * @param gui GT_ITabRenderer gui which this tab line attaches to + * @param tabLineLeft left position of the tab line in relation to the gui + * @param tabLineTop top position of the tab line in relation to the gui + * @param tabHeight height of a tab + * @param tabWidth width of a tab + * @param tabSpacing pixels between each tab + * @param xDir whether to extend the line horizontally to the right (NORMAL), the left (INVERSE) or not at + * all (NONE) + * @param yDir whether to extend the line vertically down (NORMAL), up (INVERSE) or not at all (NONE) + * @param displayMode whether to display on the left side of the GT_ITabRenderer (NORMAL), on it's right side + * (INVERSE) or not at all (NONE) + * @param tabBackground the set of textures used to draw this tab line's tab backgrounds + * @param tile The IGregTechTileEntity the covers of which we are accessing + * @param colorization The colorization of the GUI we are adding tabs to + */ + public GT_GuiCoverTabLine(GT_GUIContainerMetaTile_Machine gui, int tabLineLeft, int tabLineTop, int tabHeight, + int tabWidth, int tabSpacing, DisplayStyle xDir, DisplayStyle yDir, DisplayStyle displayMode, + GT_GuiTabIconSet tabBackground, IGregTechTileEntity tile, int colorization) { + super(gui, 6, tabLineLeft, tabLineTop, tabHeight, tabWidth, tabSpacing, xDir, yDir, displayMode, tabBackground); + this.tile = tile; + this.colorization = colorization; + this.translatedSides = new String[6]; + setupTabs(); + } + + /** + * Add a tab for each existing cover on this IGregTechTileEntity at creation time + */ + private void setupTabs() { + for (final ForgeDirection side : ForgeDirection.VALID_DIRECTIONS) { + final ItemStack cover = tile.getCoverItemAtSide(side); + if (cover != null) { + addCoverToTabs(side, cover); + } + } + } + + @Override + protected void drawBackground(float parTicks, int mouseX, int mouseY) { + // Apply this tile's coloration to draw the background + GL11.glColor3ub( + (byte) ((colorization >> 16) & 0xFF), + (byte) ((colorization >> 8) & 0xFF), + (byte) (colorization & 0xFF)); + super.drawBackground(parTicks, mouseX, mouseY); + } + + @Override + protected void tabClicked(int tabId, int mouseButton) { + if (mouseButton == 0 && mTabs[tabId].enabled) { + GT_Values.NW.sendToServer( + new GT_Packet_GtTileEntityGuiRequest( + this.tile.getXCoord(), + this.tile.getYCoord(), + this.tile.getZCoord(), + tabId + GT_Proxy.GUI_ID_COVER_SIDE_BASE, + this.tile.getWorld().provider.dimensionId, + Minecraft.getMinecraft().thePlayer.getEntityId(), + 0)); + } + } + + /** + * Add the cover on this side of the IGregTechTileEntity to the tabs + * + * @param side side to apply the cover to + * @param cover cover to add + */ + private void addCoverToTabs(ForgeDirection side, ItemStack cover) { + final boolean enabled = this.tile.getCoverBehaviorAtSideNew(side) + .hasCoverGUI(); + final int ordinalSide = side.ordinal(); + this.setTab(ordinalSide, cover, null, getTooltipForCoverTab(side, cover, enabled)); + this.setTabEnabled(ordinalSide, enabled); + } + + /** + * Decorate the cover's tooltips according to the side it's on and on whether the tab is enabled or not + * + * @param side side + * @param cover cover which tooltip to decorate + * @param enabled if the tab is enabled + * @return This cover tab's tooltip + */ + private String[] getTooltipForCoverTab(ForgeDirection side, ItemStack cover, boolean enabled) { + final List<String> tooltip = cover.getTooltip(Minecraft.getMinecraft().thePlayer, true); + tooltip.set( + 0, + (enabled ? EnumChatFormatting.UNDERLINE : EnumChatFormatting.DARK_GRAY) + getSideDescription(side) + + (enabled ? EnumChatFormatting.RESET + ": " : ": " + EnumChatFormatting.RESET) + + tooltip.get(0)); + return tooltip.toArray(new String[0]); + } + + /** + * Get the translated name for a side of the IGregTechTileEntity + * + * @param side side of the entity + * @return translated name for a side of the IGregTechTileEntity + */ + private String getSideDescription(ForgeDirection side) { + final int ordinalSide = side.ordinal(); + if (ordinalSide < SIDES.length) { + if (this.translatedSides[ordinalSide] == null) { + this.translatedSides[ordinalSide] = StatCollector.translateToLocal(SIDES[ordinalSide]); + } + return this.translatedSides[ordinalSide]; + } + return null; + } + + /** + * Hide any NEI slots that would intersect with a cover tab + */ + static class CoverTabLineNEIHandler extends INEIGuiAdapter { + + @Override + public boolean hideItemPanelSlot(GuiContainer gui, int x, int y, int w, int h) { + final Rectangle neiSlotArea = new Rectangle(x, y, w, h); + if (gui instanceof GT_GUIContainerMetaTile_Machine) { + final GT_GuiTabLine tabLine = ((GT_GUIContainerMetaTile_Machine) gui).coverTabs; + if (!tabLine.visible) { + return false; + } + for (int i = 0; i < tabLine.mTabs.length; i++) { + if (tabLine.mTabs[i] != null && tabLine.mTabs[i].getBounds() + .intersects(neiSlotArea)) { + return true; + } + } + } + return false; + } + } + + static { + API.registerNEIGuiHandler(new CoverTabLineNEIHandler()); + } +} diff --git a/src/main/java/gregtech/api/gui/widgets/GT_GuiFakeItemButton.java b/src/main/java/gregtech/api/gui/widgets/GT_GuiFakeItemButton.java new file mode 100644 index 0000000000..9f4287a65b --- /dev/null +++ b/src/main/java/gregtech/api/gui/widgets/GT_GuiFakeItemButton.java @@ -0,0 +1,162 @@ +package gregtech.api.gui.widgets; + +import java.awt.Rectangle; +import java.util.List; + +import net.minecraft.client.Minecraft; +import net.minecraft.item.ItemBlock; +import net.minecraft.item.ItemStack; + +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL12; + +import codechicken.lib.gui.GuiDraw; +import gregtech.api.interfaces.IGuiScreen; +import gregtech.api.util.GT_UtilityClient; + +public class GT_GuiFakeItemButton implements IGuiScreen.IGuiElement { + + private GT_GuiIcon bgIcon; + private ItemStack item; + private final IGuiScreen gui; + private int xPosition, yPosition; + private List<String> itemTooltips; + private final GT_GuiTooltip tooltip = new GT_GuiTooltip(null) { + + @Override + public List<String> getToolTipText() { + return itemTooltips; + } + + @Override + public boolean isDelayed() { + return false; + } + + @Override + public Rectangle getBounds() { + return GT_GuiFakeItemButton.this.getBounds(); + } + }; + private final Rectangle rectangle; + private boolean mimicSlot; + + public GT_GuiFakeItemButton(IGuiScreen gui, int x, int y, GT_GuiIcon bgIcon) { + this.gui = gui; + this.bgIcon = bgIcon; + item = null; + rectangle = new Rectangle(x, y, 18, 18); + gui.addElement(this); + } + + public GT_GuiFakeItemButton setItem(ItemStack i) { + item = i; + if (getMimicSlot()) updateTooltip(); + return this; + } + + private void updateTooltip() { + itemTooltips = item == null ? null : GT_UtilityClient.getTooltip(item, true); + } + + public ItemStack getItem() { + return item; + } + + public GT_GuiFakeItemButton setMimicSlot(boolean mimicSlot) { + if (mimicSlot != this.mimicSlot) { + if (mimicSlot) { + updateTooltip(); + gui.addToolTip(tooltip); + } else { + gui.removeToolTip(tooltip); + } + this.mimicSlot = mimicSlot; + } + return this; + } + + public boolean getMimicSlot() { + return mimicSlot; + } + + public GT_GuiIcon getBgIcon() { + return bgIcon; + } + + public GT_GuiFakeItemButton setBgIcon(GT_GuiIcon bgIcon) { + this.bgIcon = bgIcon; + return this; + } + + @Override + public void onInit() { + xPosition = rectangle.x + gui.getGuiLeft(); + yPosition = rectangle.y + gui.getGuiTop(); + } + + @Override + public void onRemoved() { + if (mimicSlot) gui.removeToolTip(tooltip); + } + + @Override + public void draw(int mouseX, int mouseY, float parTicks) { + GL11.glColor4f(1, 1, 1, 1); + GL11.glPushAttrib(GL11.GL_ENABLE_BIT); + GL11.glEnable(GL11.GL_BLEND); + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + + if (bgIcon != null) { + GT_GuiIcon.render(bgIcon, xPosition - 1, yPosition - 1, 18, 18, 0, true); + } + + if (item != null) { + if (item.getItem() instanceof ItemBlock) { + GL11.glPushAttrib(GL11.GL_ENABLE_BIT); + GL11.glEnable(GL12.GL_RESCALE_NORMAL); + } + gui.getItemRenderer() + .renderItemAndEffectIntoGUI( + gui.getFontRenderer(), + Minecraft.getMinecraft() + .getTextureManager(), + item, + xPosition, + yPosition); + + if (item.getItem() instanceof ItemBlock) GL11.glPopAttrib(); + } + + if (getMimicSlot()) if (getBounds().contains(mouseX - gui.getGuiLeft(), mouseY - gui.getGuiTop())) { + GL11.glDisable(GL11.GL_LIGHTING); + GL11.glDisable(GL11.GL_DEPTH_TEST); + GL11.glColorMask(true, true, true, false); + GuiDraw.drawGradientRect(xPosition, yPosition, 16, 16, 0x80ffffff, 0x80ffffff); + GL11.glColorMask(true, true, true, true); + // no glEnable, state will be recovered by glPopAttrib + } + + GL11.glPopAttrib(); + } + + public Rectangle getBounds() { + return rectangle; + } + + public void setX(int x) { + rectangle.x = x; + } + + public void setY(int y) { + rectangle.y = y; + } + + public void setWidth(int width) { + rectangle.width = width; + } + + public void setHeight(int height) { + rectangle.height = height; + } +} diff --git a/src/main/java/gregtech/api/gui/widgets/GT_GuiIcon.java b/src/main/java/gregtech/api/gui/widgets/GT_GuiIcon.java new file mode 100644 index 0000000000..66ab27356e --- /dev/null +++ b/src/main/java/gregtech/api/gui/widgets/GT_GuiIcon.java @@ -0,0 +1,157 @@ +package gregtech.api.gui.widgets; + +import static gregtech.api.enums.Mods.GregTech; + +import java.util.Arrays; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.util.ResourceLocation; + +import gregtech.api.interfaces.IGuiIcon; + +public enum GT_GuiIcon implements IGuiIcon { + + BUTTON_NORMAL(0, 0, 0), + BUTTON_DOWN(0, 32, 0), + BUTTON_HIGHLIGHT(0, 32 * 2, 0), + BUTTON_HIGHLIGHT_DOWN(0, 32 * 3, 0), + BUTTON_DISABLED(0, 32 * 4, 0), + + DISABLE(0, 0, 32), + REDSTONE_OFF(0, 32, 32), + REDSTONE_ON(0, 32 * 2, 32), + CHECKMARK(0, 32 * 3, 32), + CROSS(0, 32 * 4, 32), + WHITELIST(0, 32 * 5, 32), + BLACKLIST(0, 32 * 6, 32), + PROGRESS(0, 32 * 7, 32), + + EXPORT(0, 0, 32 * 2), + IMPORT(0, 32, 32 * 2), + ALLOW_INPUT(0, 32 * 2, 32 * 2), + BLOCK_INPUT(0, 32 * 3, 32 * 2), + GREEN_ARROW_UP(0, 32 * 4, 32 * 2), + GREEN_ARROW_DOWN(0, 32 * 5, 32 * 2), + CYCLIC(0, 32 * 6, 32 * 2), + + AND_GATE(0, 0, 32 * 3), + NAND_GATE(0, 32, 32 * 3), + OR_GATE(0, 32 * 2, 32 * 3), + NOR_GATE(0, 32 * 3, 32 * 3), + ANALOG_MODE(0, 32 * 4, 32 * 3), + + SLOT_DARKGRAY(1, 176, 0, 18, 18), + SLOT_GRAY(1, 176, 18, 18, 18), + + TAB_NORMAL(2, 0, 0, 18, 20), + TAB_HIGHLIGHT(2, 18, 0, 18, 20), + TAB_DISABLED(2, 18 * 2, 0, 18, 20), + TAB_NORMAL_BRONZE(2, 0, 20, 18, 20), + TAB_HIGHLIGHT_BRONZE(2, 18, 20, 18, 20), + TAB_DISABLED_BRONZE(2, 18 * 2, 20, 18, 20), + TAB_NORMAL_STEEL(2, 0, 2 * 20, 18, 20), + TAB_HIGHLIGHT_STEEL(2, 18, 2 * 20, 18, 20), + TAB_DISABLED_STEEL(2, 18 * 2, 2 * 20, 18, 20), + TAB_NORMAL_BRICK(2, 0, 3 * 20, 18, 20), + TAB_HIGHLIGHT_BRICK(2, 18, 3 * 20, 18, 20), + TAB_DISABLED_BRICK(2, 18 * 2, 3 * 20, 18, 20), + TAB_INFO_GRAY(2, 220, 0, 18, 20), + TAB_INFO_BLUE(2, 220 + 18, 0, 18, 20),; + + private static final int T_SIZE = 256; + private static ResourceLocation[] TEXTURES = { new ResourceLocation(GregTech.ID, "textures/gui/GuiButtons.png"), + new ResourceLocation(GregTech.ID, "textures/gui/GuiCover.png"), + new ResourceLocation(GregTech.ID, "textures/gui/GuiTabs.png"), }; + + public final int x, y, width, height; + public final IGuiIcon overlay; + private final int texID; + + GT_GuiIcon(int texID, int x, int y, int width, int height, IGuiIcon overlay) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + this.overlay = overlay; + this.texID = texID; + } + + GT_GuiIcon(int texID, int x, int y) { + this(texID, x, y, 32, 32, null); + } + + GT_GuiIcon(int texID, int x, int y, int width, int height) { + this(texID, x, y, width, height, null); + } + + public static void render(IGuiIcon icon, double x, double y, double width, double height, double zLevel, + boolean doDraw) { + render(icon, x, y, width, height, zLevel, doDraw, false); + } + + public static void render(IGuiIcon icon, double x, double y, double width, double height, double zLevel, + boolean doDraw, boolean flipHoritontally) { + Tessellator tess = Tessellator.instance; + if (doDraw) { + Minecraft.getMinecraft().renderEngine.bindTexture(TEXTURES[icon.getTexId()]); + tess.startDrawingQuads(); + } + double minU = (double) (icon.getX() + (flipHoritontally ? icon.getWidth() : 0)) / T_SIZE; + double maxU = (double) (icon.getX() + (flipHoritontally ? 0 : icon.getWidth())) / T_SIZE; + double minV = (double) icon.getY() / T_SIZE; + double maxV = (double) (icon.getY() + icon.getHeight()) / T_SIZE; + tess.addVertexWithUV(x, y + height, zLevel, minU, maxV); + tess.addVertexWithUV(x + width, y + height, zLevel, maxU, maxV); + tess.addVertexWithUV(x + width, y + 0, zLevel, maxU, minV); + tess.addVertexWithUV(x, y + 0, zLevel, minU, minV); + + if (icon.getOverlay() != null) render(icon.getOverlay(), x, y, width, height, zLevel, false); + + if (doDraw) tess.draw(); + } + + /** + * This is intended to enable addon mods to register additional textures. They can then add to this enum using + * EnumHelper.addEnum or by creating their enum that implements IGuiIcon (still requires adding a texture here) + * + * @param location location of the texture to add + */ + public static void addTextures(ResourceLocation... location) { + if (location == null || location.length == 0) return; + + int startIndex = TEXTURES.length; + TEXTURES = Arrays.copyOf(TEXTURES, location.length); + System.arraycopy(location, 0, TEXTURES, startIndex, location.length); + } + + @Override + public int getX() { + return this.x; + } + + @Override + public int getY() { + return this.y; + } + + @Override + public int getWidth() { + return this.width; + } + + @Override + public int getHeight() { + return this.height; + } + + @Override + public int getTexId() { + return this.texID; + } + + @Override + public IGuiIcon getOverlay() { + return this.overlay; + } +} diff --git a/src/main/java/gregtech/api/gui/widgets/GT_GuiIconButton.java b/src/main/java/gregtech/api/gui/widgets/GT_GuiIconButton.java new file mode 100644 index 0000000000..d4bfe31404 --- /dev/null +++ b/src/main/java/gregtech/api/gui/widgets/GT_GuiIconButton.java @@ -0,0 +1,114 @@ +package gregtech.api.gui.widgets; + +import java.awt.Rectangle; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiButton; + +import org.lwjgl.opengl.GL11; + +import gregtech.api.interfaces.IGuiScreen; + +public class GT_GuiIconButton extends GuiButton implements IGuiScreen.IGuiElement { + + public static final int DEFAULT_WIDTH = 16; + public static final int DEFAULT_HEIGHT = 16; + + protected GT_GuiIcon icon; + private final int x0; + private final int y0; + protected final IGuiScreen gui; + + private GT_GuiTooltip tooltip; + + public GT_GuiIconButton(IGuiScreen gui, int id, int x, int y, GT_GuiIcon icon) { + super(id, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT, ""); + this.gui = gui; + this.icon = icon; + this.x0 = x; + this.y0 = y; + gui.addElement(this); + } + + @Override + public void onInit() { + if (tooltip != null) gui.addToolTip(tooltip); + xPosition = x0 + gui.getGuiLeft(); + yPosition = y0 + gui.getGuiTop(); + } + + @Override + public void draw(int mouseX, int mouseY, float parTicks) { + drawButton(Minecraft.getMinecraft(), mouseX, mouseY); + } + + @Override + public void drawButton(Minecraft mc, int mouseX, int mouseY) { + if (this.tooltip != null) this.tooltip.enabled = true; + + if (this.visible) { + // moused over + this.field_146123_n = mouseX >= this.xPosition && mouseY >= this.yPosition + && mouseX < this.xPosition + width + && mouseY < this.yPosition + height; + + mouseDragged(mc, mouseX, mouseY); + + GL11.glPushAttrib(GL11.GL_ENABLE_BIT); + GL11.glEnable(GL11.GL_BLEND); + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + + int x = xPosition; + int y = yPosition; + if (!this.field_146123_n) { + // GL11.glColor4f(200F/255F, 210F/255F, 1, 1); + } else GL11.glColor4f(1, 1, 1, 1); + + GT_GuiIcon.render(getButtonTexture(this.field_146123_n), x, y, width, height, 0, true); + + GL11.glColor4f(1, 1, 1, 1); + if (icon != null) { + GT_GuiIcon.render(icon, x, y, width, height, 0, true); + } + + GL11.glPopAttrib(); + } + } + + @Override + public void mouseReleased(int mouseX, int mouseY) { + this.gui.clearSelectedButton(); + if (mousePressed(Minecraft.getMinecraft(), mouseX, mouseY)) this.gui.buttonClicked(this); + } + + public GT_GuiIcon getButtonTexture(boolean mouseOver) { + if (!enabled) return GT_GuiIcon.BUTTON_DISABLED; + if (this.equals(this.gui.getSelectedButton())) + return mouseOver ? GT_GuiIcon.BUTTON_HIGHLIGHT_DOWN : GT_GuiIcon.BUTTON_DOWN; + + return mouseOver ? GT_GuiIcon.BUTTON_HIGHLIGHT : GT_GuiIcon.BUTTON_NORMAL; + } + + public GT_GuiIcon getIcon() { + return icon; + } + + public GT_GuiIconButton setIcon(GT_GuiIcon icon) { + this.icon = icon; + return this; + } + + public GT_GuiTooltip getTooltip() { + return tooltip; + } + + public GT_GuiIconButton setTooltipText(String... text) { + if (tooltip == null) tooltip = new GT_GuiTooltip(getBounds(), text); + else tooltip.setToolTipText(text); + return this; + } + + public Rectangle getBounds() { + return new Rectangle(x0, y0, width, height); + } +} diff --git a/src/main/java/gregtech/api/gui/widgets/GT_GuiIconCheckButton.java b/src/main/java/gregtech/api/gui/widgets/GT_GuiIconCheckButton.java new file mode 100644 index 0000000000..5b5007fef3 --- /dev/null +++ b/src/main/java/gregtech/api/gui/widgets/GT_GuiIconCheckButton.java @@ -0,0 +1,43 @@ +package gregtech.api.gui.widgets; + +import gregtech.api.interfaces.IGuiScreen; + +public class GT_GuiIconCheckButton extends GT_GuiIconButton { + + private final GT_GuiIcon checkedIcon; + private final GT_GuiIcon normalIcon; + private final String checkedTooltip; + private final String normalTooltip; + private boolean checked = false; + + public GT_GuiIconCheckButton(IGuiScreen gui, int id, int x, int y, GT_GuiIcon checkedIcon, GT_GuiIcon normalIcon) { + this(gui, id, x, y, checkedIcon, normalIcon, null, null); + } + + public GT_GuiIconCheckButton(IGuiScreen gui, int id, int x, int y, GT_GuiIcon checkedIcon, GT_GuiIcon normalIcon, + String checkedTooltip, String normalTooltip) { + super(gui, id, x, y, normalIcon); + this.checkedIcon = checkedIcon; + this.normalIcon = normalIcon; + this.checkedTooltip = checkedTooltip; + this.normalTooltip = normalTooltip; + } + + @Override + public GT_GuiIcon getButtonTexture(boolean mouseOver) { + if (!enabled) return GT_GuiIcon.BUTTON_DISABLED; + if (this.equals(super.gui.getSelectedButton())) + return mouseOver ? GT_GuiIcon.BUTTON_HIGHLIGHT_DOWN : GT_GuiIcon.BUTTON_DOWN; + return mouseOver ? GT_GuiIcon.BUTTON_HIGHLIGHT : GT_GuiIcon.BUTTON_NORMAL; + } + + public boolean isChecked() { + return checked; + } + + public void setChecked(boolean checked) { + super.setIcon(checked ? checkedIcon : normalIcon); + super.setTooltipText(checked ? checkedTooltip : normalTooltip); + this.checked = checked; + } +} diff --git a/src/main/java/gregtech/api/gui/widgets/GT_GuiIntegerTextBox.java b/src/main/java/gregtech/api/gui/widgets/GT_GuiIntegerTextBox.java new file mode 100644 index 0000000000..2d3c7374bd --- /dev/null +++ b/src/main/java/gregtech/api/gui/widgets/GT_GuiIntegerTextBox.java @@ -0,0 +1,73 @@ +package gregtech.api.gui.widgets; + +import java.awt.Rectangle; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiTextField; + +import gregtech.api.interfaces.IGuiScreen; + +public class GT_GuiIntegerTextBox extends GuiTextField implements IGuiScreen.IGuiElement { + + private final int x0, y0; + private final IGuiScreen gui; + public final int id; + private boolean enabled; + + public GT_GuiIntegerTextBox(IGuiScreen gui, int id, int x, int y, int width, int height) { + super(Minecraft.getMinecraft().fontRenderer, x, y, width, height); + super.setText(""); + this.id = id; + x0 = x; + y0 = y; + this.gui = gui; + enabled = true; + gui.addElement(this); + } + + @Override + public void onInit() { + xPosition = x0 + gui.getGuiLeft(); + yPosition = y0 + gui.getGuiTop(); + } + + @Override + public void draw(int mouseX, int mouseY, float parTicks) { + super.drawTextBox(); + } + + public Rectangle getBounds() { + return new Rectangle(x0, y0, width, height); + } + + public boolean validChar(char c, int key) { + return Character.isDigit(c); + } + + @Override + public boolean textboxKeyTyped(char c, int key) { + if (validChar(c, key) || c == 1 + || c == 3 + || c == 22 + || c == 24 + || key == 14 + || key == 199 + || key == 203 + || key == 205 + || key == 207 + || key == 211) { + return super.textboxKeyTyped(c, key); + } + return false; + } + + @Override + public void setEnabled(boolean p_146184_1_) { + super.setEnabled(p_146184_1_); + enabled = p_146184_1_; + } + + public boolean isEnabled() { + return enabled; + } +} diff --git a/src/main/java/gregtech/api/gui/widgets/GT_GuiSlotTooltip.java b/src/main/java/gregtech/api/gui/widgets/GT_GuiSlotTooltip.java new file mode 100644 index 0000000000..015c8c7697 --- /dev/null +++ b/src/main/java/gregtech/api/gui/widgets/GT_GuiSlotTooltip.java @@ -0,0 +1,24 @@ +package gregtech.api.gui.widgets; + +import java.awt.Rectangle; + +import net.minecraft.inventory.Slot; + +import gregtech.api.util.GT_TooltipDataCache.TooltipData; + +public class GT_GuiSlotTooltip extends GT_GuiTooltip { + + private final Slot slot; + + public GT_GuiSlotTooltip(Slot slot, TooltipData data) { + super(new Rectangle(slot.xDisplayPosition - 1, slot.yDisplayPosition - 1, 18, 18), data); + this.slot = slot; + } + + @Override + protected void onTick() { + super.onTick(); + // If disabled by super, stay disabled. + this.enabled = this.enabled && this.slot.getStack() == null; + } +} diff --git a/src/main/java/gregtech/api/gui/widgets/GT_GuiSmartTooltip.java b/src/main/java/gregtech/api/gui/widgets/GT_GuiSmartTooltip.java new file mode 100644 index 0000000000..ffae5c30e6 --- /dev/null +++ b/src/main/java/gregtech/api/gui/widgets/GT_GuiSmartTooltip.java @@ -0,0 +1,27 @@ +package gregtech.api.gui.widgets; + +import java.awt.Rectangle; + +import gregtech.api.util.GT_TooltipDataCache.TooltipData; + +public class GT_GuiSmartTooltip extends GT_GuiTooltip { + + public interface TooltipVisibilityProvider { + + boolean shouldShowTooltip(); + } + + private final TooltipVisibilityProvider visibilityProvider; + + public GT_GuiSmartTooltip(Rectangle bounds, TooltipVisibilityProvider visibilityProvider, TooltipData data) { + super(bounds, data); + this.visibilityProvider = visibilityProvider; + } + + @Override + protected void onTick() { + super.onTick(); + // If disabled by super, stay disabled. + this.enabled = this.enabled && this.visibilityProvider.shouldShowTooltip(); + } +} diff --git a/src/main/java/gregtech/api/gui/widgets/GT_GuiTab.java b/src/main/java/gregtech/api/gui/widgets/GT_GuiTab.java new file mode 100644 index 0000000000..d06c2bd2eb --- /dev/null +++ b/src/main/java/gregtech/api/gui/widgets/GT_GuiTab.java @@ -0,0 +1,174 @@ +package gregtech.api.gui.widgets; + +import java.awt.Rectangle; + +import net.minecraft.client.Minecraft; +import net.minecraft.item.ItemBlock; +import net.minecraft.item.ItemStack; + +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL12; + +import gregtech.api.gui.widgets.GT_GuiTabLine.GT_GuiTabIconSet; +import gregtech.api.gui.widgets.GT_GuiTabLine.GT_ITabRenderer; +import gregtech.api.interfaces.IGuiIcon; + +/** + * A tab to be attached to a tab line + */ +public class GT_GuiTab { + + private static final int SLOT_SIZE = 18; + + public boolean visible = true, mousedOver, enabled = true; + + private Rectangle bounds; + private final GT_GuiTabIconSet tabBackground; + private final ItemStack item; + private final GT_ITabRenderer gui; + private GT_GuiTooltip tooltip; + private final IGuiIcon overlay; + private final boolean flipHorizontally; + + /** + * A tab to be attached to a tab line + * + * @param gui IGregTechTileEntity the tab line this tab belongs to is attached to + * @param id both the ID and position in the tab line of this tab. Not used, kept for compatibility. + * @param bounds bounds of this tab + * @param tabBackground set of background textures + * @param item item to draw atop the background texture, not colored + * @param overlay texture to draw atop the background texture, not colored + * @param tooltipText tooltip of this tab + * @param flipHorizontally whether to draw this tab on the right side of the IGregTechTileEntity + */ + public GT_GuiTab(GT_ITabRenderer gui, int id, Rectangle bounds, GT_GuiTabIconSet tabBackground, ItemStack item, + IGuiIcon overlay, String[] tooltipText, boolean flipHorizontally) { + this.gui = gui; + this.bounds = bounds; + this.item = item; + this.tabBackground = tabBackground; + this.overlay = overlay; + if (tooltipText != null) { + setTooltipText(tooltipText); + } + this.flipHorizontally = flipHorizontally; + } + + public GT_GuiTab(GT_ITabRenderer gui, int id, Rectangle bounds, GT_GuiTabIconSet tabBackground) { + this(gui, id, bounds, tabBackground, null, null, null, false); + } + + /** + * Set this tab's tooltip text + * + * @param text text to set + * @return This tab for chaining + */ + public GT_GuiTab setTooltipText(String... text) { + if (tooltip == null) { + tooltip = new GT_GuiTooltip(bounds, text); + gui.addToolTip(tooltip); + } else { + tooltip.setToolTipText(text); + } + return this; + } + + /** + * @return This tab's tooltip object + */ + public GT_GuiTooltip getTooltip() { + return tooltip; + } + + /** + * Draw the background texture for this tab + * + * @param mouseX not used, likely kept for backward compatibility + * @param mouseY not used, likely kept for backward compatibility + * @param parTicks not used, likely kept for backward compatibility + */ + public void drawBackground(int mouseX, int mouseY, float parTicks) { + if (this.visible) { + GT_GuiIcon.render( + getBackgroundTexture(), + bounds.x, + bounds.y, + bounds.width, + bounds.height, + 1, + true, + this.flipHorizontally); + } + } + + /** + * Draw overlay textures and items atop the background texture + * + * @param mouseX X mouse coordinate + * @param mouseY Y mouse coordinate + * @param parTicks not used, likely kept for backward compatibility + */ + public void drawOverlays(int mouseX, int mouseY, float parTicks) { + this.mousedOver = bounds.contains(mouseX, mouseY); + + if (this.tooltip != null) { + this.tooltip.enabled = this.visible; + } + + if (this.visible) { + if (overlay != null) { + GL11.glColor4f(1, 1, 1, 1); + GT_GuiIcon.render(overlay, bounds.x, bounds.y, bounds.width, bounds.height, 1, true); + } + if (item != null) { + GL11.glPushAttrib(GL11.GL_ENABLE_BIT); + + if (item.getItem() instanceof ItemBlock) { + GL11.glPushAttrib(GL11.GL_ENABLE_BIT); + GL11.glEnable(GL12.GL_RESCALE_NORMAL); + } + int margin = (bounds.height - SLOT_SIZE); + gui.getItemRenderer() + .renderItemAndEffectIntoGUI( + gui.getFontRenderer(), + Minecraft.getMinecraft() + .getTextureManager(), + item, + bounds.x + (this.flipHorizontally ? 0 : margin), + bounds.y + margin); + + if (item.getItem() instanceof ItemBlock) GL11.glPopAttrib(); + + GL11.glPopAttrib(); + } + } + } + + /** + * @return the texture this tab should currently use as it's background + */ + protected IGuiIcon getBackgroundTexture() { + if (!enabled) return tabBackground.disabled; + + return mousedOver ? tabBackground.highlight : tabBackground.normal; + } + + /** + * @return the screen space occupied by this tab + */ + public Rectangle getBounds() { + return this.bounds; + } + + /** + * Reposition this tab on the screen + * + * @param xPos X tab coordinate + * @param yPos Y tab coordinate + */ + public void setPosition(int xPos, int yPos) { + this.bounds = new Rectangle(xPos, yPos, bounds.width, bounds.height); + } +} diff --git a/src/main/java/gregtech/api/gui/widgets/GT_GuiTabLine.java b/src/main/java/gregtech/api/gui/widgets/GT_GuiTabLine.java new file mode 100644 index 0000000000..950478cdfa --- /dev/null +++ b/src/main/java/gregtech/api/gui/widgets/GT_GuiTabLine.java @@ -0,0 +1,274 @@ +package gregtech.api.gui.widgets; + +import java.awt.Rectangle; + +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.renderer.entity.RenderItem; +import net.minecraft.item.ItemStack; + +import org.lwjgl.opengl.GL11; + +import gregtech.api.interfaces.IGuiIcon; + +/** + * Draws clickable and configurable tabs on the left or right side of another GUI + */ +public class GT_GuiTabLine { + + /** + * Defines a set of textures a tab line can use to render it's tab backgrounds + */ + public static class GT_GuiTabIconSet { + + public IGuiIcon disabled; + public IGuiIcon normal; + public IGuiIcon highlight; + + public GT_GuiTabIconSet(IGuiIcon normalIcon, IGuiIcon highlightIcon, IGuiIcon disabledIcon) { + this.normal = normalIcon; + this.highlight = highlightIcon; + this.disabled = disabledIcon; + } + } + + /** + * Controls the rendering style of the tab line + */ + public enum DisplayStyle { + + NONE((byte) 0), + NORMAL((byte) 1), + INVERSE((byte) -1); + + private final byte value; + + DisplayStyle(byte value) { + this.value = value; + } + + public byte getValue() { + return value; + } + } + + /** + * A GUI should implement these methods as well as call the tab line's onMouseClicked, onInit and drawTabs for the + * tab line to attach to it properly. + */ + public interface GT_ITabRenderer { + + int getGuiLeft(); + + int getGuiTop(); + + int getXSize(); + + RenderItem getItemRenderer(); + + FontRenderer getFontRenderer(); + + void addToolTip(GT_GuiTooltip tooltip); + + boolean removeToolTip(GT_GuiTooltip tooltip); + } + + // The tabs are arranged according to their index in this array + protected final GT_GuiTab[] mTabs; + + private final int tabLineLeft; + private final int tabLineTop; + private final int tabHeight; + private final int tabWidth; + private final int tabSpacing; + + // In which direction to draw the tab line + private final DisplayStyle xDir; + private final DisplayStyle yDir; + + // Whether to display on the right side of the GT_ITabRenderer instead of left + protected final boolean flipHorizontally; + protected final boolean visible; + + private final GT_GuiTabIconSet tabBackground; + private final GT_ITabRenderer gui; + + /** + * Draws clickable and configurable tabs on the left or right side of a GT_ITabRenderer + * + * @param gui GT_ITabRenderer gui which this tab line attaches to + * @param numTabs number of tab positions in this tab line + * @param tabLineLeft left position of the tab line in relation to the gui + * @param tabLineTop top position of the tab line in relation to the gui + * @param tabHeight height of a tab + * @param tabWidth width of a tab + * @param tabSpacing pixels between each tab + * @param xDir whether to extend the line horizontally to the right (NORMAL), the left (INVERSE) or not at + * all (NONE) + * @param yDir whether to extend the line vertically down (NORMAL), up (INVERSE) or not at all (NONE) + * @param displayMode whether to display on the left side of the GT_ITabRenderer (NORMAL), on it's right side + * (INVERSE) or not at all (NONE) + * @param tabBackground the set of textures used to draw this tab line's tab backgrounds + */ + public GT_GuiTabLine(GT_ITabRenderer gui, int numTabs, int tabLineLeft, int tabLineTop, int tabHeight, int tabWidth, + int tabSpacing, DisplayStyle xDir, DisplayStyle yDir, DisplayStyle displayMode, + GT_GuiTabIconSet tabBackground) { + this.gui = gui; + this.mTabs = new GT_GuiTab[numTabs]; + this.tabLineLeft = tabLineLeft; + this.tabLineTop = tabLineTop; + this.tabHeight = tabHeight; + this.tabWidth = tabWidth; + this.tabSpacing = tabSpacing; + this.xDir = xDir; + this.yDir = yDir; + this.tabBackground = tabBackground; + this.flipHorizontally = displayMode == DisplayStyle.INVERSE; + this.visible = !(displayMode == DisplayStyle.NONE); + } + + /** + * Creates a new tab at the specified position with the given parameters. This class handles the positioning. + * + * @param tabId tab ID + * @param item item to draw atop the background texture, not colored + * @param overlay texture to draw atop the background texture, not colored + * @param text tooltip of this tab + */ + public void setTab(int tabId, ItemStack item, IGuiIcon overlay, String[] text) { + mTabs[tabId] = new GT_GuiTab( + this.gui, + tabId, + getBoundsForTab(tabId), + this.tabBackground, + item, + overlay, + text, + this.flipHorizontally); + } + + /** + * Get the bounds a given tab should occupy + * + * @param tabId tab ID + * @return tab bounds + */ + protected Rectangle getBoundsForTab(int tabId) { + return new Rectangle(getTabX(tabId), getTabY(tabId), this.tabWidth, this.tabHeight); + } + + /** + * Enable or disable a tab. Disabled tabs have a dark background. + * + * @param tabId tab ID + * @param enable true to enable, false to disable + */ + public void setTabEnabled(int tabId, boolean enable) { + if (mTabs[tabId] != null) { + mTabs[tabId].enabled = enable; + } + } + + /** + * Draw the tabs for this tab bar GT_ITabRenderer must call this method on drawGuiContainerBackgroundLayer or on + * drawScreen. + * + * @param parTicks + */ + public void drawTabs(float parTicks, int mouseX, int mouseY) { + if (this.visible) { + GL11.glPushAttrib(GL11.GL_ENABLE_BIT); + GL11.glEnable(GL11.GL_BLEND); + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + drawBackground(parTicks, mouseX, mouseY); + drawOverlays(parTicks, mouseX, mouseY); + GL11.glPopAttrib(); + } + } + + /** + * Draw the tab's backgrounds first + * + * @param parTicks not used, likely kept for compatibility + * @param mouseX mouse X position + * @param mouseY mouse Y position + */ + protected void drawOverlays(float parTicks, int mouseX, int mouseY) { + for (GT_GuiTab mTab : mTabs) { + if (mTab != null) { + mTab.drawOverlays(mouseX, mouseY, parTicks); + } + } + } + + /** + * Draw anything that overlays the tab's background texture + * + * @param parTicks not used, likely kept for compatibility + * @param mouseX mouse X position + * @param mouseY mouse Y position + */ + protected void drawBackground(float parTicks, int mouseX, int mouseY) { + for (GT_GuiTab mTab : mTabs) { + if (mTab != null) { + mTab.drawBackground(mouseX, mouseY, parTicks); + } + } + } + + /** + * Call tabClick for every tab that was clicked. GT_ITabRenderer must call this method on mouseClicked. + * + * @param mouseX mouse X position + * @param mouseY mouse Y position + * @param mouseButton which mouse button was used to click + */ + public void onMouseClicked(int mouseX, int mouseY, int mouseButton) { + for (int tabId = 0; tabId < mTabs.length; tabId++) { + if (mTabs[tabId] != null && mTabs[tabId].getBounds() + .contains(mouseX, mouseY)) { + tabClicked(tabId, mouseButton); + return; + } + } + } + + /** + * Act on a tab being clicked. + * + * @param tabId tab ID + * @param mouseButton which mouse button was used to click + */ + protected void tabClicked(int tabId, int mouseButton) {} + + /** + * Reposition ourselves whenever the GT_ITabRenderer does so. GT_ITabRenderer must call this method on Init. + */ + public void onInit() { + for (int i = 0; i < mTabs.length; i++) { + if (mTabs[i] != null) { + mTabs[i].setPosition(getTabX(i), getTabY(i)); + } + } + } + + /** + * Get the proper X position for a given tab + * + * @param tabId tab ID + * @return X position of the tab + */ + private int getTabX(int tabId) { + return this.gui.getGuiLeft() + (flipHorizontally ? (gui.getXSize() - tabLineLeft - tabWidth) : tabLineLeft) + + (tabId * (tabWidth + tabSpacing) * xDir.getValue()); + } + + /** + * Get the proper Y position for a given tab + * + * @param tabId tab ID + * @return Y position of the tab + */ + private int getTabY(int tabId) { + return this.gui.getGuiTop() + tabLineTop + (tabId * (tabHeight + tabSpacing) * yDir.getValue()); + } +} diff --git a/src/main/java/gregtech/api/gui/widgets/GT_GuiTooltip.java b/src/main/java/gregtech/api/gui/widgets/GT_GuiTooltip.java new file mode 100644 index 0000000000..fe20b2b57a --- /dev/null +++ b/src/main/java/gregtech/api/gui/widgets/GT_GuiTooltip.java @@ -0,0 +1,121 @@ +package gregtech.api.gui.widgets; + +import java.awt.Rectangle; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.lwjgl.input.Keyboard; + +import gregtech.api.util.GT_TooltipDataCache.TooltipData; + +public class GT_GuiTooltip { + + protected final Rectangle bounds; + protected TooltipData data; + private List<String> displayedText; + public boolean enabled = true; + + /** + * Used to create a tooltip that will appear over the specified bounds. This will initially be a "static" tooltip + * that doesn't respect verbosity levels or respond to the shift key. + * + * @param bounds tooltip bounds + * @param text tooltip text + */ + public GT_GuiTooltip(Rectangle bounds, String... text) { + this.bounds = bounds; + setToolTipText(text); + } + + /** + * Used to create a tooltip that will appear over the specified bounds. This will initially be a "dynamic" tooltip + * that respects verbosity levels and responds to the shift key. + * + * @param bounds tooltip bounds + * @param data tooltip data + */ + public GT_GuiTooltip(Rectangle bounds, TooltipData data) { + this.bounds = bounds; + // Trust that the tooltips have already been formatted and colored, just make sure it has no nulls + this.data = sanitizeTooltipData(data); + } + + private TooltipData sanitizeTooltipData(TooltipData data) { + if (data.text == null) { + data.text = Collections.emptyList(); + } + if (data.shiftText == null) { + data.shiftText = Collections.emptyList(); + } + return data; + } + + /** + * Called before the tooltip manager checks whether this tooltip is enabled + */ + protected void onTick() { + // Switch which of our 2 stored texts we're displaying now. + this.displayedText = Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) ? this.data.shiftText : this.data.text; + // If this text is empty, let's not display a tooltip at all. + this.enabled = this.displayedText.size() != 0; + } + + /** + * Called once this tooltip has been determined to be enabled + */ + protected void updateText() {} + + /** + * Used to set a "static" tooltip that doesn't respect verbosity levels or respond to the shift key + * + * @param text tooltip text + */ + public void setToolTipText(String... text) { + this.data = formatTooltip(text); + this.displayedText = data.text; + } + + /** + * Used to set a "dynamic" tooltip that respects verbosity levels and responds to the shift key + * + * @param data tooltip data + */ + public void setToolTipText(TooltipData data) { + // Trust that the tooltips have already been formatted and colored, just make sure it has no nulls + this.data = sanitizeTooltipData(data); + } + + /** + * Apply tooltip colors in case the text doesn't contain them and return as tooltip data + * + * @param text text to apply the colors to + * @return colored tooltip lines as list + */ + protected TooltipData formatTooltip(String[] text) { + List<String> list; + if (text != null) { + list = new ArrayList<>(text.length); + for (String s : text) { + if (s == null) continue; + if (list.isEmpty()) list.add("\u00a7f" + s); + else list.add("\u00a77" + s); + } + } else { + list = Collections.emptyList(); + } + return new TooltipData(list, list); + } + + public List<String> getToolTipText() { + return this.displayedText; + } + + public Rectangle getBounds() { + return bounds; + } + + public boolean isDelayed() { + return true; + } +} diff --git a/src/main/java/gregtech/api/gui/widgets/GT_GuiTooltipManager.java b/src/main/java/gregtech/api/gui/widgets/GT_GuiTooltipManager.java new file mode 100644 index 0000000000..4304ca14fc --- /dev/null +++ b/src/main/java/gregtech/api/gui/widgets/GT_GuiTooltipManager.java @@ -0,0 +1,80 @@ +package gregtech.api.gui.widgets; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraft.client.gui.FontRenderer; + +public class GT_GuiTooltipManager { + + public interface GT_IToolTipRenderer { + + int getGuiLeft(); + + int getGuiTop(); + + int getXSize(); + + FontRenderer getFontRenderer(); + + void drawHoveringText(List<String> text, int mouseX, int mouseY, FontRenderer font); + } + + private static final long DELAY = 5; + private int mouseStopped; + private int lastMouseX = -1; + private int lastMouseY = -1; + private final List<GT_GuiTooltip> tips = new ArrayList<>(); + + public void addToolTip(GT_GuiTooltip tip) { + if (tip != null && !tips.contains(tip)) tips.add(tip); + } + + public boolean removeToolTip(GT_GuiTooltip tip) { + return tips.remove(tip); + } + + public final void onTick(GT_IToolTipRenderer render, int mouseX, int mouseY) { + if ((Math.abs(mouseX - lastMouseX) < 2) && (Math.abs(mouseY - lastMouseY) < 2)) { + mouseStopped = Math.min(mouseStopped + 1, 50); + } else { + mouseStopped = 0; + } + + lastMouseX = mouseX; + lastMouseY = mouseY; + + mouseX -= render.getGuiLeft(); + mouseY -= render.getGuiTop(); + for (GT_GuiTooltip tip : tips) { + // Give the tooltip the opportunity to decide whether they should be enabled + tip.onTick(); + if (tip.enabled && (!tip.isDelayed() || mouseStopped > DELAY) + && tip.getBounds() + .contains(mouseX, mouseY)) { + tip.updateText(); + drawTooltip(tip, mouseX, mouseY, render); + break; + } + } + } + + private void drawTooltip(GT_GuiTooltip tip, int mouseX, int mouseY, GT_IToolTipRenderer render) { + List<String> text = tip.getToolTipText(); + if (text == null) return; + + if (mouseX > render.getGuiLeft() + render.getXSize() / 2) { + int maxWidth = 0; + for (String s : text) { + int w = render.getFontRenderer() + .getStringWidth(s); + if (w > maxWidth) { + maxWidth = w; + } + } + mouseX -= (maxWidth + 18); + } + + render.drawHoveringText(text, mouseX, mouseY, render.getFontRenderer()); + } +} diff --git a/src/main/java/gregtech/api/gui/widgets/GT_LockedWhileActiveButton.java b/src/main/java/gregtech/api/gui/widgets/GT_LockedWhileActiveButton.java new file mode 100644 index 0000000000..9a93a8fadf --- /dev/null +++ b/src/main/java/gregtech/api/gui/widgets/GT_LockedWhileActiveButton.java @@ -0,0 +1,90 @@ +package gregtech.api.gui.widgets; + +import java.util.Arrays; +import java.util.List; +import java.util.function.BiConsumer; +import java.util.function.Supplier; + +import net.minecraft.util.StatCollector; + +import org.jetbrains.annotations.NotNull; + +import com.google.common.collect.ImmutableList; +import com.gtnewhorizons.modularui.api.drawable.IDrawable; +import com.gtnewhorizons.modularui.api.screen.ModularWindow; +import com.gtnewhorizons.modularui.api.widget.Widget; +import com.gtnewhorizons.modularui.common.widget.ButtonWidget; +import com.gtnewhorizons.modularui.common.widget.FakeSyncWidget; + +import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.interfaces.tileentity.IMachineProgress; + +public class GT_LockedWhileActiveButton extends ButtonWidget { + + @NotNull + private final IMachineProgress machine; + + public GT_LockedWhileActiveButton(@NotNull IMachineProgress machine, @NotNull ModularWindow.Builder builder) { + super(); + this.machine = machine; + + super.attachSyncer( + new FakeSyncWidget.BooleanSyncer(machine::isActive, a -> {}), + builder, + (widget, aBoolean) -> widget.notifyTooltipChange()); + + super.dynamicTooltip(this::generateTooltip); + } + + @NotNull + @Override + public ButtonWidget setOnClick(@NotNull BiConsumer<ClickData, Widget> clickAction) { + return super.setOnClick((clickData, widget) -> { + if (!machine.isActive()) { + clickAction.accept(clickData, widget); + } + }); + } + + @NotNull + @Override + public Widget setBackground(@NotNull IDrawable... drawables) { + return super.setBackground(() -> appendLockedOverlay(drawables)); + } + + @NotNull + @Override + public Widget setBackground(@NotNull Supplier<IDrawable[]> drawablesSupplier) { + return super.setBackground(() -> appendLockedOverlay(drawablesSupplier.get())); + } + + @NotNull + @Override + public Widget dynamicTooltip(@NotNull Supplier<List<String>> dynamicTooltip) { + return super.dynamicTooltip(() -> { + ImmutableList.Builder<String> tooltips = ImmutableList.<String>builder() + .addAll(dynamicTooltip.get()); + tooltips.addAll(generateTooltip()); + + return tooltips.build(); + }); + } + + @NotNull + private IDrawable[] appendLockedOverlay(@NotNull IDrawable[] drawables) { + if (machine.isActive()) { + final IDrawable[] copy = Arrays.copyOf(drawables, drawables.length + 1); + copy[drawables.length] = GT_UITextures.OVERLAY_BUTTON_LOCKED; + return copy; + } + return drawables; + } + + @NotNull + private List<String> generateTooltip() { + if (machine.isActive()) { + return ImmutableList.of(StatCollector.translateToLocal("GT5U.gui.button.forbidden_while_running")); + } + return ImmutableList.of(); + } +} |