From 28ba5669e9afda7f434c2c2eea3090315e4e8706 Mon Sep 17 00:00:00 2001 From: KilaBash Date: Thu, 22 Jul 2021 23:14:09 +0800 Subject: [PATCH 01/58] add item Terminal --- .../java/gregtech/common/items/MetaItem2.java | 7 ++----- .../java/gregtech/common/items/MetaItems.java | 1 + .../items/behaviors/GuideTerminalBehaviour.java | 12 ++++++++++++ .../resources/assets/gregtech/lang/en_us.lang | 3 +++ .../models/item/metaitems/guide_terminal.json | 6 ++++++ .../items/metaitems/tool.guide_terminal.png | Bin 0 -> 2868 bytes 6 files changed, 24 insertions(+), 5 deletions(-) create mode 100644 src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java create mode 100644 src/main/resources/assets/gregtech/models/item/metaitems/guide_terminal.json create mode 100644 src/main/resources/assets/gregtech/textures/items/metaitems/tool.guide_terminal.png diff --git a/src/main/java/gregtech/common/items/MetaItem2.java b/src/main/java/gregtech/common/items/MetaItem2.java index 8bd66297edb..17aa42a5ca3 100644 --- a/src/main/java/gregtech/common/items/MetaItem2.java +++ b/src/main/java/gregtech/common/items/MetaItem2.java @@ -15,10 +15,7 @@ import gregtech.api.unification.ore.OrePrefix; import gregtech.api.util.RandomPotionEffect; import gregtech.common.ConfigHolder; -import gregtech.common.items.behaviors.FacadeItem; -import gregtech.common.items.behaviors.NanoSaberBehavior; -import gregtech.common.items.behaviors.ScannerBehavior; -import gregtech.common.items.behaviors.TurbineRotorBehavior; +import gregtech.common.items.behaviors.*; import net.minecraft.init.Blocks; import net.minecraft.init.Items; import net.minecraft.init.MobEffects; @@ -103,7 +100,7 @@ public void registerSubItems() { NANO_SABER = addItem(578, "nano_saber").addComponents(ElectricStats.createElectricItem(4000000L, GTValues.HV)).addComponents(new NanoSaberBehavior()).setMaxStackSize(1); ENERGY_FIELD_PROJECTOR = addItem(579, "energy_field_projector").addComponents(ElectricStats.createElectricItem(16000000L, GTValues.EV)).setMaxStackSize(1); SCANNER = addItem(580, "scanner").addComponents(ElectricStats.createElectricItem(200_000L, GTValues.LV), new ScannerBehavior(50)); - + GUIDE_TERMINAL = addItem(581, "guide_terminal").addComponents(new GuideTerminalBehaviour()); INGOT_MIXED_METAL = addItem(432, "ingot.mixed_metal"); ADVANCED_ALLOY_PLATE = addItem(433, "plate.advanced_alloy"); diff --git a/src/main/java/gregtech/common/items/MetaItems.java b/src/main/java/gregtech/common/items/MetaItems.java index 188681390b2..484fcf441c7 100644 --- a/src/main/java/gregtech/common/items/MetaItems.java +++ b/src/main/java/gregtech/common/items/MetaItems.java @@ -416,6 +416,7 @@ private MetaItems() { public static MetaItem.MetaValueItem NANO_SABER; public static MetaItem.MetaValueItem ENERGY_FIELD_PROJECTOR; public static MetaItem.MetaValueItem SCANNER; + public static MetaItem.MetaValueItem GUIDE_TERMINAL; public static MetaItem.MetaValueItem[] DYE_ONLY_ITEMS = new MetaItem.MetaValueItem[EnumDyeColor.values().length]; public static MetaItem.MetaValueItem[] SPRAY_CAN_DYES = new MetaItem.MetaValueItem[EnumDyeColor.values().length]; diff --git a/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java b/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java new file mode 100644 index 00000000000..9c796d99263 --- /dev/null +++ b/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java @@ -0,0 +1,12 @@ +package gregtech.common.items.behaviors; + +import gregtech.api.items.metaitem.stats.IItemBehaviour; +import net.minecraft.item.ItemStack; + +import java.util.List; + +public class GuideTerminalBehaviour implements IItemBehaviour { + @Override + public void addInformation(ItemStack itemStack, List lines) { + } +} diff --git a/src/main/resources/assets/gregtech/lang/en_us.lang b/src/main/resources/assets/gregtech/lang/en_us.lang index aa83fd610da..663197ddd04 100644 --- a/src/main/resources/assets/gregtech/lang/en_us.lang +++ b/src/main/resources/assets/gregtech/lang/en_us.lang @@ -1892,6 +1892,9 @@ behavior.scanner.analyzing_failed=Analyzing failed! behavior.scanner.analyzing_complete=Analyzing complete! behavior.scanner.not_enough_energy=Analyzing failed: Not Enough Energy! +metaitem.guide_terminal.name=Guide Terminal +metaitem.guide_terminal.tooltip=Hope it will help you + tile.casing.ulv=ULV Machine Casing tile.casing.lv=LV Machine Casing tile.casing.mv=MV Machine Casing diff --git a/src/main/resources/assets/gregtech/models/item/metaitems/guide_terminal.json b/src/main/resources/assets/gregtech/models/item/metaitems/guide_terminal.json new file mode 100644 index 00000000000..ddeac5c5ad4 --- /dev/null +++ b/src/main/resources/assets/gregtech/models/item/metaitems/guide_terminal.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "gregtech:items/metaitems/tool.guide_terminal" + } +} diff --git a/src/main/resources/assets/gregtech/textures/items/metaitems/tool.guide_terminal.png b/src/main/resources/assets/gregtech/textures/items/metaitems/tool.guide_terminal.png new file mode 100644 index 0000000000000000000000000000000000000000..3c9b810359d1e18bae247397f2dffa1ac0ca7360 GIT binary patch literal 2868 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 Sd!AAN0000 Date: Sun, 25 Jul 2021 02:33:02 +0800 Subject: [PATCH 02/58] amongus --- .../java/gregtech/api/gui/GuiTextures.java | 2 ++ .../api/gui/resources/RenderUtil.java | 25 +++++++++++++++ .../api/terminal/TerminalBuilder.java | 4 +++ .../terminal/gui/widgets/CircleButton.java | 26 +++++++++++++++ .../behaviors/GuideTerminalBehaviour.java | 30 +++++++++++++++++- .../gui/terminal/terminal_background.png | Bin 0 -> 25109 bytes 6 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 src/main/java/gregtech/api/terminal/TerminalBuilder.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/CircleButton.java create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/terminal_background.png diff --git a/src/main/java/gregtech/api/gui/GuiTextures.java b/src/main/java/gregtech/api/gui/GuiTextures.java index 6a6e43723ce..478df98aefc 100644 --- a/src/main/java/gregtech/api/gui/GuiTextures.java +++ b/src/main/java/gregtech/api/gui/GuiTextures.java @@ -167,4 +167,6 @@ public class GuiTextures { public static final TextureArea INFO_ICON = TextureArea.fullImage("textures/gui/widget/information.png"); public static final TextureArea MULTIBLOCK_CATEGORY = TextureArea.fullImage("textures/gui/icon/coke_oven.png"); + //Terminal + public static final TextureArea TERMINAL_BACKGROUND = TextureArea.fullImage("textures/gui/terminal/terminal_background.png"); } diff --git a/src/main/java/gregtech/api/gui/resources/RenderUtil.java b/src/main/java/gregtech/api/gui/resources/RenderUtil.java index ebc04858cd4..bf0ac9dbaf2 100644 --- a/src/main/java/gregtech/api/gui/resources/RenderUtil.java +++ b/src/main/java/gregtech/api/gui/resources/RenderUtil.java @@ -13,6 +13,9 @@ import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; +import net.minecraft.client.renderer.GlStateManager.DestFactor; +import net.minecraft.client.renderer.GlStateManager.SourceFactor; +import org.lwjgl.opengl.GL11; @SideOnly(Side.CLIENT) public class RenderUtil { @@ -103,5 +106,27 @@ private static void drawFluidTexture(double xCoord, double yCoord, TextureAtlasS tessellator.draw(); } + public static void setColor(int color) { // ARGB + GlStateManager.color((color >> 16 & 255) / 255.0F, + (color >> 8 & 255) / 255.0F, + (color & 255) / 255.0F, + (color >> 24 & 255) / 255.0F); + } + + public static void renderCircle(float x, float y, float r, int color, int detail) { + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder bufferbuilder = tessellator.getBuffer(); + GlStateManager.enableBlend(); + GlStateManager.disableTexture2D(); + GlStateManager.tryBlendFuncSeparate(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ZERO); + setColor(color); + bufferbuilder.begin(GL11.GL_POLYGON, DefaultVertexFormats.POSITION); + for (int i = 0; i < detail; i++) { + bufferbuilder.pos(x + r * Math.cos(-2 * Math.PI * i / detail), y + r * Math.sin(-2 * Math.PI * i / detail), 0.0D).endVertex(); + } + tessellator.draw(); + GlStateManager.enableTexture2D(); + GlStateManager.disableBlend(); + } } diff --git a/src/main/java/gregtech/api/terminal/TerminalBuilder.java b/src/main/java/gregtech/api/terminal/TerminalBuilder.java new file mode 100644 index 00000000000..0a89229be3b --- /dev/null +++ b/src/main/java/gregtech/api/terminal/TerminalBuilder.java @@ -0,0 +1,4 @@ +package gregtech.api.terminal; + +public class TerminalBuilder { +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/CircleButton.java b/src/main/java/gregtech/api/terminal/gui/widgets/CircleButton.java new file mode 100644 index 00000000000..b8e34d99bf5 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/CircleButton.java @@ -0,0 +1,26 @@ +package gregtech.api.terminal.gui.widgets; + +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.RenderUtil; +import gregtech.api.util.Position; +import gregtech.api.util.Size; + +public class CircleButton extends Widget { + int x, y, r; + public CircleButton(int x, int y, int r) { + super(new Position(x - r, y - r), new Size(2 * r, 2 * r)); + this.r = r; + } + + @Override + public void drawInBackground(int mouseX, int mouseY, IRenderContext context) { + int r = this.getSize().getHeight() / 2; + int x = this.getPosition().x + r; + int y = this.getPosition().y + r; + + RenderUtil.renderCircle(x, y, r, 0xffff0000, 24); + RenderUtil.renderCircle(x, y, r - 2, 0xffffffff, 24); + + } +} diff --git a/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java b/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java index 9c796d99263..4b014eaec5a 100644 --- a/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java +++ b/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java @@ -1,12 +1,40 @@ package gregtech.common.items.behaviors; +import gregtech.api.gui.GuiTextures; +import gregtech.api.gui.ModularUI; +import gregtech.api.items.gui.ItemUIFactory; +import gregtech.api.items.gui.PlayerInventoryHolder; import gregtech.api.items.metaitem.stats.IItemBehaviour; +import gregtech.api.terminal.gui.widgets.CircleButton; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; +import net.minecraft.util.ActionResult; +import net.minecraft.util.EnumActionResult; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; import java.util.List; -public class GuideTerminalBehaviour implements IItemBehaviour { +public class GuideTerminalBehaviour implements IItemBehaviour, ItemUIFactory { + + @Override + public ActionResult onItemRightClick(World world, EntityPlayer player, EnumHand hand) { + ItemStack itemStack = player.getHeldItem(hand); + if (!world.isRemote) { + PlayerInventoryHolder holder = new PlayerInventoryHolder(player, hand); + holder.openUI(); + } + return ActionResult.newResult(EnumActionResult.SUCCESS, itemStack); + } + @Override public void addInformation(ItemStack itemStack, List lines) { } + + @Override + public ModularUI createUI(PlayerInventoryHolder holder, EntityPlayer entityPlayer) { + return ModularUI.builder(GuiTextures.TERMINAL_BACKGROUND, 380, 256) + .widget(new CircleButton(27, 40, 12)) + .build(holder, entityPlayer); + } } diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_background.png b/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_background.png new file mode 100644 index 0000000000000000000000000000000000000000..3bb4031f9c1324203ff6cc74b891bdd4a13e2a3f GIT binary patch literal 25109 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 Date: Sun, 25 Jul 2021 17:39:14 +0800 Subject: [PATCH 03/58] update gui system --- src/main/java/gregtech/api/gui/Widget.java | 24 +++- .../gregtech/api/gui/impl/ModularUIGui.java | 2 +- .../api/gui/resources/IGuiTexture.java | 5 + .../api/gui/resources/RenderUtil.java | 39 ++++++- .../api/gui/resources/TextureArea.java | 2 +- .../api/gui/resources/TextureItemStack.java | 27 +++++ .../api/gui/widgets/AbstractWidgetGroup.java | 4 +- .../terminal/gui/widgets/CircleButton.java | 107 +++++++++++++++++- .../terminal/gui/widgets/TerminalMenu.java | 48 ++++++++ .../behaviors/GuideTerminalBehaviour.java | 7 +- 10 files changed, 250 insertions(+), 15 deletions(-) create mode 100644 src/main/java/gregtech/api/gui/resources/IGuiTexture.java create mode 100644 src/main/java/gregtech/api/gui/resources/TextureItemStack.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/TerminalMenu.java diff --git a/src/main/java/gregtech/api/gui/Widget.java b/src/main/java/gregtech/api/gui/Widget.java index 4fccba4dc1e..0f9f16b6e7f 100644 --- a/src/main/java/gregtech/api/gui/Widget.java +++ b/src/main/java/gregtech/api/gui/Widget.java @@ -152,12 +152,21 @@ public void drawInForeground(int mouseX, int mouseY) { } /** - * Called each draw tick to draw this widget in GUI + * Called each draw tick to draw this widget in GUI (@Deprecated) */ + @Deprecated @SideOnly(Side.CLIENT) public void drawInBackground(int mouseX, int mouseY, IRenderContext context) { } + /** + * Called each draw tick to draw this widget in GUI + */ + @SideOnly(Side.CLIENT) + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + drawInBackground(mouseX, mouseY, context); + } + /** * Called when mouse wheel is moved in GUI * For some -redacted- reason mouseX position is relative against GUI not game window as in other mouse events @@ -341,24 +350,35 @@ public static final class ClickData { public final int button; public final boolean isShiftClick; public final boolean isCtrlClick; + public final boolean isClient; public ClickData(int button, boolean isShiftClick, boolean isCtrlClick) { this.button = button; this.isShiftClick = isShiftClick; this.isCtrlClick = isCtrlClick; + this.isClient = false; + } + + public ClickData(int button, boolean isShiftClick, boolean isCtrlClick, boolean isClient) { + this.button = button; + this.isShiftClick = isShiftClick; + this.isCtrlClick = isCtrlClick; + this.isClient = isClient; } public void writeToBuf(PacketBuffer buf) { buf.writeVarInt(button); buf.writeBoolean(isShiftClick); buf.writeBoolean(isCtrlClick); + buf.writeBoolean(isClient); } public static ClickData readFromBuf(PacketBuffer buf) { int button = buf.readVarInt(); boolean shiftClick = buf.readBoolean(); boolean ctrlClick = buf.readBoolean(); - return new ClickData(button, shiftClick, ctrlClick); + boolean isClient = buf.readBoolean(); + return new ClickData(button, shiftClick, ctrlClick, isClient); } } diff --git a/src/main/java/gregtech/api/gui/impl/ModularUIGui.java b/src/main/java/gregtech/api/gui/impl/ModularUIGui.java index 4d0cd3b521c..b5a94170d37 100644 --- a/src/main/java/gregtech/api/gui/impl/ModularUIGui.java +++ b/src/main/java/gregtech/api/gui/impl/ModularUIGui.java @@ -216,7 +216,7 @@ protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, i modularUI.guiWidgets.values().forEach(widget -> { GlStateManager.pushMatrix(); GlStateManager.enableBlend(); - widget.drawInBackground(mouseX, mouseY, this); + widget.drawInBackground(mouseX, mouseY, partialTicks,this); GlStateManager.color(rColorForOverlay, gColorForOverlay, bColorForOverlay, 1.0F); GlStateManager.popMatrix(); }); diff --git a/src/main/java/gregtech/api/gui/resources/IGuiTexture.java b/src/main/java/gregtech/api/gui/resources/IGuiTexture.java new file mode 100644 index 00000000000..5bc5627a626 --- /dev/null +++ b/src/main/java/gregtech/api/gui/resources/IGuiTexture.java @@ -0,0 +1,5 @@ +package gregtech.api.gui.resources; + +public interface IGuiTexture { + void draw(double x, double y, int width, int height); +} diff --git a/src/main/java/gregtech/api/gui/resources/RenderUtil.java b/src/main/java/gregtech/api/gui/resources/RenderUtil.java index bf0ac9dbaf2..e0077eb716a 100644 --- a/src/main/java/gregtech/api/gui/resources/RenderUtil.java +++ b/src/main/java/gregtech/api/gui/resources/RenderUtil.java @@ -3,10 +3,12 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.RenderItem; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.texture.TextureMap; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.item.ItemStack; import net.minecraft.util.ResourceLocation; import net.minecraftforge.fluids.Fluid; import net.minecraftforge.fluids.FluidRegistry; @@ -106,6 +108,17 @@ private static void drawFluidTexture(double xCoord, double yCoord, TextureAtlasS tessellator.draw(); } + public static void renderItemOverLay(float x, float y, float z, float scale, ItemStack itemStack) { + net.minecraft.client.renderer.RenderHelper.enableStandardItemLighting(); + GlStateManager.pushMatrix(); + GlStateManager.scale(scale, scale, 0.0001f); + GlStateManager.translate(x * 16, y * 16, z * 16); + RenderItem renderItem = Minecraft.getMinecraft().getRenderItem(); + renderItem.renderItemAndEffectIntoGUI(itemStack, 0, 0 ); + GlStateManager.popMatrix(); + net.minecraft.client.renderer.RenderHelper.disableStandardItemLighting(); + } + public static void setColor(int color) { // ARGB GlStateManager.color((color >> 16 & 255) / 255.0F, (color >> 8 & 255) / 255.0F, @@ -113,7 +126,7 @@ public static void setColor(int color) { // ARGB (color >> 24 & 255) / 255.0F); } - public static void renderCircle(float x, float y, float r, int color, int detail) { + public static void renderCircle(float x, float y, float r, int color, int segments) { Tessellator tessellator = Tessellator.getInstance(); BufferBuilder bufferbuilder = tessellator.getBuffer(); GlStateManager.enableBlend(); @@ -121,8 +134,28 @@ public static void renderCircle(float x, float y, float r, int color, int detail GlStateManager.tryBlendFuncSeparate(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ZERO); setColor(color); bufferbuilder.begin(GL11.GL_POLYGON, DefaultVertexFormats.POSITION); - for (int i = 0; i < detail; i++) { - bufferbuilder.pos(x + r * Math.cos(-2 * Math.PI * i / detail), y + r * Math.sin(-2 * Math.PI * i / detail), 0.0D).endVertex(); + for (int i = 0; i < segments; i++) { + bufferbuilder.pos(x + r * Math.cos(-2 * Math.PI * i / segments), y + r * Math.sin(-2 * Math.PI * i / segments), 0.0D).endVertex(); + } + tessellator.draw(); + GlStateManager.enableTexture2D(); + GlStateManager.disableBlend(); + } + + public static void renderSector(float x, float y, float r, int color, int segments, int from, int to) { + if (from > to || from < 0) return; + if(to > segments) to = segments; + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder bufferbuilder = tessellator.getBuffer(); + GlStateManager.enableBlend(); + GlStateManager.disableTexture2D(); + GlStateManager.tryBlendFuncSeparate(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ZERO); + setColor(color); + bufferbuilder.begin(GL11.GL_TRIANGLES, DefaultVertexFormats.POSITION); + for (int i = from; i < to; i++) { + bufferbuilder.pos(x + r * Math.cos(-2 * Math.PI * i / segments), y + r * Math.sin(-2 * Math.PI * i / segments), 0.0D).endVertex(); + bufferbuilder.pos(x + r * Math.cos(-2 * Math.PI * (i + 1) / segments), y + r * Math.sin(-2 * Math.PI * (i + 1) / segments), 0.0D).endVertex(); + bufferbuilder.pos(x, y, 0.0D).endVertex(); } tessellator.draw(); GlStateManager.enableTexture2D(); diff --git a/src/main/java/gregtech/api/gui/resources/TextureArea.java b/src/main/java/gregtech/api/gui/resources/TextureArea.java index 64102ceb95e..384f59df75b 100644 --- a/src/main/java/gregtech/api/gui/resources/TextureArea.java +++ b/src/main/java/gregtech/api/gui/resources/TextureArea.java @@ -22,7 +22,7 @@ * This representation doesn't take image size in account, so all image variables are * 0.0 - 1.0 bounds */ -public class TextureArea { +public class TextureArea implements IGuiTexture { public final ResourceLocation imageLocation; diff --git a/src/main/java/gregtech/api/gui/resources/TextureItemStack.java b/src/main/java/gregtech/api/gui/resources/TextureItemStack.java new file mode 100644 index 00000000000..394be67cc4c --- /dev/null +++ b/src/main/java/gregtech/api/gui/resources/TextureItemStack.java @@ -0,0 +1,27 @@ +package gregtech.api.gui.resources; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.client.renderer.RenderItem; +import net.minecraft.item.ItemStack; + +public class TextureItemStack implements IGuiTexture{ + private ItemStack itemStack; + + public TextureItemStack(ItemStack itemStack) { + this.itemStack = itemStack; + } + + @Override + public void draw(double x, double y, int width, int height) { + RenderHelper.enableStandardItemLighting(); + GlStateManager.pushMatrix(); + GlStateManager.scale(width / 16f, height / 16f, 0.0001); + GlStateManager.translate(x * 16 / width, y * 16 / height, 0); + RenderItem renderItem = Minecraft.getMinecraft().getRenderItem(); + renderItem.renderItemAndEffectIntoGUI(itemStack, 0, 0); + GlStateManager.popMatrix(); + RenderHelper.disableStandardItemLighting(); + } +} diff --git a/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java b/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java index 9644b91401d..6552bfb23ab 100644 --- a/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java +++ b/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java @@ -236,10 +236,10 @@ public void drawInForeground(int mouseX, int mouseY) { } @Override - public void drawInBackground(int mouseX, int mouseY, IRenderContext context) { + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { for (Widget widget : widgets) { if (isWidgetVisible(widget)) { - widget.drawInBackground(mouseX, mouseY, context); + widget.drawInBackground(mouseX, mouseY, partialTicks, context); } } GlStateManager.color(rColorForOverlay, gColorForOverlay, bColorForOverlay, 1.0F); diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/CircleButton.java b/src/main/java/gregtech/api/terminal/gui/widgets/CircleButton.java index b8e34d99bf5..77bd34dcb9e 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/CircleButton.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/CircleButton.java @@ -2,25 +2,122 @@ import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.resources.RenderUtil; import gregtech.api.util.Position; import gregtech.api.util.Size; +import net.minecraft.client.resources.I18n; +import net.minecraft.item.ItemStack; +import net.minecraft.network.PacketBuffer; +import org.lwjgl.input.Mouse; + +import java.awt.*; +import java.util.Collections; +import java.util.function.Consumer; public class CircleButton extends Widget { - int x, y, r; + private int hoverTick; + private boolean isHover; + private String hoverText; + private IGuiTexture icon; + private Consumer onPressCallback; + private final int[] colors = { + new Color(146, 146, 146).getRGB(), + new Color(39, 232, 141).getRGB(), + new Color(255, 255, 255).getRGB(), + }; + public CircleButton(int x, int y, int r) { super(new Position(x - r, y - r), new Size(2 * r, 2 * r)); - this.r = r; + } + + public CircleButton setIcon(IGuiTexture icon) { + this.icon = icon; + return this; + } + + public CircleButton setHoverText(String hoverText) { + this.hoverText = hoverText; + return this; + } + + public CircleButton setColors(int stroke, int strokeAnima, int fill) { + colors[0] = stroke; + colors[1] = strokeAnima; + colors[2] = fill; + return this; + } + + public CircleButton setFillColors(int fill) { + colors[2] = fill; + return this; + } + + public CircleButton setClickListener(Consumer onPressed) { + this.onPressCallback = onPressed; + return this; } @Override - public void drawInBackground(int mouseX, int mouseY, IRenderContext context) { + public void updateScreen() { + if (isHover) { + if (hoverTick < 8) { + hoverTick += 1; + } + } else { + if (hoverTick > 0) { + hoverTick -= 1; + } + } + } + + @Override + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { int r = this.getSize().getHeight() / 2; int x = this.getPosition().x + r; int y = this.getPosition().y + r; + int segments = 24; + + RenderUtil.renderCircle(x, y, r, colors[0], segments); + isHover = this.isMouseOverElement(mouseX, mouseY); + if (isHover || hoverTick != 0) { + RenderUtil.renderSector(x, y, r, colors[1], segments, 0, (int) (segments * ((hoverTick + partialTicks) / 8))); + } + RenderUtil.renderCircle(x, y, r - 2, colors[2], segments); + if (icon != null) { + icon.draw(x - 8, y - 8, 16, 16); + } + } + + @Override + public void drawInForeground(int mouseX, int mouseY) { + if (this.isMouseOverElement(mouseX, mouseY)) { + this.drawHoveringText(ItemStack.EMPTY, Collections.singletonList(I18n.format(hoverText)), 300, mouseX, mouseY); + } + } - RenderUtil.renderCircle(x, y, r, 0xffff0000, 24); - RenderUtil.renderCircle(x, y, r - 2, 0xffffffff, 24); + @Override + public boolean mouseClicked(int mouseX, int mouseY, int button) { + if (isMouseOverElement(mouseX, mouseY)) { + ClickData clickData = new ClickData(Mouse.getEventButton(), isShiftDown(), isCtrlDown(), false); + writeClientAction(1, clickData::writeToBuf); + playButtonClickSound(); + if (onPressCallback != null) { + onPressCallback.accept(new ClickData(Mouse.getEventButton(), isShiftDown(), isCtrlDown(), true)); + } + return true; + } + return false; + } + @Override + public void handleClientAction(int id, PacketBuffer buffer) { + if (id == 1) { + ClickData clickData = ClickData.readFromBuf(buffer); + if (onPressCallback != null) { + onPressCallback.accept(clickData); + } + } } + } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/TerminalMenu.java b/src/main/java/gregtech/api/terminal/gui/widgets/TerminalMenu.java new file mode 100644 index 00000000000..0f0de4667a7 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/TerminalMenu.java @@ -0,0 +1,48 @@ +package gregtech.api.terminal.gui.widgets; + +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.widgets.AbstractWidgetGroup; +import gregtech.api.util.Position; +import gregtech.api.util.Size; + +import java.util.function.Supplier; + +public class TerminalMenu extends AbstractWidgetGroup { + private IGuiTexture background; + private Widget activeContent; + private CircleButton activeButton; + public TerminalMenu(int xPosition, int yPosition, int width, int height) { + super(new Position(xPosition, yPosition), new Size(width, height)); + } + + public TerminalMenu setBackGround(IGuiTexture background) { + this.background = background; + return this; + } + + public TerminalMenu addApp(IGuiTexture icon, String nameKey, Supplier content){ + CircleButton button = new CircleButton(27,40,12).setIcon(icon).setHoverText(nameKey); + button.setClickListener(clickData -> { + if (button != activeButton) { + removeWidget(activeContent); + if(content != null) { + activeContent = content.get(); + addWidget(activeContent); + } + activeButton.setFillColors(0xffffffff); + activeButton = button; + activeButton.setFillColors(0xFF929292); + } + }); + this.addWidget(button); + return this; + } + + @Override + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + background.draw(this.getPosition().x, this.getPosition().y, this.getSize().width, this.getSize().height); + super.drawInBackground(mouseX, mouseY, partialTicks, context); + } +} diff --git a/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java b/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java index 4b014eaec5a..bb3487c1f7a 100644 --- a/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java +++ b/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java @@ -2,11 +2,14 @@ import gregtech.api.gui.GuiTextures; import gregtech.api.gui.ModularUI; +import gregtech.api.gui.resources.TextureItemStack; import gregtech.api.items.gui.ItemUIFactory; import gregtech.api.items.gui.PlayerInventoryHolder; import gregtech.api.items.metaitem.stats.IItemBehaviour; import gregtech.api.terminal.gui.widgets.CircleButton; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Blocks; +import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.util.ActionResult; import net.minecraft.util.EnumActionResult; @@ -33,8 +36,10 @@ public void addInformation(ItemStack itemStack, List lines) { @Override public ModularUI createUI(PlayerInventoryHolder holder, EntityPlayer entityPlayer) { + CircleButton circleButton = new CircleButton(27, 40, 12) + .setIcon(new TextureItemStack(Item.getItemFromBlock(Blocks.CHEST).getDefaultInstance())); return ModularUI.builder(GuiTextures.TERMINAL_BACKGROUND, 380, 256) - .widget(new CircleButton(27, 40, 12)) + .widget(circleButton) .build(holder, entityPlayer); } } From d3db429c820ea5ae049184bdd77161ee4bdba44d Mon Sep 17 00:00:00 2001 From: KilaBash Date: Thu, 29 Jul 2021 11:18:21 +0800 Subject: [PATCH 04/58] textbox image widgets --- src/main/java/gregtech/api/GregTechAPI.java | 6 + src/main/java/gregtech/api/gui/Widget.java | 38 +- .../gregtech/api/gui/impl/ModularUIGui.java | 2 + .../api/gui/resources/IGuiTexture.java | 1 + ...reItemStack.java => ItemStackTexture.java} | 9 +- .../api/gui/resources/RenderUtil.java | 55 ++ .../api/gui/resources/URLTexture.java | 77 ++ .../resources/onlinepic/DownloadThread.java | 260 +++++++ .../gui/resources/onlinepic/GifDecoder.java | 721 ++++++++++++++++++ .../onlinepic/ProcessedImageData.java | 137 ++++ .../gui/resources/onlinepic/TextureCache.java | 150 ++++ .../AnimatedPictureTexture.java | 66 ++ .../onlinepictexture/OrdinaryTexture.java | 23 + .../onlinepictexture/PictureTexture.java | 65 ++ .../onlinepictexture/VideoTexture.java | 19 + .../api/gui/widgets/AbstractWidgetGroup.java | 56 +- .../gregtech/api/gui/widgets/TabGroup.java | 1 - .../gregtech/api/gui/widgets/WidgetGroup.java | 10 + .../api/terminal/TerminalBuilder.java | 21 + .../api/terminal/app/AbstractApplication.java | 32 + .../api/terminal/app/guide/GuideApp.java | 114 +++ .../api/terminal/app/guide/ItemGuideApp.java | 34 + .../app/guide/MultiBlockGuideApp.java | 47 ++ .../app/guide/SimpleMachineGuideApp.java | 46 ++ .../terminal/app/guide/TutorialGuideApp.java | 46 ++ ...cleButton.java => CircleButtonWidget.java} | 14 +- .../terminal/gui/widgets/TerminalMenu.java | 48 -- .../gui/widgets/TerminalMenuWidget.java | 54 ++ .../gui/widgets/guide/GuidePageWidget.java | 83 ++ .../gui/widgets/guide/GuideWidget.java | 69 ++ .../gui/widgets/guide/IGuideWidget.java | 10 + .../gui/widgets/guide/ImageWidget.java | 61 ++ .../gui/widgets/guide/TextBoxWidget.java | 83 ++ .../gui/widgets/guide/TextTreeWidget.java | 150 ++++ .../gregtech/api/terminal/util/IContent.java | 4 + .../gregtech/api/terminal/util/TreeNode.java | 51 ++ .../java/gregtech/common/CommonProxy.java | 17 +- .../behaviors/GuideTerminalBehaviour.java | 12 +- .../terminal/guide/items/default.json | 34 + .../terminal/guide/multiblocks/default.json | 24 + .../guide/simplemachines/default.json | 34 + .../guide/tutorials/api_0_guidepage.json | 36 + .../guide/tutorials/api_1_textbox.json | 265 +++++++ .../terminal/guide/tutorials/api_2_image.json | 80 ++ 44 files changed, 3071 insertions(+), 94 deletions(-) rename src/main/java/gregtech/api/gui/resources/{TextureItemStack.java => ItemStackTexture.java} (79%) create mode 100644 src/main/java/gregtech/api/gui/resources/URLTexture.java create mode 100644 src/main/java/gregtech/api/gui/resources/onlinepic/DownloadThread.java create mode 100644 src/main/java/gregtech/api/gui/resources/onlinepic/GifDecoder.java create mode 100644 src/main/java/gregtech/api/gui/resources/onlinepic/ProcessedImageData.java create mode 100644 src/main/java/gregtech/api/gui/resources/onlinepic/TextureCache.java create mode 100644 src/main/java/gregtech/api/gui/resources/onlinepictexture/AnimatedPictureTexture.java create mode 100644 src/main/java/gregtech/api/gui/resources/onlinepictexture/OrdinaryTexture.java create mode 100644 src/main/java/gregtech/api/gui/resources/onlinepictexture/PictureTexture.java create mode 100644 src/main/java/gregtech/api/gui/resources/onlinepictexture/VideoTexture.java create mode 100644 src/main/java/gregtech/api/terminal/app/AbstractApplication.java create mode 100644 src/main/java/gregtech/api/terminal/app/guide/GuideApp.java create mode 100644 src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java create mode 100644 src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java create mode 100644 src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java create mode 100644 src/main/java/gregtech/api/terminal/app/guide/TutorialGuideApp.java rename src/main/java/gregtech/api/terminal/gui/widgets/{CircleButton.java => CircleButtonWidget.java} (88%) delete mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/TerminalMenu.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/TerminalMenuWidget.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java create mode 100644 src/main/java/gregtech/api/terminal/util/IContent.java create mode 100644 src/main/java/gregtech/api/terminal/util/TreeNode.java create mode 100644 src/main/resources/assets/gregtech/terminal/guide/items/default.json create mode 100644 src/main/resources/assets/gregtech/terminal/guide/multiblocks/default.json create mode 100644 src/main/resources/assets/gregtech/terminal/guide/simplemachines/default.json create mode 100644 src/main/resources/assets/gregtech/terminal/guide/tutorials/api_0_guidepage.json create mode 100644 src/main/resources/assets/gregtech/terminal/guide/tutorials/api_1_textbox.json create mode 100644 src/main/resources/assets/gregtech/terminal/guide/tutorials/api_2_image.json diff --git a/src/main/java/gregtech/api/GregTechAPI.java b/src/main/java/gregtech/api/GregTechAPI.java index 09a64812f21..b20965d1667 100644 --- a/src/main/java/gregtech/api/GregTechAPI.java +++ b/src/main/java/gregtech/api/GregTechAPI.java @@ -2,6 +2,8 @@ import gregtech.api.block.machines.BlockMachine; import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.multiblock.MultiblockControllerBase; +import gregtech.api.terminal.app.guide.MultiBlockGuideApp; import gregtech.api.unification.OreDictUnifier; import gregtech.api.unification.material.Materials; import gregtech.api.unification.material.type.DustMaterial; @@ -11,6 +13,7 @@ import gregtech.api.util.GTControlledRegistry; import gregtech.api.util.IBlockOre; import gregtech.common.items.MetaItems; +import gregtech.common.metatileentities.electric.multiblockpart.MetaTileEntityMultiblockPart; import net.minecraft.util.ResourceLocation; import java.util.HashMap; @@ -32,6 +35,9 @@ public class GregTechAPI { public static T registerMetaTileEntity(int id, T sampleMetaTileEntity) { META_TILE_ENTITY_REGISTRY.register(id, sampleMetaTileEntity.metaTileEntityId, sampleMetaTileEntity); + if (sampleMetaTileEntity instanceof MultiblockControllerBase || sampleMetaTileEntity instanceof MetaTileEntityMultiblockPart) { + MultiBlockGuideApp.registerMultiBlock(sampleMetaTileEntity); + } return sampleMetaTileEntity; } diff --git a/src/main/java/gregtech/api/gui/Widget.java b/src/main/java/gregtech/api/gui/Widget.java index 0f9f16b6e7f..45f25a9fa13 100644 --- a/src/main/java/gregtech/api/gui/Widget.java +++ b/src/main/java/gregtech/api/gui/Widget.java @@ -37,13 +37,14 @@ */ public abstract class Widget { - protected ModularUI gui; - protected ISizeProvider sizes; - protected WidgetUIAccess uiAccess; - private Position parentPosition = Position.ORIGIN; - private Position selfPosition; - private Position position; - private Size size; + protected transient ModularUI gui; + protected transient ISizeProvider sizes; + protected transient WidgetUIAccess uiAccess; + private transient Position parentPosition = Position.ORIGIN; + private transient Position selfPosition; + private transient Position position; + private transient Size size; + private transient boolean isVisible; public Widget(Position selfPosition, Size size) { Preconditions.checkNotNull(selfPosition, "selfPosition"); @@ -51,6 +52,11 @@ public Widget(Position selfPosition, Size size) { this.selfPosition = selfPosition; this.size = size; this.position = this.parentPosition.add(selfPosition); + this.isVisible = true; + } + + public Widget(int x, int y, int width, int height) { + this(new Position(x, y), new Size(width, height)); } public void setGui(ModularUI gui) { @@ -91,6 +97,14 @@ public final Size getSize() { return size; } + public boolean isVisible() { + return isVisible; + } + + public void setVisible(boolean visible) { + isVisible = visible; + } + public Rectangle toRectangleBox() { Position pos = getPosition(); Size size = getSize(); @@ -112,7 +126,7 @@ protected void onSizeUpdate() { } public boolean isMouseOverElement(int mouseX, int mouseY, boolean correctPositionOnMouseWheelMoveEvent) { - mouseX = correctPositionOnMouseWheelMoveEvent ? mouseX + getPosition().x : mouseX; + mouseX = correctPositionOnMouseWheelMoveEvent ? mouseX + this.gui.getGuiLeft(): mouseX; return isMouseOverElement(mouseX, mouseY); } @@ -241,6 +255,14 @@ protected final void writeClientAction(int id, Consumer packetBuff } } + @SideOnly(Side.CLIENT) + protected void drawBorder(int x, int y, int width, int height, int stroke, int stroke_width) { + drawGradientRect(x - stroke_width, y - stroke_width, width + 2 * stroke_width, stroke_width, stroke, stroke); + drawGradientRect(x - stroke_width, y + height, width + 2 * stroke_width, stroke_width, stroke, stroke); + drawGradientRect(x - stroke_width, y - stroke_width, stroke_width, height + 2 * stroke_width, stroke, stroke); + drawGradientRect(x + width, y - stroke_width, stroke_width, height + 2 * stroke_width, stroke, stroke); + } + @SideOnly(Side.CLIENT) protected void drawHoveringText(ItemStack itemStack, List tooltip, int maxTextWidth, int mouseX, int mouseY) { Minecraft mc = Minecraft.getMinecraft(); diff --git a/src/main/java/gregtech/api/gui/impl/ModularUIGui.java b/src/main/java/gregtech/api/gui/impl/ModularUIGui.java index b5a94170d37..c45fd42b154 100644 --- a/src/main/java/gregtech/api/gui/impl/ModularUIGui.java +++ b/src/main/java/gregtech/api/gui/impl/ModularUIGui.java @@ -199,6 +199,7 @@ private void renderReturningItemStack() { @Override protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { modularUI.guiWidgets.values().forEach(widget -> { + if (!widget.isVisible()) return; GlStateManager.pushMatrix(); GlStateManager.color(1.0f, 1.0f, 1.0f); widget.drawInForeground(mouseX, mouseY); @@ -214,6 +215,7 @@ protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, i GlStateManager.popMatrix(); modularUI.backgroundPath.draw(guiLeft, guiTop, xSize, ySize); modularUI.guiWidgets.values().forEach(widget -> { + if (!widget.isVisible()) return; GlStateManager.pushMatrix(); GlStateManager.enableBlend(); widget.drawInBackground(mouseX, mouseY, partialTicks,this); diff --git a/src/main/java/gregtech/api/gui/resources/IGuiTexture.java b/src/main/java/gregtech/api/gui/resources/IGuiTexture.java index 5bc5627a626..ee40a3b2004 100644 --- a/src/main/java/gregtech/api/gui/resources/IGuiTexture.java +++ b/src/main/java/gregtech/api/gui/resources/IGuiTexture.java @@ -2,4 +2,5 @@ public interface IGuiTexture { void draw(double x, double y, int width, int height); + default void updateTick() { } } diff --git a/src/main/java/gregtech/api/gui/resources/TextureItemStack.java b/src/main/java/gregtech/api/gui/resources/ItemStackTexture.java similarity index 79% rename from src/main/java/gregtech/api/gui/resources/TextureItemStack.java rename to src/main/java/gregtech/api/gui/resources/ItemStackTexture.java index 394be67cc4c..1bcdc7a461d 100644 --- a/src/main/java/gregtech/api/gui/resources/TextureItemStack.java +++ b/src/main/java/gregtech/api/gui/resources/ItemStackTexture.java @@ -4,15 +4,20 @@ import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.RenderHelper; import net.minecraft.client.renderer.RenderItem; +import net.minecraft.item.Item; import net.minecraft.item.ItemStack; -public class TextureItemStack implements IGuiTexture{ +public class ItemStackTexture implements IGuiTexture{ private ItemStack itemStack; - public TextureItemStack(ItemStack itemStack) { + public ItemStackTexture(ItemStack itemStack) { this.itemStack = itemStack; } + public ItemStackTexture(Item item) { + this.itemStack = new ItemStack(item); + } + @Override public void draw(double x, double y, int width, int height) { RenderHelper.enableStandardItemLighting(); diff --git a/src/main/java/gregtech/api/gui/resources/RenderUtil.java b/src/main/java/gregtech/api/gui/resources/RenderUtil.java index e0077eb716a..b0dce74f99b 100644 --- a/src/main/java/gregtech/api/gui/resources/RenderUtil.java +++ b/src/main/java/gregtech/api/gui/resources/RenderUtil.java @@ -162,4 +162,59 @@ public static void renderSector(float x, float y, float r, int color, int segmen GlStateManager.disableBlend(); } + public static void renderRect(float x, float y, float width, float height, float z, int color) { + renderGradientRect(x, y, width, height, z, color, color, false); + } + + public static void renderGradientRect(float x, float y, float width, float height, float z, int startColor, int endColor, boolean horizontal) { + float startAlpha = (float) (startColor >> 24 & 255) / 255.0F; + float startRed = (float) (startColor >> 16 & 255) / 255.0F; + float startGreen = (float) (startColor >> 8 & 255) / 255.0F; + float startBlue = (float) (startColor & 255) / 255.0F; + float endAlpha = (float) (endColor >> 24 & 255) / 255.0F; + float endRed = (float) (endColor >> 16 & 255) / 255.0F; + float endGreen = (float) (endColor >> 8 & 255) / 255.0F; + float endBlue = (float) (endColor & 255) / 255.0F; + GlStateManager.disableTexture2D(); + GlStateManager.enableBlend(); + GlStateManager.disableAlpha(); + GlStateManager.tryBlendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO); + GlStateManager.shadeModel(GL11.GL_SMOOTH); + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder buffer = tessellator.getBuffer(); + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR); + if (horizontal) { + buffer.pos(x + width, y, z).color(endRed, endGreen, endBlue, endAlpha).endVertex(); + buffer.pos(x, y, z).color(startRed, startGreen, startBlue, startAlpha).endVertex(); + buffer.pos(x, y + height, z).color(startRed, startGreen, startBlue, startAlpha).endVertex(); + buffer.pos(x + width, y + height, z).color(endRed, endGreen, endBlue, endAlpha).endVertex(); + tessellator.draw(); + } else { + buffer.pos(x + width, y, z).color(startRed, startGreen, startBlue, startAlpha).endVertex(); + buffer.pos(x, y, z).color(startRed, startGreen, startBlue, startAlpha).endVertex(); + buffer.pos(x, y + height, z).color(endRed, endGreen, endBlue, endAlpha).endVertex(); + buffer.pos(x + width, y + height, z).color(endRed, endGreen, endBlue, endAlpha).endVertex(); + tessellator.draw(); + } + GlStateManager.shadeModel(GL11.GL_FLAT); + GlStateManager.disableBlend(); + GlStateManager.enableAlpha(); + GlStateManager.enableTexture2D(); + } + + public static void renderTextureArea(TextureArea textureArea, float x, float y, float width, float height, float z) { + double imageU = textureArea.offsetX; + double imageV = textureArea.offsetY; + double imageWidth = textureArea.imageWidth; + double imageHeight = textureArea.imageHeight; + Minecraft.getMinecraft().renderEngine.bindTexture(textureArea.imageLocation); + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder bufferbuilder = tessellator.getBuffer(); + bufferbuilder.begin(7, DefaultVertexFormats.POSITION_TEX); + bufferbuilder.pos(x, y + height, z).tex(imageU, imageV + imageHeight).endVertex(); + bufferbuilder.pos(x + width, y + height, z).tex(imageU + imageWidth, imageV + imageHeight).endVertex(); + bufferbuilder.pos(x + width, y, z).tex(imageU + imageWidth, imageV).endVertex(); + bufferbuilder.pos(x, y, z).tex(imageU, imageV).endVertex(); + tessellator.draw(); + } } diff --git a/src/main/java/gregtech/api/gui/resources/URLTexture.java b/src/main/java/gregtech/api/gui/resources/URLTexture.java new file mode 100644 index 00000000000..7f2fd4679d1 --- /dev/null +++ b/src/main/java/gregtech/api/gui/resources/URLTexture.java @@ -0,0 +1,77 @@ +package gregtech.api.gui.resources; + +import gregtech.api.gui.resources.onlinepic.DownloadThread; +import gregtech.api.gui.resources.onlinepictexture.PictureTexture; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +public class URLTexture implements IGuiTexture{ + private final String url; + @SideOnly(Side.CLIENT) + private DownloadThread downloader; + @SideOnly(Side.CLIENT) + private PictureTexture texture; + @SideOnly(Side.CLIENT) + private boolean failed; + @SideOnly(Side.CLIENT) + private String error; + + + public URLTexture(String url) { + this.url = url; + } + + @SideOnly(Side.CLIENT) + @Override + public void updateTick() { + if(this.texture != null) { + texture.tick(); // gif\video update + } + } + + @Override + public void draw(double x, double y, int width, int height) { + if (url != null &&!this.url.equals("")) { + if (texture != null && texture.hasTexture()) { + texture.render((float)x, (float)y, width, height, 0, 1, 1, false, false); + } else { + this.loadTexture(); + if (failed) { + + } else { + + } + } + } + } + + @SideOnly(Side.CLIENT) + public void loadTexture() { + if (texture == null && !failed) { + if (downloader == null && DownloadThread.activeDownloads < DownloadThread.MAXIMUM_ACTIVE_DOWNLOADS) { + PictureTexture loadedTexture = DownloadThread.loadedImages.get(url); + + if (loadedTexture == null) { + synchronized (DownloadThread.LOCK) { + if (!DownloadThread.loadingImages.contains(url)) { + downloader = new DownloadThread(url); + return; + } + } + } else { + texture = loadedTexture; + } + } + if (downloader != null && downloader.hasFinished()) { + if (downloader.hasFailed()) { + failed = true; + error = downloader.getError(); + DownloadThread.LOGGER.error("Could not load image of " + url + " : " + error); + } else { + texture = DownloadThread.loadImage(downloader); + } + downloader = null; + } + } + } +} diff --git a/src/main/java/gregtech/api/gui/resources/onlinepic/DownloadThread.java b/src/main/java/gregtech/api/gui/resources/onlinepic/DownloadThread.java new file mode 100644 index 00000000000..fb344586ed2 --- /dev/null +++ b/src/main/java/gregtech/api/gui/resources/onlinepic/DownloadThread.java @@ -0,0 +1,260 @@ +package gregtech.api.gui.resources.onlinepic; + +import gregtech.GregTechMod; +import gregtech.api.gui.resources.onlinepictexture.AnimatedPictureTexture; +import gregtech.api.gui.resources.onlinepictexture.OrdinaryTexture; +import gregtech.api.gui.resources.onlinepictexture.PictureTexture; +import gregtech.api.gui.resources.onlinepictexture.VideoTexture; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import org.apache.commons.compress.utils.IOUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import javax.imageio.ImageIO; +import javax.imageio.ImageReadParam; +import javax.imageio.ImageReader; +import javax.imageio.stream.ImageInputStream; +import java.awt.image.BufferedImage; +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLConnection; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.*; + +@SideOnly(Side.CLIENT) +public class DownloadThread extends Thread { + public static final Logger LOGGER = LogManager.getLogger(GregTechMod.class); + + public static final TextureCache TEXTURE_CACHE = new TextureCache(); + public static final DateFormat FORMAT = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z"); + public static final Object LOCK = new Object(); + public static final int MAXIMUM_ACTIVE_DOWNLOADS = 5; + + public static int activeDownloads = 0; + + public static HashMap loadedImages = new HashMap<>(); + public static Set loadingImages = new HashSet<>(); + + private final String url; + + private ProcessedImageData processedImage; + private String error; + private boolean complete; + private boolean isVideo; + + public DownloadThread(String url) { + this.url = url; + synchronized (DownloadThread.LOCK) { + DownloadThread.loadingImages.add(url); + DownloadThread.activeDownloads++; + } + setName("OPF Download \"" + url + "\""); + setDaemon(true); + start(); + } + + public boolean hasFinished() { + return complete; + } + + public boolean hasFailed() { + return hasFinished() && error != null; + } + + public boolean isVideo() { + return isVideo; + } + + public String getError() { + return error; + } + + @Override + public void run() { + Exception exception = null; + try { + byte[] data = load(url); + String type = readType(data); + ByteArrayInputStream in = null; + try { + in = new ByteArrayInputStream(data); + if (type.equalsIgnoreCase("gif")) { + GifDecoder gif = new GifDecoder(); + int status = gif.read(in); + if (status == GifDecoder.STATUS_OK) { + processedImage = new ProcessedImageData(gif); + } else { + LOGGER.error("Failed to read gif: {}", status); + } + } else { + try { + BufferedImage image = ImageIO.read(in); + if (image != null) { + processedImage = new ProcessedImageData(image); + } + } catch (IOException e1) { + exception = e1; + LOGGER.error("Failed to parse BufferedImage from stream", e1); + } + } + } finally { + IOUtils.closeQuietly(in); + } + } catch (FoundVideoException e) { + isVideo = true; + } catch (Exception e) { + exception = e; + LOGGER.error("An exception occurred while loading OPFrame image", e); + } + if (!isVideo && processedImage == null) { + if (exception == null) + error = "download.exception.gif"; + else if (exception.getMessage() == null) + error = "download.exception.invalid"; + else if (exception.getMessage().startsWith("Server returned HTTP response code: 403")) + error = "download.exception.forbidden"; + else if (exception.getMessage().startsWith("Server returned HTTP response code: 404")) + error = "download.exception.notfound"; + else + error = "download.exception.invalid"; + TEXTURE_CACHE.deleteEntry(url); + } + complete = true; + + synchronized (DownloadThread.LOCK) { + DownloadThread.loadingImages.remove(url); + DownloadThread.activeDownloads--; + } + } + + public static byte[] load(String url) throws IOException, FoundVideoException { + TextureCache.CacheEntry entry = TEXTURE_CACHE.getEntry(url); + long requestTime = System.currentTimeMillis(); + URLConnection connection = new URL(url).openConnection(); + connection.addRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:25.0) Gecko/20100101 Firefox/25.0"); + int responseCode = -1; + if (connection instanceof HttpURLConnection) { + HttpURLConnection httpConnection = (HttpURLConnection) connection; + if (entry != null) { + if (entry.getEtag() != null) { + httpConnection.setRequestProperty("If-None-Match", entry.getEtag()); + } else if (entry.getTime() != -1) { + httpConnection.setRequestProperty("If-Modified-Since", FORMAT.format(new Date(entry.getTime()))); + } + } + responseCode = httpConnection.getResponseCode(); + } + InputStream in = null; + try { + in = connection.getInputStream(); + if (!connection.getContentType().startsWith("image")) + throw new FoundVideoException(); + String etag = connection.getHeaderField("ETag"); + long lastModifiedTimestamp; + long expireTimestamp = -1; + String maxAge = connection.getHeaderField("max-age"); + if (maxAge != null && !maxAge.isEmpty()) { + try { + expireTimestamp = requestTime + Long.parseLong(maxAge) * 1000; + } catch (NumberFormatException ignored) {} + } + String expires = connection.getHeaderField("Expires"); + if (expires != null && !expires.isEmpty()) { + try { + expireTimestamp = FORMAT.parse(expires).getTime(); + } catch (ParseException ignored) {} + } + String lastModified = connection.getHeaderField("Last-Modified"); + if (lastModified != null && !lastModified.isEmpty()) { + try { + lastModifiedTimestamp = FORMAT.parse(lastModified).getTime(); + } catch (ParseException e) { + lastModifiedTimestamp = requestTime; + } + } else { + lastModifiedTimestamp = requestTime; + } + if (entry != null) { + if (etag != null && !etag.isEmpty()) { + entry.setEtag(etag); + } + entry.setTime(lastModifiedTimestamp); + if (responseCode == HttpURLConnection.HTTP_NOT_MODIFIED) { + File file = entry.getFile(); + if (file.exists()) { + try (FileInputStream fileStream = new FileInputStream(file)) { + return IOUtils.toByteArray(fileStream); + } + + } + } + } + byte[] data = IOUtils.toByteArray(in); + TEXTURE_CACHE.save(url, etag, lastModifiedTimestamp, expireTimestamp, data); + return data; + } finally { + IOUtils.closeQuietly(in); + } + } + + private static String readType(byte[] input) throws IOException { + InputStream in = null; + try { + in = new ByteArrayInputStream(input); + return readType(in); + } finally { + IOUtils.closeQuietly(in); + } + } + + private static String readType(InputStream input) throws IOException { + ImageInputStream stream = ImageIO.createImageInputStream(input); + Iterator iter = ImageIO.getImageReaders(stream); + if (!iter.hasNext()) { + return ""; + } + ImageReader reader = iter.next(); + + if (reader.getFormatName().equalsIgnoreCase("gif")) + return "gif"; + + ImageReadParam param = reader.getDefaultReadParam(); + reader.setInput(stream, true, true); + try { + reader.read(0, param); + } catch (IOException e) { + LOGGER.error("Failed to parse input format", e); + } finally { + reader.dispose(); + IOUtils.closeQuietly(stream); + } + input.reset(); + return reader.getFormatName(); + } + + public static PictureTexture loadImage(DownloadThread thread) { + PictureTexture texture = null; + + if (!thread.hasFailed()) { + if (thread.isVideo()) + texture = new VideoTexture(thread.url); + else if (thread.processedImage.isAnimated()) + texture = new AnimatedPictureTexture(thread.processedImage); + else + texture = new OrdinaryTexture(thread.processedImage); + } + if (texture != null) + synchronized (LOCK) { + loadedImages.put(thread.url, texture); + } + return texture; + } + + public static class FoundVideoException extends Exception { + + } +} diff --git a/src/main/java/gregtech/api/gui/resources/onlinepic/GifDecoder.java b/src/main/java/gregtech/api/gui/resources/onlinepic/GifDecoder.java new file mode 100644 index 00000000000..425953dab42 --- /dev/null +++ b/src/main/java/gregtech/api/gui/resources/onlinepic/GifDecoder.java @@ -0,0 +1,721 @@ +package gregtech.api.gui.resources.onlinepic; + +import java.awt.*; +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferInt; +import java.io.BufferedInputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.ArrayList; + +/** Class GifDecoder - Decodes a GIF file into one or more frames. + * + * Example: + * + *
+ * {
+ *     @code
+ *     GifDecoder d = new GifDecoder();
+ *     d.read("sample.gif");
+ *     int n = d.getFrameCount();
+ *     for (int i = 0; i < n; i++) {
+ *         BufferedImage frame = d.getFrame(i); // frame i
+ *         int t = d.getDelay(i); // display duration of frame in milliseconds
+ *         // do something with frame
+ *     }
+ * }
+ * 
+ * + * No copyright asserted on the source code of this class. May be used for + * any purpose, however, refer to the Unisys LZW patent for any additional + * restrictions. Please forward any corrections to questions at fmsware.com. + * + * @author Kevin Weiner, FM Software; LZW decoder adapted from John Cristy's ImageMagick. + * @version 1.03 November 2003 */ + +public class GifDecoder { + + /** File read status: No errors. */ + public static final int STATUS_OK = 0; + + /** File read status: Error decoding file (may be partially decoded) */ + public static final int STATUS_FORMAT_ERROR = 1; + + /** File read status: Unable to open source. */ + public static final int STATUS_OPEN_ERROR = 2; + + protected BufferedInputStream in; + protected int status; + + protected int width; // full image width + protected int height; // full image height + protected boolean gctFlag; // global color table used + protected int gctSize; // size of global color table + protected int loopCount = 1; // iterations; 0 = repeat forever + + protected int[] gct; // global color table + protected int[] lct; // local color table + protected int[] act; // active color table + + protected int bgIndex; // background color index + protected int bgColor; // background color + protected int lastBgColor; // previous bg color + protected int pixelAspect; // pixel aspect ratio + + protected boolean lctFlag; // local color table flag + protected boolean interlace; // interlace flag + protected int lctSize; // local color table size + + protected int ix, iy, iw, ih; // current image rectangle + protected Rectangle lastRect; // last image rect + protected BufferedImage image; // current frame + protected BufferedImage lastImage; // previous frame + + protected byte[] block = new byte[256]; // current data block + protected int blockSize = 0; // block size + + // last graphic control extension info + protected int dispose = 0; + // 0=no action; 1=leave in place; 2=restore to bg; 3=restore to prev + protected int lastDispose = 0; + protected boolean transparency = false; // use transparent color + protected int delay = 0; // delay in milliseconds + protected int transIndex; // transparent color index + + protected static final int MaxStackSize = 4096; + // max decoder pixel stack size + + // LZW decoder working arrays + protected short[] prefix; + protected byte[] suffix; + protected byte[] pixelStack; + protected byte[] pixels; + + protected ArrayList frames; // frames read from current file + protected int frameCount; + + static class GifFrame { + public GifFrame(BufferedImage im, int del) { + image = im; + delay = del; + } + + public BufferedImage image; + public int delay; + } + + /** Gets display duration for specified frame. + * + * @param n + * int index of frame + * @return delay in milliseconds */ + public int getDelay(int n) { + // + delay = -1; + if ((n >= 0) && (n < frameCount)) { + delay = ((GifFrame) frames.get(n)).delay; + } + return delay; + } + + /** Gets the number of frames read from file. + * + * @return frame count */ + public int getFrameCount() { + return frameCount; + } + + /** Gets the first (or only) image read. + * + * @return BufferedImage containing first frame, or null if none. */ + public BufferedImage getImage() { + return getFrame(0); + } + + /** Gets the "Netscape" iteration count, if any. + * A count of 0 means repeat indefinitiely. + * + * @return iteration count if one was specified, else 1. */ + public int getLoopCount() { + return loopCount; + } + + /** Creates new frame image from current data (and previous + * frames as specified by their disposition codes). */ + protected void setPixels() { + // expose destination image's pixels as int array + int[] dest = ((DataBufferInt) image.getRaster().getDataBuffer()).getData(); + + // fill in starting image contents based on last image's dispose code + if (lastDispose > 0) { + if (lastDispose == 3) { + // use image before last + int n = frameCount - 2; + if (n > 0) { + lastImage = getFrame(n - 1); + } else { + lastImage = null; + } + } + + if (lastImage != null) { + int[] prev = ((DataBufferInt) lastImage.getRaster().getDataBuffer()).getData(); + System.arraycopy(prev, 0, dest, 0, width * height); + // copy pixels + + if (lastDispose == 2) { + // fill last image rect area with background color + Graphics2D g = image.createGraphics(); + Color c = null; + if (transparency) { + c = new Color(0, 0, 0, 0); // assume background is transparent + } else { + c = new Color(lastBgColor); // use given background color + } + g.setColor(c); + g.setComposite(AlphaComposite.Src); // replace area + g.fill(lastRect); + g.dispose(); + } + } + } + + // copy each source line to the appropriate place in the destination + int pass = 1; + int inc = 8; + int iline = 0; + for (int i = 0; i < ih; i++) { + int line = i; + if (interlace) { + if (iline >= ih) { + pass++; + switch (pass) { + case 2: + iline = 4; + break; + case 3: + iline = 2; + inc = 4; + break; + case 4: + iline = 1; + inc = 2; + } + } + line = iline; + iline += inc; + } + line += iy; + if (line < height) { + int k = line * width; + int dx = k + ix; // start of line in dest + int dlim = dx + iw; // end of dest line + if ((k + width) < dlim) { + dlim = k + width; // past dest edge + } + int sx = i * iw; // start of line in source + while (dx < dlim) { + // map color and insert in destination + int index = (pixels[sx++]) & 0xff; + int c = act[index]; + if (c != 0) { + dest[dx] = c; + } + dx++; + } + } + } + } + + /** Gets the image contents of frame n. + * + * @return BufferedImage representation of frame, or null if n is invalid. */ + public BufferedImage getFrame(int n) { + BufferedImage im = null; + if ((n >= 0) && (n < frameCount)) { + im = ((GifFrame) frames.get(n)).image; + } + return im; + } + + /** Gets image size. + * + * @return GIF image dimensions */ + public Dimension getFrameSize() { + return new Dimension(width, height); + } + + /** Reads GIF image from stream + * + * @param is + * BufferedInputStream containing GIF file. + * @return read status code (0 = no errors) */ + public int read(BufferedInputStream is) { + init(); + if (is != null) { + in = is; + readHeader(); + if (!err()) { + readContents(); + if (frameCount < 0) { + status = STATUS_FORMAT_ERROR; + } + } + } else { + status = STATUS_OPEN_ERROR; + } + try { + is.close(); + } catch (IOException e) { + } + return status; + } + + /** Reads GIF image from stream + * + * @param is + * InputStream containing GIF file. + * @return read status code (0 = no errors) */ + public int read(InputStream is) { + init(); + if (is != null) { + if (!(is instanceof BufferedInputStream)) + is = new BufferedInputStream(is); + in = (BufferedInputStream) is; + readHeader(); + if (!err()) { + readContents(); + if (frameCount < 0) { + status = STATUS_FORMAT_ERROR; + } + } + } else { + status = STATUS_OPEN_ERROR; + } + try { + is.close(); + } catch (IOException e) { + } + return status; + } + + /** Reads GIF file from specified file/URL source + * (URL assumed if name contains ":/" or "file:") + * + * @param name + * String containing source + * @return read status code (0 = no errors) */ + public int read(String name) { + status = STATUS_OK; + try { + name = name.trim().toLowerCase(); + if ((name.indexOf("file:") >= 0) || (name.indexOf(":/") > 0)) { + URL url = new URL(name); + in = new BufferedInputStream(url.openStream()); + } else { + in = new BufferedInputStream(new FileInputStream(name)); + } + status = read(in); + } catch (IOException e) { + status = STATUS_OPEN_ERROR; + } + + return status; + } + + /** Decodes LZW image data into pixel array. + * Adapted from John Cristy's ImageMagick. */ + protected void decodeImageData() { + int NullCode = -1; + int npix = iw * ih; + int available, clear, code_mask, code_size, end_of_information, in_code, old_code, bits, code, count, i, datum, + data_size, first, top, bi, pi; + + if ((pixels == null) || (pixels.length < npix)) { + pixels = new byte[npix]; // allocate new pixel array + } + if (prefix == null) + prefix = new short[MaxStackSize]; + if (suffix == null) + suffix = new byte[MaxStackSize]; + if (pixelStack == null) + pixelStack = new byte[MaxStackSize + 1]; + + // Initialize GIF data stream decoder. + + data_size = read(); + clear = 1 << data_size; + end_of_information = clear + 1; + available = clear + 2; + old_code = NullCode; + code_size = data_size + 1; + code_mask = (1 << code_size) - 1; + for (code = 0; code < clear; code++) { + prefix[code] = 0; + suffix[code] = (byte) code; + } + + // Decode GIF pixel stream. + + datum = bits = count = first = top = pi = bi = 0; + + for (i = 0; i < npix;) { + if (top == 0) { + if (bits < code_size) { + // Load bytes until there are enough bits for a code. + if (count == 0) { + // Read a new data block. + count = readBlock(); + if (count <= 0) + break; + bi = 0; + } + datum += ((block[bi]) & 0xff) << bits; + bits += 8; + bi++; + count--; + continue; + } + + // Get the next code. + + code = datum & code_mask; + datum >>= code_size; + bits -= code_size; + + // Interpret the code + + if ((code > available) || (code == end_of_information)) + break; + if (code == clear) { + // Reset decoder. + code_size = data_size + 1; + code_mask = (1 << code_size) - 1; + available = clear + 2; + old_code = NullCode; + continue; + } + if (old_code == NullCode) { + pixelStack[top++] = suffix[code]; + old_code = code; + first = code; + continue; + } + in_code = code; + if (code == available) { + pixelStack[top++] = (byte) first; + code = old_code; + } + while (code > clear) { + pixelStack[top++] = suffix[code]; + code = prefix[code]; + } + first = (suffix[code]) & 0xff; + + // Add a new string to the string table, + + if (available >= MaxStackSize) { + pixelStack[top++] = (byte) first; + continue; + } + pixelStack[top++] = (byte) first; + prefix[available] = (short) old_code; + suffix[available] = (byte) first; + available++; + if (((available & code_mask) == 0) && (available < MaxStackSize)) { + code_size++; + code_mask += available; + } + old_code = in_code; + } + + // Pop a pixel off the pixel stack. + + top--; + pixels[pi++] = pixelStack[top]; + i++; + } + + for (i = pi; i < npix; i++) { + pixels[i] = 0; // clear missing pixels + } + + } + + /** Returns true if an error was encountered during reading/decoding */ + protected boolean err() { + return status != STATUS_OK; + } + + /** Initializes or re-initializes reader */ + protected void init() { + status = STATUS_OK; + frameCount = 0; + frames = new ArrayList(); + gct = null; + lct = null; + } + + /** Reads a single byte from the input stream. */ + protected int read() { + int curByte = 0; + try { + curByte = in.read(); + } catch (IOException e) { + status = STATUS_FORMAT_ERROR; + } + return curByte; + } + + /** Reads next variable length block from input. + * + * @return number of bytes stored in "buffer" */ + protected int readBlock() { + blockSize = read(); + int n = 0; + if (blockSize > 0) { + try { + int count = 0; + while (n < blockSize) { + count = in.read(block, n, blockSize - n); + if (count == -1) + break; + n += count; + } + } catch (IOException e) { + } + + if (n < blockSize) { + status = STATUS_FORMAT_ERROR; + } + } + return n; + } + + /** Reads color table as 256 RGB integer values + * + * @param ncolors + * int number of colors to read + * @return int array containing 256 colors (packed ARGB with full alpha) */ + protected int[] readColorTable(int ncolors) { + int nbytes = 3 * ncolors; + int[] tab = null; + byte[] c = new byte[nbytes]; + int n = 0; + try { + n = in.read(c); + } catch (IOException e) { + } + if (n < nbytes) { + status = STATUS_FORMAT_ERROR; + } else { + tab = new int[256]; // max size to avoid bounds checks + int i = 0; + int j = 0; + while (i < ncolors) { + int r = (c[j++]) & 0xff; + int g = (c[j++]) & 0xff; + int b = (c[j++]) & 0xff; + tab[i++] = 0xff000000 | (r << 16) | (g << 8) | b; + } + } + return tab; + } + + /** Main file parser. Reads GIF content blocks. */ + protected void readContents() { + // read GIF file content blocks + boolean done = false; + while (!(done || err())) { + int code = read(); + switch (code) { + + case 0x2C: // image separator + readImage(); + break; + + case 0x21: // extension + code = read(); + switch (code) { + case 0xf9: // graphics control extension + readGraphicControlExt(); + break; + + case 0xff: // application extension + readBlock(); + String app = ""; + for (int i = 0; i < 11; i++) { + app += (char) block[i]; + } + if (app.equals("NETSCAPE2.0")) { + readNetscapeExt(); + } else + skip(); // don't care + break; + + default: // uninteresting extension + skip(); + } + break; + + case 0x3b: // terminator + done = true; + break; + + case 0x00: // bad byte, but keep going and see what happens + break; + + default: + status = STATUS_FORMAT_ERROR; + } + } + } + + /** Reads Graphics Control Extension values */ + protected void readGraphicControlExt() { + read(); // block size + int packed = read(); // packed fields + dispose = (packed & 0x1c) >> 2; // disposal method + if (dispose == 0) { + dispose = 1; // elect to keep old image if discretionary + } + transparency = (packed & 1) != 0; + delay = readShort() * 10; // delay in milliseconds + transIndex = read(); // transparent color index + read(); // block terminator + } + + /** Reads GIF file header information. */ + protected void readHeader() { + String id = ""; + for (int i = 0; i < 6; i++) { + id += (char) read(); + } + if (!id.startsWith("GIF")) { + status = STATUS_FORMAT_ERROR; + return; + } + + readLSD(); + if (gctFlag && !err()) { + gct = readColorTable(gctSize); + bgColor = gct[bgIndex]; + } + } + + /** Reads next frame image */ + protected void readImage() { + ix = readShort(); // (sub)image position & size + iy = readShort(); + iw = readShort(); + ih = readShort(); + + int packed = read(); + lctFlag = (packed & 0x80) != 0; // 1 - local color table flag + interlace = (packed & 0x40) != 0; // 2 - interlace flag + // 3 - sort flag + // 4-5 - reserved + lctSize = 2 << (packed & 7); // 6-8 - local color table size + + if (lctFlag) { + lct = readColorTable(lctSize); // read table + act = lct; // make local table active + } else { + act = gct; // make global table active + if (bgIndex == transIndex) + bgColor = 0; + } + int save = 0; + if (transparency) { + save = act[transIndex]; + act[transIndex] = 0; // set transparent color if specified + } + + if (act == null) { + status = STATUS_FORMAT_ERROR; // no color table defined + } + + if (err()) + return; + + decodeImageData(); // decode pixel data + skip(); + + if (err()) + return; + + frameCount++; + + // create new image to receive frame data + image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB_PRE); + + setPixels(); // transfer pixel data to image + + frames.add(new GifFrame(image, delay)); // add image to frame list + + if (transparency) { + act[transIndex] = save; + } + resetFrame(); + + } + + /** Reads Logical Screen Descriptor */ + protected void readLSD() { + + // logical screen size + width = readShort(); + height = readShort(); + + // packed fields + int packed = read(); + gctFlag = (packed & 0x80) != 0; // 1 : global color table flag + // 2-4 : color resolution + // 5 : gct sort flag + gctSize = 2 << (packed & 7); // 6-8 : gct size + + bgIndex = read(); // background color index + pixelAspect = read(); // pixel aspect ratio + } + + /** Reads Netscape extenstion to obtain iteration count */ + protected void readNetscapeExt() { + do { + readBlock(); + if (block[0] == 1) { + // loop count sub-block + int b1 = (block[1]) & 0xff; + int b2 = (block[2]) & 0xff; + loopCount = (b2 << 8) | b1; + } + } while ((blockSize > 0) && !err()); + } + + /** Reads next 16-bit value, LSB first */ + protected int readShort() { + // read 16-bit value, LSB first + return read() | (read() << 8); + } + + /** Resets frame state for reading next image. */ + protected void resetFrame() { + lastDispose = dispose; + lastRect = new Rectangle(ix, iy, iw, ih); + lastImage = image; + lastBgColor = bgColor; + int dispose = 0; + boolean transparency = false; + int delay = 0; + lct = null; + } + + /** Skips variable length blocks up to and including + * next zero length block. */ + protected void skip() { + do { + readBlock(); + } while ((blockSize > 0) && !err()); + } +} diff --git a/src/main/java/gregtech/api/gui/resources/onlinepic/ProcessedImageData.java b/src/main/java/gregtech/api/gui/resources/onlinepic/ProcessedImageData.java new file mode 100644 index 00000000000..794c2f28afe --- /dev/null +++ b/src/main/java/gregtech/api/gui/resources/onlinepic/ProcessedImageData.java @@ -0,0 +1,137 @@ +package gregtech.api.gui.resources.onlinepic; + +import org.lwjgl.BufferUtils; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL12; + +import java.awt.*; +import java.awt.image.BufferedImage; +import java.nio.ByteBuffer; + + +public class ProcessedImageData { + private final int width; + private final int height; + private final Frame[] frames; + private final long[] delay; + private final long duration; + + public ProcessedImageData(BufferedImage image) { + width = image.getWidth(); + height = image.getHeight(); + frames = new Frame[] { loadFrom(image) }; + delay = new long[] { 0 }; + duration = 0; + } + + public ProcessedImageData(GifDecoder decoder) { + Dimension frameSize = decoder.getFrameSize(); + width = (int) frameSize.getWidth(); + height = (int) frameSize.getHeight(); + frames = new Frame[decoder.getFrameCount()]; + delay = new long[decoder.getFrameCount()]; + long time = 0; + for (int i = 0; i < decoder.getFrameCount(); i++) { + frames[i] = loadFrom(decoder.getFrame(i)); + delay[i] = time; + time += decoder.getDelay(i); + } + duration = time; + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public long[] getDelay() { + return delay; + } + + public long getDuration() { + return duration; + } + + public boolean isAnimated() { + return frames.length > 1; + } + + public int getFrameCount() { + return frames.length; + } + + public int uploadFrame(int index) { + if (index >= 0 && index < frames.length) { + Frame frame = frames[index]; + if (frame != null) { + frames[index] = null; + return uploadFrame(frame.buffer, frame.hasAlpha, width, height); + } + } + return -1; + } + + private static int uploadFrame(ByteBuffer buffer, boolean hasAlpha, int width, int height) { + int textureID = GL11.glGenTextures(); //Generate texture ID + GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureID); //Bind texture ID + + //Setup wrap mode + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE); + + //Setup texture scaling filtering + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); + + if (!hasAlpha) { + GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1); + } + + //Send texel data to OpenGL + GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, hasAlpha ? GL11.GL_RGBA8 : GL11.GL_RGB8, width, height, 0, hasAlpha ? GL11.GL_RGBA : GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, buffer); + + //Return the texture ID so we can bind it later again + return textureID; + } + + private static Frame loadFrom(BufferedImage image) { + int width = image.getWidth(); + int height = image.getHeight(); + int[] pixels = new int[width * height]; + image.getRGB(0, 0, width, height, pixels, 0, width); + boolean hasAlpha = false; + if (image.getColorModel().hasAlpha()) { + for (int pixel : pixels) { + if ((pixel >> 24 & 0xFF) < 0xFF) { + hasAlpha = true; + break; + } + } + } + int bytesPerPixel = hasAlpha ? 4 : 3; + ByteBuffer buffer = BufferUtils.createByteBuffer(width * height * bytesPerPixel); + for (int pixel : pixels) { + buffer.put((byte) ((pixel >> 16) & 0xFF)); // Red component + buffer.put((byte) ((pixel >> 8) & 0xFF)); // Green component + buffer.put((byte) (pixel & 0xFF)); // Blue component + if (hasAlpha) { + buffer.put((byte) ((pixel >> 24) & 0xFF)); // Alpha component. Only for RGBA + } + } + buffer.flip(); + return new Frame(buffer, hasAlpha); + } + + private static class Frame { + private final ByteBuffer buffer; + private final boolean hasAlpha; + + public Frame(ByteBuffer buffer, boolean alpha) { + this.buffer = buffer; + this.hasAlpha = alpha; + } + } +} diff --git a/src/main/java/gregtech/api/gui/resources/onlinepic/TextureCache.java b/src/main/java/gregtech/api/gui/resources/onlinepic/TextureCache.java new file mode 100644 index 00000000000..d48678e5153 --- /dev/null +++ b/src/main/java/gregtech/api/gui/resources/onlinepic/TextureCache.java @@ -0,0 +1,150 @@ +package gregtech.api.gui.resources.onlinepic; + +import net.minecraft.client.Minecraft; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.io.IOUtils; + +import java.io.*; +import java.util.HashMap; +import java.util.Map; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; + +public class TextureCache { + private File cacheDirectory = new File(Minecraft.getMinecraft().gameDir, "opframe_cache"); + private File index = new File(cacheDirectory, "index"); + + private Map entries = new HashMap(); + + public TextureCache() { + if (!cacheDirectory.exists()) { + cacheDirectory.mkdirs(); + } + loadIndex(); + } + + public void save(String url, String etag, long time, long expireTime, byte[] data) { + CacheEntry entry = new CacheEntry(url, etag, time, expireTime); + boolean saved = false; + OutputStream out = null; + try { + out = new FileOutputStream(entry.getFile()); + out.write(data); + saved = true; + } catch (IOException e) { + DownloadThread.LOGGER.error("Failed to save cache entry {}", e, url); + } finally { + IOUtils.closeQuietly(out); + } + if (saved) { + entries.put(url, entry); + saveIndex(); + } + } + + public CacheEntry getEntry(String url) { + return entries.get(url); + } + + private void loadIndex() { + if (index.exists()) { + Map previousEntries = entries; + entries = new HashMap(); + DataInputStream in = null; + try { + in = new DataInputStream(new GZIPInputStream(new FileInputStream(index))); + int length = in.readInt(); + for (int i = 0; i < length; i++) { + String url = in.readUTF(); + String etag = in.readUTF(); + long time = in.readLong(); + long expireTime = in.readLong(); + CacheEntry entry = new CacheEntry(url, etag.length() > 0 ? etag : null, time, expireTime); + entries.put(entry.getUrl(), entry); + } + } catch (IOException e) { + DownloadThread.LOGGER.error("Failed to load cache index", e); + entries = previousEntries; + } finally { + IOUtils.closeQuietly(in); + } + } + } + + private void saveIndex() { + DataOutputStream out = null; + try { + out = new DataOutputStream(new GZIPOutputStream(new FileOutputStream(index))); + out.writeInt(entries.size()); + for (Map.Entry mapEntry : entries.entrySet()) { + CacheEntry entry = mapEntry.getValue(); + out.writeUTF(entry.getUrl()); + out.writeUTF(entry.getEtag() == null ? "" : entry.getEtag()); + out.writeLong(entry.getTime()); + out.writeLong(entry.getExpireTime()); + } + } catch (IOException e) { + DownloadThread.LOGGER.error("Failed to save cache index", e); + } finally { + IOUtils.closeQuietly(out); + } + } + + public void deleteEntry(String url) { + entries.remove(url); + File file = getFile(url); + if (file.exists()) { + file.delete(); + } + } + + private static File getFile(String url) { + return new File(DownloadThread.TEXTURE_CACHE.cacheDirectory, Base64.encodeBase64String(url.getBytes())); + } + + public static class CacheEntry { + private String url; + private String etag; + private long time; + private long expireTime; + + public CacheEntry(String url, String etag, long time, long expireTime) { + this.url = url; + this.etag = etag; + this.time = time; + this.expireTime = expireTime; + } + + public void setEtag(String etag) { + this.etag = etag; + } + + public void setTime(long time) { + this.time = time; + } + + public void setExpireTime(long expireTime) { + this.expireTime = expireTime; + } + + public String getUrl() { + return url; + } + + public String getEtag() { + return etag; + } + + public long getTime() { + return time; + } + + public long getExpireTime() { + return expireTime; + } + + public File getFile() { + return TextureCache.getFile(url); + } + } +} diff --git a/src/main/java/gregtech/api/gui/resources/onlinepictexture/AnimatedPictureTexture.java b/src/main/java/gregtech/api/gui/resources/onlinepictexture/AnimatedPictureTexture.java new file mode 100644 index 00000000000..bee61ca36b3 --- /dev/null +++ b/src/main/java/gregtech/api/gui/resources/onlinepictexture/AnimatedPictureTexture.java @@ -0,0 +1,66 @@ +package gregtech.api.gui.resources.onlinepictexture; + + +import gregtech.api.gui.resources.onlinepic.ProcessedImageData; +import net.minecraft.client.renderer.GlStateManager; + +import java.util.Arrays; + +public class AnimatedPictureTexture extends PictureTexture { + private final int[] textureIDs; + private final long[] delay; + private final long duration; + + private int completedFrames; + private ProcessedImageData imageData; + + public AnimatedPictureTexture(ProcessedImageData image) { + super(image.getWidth(), image.getHeight()); + imageData = image; + textureIDs = new int[image.getFrameCount()]; + delay = image.getDelay(); + duration = image.getDuration(); + Arrays.fill(textureIDs, -1); + } + + @Override + public void tick() { + if (imageData != null) { + long startTime = System.currentTimeMillis(); + int index = 0; + while (completedFrames < textureIDs.length && index < textureIDs.length && System.currentTimeMillis() - startTime < 10) { + while (textureIDs[index] != -1 && index < textureIDs.length - 1) + index++; + if (textureIDs[index] == -1) + textureIDs[index] = uploadFrame(index); + } + } + } + + @Override + public int getTextureID() { + long time = duration > 0 ? System.currentTimeMillis() % duration : 0; + int index = 0; + for (int i = 0; i < delay.length; i++) { + if (delay[i] >= time) { + index = i; + break; + } + } + return textureIDs[index]; + } + + private int uploadFrame(int index) { + int id = imageData.uploadFrame(index); + textureIDs[index] = id; + if (++completedFrames >= imageData.getFrameCount()) { + imageData = null; + } + return id; + } + + @Override + public void release() { + for (int textureID : textureIDs) GlStateManager.deleteTexture(textureID); + } +} diff --git a/src/main/java/gregtech/api/gui/resources/onlinepictexture/OrdinaryTexture.java b/src/main/java/gregtech/api/gui/resources/onlinepictexture/OrdinaryTexture.java new file mode 100644 index 00000000000..2eea82b9ea8 --- /dev/null +++ b/src/main/java/gregtech/api/gui/resources/onlinepictexture/OrdinaryTexture.java @@ -0,0 +1,23 @@ +package gregtech.api.gui.resources.onlinepictexture; + +import gregtech.api.gui.resources.onlinepic.ProcessedImageData; + +public class OrdinaryTexture extends PictureTexture { + + private final int textureID; + + public OrdinaryTexture(ProcessedImageData image) { + super(image.getWidth(), image.getHeight()); + textureID = image.uploadFrame(0); + } + + @Override + public void tick() { + } + + @Override + public int getTextureID() { + return textureID; + } +} + diff --git a/src/main/java/gregtech/api/gui/resources/onlinepictexture/PictureTexture.java b/src/main/java/gregtech/api/gui/resources/onlinepictexture/PictureTexture.java new file mode 100644 index 00000000000..268734fb623 --- /dev/null +++ b/src/main/java/gregtech/api/gui/resources/onlinepictexture/PictureTexture.java @@ -0,0 +1,65 @@ +package gregtech.api.gui.resources.onlinepictexture; + +import gregtech.api.gui.resources.IGuiTexture; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.OpenGlHelper; +import org.lwjgl.opengl.GL11; + +public abstract class PictureTexture implements IGuiTexture { + public int width; + public int height; + + public PictureTexture(int width, int height) { + this.width = width; + this.height = height; + + } + + public void beforeRender() { + + } + + @Override + public void draw(double x, double y, int width, int height) { + render((float)x, (float)y, 1, 1, 0, width, height, false, false); + } + + public void render(float x, float y, float ux, float uv, float rotation, float sizeX, float sizeY, boolean flippedX, boolean flippedY) { + this.beforeRender(); + GlStateManager.color(1,1,1,1); + GlStateManager.enableBlend(); + OpenGlHelper.glBlendFunc(770, 771, 1, 0); + GlStateManager.bindTexture(this.getTextureID()); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); + GlStateManager.pushMatrix(); + GL11.glRotated(rotation, 0, 0, 1); + GlStateManager.enableRescaleNormal(); + GL11.glScaled(sizeX, sizeY, 1); + GL11.glBegin(GL11.GL_POLYGON); + GL11.glTexCoord3f(flippedY ? 1 : 0, flippedX ? 1 : 0, 0); + GL11.glVertex3f(x, y, 0.01f); + GL11.glTexCoord3f(flippedY ? 1 : 0, flippedX ? 0 : 1, 0); + GL11.glVertex3f(x, y + uv, 0.01f); + GL11.glTexCoord3f(flippedY ? 0 : 1, flippedX ? 0 : 1, 0); + GL11.glVertex3f(x + ux, y + uv, 0.01f); + GL11.glTexCoord3f(flippedY ? 0 : 1, flippedX ? 1 : 0, 0); + GL11.glVertex3f(x + ux, y, 0.01f); + GL11.glEnd(); + GlStateManager.popMatrix(); + GlStateManager.disableRescaleNormal(); + GlStateManager.disableBlend(); + } + + public abstract void tick(); + + public abstract int getTextureID(); + + public boolean hasTexture() { + return getTextureID() != -1; + } + + public void release() { + GlStateManager.deleteTexture(getTextureID()); + } +} diff --git a/src/main/java/gregtech/api/gui/resources/onlinepictexture/VideoTexture.java b/src/main/java/gregtech/api/gui/resources/onlinepictexture/VideoTexture.java new file mode 100644 index 00000000000..af5ea14b8fe --- /dev/null +++ b/src/main/java/gregtech/api/gui/resources/onlinepictexture/VideoTexture.java @@ -0,0 +1,19 @@ +package gregtech.api.gui.resources.onlinepictexture; + +public class VideoTexture extends PictureTexture { + //TODO implementations of it in the future + + public VideoTexture(String url) { + super(100, 100); + } + + @Override + public void tick() { + + } + + @Override + public int getTextureID() { + return 0; + } +} diff --git a/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java b/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java index 6552bfb23ab..286c38be809 100644 --- a/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java +++ b/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java @@ -23,7 +23,6 @@ public class AbstractWidgetGroup extends Widget implements IGhostIngredientTarge protected final List widgets = new ArrayList<>(); private final WidgetGroupUIAccess groupUIAccess = new WidgetGroupUIAccess(); - private boolean isVisible = true; private final boolean isDynamicSized; private boolean initialized = false; @@ -95,14 +94,10 @@ protected Size computeDynamicSize() { } public void setVisible(boolean visible) { - this.isVisible = visible; + super.setVisible(visible); widgets.stream().flatMap(it -> it.getNativeWidgets().stream()).forEach(it -> it.setEnabled(visible)); } - public boolean isVisible() { - return isVisible; - } - protected void addWidget(Widget widget) { if (widget == this) { throw new IllegalArgumentException("Cannot add self"); @@ -153,12 +148,8 @@ protected void clearAllWidgets() { } } - public boolean isWidgetVisible(Widget widget) { - return this.isVisible; - } - public boolean isWidgetClickable(Widget widget) { - return isWidgetVisible(widget); + return isVisible(); } @Override @@ -185,7 +176,7 @@ public List getNativeWidgets() { @Override public List> getPhantomTargets(Object ingredient) { - if (!isVisible) { + if (!isVisible()) { return Collections.emptyList(); } ArrayList> targets = new ArrayList<>(); @@ -199,7 +190,7 @@ public List> getPhantomTargets(Object ingredient) { @Override public Object getIngredientOverMouse(int mouseX, int mouseY) { - if (!isVisible) { + if (!isVisible()) { return Collections.emptyList(); } for (Widget widget : widgets) { @@ -229,7 +220,7 @@ public void updateScreen() { @Override public void drawInForeground(int mouseX, int mouseY) { for (Widget widget : widgets) { - if (isWidgetVisible(widget)) { + if (widget.isVisible()) { widget.drawInForeground(mouseX, mouseY); } } @@ -238,7 +229,7 @@ public void drawInForeground(int mouseX, int mouseY) { @Override public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { for (Widget widget : widgets) { - if (isWidgetVisible(widget)) { + if (widget.isVisible()) { widget.drawInBackground(mouseX, mouseY, partialTicks, context); } } @@ -247,27 +238,52 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender @Override public boolean mouseWheelMove(int mouseX, int mouseY, int wheelDelta) { - return widgets.stream().filter(this::isWidgetClickable).anyMatch(it -> it.mouseWheelMove(mouseX, mouseY, wheelDelta)); + for (Widget widget : widgets) { + if(widget.mouseWheelMove(mouseX, mouseY, wheelDelta)) { + return true; + } + } + return false; } @Override public boolean mouseClicked(int mouseX, int mouseY, int button) { - return widgets.stream().filter(this::isWidgetClickable).anyMatch(it -> it.mouseClicked(mouseX, mouseY, button)); + for (Widget widget : widgets) { + if(widget.mouseClicked(mouseX, mouseY, button)) { + return true; + } + } + return false; } @Override public boolean mouseDragged(int mouseX, int mouseY, int button, long timeDragged) { - return widgets.stream().filter(this::isWidgetClickable).anyMatch(it -> it.mouseDragged(mouseX, mouseY, button, timeDragged)); + for (Widget widget : widgets) { + if(widget.mouseDragged(mouseX, mouseY, button, timeDragged)) { + return true; + } + } + return false; } @Override public boolean mouseReleased(int mouseX, int mouseY, int button) { - return widgets.stream().filter(this::isWidgetClickable).anyMatch(it -> it.mouseReleased(mouseX, mouseY, button)); + for (Widget widget : widgets) { + if(widget.mouseReleased(mouseX, mouseY, button)) { + return true; + } + } + return false; } @Override public boolean keyTyped(char charTyped, int keyCode) { - return widgets.stream().filter(this::isWidgetClickable).anyMatch(it -> it.keyTyped(charTyped, keyCode)); + for (Widget widget : widgets) { + if(widget.keyTyped(charTyped, keyCode)) { + return true; + } + } + return false; } @Override diff --git a/src/main/java/gregtech/api/gui/widgets/TabGroup.java b/src/main/java/gregtech/api/gui/widgets/TabGroup.java index bbe6cfedf71..d9741df338e 100644 --- a/src/main/java/gregtech/api/gui/widgets/TabGroup.java +++ b/src/main/java/gregtech/api/gui/widgets/TabGroup.java @@ -141,7 +141,6 @@ private static boolean isMouseOverTab(int mouseX, int mouseY, int[] tabSizes) { return mouseX >= minX && mouseY >= minY && mouseX < maxX && mouseY < maxY; } - @Override public boolean isWidgetVisible(Widget widget) { return tabWidgets.containsKey(selectedTabIndex) && tabWidgets.get(selectedTabIndex) == widget; } diff --git a/src/main/java/gregtech/api/gui/widgets/WidgetGroup.java b/src/main/java/gregtech/api/gui/widgets/WidgetGroup.java index 0bea41fee67..9cd81ffd057 100644 --- a/src/main/java/gregtech/api/gui/widgets/WidgetGroup.java +++ b/src/main/java/gregtech/api/gui/widgets/WidgetGroup.java @@ -22,4 +22,14 @@ public WidgetGroup(Position position, Size size) { public void addWidget(Widget widget) { super.addWidget(widget); } + + @Override + public void removeWidget(Widget widget) { + super.removeWidget(widget); + } + + @Override + public void clearAllWidgets() { + super.clearAllWidgets(); + } } diff --git a/src/main/java/gregtech/api/terminal/TerminalBuilder.java b/src/main/java/gregtech/api/terminal/TerminalBuilder.java index 0a89229be3b..fb667768b4c 100644 --- a/src/main/java/gregtech/api/terminal/TerminalBuilder.java +++ b/src/main/java/gregtech/api/terminal/TerminalBuilder.java @@ -1,4 +1,25 @@ package gregtech.api.terminal; +import gregtech.api.terminal.app.*; +import gregtech.api.terminal.app.guide.ItemGuideApp; +import gregtech.api.terminal.app.guide.MultiBlockGuideApp; +import gregtech.api.terminal.app.guide.SimpleMachineGuideApp; +import gregtech.api.terminal.app.guide.TutorialGuideApp; + +import java.util.ArrayList; +import java.util.List; + public class TerminalBuilder { + private static final List appRegister = new ArrayList<>(); + + public static void init() { + appRegister.add(new SimpleMachineGuideApp()); + appRegister.add(new MultiBlockGuideApp()); + appRegister.add(new ItemGuideApp()); + appRegister.add(new TutorialGuideApp()); + } + + public static List getApplications() { + return appRegister; + } } diff --git a/src/main/java/gregtech/api/terminal/app/AbstractApplication.java b/src/main/java/gregtech/api/terminal/app/AbstractApplication.java new file mode 100644 index 00000000000..b1d2fd1ffaf --- /dev/null +++ b/src/main/java/gregtech/api/terminal/app/AbstractApplication.java @@ -0,0 +1,32 @@ +package gregtech.api.terminal.app; + +import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.widgets.WidgetGroup; + +public abstract class AbstractApplication { + protected final String name; + protected final IGuiTexture icon; + + public AbstractApplication (String name, IGuiTexture icon) { + this.name = name; + this.icon = icon; + } + + public String getName() { + return name; + } + + public IGuiTexture getIcon() { + return icon; + } + + public void loadApp(WidgetGroup group, boolean isClient) { + + } + + public void unloadApp(boolean isClient) { + + } + +} diff --git a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java new file mode 100644 index 00000000000..4156d7a2abb --- /dev/null +++ b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java @@ -0,0 +1,114 @@ +package gregtech.api.terminal.app.guide; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import gregtech.api.GTValues; +import gregtech.api.gui.GuiTextures; +import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.terminal.app.AbstractApplication; +import gregtech.api.terminal.gui.widgets.guide.*; +import gregtech.api.terminal.util.TreeNode; +import net.minecraft.client.Minecraft; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.Tuple; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public abstract class GuideApp extends AbstractApplication { + private static final Map REGISTER_WIDGETS = new HashMap<>(); + static { //register guide widgets + REGISTER_WIDGETS.put("textbox", new TextBoxWidget()); + REGISTER_WIDGETS.put("image", new ImageWidget()); + } + private GuidePageWidget pageWidget; + public GuideApp(String name, IGuiTexture icon) { + super(name, icon); + } + + @Override + public void loadApp(WidgetGroup group, boolean isClient) { + pageWidget = null; + if (isClient && getTree() != null) { + group.addWidget( + new TextTreeWidget<>(0, 0, 100, 232, getTree(), leaf -> { + if (pageWidget != null) { + group.removeWidget(pageWidget); + } + pageWidget = loadLeaf(leaf); + group.addWidget(pageWidget); + }, this::itemIcon, this::itemName).setNodeTexture(GuiTextures.BORDERED_BACKGROUND).setLeafTexture(GuiTextures.SLOT_DARKENED) + ); + } + } + + protected IGuiTexture itemIcon(T item) { + return null; + } + + protected String itemName(T item) { + return null; + } + + + protected abstract TreeNode> getTree(); + + public static JsonObject getConfig(String fileName) { + try { + InputStream inputStream = Minecraft.getMinecraft().getResourceManager().getResource(new ResourceLocation(GTValues.MODID, fileName)).getInputStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); + JsonElement je = new Gson().fromJson(reader, JsonElement.class); + reader.close(); + inputStream.close(); + return je.getAsJsonObject(); + } catch (IOException e) { + return null; + } + } + + private GuidePageWidget loadLeaf(TreeNode> leaf) { + GuidePageWidget page = new GuidePageWidget(100, 0, 200, 232); + if (leaf.isLeaf() && leaf.content != null) { + JsonObject config = leaf.content.getSecond(); + // add title + Widget title = new TextBoxWidget(5, 2, 190, + Collections.singletonList(config.get("title").getAsString()), + 0, 15, 0xffffffff, 0x6fff0000, 0xff000000, + true, true); + page.addWidget(title); + + // add stream widgets + if (config.has("stream")) { + int y = title.getSize().height + 10; + for (JsonElement element : config.getAsJsonArray("stream")) { + JsonObject widgetConfig = element.getAsJsonObject(); + Widget widget = REGISTER_WIDGETS.get(widgetConfig.get("type").getAsString()).createStreamWidget(5, y, 190, widgetConfig); + y += widget.getSize().height + 5; + page.addWidget(widget); + } + } + // add fixed widgets + if (config.has("fixed")) { + for (JsonElement element : config.getAsJsonArray("fixed")) { + JsonObject widgetConfig = element.getAsJsonObject(); + Widget widget = REGISTER_WIDGETS.get(widgetConfig.get("type").getAsString()).createFixedWidget( + widgetConfig.get("x").getAsInt(), + widgetConfig.get("y").getAsInt(), + widgetConfig.get("width").getAsInt(), + widgetConfig.get("height").getAsInt(), + widgetConfig); + page.addWidget(widget); + } + } + } + return page; + } +} diff --git a/src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java new file mode 100644 index 00000000000..a79e4d4acc6 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java @@ -0,0 +1,34 @@ +package gregtech.api.terminal.app.guide; + +import com.google.gson.JsonObject; +import gregtech.api.gui.resources.ItemStackTexture; +import gregtech.api.items.metaitem.MetaItem; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.terminal.util.TreeNode; +import gregtech.common.items.MetaItems; +import net.minecraft.util.Tuple; +import net.minecraftforge.fml.common.FMLCommonHandler; + +public class ItemGuideApp extends GuideApp> { + private static TreeNode, JsonObject>> ROOT; + private static JsonObject DEFAULT; + static { + if (FMLCommonHandler.instance().getSide().isClient()) { + ROOT = new TreeNode<>(0,"root"); + DEFAULT = getConfig("terminal/guide/items/default.json"); + } + } + + public ItemGuideApp() { + super("Items Machines", new ItemStackTexture(MetaItems.SCANNER.getStackForm())); + } + + @Override + protected TreeNode, JsonObject>> getTree() { + return ROOT; + } + + public static void registerItem(MetaTileEntity mte) { + + } +} diff --git a/src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java new file mode 100644 index 00000000000..311e0dbec03 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java @@ -0,0 +1,47 @@ +package gregtech.api.terminal.app.guide; + +import com.google.gson.JsonObject; +import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.resources.ItemStackTexture; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.terminal.util.TreeNode; +import gregtech.common.metatileentities.MetaTileEntities; +import net.minecraft.util.Tuple; +import net.minecraftforge.fml.common.FMLCommonHandler; + +public class MultiBlockGuideApp extends GuideApp { + private static TreeNode> ROOT; + private static JsonObject DEFAULT; + static { + if (FMLCommonHandler.instance().getSide().isClient()) { + ROOT = new TreeNode<>(0, "root"); + DEFAULT = getConfig("terminal/guide/multiblocks/default.json"); + } + } + + public MultiBlockGuideApp() { + super("Multi-Block Machines", new ItemStackTexture(MetaTileEntities.ELECTRIC_BLAST_FURNACE.getStackForm())); + } + + @Override + protected TreeNode> getTree() { + return ROOT; + } + + @Override + protected IGuiTexture itemIcon(MetaTileEntity item) { + return new ItemStackTexture(item.getStackForm()); + } + + public static void registerMultiBlock(MetaTileEntity mte) { + if (FMLCommonHandler.instance().getSide().isClient()) { + JsonObject config = getConfig("terminal/guide/multiblocks/" + mte.metaTileEntityId.getPath() + ".json"); + if (config == null) { + ROOT.getOrCreateChild("default").addContent(mte.getMetaFullName(), new Tuple<>(mte, DEFAULT)); + } else { + ROOT.getOrCreateChild(config.get("section").getAsString()).addContent(mte.getMetaFullName(), new Tuple<>(mte, config)); + } + } + } + +} diff --git a/src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java new file mode 100644 index 00000000000..633e4943ad9 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java @@ -0,0 +1,46 @@ +package gregtech.api.terminal.app.guide; + +import com.google.gson.JsonObject; +import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.resources.ItemStackTexture; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.terminal.util.TreeNode; +import gregtech.common.metatileentities.MetaTileEntities; +import net.minecraft.util.Tuple; +import net.minecraftforge.fml.common.FMLCommonHandler; + +public class SimpleMachineGuideApp extends GuideApp { + private static TreeNode> ROOT; + private static JsonObject DEFAULT; + static { + if (FMLCommonHandler.instance().getSide().isClient()) { + ROOT = new TreeNode<>(0,"root"); + DEFAULT = getConfig("terminal/guide/simplemachines/default.json"); + } + } + + public SimpleMachineGuideApp() { + super("Simple Machines", new ItemStackTexture(MetaTileEntities.CHEMICAL_REACTOR[0].getStackForm())); + } + + @Override + protected TreeNode> getTree() { + return ROOT; + } + + @Override + protected IGuiTexture itemIcon(MetaTileEntity item) { + return new ItemStackTexture(item.getStackForm()); + } + + public static void registerSimpleMachine(MetaTileEntity mte) { + if (FMLCommonHandler.instance().getSide().isClient()) { + JsonObject config = getConfig("terminal/guide/simplemachines/" + mte.metaTileEntityId.getPath() + ".json"); + if (config == null) { + ROOT.getOrCreateChild("default").addContent(mte.getMetaFullName(), new Tuple<>(mte, DEFAULT)); + } else { + ROOT.getOrCreateChild(config.get("section").getAsString()).addContent(mte.getMetaFullName(), new Tuple<>(mte, config)); + } + } + } +} diff --git a/src/main/java/gregtech/api/terminal/app/guide/TutorialGuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/TutorialGuideApp.java new file mode 100644 index 00000000000..32aad915681 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/app/guide/TutorialGuideApp.java @@ -0,0 +1,46 @@ +package gregtech.api.terminal.app.guide; + +import com.google.gson.JsonObject; +import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.resources.ItemStackTexture; +import gregtech.api.terminal.util.TreeNode; +import net.minecraft.init.Items; +import net.minecraft.util.Tuple; +import net.minecraftforge.fml.common.FMLCommonHandler; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URL; + +public class TutorialGuideApp extends GuideApp { + private static TreeNode> ROOT; + static { + if (FMLCommonHandler.instance().getSide().isClient()) { + ROOT = new TreeNode<>(0,"root"); + try { + URL folder = ClassLoader.getSystemClassLoader().getResource("assets/gregtech/terminal/guide/tutorials"); + if (folder != null) { + new BufferedReader(new InputStreamReader(folder.openStream())).lines().forEach(file->{ + JsonObject config = getConfig("terminal/guide/tutorials/" + file); + if (config != null) { + ROOT.getOrCreateChild(config.get("section").getAsString()).addContent(config.get("title").getAsString(), new Tuple<>(null, config)); + } + }); + + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + public TutorialGuideApp() { + super("Tutorials", new ItemStackTexture(Items.PAPER)); + } + + @Override + protected TreeNode> getTree() { + return ROOT; + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/CircleButton.java b/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java similarity index 88% rename from src/main/java/gregtech/api/terminal/gui/widgets/CircleButton.java rename to src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java index 77bd34dcb9e..9eadc58360f 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/CircleButton.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java @@ -15,7 +15,7 @@ import java.util.Collections; import java.util.function.Consumer; -public class CircleButton extends Widget { +public class CircleButtonWidget extends Widget { private int hoverTick; private boolean isHover; private String hoverText; @@ -27,33 +27,33 @@ public class CircleButton extends Widget { new Color(255, 255, 255).getRGB(), }; - public CircleButton(int x, int y, int r) { + public CircleButtonWidget(int x, int y, int r) { super(new Position(x - r, y - r), new Size(2 * r, 2 * r)); } - public CircleButton setIcon(IGuiTexture icon) { + public CircleButtonWidget setIcon(IGuiTexture icon) { this.icon = icon; return this; } - public CircleButton setHoverText(String hoverText) { + public CircleButtonWidget setHoverText(String hoverText) { this.hoverText = hoverText; return this; } - public CircleButton setColors(int stroke, int strokeAnima, int fill) { + public CircleButtonWidget setColors(int stroke, int strokeAnima, int fill) { colors[0] = stroke; colors[1] = strokeAnima; colors[2] = fill; return this; } - public CircleButton setFillColors(int fill) { + public CircleButtonWidget setFillColors(int fill) { colors[2] = fill; return this; } - public CircleButton setClickListener(Consumer onPressed) { + public CircleButtonWidget setClickListener(Consumer onPressed) { this.onPressCallback = onPressed; return this; } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/TerminalMenu.java b/src/main/java/gregtech/api/terminal/gui/widgets/TerminalMenu.java deleted file mode 100644 index 0f0de4667a7..00000000000 --- a/src/main/java/gregtech/api/terminal/gui/widgets/TerminalMenu.java +++ /dev/null @@ -1,48 +0,0 @@ -package gregtech.api.terminal.gui.widgets; - -import gregtech.api.gui.IRenderContext; -import gregtech.api.gui.Widget; -import gregtech.api.gui.resources.IGuiTexture; -import gregtech.api.gui.widgets.AbstractWidgetGroup; -import gregtech.api.util.Position; -import gregtech.api.util.Size; - -import java.util.function.Supplier; - -public class TerminalMenu extends AbstractWidgetGroup { - private IGuiTexture background; - private Widget activeContent; - private CircleButton activeButton; - public TerminalMenu(int xPosition, int yPosition, int width, int height) { - super(new Position(xPosition, yPosition), new Size(width, height)); - } - - public TerminalMenu setBackGround(IGuiTexture background) { - this.background = background; - return this; - } - - public TerminalMenu addApp(IGuiTexture icon, String nameKey, Supplier content){ - CircleButton button = new CircleButton(27,40,12).setIcon(icon).setHoverText(nameKey); - button.setClickListener(clickData -> { - if (button != activeButton) { - removeWidget(activeContent); - if(content != null) { - activeContent = content.get(); - addWidget(activeContent); - } - activeButton.setFillColors(0xffffffff); - activeButton = button; - activeButton.setFillColors(0xFF929292); - } - }); - this.addWidget(button); - return this; - } - - @Override - public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { - background.draw(this.getPosition().x, this.getPosition().y, this.getSize().width, this.getSize().height); - super.drawInBackground(mouseX, mouseY, partialTicks, context); - } -} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/TerminalMenuWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/TerminalMenuWidget.java new file mode 100644 index 00000000000..673d6b5b7c8 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/TerminalMenuWidget.java @@ -0,0 +1,54 @@ +package gregtech.api.terminal.gui.widgets; + +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.widgets.AbstractWidgetGroup; +import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.terminal.app.AbstractApplication; +import gregtech.api.util.Position; +import gregtech.api.util.Size; + +public class TerminalMenuWidget extends AbstractWidgetGroup { + private int appCount; + private IGuiTexture background; + private final WidgetGroup activeContent; + private CircleButtonWidget activeButton; + public TerminalMenuWidget(int xPosition, int yPosition, int width, int height) { + super(new Position(xPosition, yPosition), new Size(width, height)); + this.activeContent = new WidgetGroup(new Position(27,-19), new Size(300, 232)); + this.addWidget(activeContent); + } + + public TerminalMenuWidget setBackground(IGuiTexture background) { + this.background = background; + return this; + } + + public void addApp(AbstractApplication application){ + int x = this.getSize().width / 2; + int r = 12; + int y = appCount * (2 * r + 4) + r; + CircleButtonWidget button = new CircleButtonWidget(x,y,r).setIcon(application.getIcon()).setHoverText(application.getName()); + button.setClickListener(clickData -> { + if (button != activeButton) { + activeContent.clearAllWidgets(); + application.loadApp(activeContent, clickData.isClient); + if (activeButton != null) { + activeButton.setFillColors(0xffffffff); + } + activeButton = button; + activeButton.setFillColors(0xFFAAF1DB); + } + }); + this.addWidget(button); + appCount++; + } + + @Override + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + if( background != null) { + background.draw(this.getPosition().x, this.getPosition().y, this.getSize().width, this.getSize().height); + } + super.drawInBackground(mouseX, mouseY, partialTicks, context); + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java new file mode 100644 index 00000000000..44b298de62b --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java @@ -0,0 +1,83 @@ +package gregtech.api.terminal.gui.widgets.guide; + + +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.resources.URLTexture; +import gregtech.api.gui.widgets.AbstractWidgetGroup; +import gregtech.api.util.Position; +import gregtech.api.util.RenderUtil; +import gregtech.api.util.Size; +import javafx.geometry.Pos; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.util.math.MathHelper; + +import static gregtech.api.gui.impl.ModularUIGui.*; + +public class GuidePageWidget extends AbstractWidgetGroup { + private IGuiTexture background; + private int scrollYOffset; + private int maxHeight; + + public GuidePageWidget(int xPosition, int yPosition, int width, int height) { + super(new Position(xPosition, yPosition), new Size(width, height)); + } + + public GuidePageWidget setBackground(IGuiTexture background) { + this.background = background; + return this; + } + + protected void setScrollYOffset(int scrollYOffset) { + if (scrollYOffset == this.scrollYOffset) return; + this.scrollYOffset = scrollYOffset; + int minY = this.scrollYOffset + getPosition().y; + int maxY = minY + getSize().height; + for (Widget widget : widgets) { + if (widget.getPosition().y < maxY && widget.getPosition().y + widget.getSize().height > minY) { + widget.setVisible(true); + } + } + } + + @Override + public void addWidget(Widget widget) { + maxHeight = Math.max(maxHeight, widget.getSize().height + widget.getPosition().y); + super.addWidget(widget); + if (widget instanceof IGuideWidget) { + ((IGuideWidget) widget).setPage(this); + } + } + + @Override + public boolean mouseWheelMove(int mouseX, int mouseY, int wheelDelta) { + if (this.isMouseOverElement(mouseX, mouseY, true)) { + int moveDelta = -MathHelper.clamp(wheelDelta, -1, 1) * 5; + setScrollYOffset(MathHelper.clamp(scrollYOffset + moveDelta, 0, Math.max(maxHeight - getSize().height, 0))); + return true; + } + return false; + } + + @Override + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + Position position = getPosition(); + Size size = getSize(); + if (background != null) { + background.draw(position.x, position.y, size.width, size.height); + } else { + gregtech.api.gui.resources.RenderUtil.renderRect(position.x, position.y, size.width, size.height, 0, 0xffffffff); + } + GlStateManager.translate(0, -scrollYOffset, 0); + RenderUtil.useScissor(position.x, position.y, size.width, size.height, ()->{ + for (Widget widget : widgets) { + if (widget.isVisible()) { + widget.drawInBackground(mouseX, mouseY, partialTicks, context); + } + } + GlStateManager.color(rColorForOverlay, gColorForOverlay, bColorForOverlay, 1.0F); + }); + GlStateManager.translate(0, scrollYOffset, 0); + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java new file mode 100644 index 00000000000..395c3f36e6c --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java @@ -0,0 +1,69 @@ +package gregtech.api.terminal.gui.widgets.guide; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.sun.istack.internal.Nullable; +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.Widget; +import gregtech.api.util.Position; +import gregtech.api.util.Size; + +public abstract class GuideWidget extends Widget implements IGuideWidget { + //config + public String ref; + public int fill; + public int stroke; + public int stroke_width = 1; + + private static final Gson GSON = new Gson(); + protected transient GuidePageWidget page; + + public GuideWidget(int x, int y, int width, int height) { + super(x, y, width, height); + } + + public GuideWidget(){ + super(Position.ORIGIN, Size.ZERO); + } + + @Override + public Widget createStreamWidget(int x, int y, int pageWidth, JsonObject config) { + GuideWidget widget = GSON.fromJson(config, this.getClass()); + widget.setSelfPosition(new Position(x, y)); + widget.setSize(new Size(pageWidth, 0)); + return widget.initStream(x, y, pageWidth, config); + } + + @Override + public Widget createFixedWidget(int x, int y, int width, int height, JsonObject config) { + GuideWidget widget = GSON.fromJson(config, this.getClass()); + widget.setSelfPosition(new Position(x, y)); + widget.setSize(new Size(width, height)); + return widget.initFixed(x, y, width, height, config); + } + + protected Widget initStream(int x, int y, int pageWidth, @Nullable JsonObject config) { + return initFixed(x, y, pageWidth, 0, config); + } + + protected Widget initFixed(int x, int y, int width, int height, @Nullable JsonObject config) { + return this; + } + + @Override + public void setPage(GuidePageWidget page) { + this.page = page; + } + + @Override + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + Position position = getPosition(); + Size size = getSize(); + if(stroke != 0) { + drawBorder(position.x, position.y, size.width, size.height, stroke, stroke_width); + } + if (fill != 0) { + drawGradientRect(position.x, position.y, size.width, size.height, fill, fill); + } + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java new file mode 100644 index 00000000000..9bec77e3724 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java @@ -0,0 +1,10 @@ +package gregtech.api.terminal.gui.widgets.guide; + +import com.google.gson.JsonObject; +import gregtech.api.gui.Widget; + +public interface IGuideWidget { + Widget createStreamWidget(int x, int y, int pageWidth, JsonObject config); + Widget createFixedWidget(int x, int y, int width, int height, JsonObject config); + void setPage(GuidePageWidget page); +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java new file mode 100644 index 00000000000..f2f0da27cf9 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java @@ -0,0 +1,61 @@ +package gregtech.api.terminal.gui.widgets.guide; + +import com.google.gson.JsonObject; +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.resources.ItemStackTexture; +import gregtech.api.gui.resources.TextureArea; +import gregtech.api.gui.resources.URLTexture; +import gregtech.api.util.Position; +import gregtech.api.util.Size; +import net.minecraft.item.Item; + +public class ImageWidget extends GuideWidget{ + //config + public String form; + public String source; + public int width; + public int height; + + public IGuiTexture image; + + @Override + public void updateScreen() { + if (image != null) { + image.updateTick(); + } + } + + @Override + protected Widget initStream(int x, int y, int pageWidth, JsonObject config) { + this.setSelfPosition(new Position(x + (pageWidth - width) / 2, y)); + this.setSize(new Size(width, height)); + return super.initStream(x, y, pageWidth, config); + } + + @Override + protected Widget initFixed(int x, int y, int width, int height, JsonObject config) { + switch (form) { + case "url": + image = new URLTexture(source); + break; + case "item": + image = new ItemStackTexture(Item.getByNameOrId(source)); + break; + case "resource": + image = TextureArea.fullImage(source); + break; + } + return this; + } + + @Override + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + if (image != null) { + super.drawInBackground(mouseX, mouseY, partialTicks,context); + Position position = getPosition(); + image.draw(position.x, position.y, width, height); + } + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java new file mode 100644 index 00000000000..7f0d67d3e0a --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java @@ -0,0 +1,83 @@ +package gregtech.api.terminal.gui.widgets.guide; + +import com.google.gson.JsonObject; +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.RenderUtil; +import gregtech.api.util.Position; +import gregtech.api.util.Size; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.resources.I18n; + +import java.util.ArrayList; +import java.util.List; + +public class TextBoxWidget extends GuideWidget { + // config + public List content; + public int space = 1; + public int fontSize = 9; + public int fontColor = 0xff000000; + public boolean isShadow = false; + public boolean isCenter = false; + + private List textLines; + + public TextBoxWidget(int x, int y, int width, List content, int space, int fontSize, int fontColor, int fill, int stroke, boolean isCenter, boolean isShadow) { + super(x, y, width, 0); + this.content = content; + this.space = space; + this.fontSize = fontSize; + this.fontColor = fontColor; + this.fill = fill; + this.stroke = stroke; + this.isCenter = isCenter; + this.isShadow = isShadow; + this.initFixed(x, y, width, 0, null); + } + + public TextBoxWidget() {} + + @Override + protected Widget initFixed(int x, int y, int width, int height, JsonObject config) { + this.textLines = new ArrayList<>(); + FontRenderer font = Minecraft.getMinecraft().fontRenderer; + this.space = Math.max(space, 0); + this.fontSize = Math.max(fontSize, 1); + int wrapWidth = width * font.FONT_HEIGHT / fontSize; + if (content != null) { + for (String textLine : content) { + this.textLines.addAll(font.listFormattedStringToWidth(I18n.format(textLine), wrapWidth)); + } + } + this.setSize(new Size(this.getSize().width, this.textLines.size() * (fontSize + space))); + return this; + } + + @Override + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + super.drawInBackground(mouseX, mouseY, partialTicks, context); + if (!textLines.isEmpty()) { + Position position = getPosition(); + Size size = getSize(); + FontRenderer font = Minecraft.getMinecraft().fontRenderer; + float scale = fontSize * 1.0f / font.FONT_HEIGHT; + GlStateManager.pushMatrix(); + GlStateManager.scale(scale, scale, 1); + GlStateManager.translate(position.x / scale, position.y / scale, 0); + float x = 0; + float y = 0; + float ySpace = font.FONT_HEIGHT + space / scale; + for (String textLine : textLines) { + if (isCenter) { + x = (size.width / scale - font.getStringWidth(textLine)) / 2; + } + font.drawString(textLine, x, y, fontColor, isShadow); + y += ySpace; + } + GlStateManager.popMatrix(); + } + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java new file mode 100644 index 00000000000..d20a9a82ccb --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java @@ -0,0 +1,150 @@ +package gregtech.api.terminal.gui.widgets.guide; + +import com.google.gson.JsonObject; +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.terminal.util.TreeNode; +import gregtech.api.util.Position; +import gregtech.api.util.RenderUtil; +import gregtech.api.util.Size; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.resources.I18n; +import net.minecraft.util.Tuple; +import net.minecraft.util.math.MathHelper; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Function; + +public class TextTreeWidget extends Widget { + private static final int ITEM_HEIGHT = 11; + protected int scrollOffset; + protected List>> list; + protected TreeNode> selected; + protected IGuiTexture background; + protected IGuiTexture nodeTexture; + protected IGuiTexture leafTexture; + protected Consumer>> onSelected; + protected Function iconSupplier; + protected Function nameSupplier; + + public TextTreeWidget(int xPosition, int yPosition, int width, int height, + TreeNode> root, + Consumer>> onSelected, + Function iconSupplier, + Function nameSupplier) { + super(new Position(xPosition, yPosition), new Size(width, height)); + list = new ArrayList<>(); + if (root.children != null) { + list.addAll(root.children); + } + this.onSelected = onSelected; + this.iconSupplier = iconSupplier; + this.nameSupplier = nameSupplier; + } + + public TextTreeWidget setBackground(IGuiTexture background) { + this.background = background; + return this; + } + + public TextTreeWidget setNodeTexture(IGuiTexture nodeTexture) { + this.nodeTexture = nodeTexture; + return this; + } + + public TextTreeWidget setLeafTexture(IGuiTexture leafTexture) { + this.leafTexture = leafTexture; + return this; + } + + @Override + public boolean mouseWheelMove(int mouseX, int mouseY, int wheelDelta) { + if (this.isMouseOverElement(mouseX, mouseY, true)) { + int moveDelta = -MathHelper.clamp(wheelDelta, -1, 1) * 5; + this.scrollOffset = MathHelper.clamp(scrollOffset + moveDelta, 0, Math.max(list.size() * ITEM_HEIGHT - getSize().height, 0)); + return true; + } + return false; + } + + @Override + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + Position position = getPosition(); + Size size = getSize(); + if (background != null) { + background.draw(position.x, position.y, size.width, size.height); + } else { + gregtech.api.gui.resources.RenderUtil.renderRect(position.x, position.y, size.width, size.height, 0, 0x8f000000); + } + RenderUtil.useScissor(position.x, position.y, size.width, size.height, ()->{ + FontRenderer fr = Minecraft.getMinecraft().fontRenderer; + int minToRender = scrollOffset / ITEM_HEIGHT; + int maxToRender = Math.min(list.size(), size.height / ITEM_HEIGHT + 2 + minToRender); + + for (int i = minToRender; i < maxToRender; i++) { + GlStateManager.color(1,1,1,1); + TreeNode> node = list.get(i); + int x = position.x + 10 * node.dimension; + int y = position.y - scrollOffset + i * ITEM_HEIGHT; + String name = node.key; + if (node.isLeaf()) { + if (leafTexture != null) { + leafTexture.draw(position.x, y, size.width, ITEM_HEIGHT); + } else { + gregtech.api.gui.resources.RenderUtil.renderRect(position.x, y, size.width, ITEM_HEIGHT, 0, 0xffff0000); + } + if (node.content != null) { + String nameS = nameSupplier.apply(node.content.getFirst()); + name = nameS == null ? name : nameS; + IGuiTexture icon = iconSupplier.apply(node.content.getFirst()); + if (icon != null) { + icon.draw(x - 9, y + 1, 8, 8); + } + } + } else { + if (nodeTexture != null) { + nodeTexture.draw(position.x, y, size.width, ITEM_HEIGHT); + } else { + gregtech.api.gui.resources.RenderUtil.renderRect(position.x, y, size.width, ITEM_HEIGHT, 0, 0xffffff00); + } + } + if (node == selected) { + gregtech.api.gui.resources.RenderUtil.renderRect(position.x, y, size.width, ITEM_HEIGHT, 0, 0x7f000000); + } + fr.drawString(I18n.format(name), x, y + 2, 0xff000000); + } + }); + } + + @Override + public boolean mouseClicked(int mouseX, int mouseY, int button) { + if (this.isMouseOverElement(mouseX, mouseY)) { + int index = ((mouseY - getPosition().y) + scrollOffset) / ITEM_HEIGHT; + if (index < list.size()) { + TreeNode> node = list.get(index); + if (node.isLeaf()) { + if (node != this.selected) { + this.selected = node; + onSelected.accept(node); + } + } else if (list.contains(node.children.get(node.children.size() - 1))){ + for (TreeNode> child : node.children) { + list.remove(child); + } + } else { + for (TreeNode> child : node.children) { + list.add(index + 1, child); + } + } + playButtonClickSound(); + } + return true; + } + return false; + } +} diff --git a/src/main/java/gregtech/api/terminal/util/IContent.java b/src/main/java/gregtech/api/terminal/util/IContent.java new file mode 100644 index 00000000000..5e0652455e7 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/util/IContent.java @@ -0,0 +1,4 @@ +package gregtech.api.terminal.util; + +public class IContent { +} diff --git a/src/main/java/gregtech/api/terminal/util/TreeNode.java b/src/main/java/gregtech/api/terminal/util/TreeNode.java new file mode 100644 index 00000000000..e8d5c1aa7fb --- /dev/null +++ b/src/main/java/gregtech/api/terminal/util/TreeNode.java @@ -0,0 +1,51 @@ +package gregtech.api.terminal.util; + + +import java.util.ArrayList; +import java.util.List; + +/*** + * Tree + * @param key + * @param leaf + */ +public class TreeNode { + public int dimension; + public List> children; + public final T key; + public K content; + + public TreeNode(int dimension, T key) { + this.dimension = dimension; + this.key = key; + } + + public boolean isLeaf(){ + return children == null || children.isEmpty(); + } + + public TreeNode getOrCreateChild (T childKey) { + TreeNode result; + if (children != null) { + result = children.stream().filter(child->child.key.equals(childKey)).findFirst().orElseGet(()->{ + TreeNode newNode = new TreeNode<>(dimension + 1, childKey); + children.add(newNode); + return newNode; + }); + } else { + children = new ArrayList<>(); + result = new TreeNode<>(dimension + 1, childKey); + children.add(result); + } + return result; + } + + public void addContent (T key, K content) { + getOrCreateChild(key).content = content; + } + + @Override + public String toString() { + return key.toString(); + } +} diff --git a/src/main/java/gregtech/common/CommonProxy.java b/src/main/java/gregtech/common/CommonProxy.java index f5ff3f854b6..aaa4927137d 100644 --- a/src/main/java/gregtech/common/CommonProxy.java +++ b/src/main/java/gregtech/common/CommonProxy.java @@ -1,5 +1,9 @@ package gregtech.common; +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import forestry.core.config.Constants; import gregtech.api.GTValues; import gregtech.api.block.machines.MachineItemBlock; import gregtech.api.enchants.EnchantmentEnderDamage; @@ -7,6 +11,7 @@ import gregtech.api.recipes.crafttweaker.MetaItemBracketHandler; import gregtech.api.recipes.recipeproperties.BlastTemperatureProperty; import gregtech.api.recipes.recipeproperties.FusionEUToStartProperty; +import gregtech.api.terminal.TerminalBuilder; import gregtech.api.unification.material.type.DustMaterial; import gregtech.api.unification.material.type.Material; import gregtech.api.unification.ore.OrePrefix; @@ -26,12 +31,14 @@ import gregtech.loaders.recipe.*; import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; +import net.minecraft.client.Minecraft; import net.minecraft.enchantment.Enchantment; import net.minecraft.item.Item; import net.minecraft.item.ItemBlock; import net.minecraft.item.ItemMultiTexture; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.IRecipe; +import net.minecraft.util.ResourceLocation; import net.minecraftforge.common.config.Config.Type; import net.minecraftforge.common.config.ConfigManager; import net.minecraftforge.event.RegistryEvent; @@ -42,7 +49,14 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.registries.IForgeRegistry; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; +import java.util.Enumeration; import java.util.function.Function; +import java.util.stream.Collectors; import static gregtech.common.blocks.MetaBlocks.*; @@ -194,7 +208,7 @@ public static void registerRecipesLowest(RegistryEvent.Register event) DecompositionRecipeHandler.runRecipeGeneration(); RecyclingRecipes.init(); WoodMachineRecipes.init(); - + if (GTValues.isModLoaded(GTValues.MODID_CT)){ MetaItemBracketHandler.rebuildComponentRegistry(); } @@ -259,5 +273,6 @@ public void onLoad() { public void onPostLoad() { WoodMachineRecipes.postInit(); + TerminalBuilder.init(); } } diff --git a/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java b/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java index bb3487c1f7a..8cc400aa343 100644 --- a/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java +++ b/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java @@ -2,14 +2,12 @@ import gregtech.api.gui.GuiTextures; import gregtech.api.gui.ModularUI; -import gregtech.api.gui.resources.TextureItemStack; import gregtech.api.items.gui.ItemUIFactory; import gregtech.api.items.gui.PlayerInventoryHolder; import gregtech.api.items.metaitem.stats.IItemBehaviour; -import gregtech.api.terminal.gui.widgets.CircleButton; +import gregtech.api.terminal.TerminalBuilder; +import gregtech.api.terminal.gui.widgets.TerminalMenuWidget; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.Blocks; -import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.util.ActionResult; import net.minecraft.util.EnumActionResult; @@ -36,10 +34,10 @@ public void addInformation(ItemStack itemStack, List lines) { @Override public ModularUI createUI(PlayerInventoryHolder holder, EntityPlayer entityPlayer) { - CircleButton circleButton = new CircleButton(27, 40, 12) - .setIcon(new TextureItemStack(Item.getItemFromBlock(Blocks.CHEST).getDefaultInstance())); + TerminalMenuWidget menu = new TerminalMenuWidget(15, 30, 24, 24); + TerminalBuilder.getApplications().forEach(menu::addApp); return ModularUI.builder(GuiTextures.TERMINAL_BACKGROUND, 380, 256) - .widget(circleButton) + .widget(menu) .build(holder, entityPlayer); } } diff --git a/src/main/resources/assets/gregtech/terminal/guide/items/default.json b/src/main/resources/assets/gregtech/terminal/guide/items/default.json new file mode 100644 index 00000000000..460662d7376 --- /dev/null +++ b/src/main/resources/assets/gregtech/terminal/guide/items/default.json @@ -0,0 +1,34 @@ +{ + "section": "default", + "title": "Json Tutorial", + "stream": [ + { + "type": "textbox", + "isCenter": false, + "content": [ + "If you see this page, §4unfortunately§r, this item lacks a Guide Page.", + "Let's start the tutorial.Rest assured, this is not difficult, you can easily customize the Guide Page with JSON. We look forward to your contributions.", + "------------" + ] + }, + { + "type": "textbox", + "isCenter": true, + "fontSize": 5, + "content": [ + "§nMinecraft Formatting", + "§r§00 §11 §22 §33", + "§44 §55 §66 §77", + "§88 §99 §aa §bb", + "§cc §dd §ee §ff", + "§r§0k §kMinecraft", + "§rl §lMinecraft", + "§rm §mMinecraft", + "§rn §nMinecraft", + "§ro §oMinecraft", + "§rr §rMinecraft" + ] + } + ], + "fixed": [] +} diff --git a/src/main/resources/assets/gregtech/terminal/guide/multiblocks/default.json b/src/main/resources/assets/gregtech/terminal/guide/multiblocks/default.json new file mode 100644 index 00000000000..8e1f44a4c3c --- /dev/null +++ b/src/main/resources/assets/gregtech/terminal/guide/multiblocks/default.json @@ -0,0 +1,24 @@ +{ + "section": "default", + "title": "Missing Guide", + "stream": [ + { + "type": "textbox", + "isCenter": false, + "content": [ + "If you see this page, §4unfortunately§r, this item lacks a Guide Page.", + "You can learn it from the APP §lTutorial§r. Don't worry, it is not difficult, you can easily customize the Guide Page with JSON. We look forward to your contributions.", + "-------------------------------" + ] + }, + { + "type": "textbox", + "isCenter": false, + "content": [ + "§c§lNote§r: Configuration files should in §n\"assets/gregtech/terminal/guide/multiblocks\"§r", + "Please name the file with the registered name of a machine to help the system automatically match the machines." + ] + } + ], + "fixed": [] +} diff --git a/src/main/resources/assets/gregtech/terminal/guide/simplemachines/default.json b/src/main/resources/assets/gregtech/terminal/guide/simplemachines/default.json new file mode 100644 index 00000000000..460662d7376 --- /dev/null +++ b/src/main/resources/assets/gregtech/terminal/guide/simplemachines/default.json @@ -0,0 +1,34 @@ +{ + "section": "default", + "title": "Json Tutorial", + "stream": [ + { + "type": "textbox", + "isCenter": false, + "content": [ + "If you see this page, §4unfortunately§r, this item lacks a Guide Page.", + "Let's start the tutorial.Rest assured, this is not difficult, you can easily customize the Guide Page with JSON. We look forward to your contributions.", + "------------" + ] + }, + { + "type": "textbox", + "isCenter": true, + "fontSize": 5, + "content": [ + "§nMinecraft Formatting", + "§r§00 §11 §22 §33", + "§44 §55 §66 §77", + "§88 §99 §aa §bb", + "§cc §dd §ee §ff", + "§r§0k §kMinecraft", + "§rl §lMinecraft", + "§rm §mMinecraft", + "§rn §nMinecraft", + "§ro §oMinecraft", + "§rr §rMinecraft" + ] + } + ], + "fixed": [] +} diff --git a/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_0_guidepage.json b/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_0_guidepage.json new file mode 100644 index 00000000000..34873e69ca1 --- /dev/null +++ b/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_0_guidepage.json @@ -0,0 +1,36 @@ +{ + "section": "Guide Widget API", + "title": "Guide Page", + "stream": [ + { + "type": "textbox", + "content": [ + "In this section we'll learn how to write a guide page.", + "-------------------------------", + "Let's take a look at an example config file for a guide page.", + "§lJSON§r:", + "{", + " \"section\": \"section name here\",", + " \"title\": \"title here\",", + " \"stream\": [", + " {", + " \"type\": \"textbox\",", + " \"content\": [\"TextBox widget\"]", + " }", + " ],", + " \"fixed\": [", + " {", + " \"x\": 50,", + " \"y\": 100,", + " \"width\": 150,", + " \"height\": 40,", + " \"type\": 0,", + " \"content\": [\"TextBox widget\"]", + " }", + " ]", + "}" + ] + } + ], + "fixed": [] +} diff --git a/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_1_textbox.json b/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_1_textbox.json new file mode 100644 index 00000000000..8f20574c947 --- /dev/null +++ b/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_1_textbox.json @@ -0,0 +1,265 @@ +{ + "section": "Guide Widget API", + "title": "TextBox Widget", + "stream": [ + { + "type": "textbox", + "content": [ + "In this section we'll learn how to use the powerful §4§lTextBox§r, which is the most commonly used. So you should read the API documentation carefully.", + "-------------------------------", + "§lWidget Type§r: §ntextbox§r", + "-------------------------------", + "§lJSON§r:", + "{", + " \"type\": \"textbox\",", + " \"space\": 1,", + " \"fontSize\": 9,", + " \"fontColor\": 4278190080,", + " \"fill\": 0,", + " \"stroke\": 0,", + " \"isCenter\": false,", + " \"isShadow\": false,", + " \"content\": [\"content here!\"]", + "}" + ] + }, { + "type": "textbox", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §ncontent§r (§4required§r)", + "§ltype§r: Array", + "§lillustrate§r: Text contents, each item will be a newline.Text that is too long will auto wrap itself. (Supporting Minecraft Formatting Code)" + ] + }, + { + "type": "textbox", + "isCenter": true, + "stroke": 4294901760, + "content": [ + "§lDemo§r: [...]", + "§nMinecraft Formatting", + "§r§00 §11 §22 §33", + "§44 §55 §66 §77", + "§88 §99 §aa §bb", + "§cc §dd §ee §ff", + "§r§0k §kMinecraft", + "§rl §lMinecraft", + "§rm §mMinecraft", + "§rn §nMinecraft", + "§ro §oMinecraft", + "§rr §rMinecraft" + ] + }, + { + "type": "textbox", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §nspace§r (§6optional§r)", + "§ltype§r: Number", + "§ldefault§r: 1", + "§lillustrate§r: The spacing between lines of text." + ] + }, + { + "type": "textbox", + "isCenter": true, + "stroke": 4294901760, + "space": 5, + "content": [ + "§lDemo§r: 5", + "§nMinecraft Formatting", + "§r§00 §11 §22 §33", + "§44 §55 §66 §77", + "§88 §99 §aa §bb", + "§cc §dd §ee §ff", + "§r§0k §kMinecraft", + "§rl §lMinecraft", + "§rm §mMinecraft", + "§rn §nMinecraft", + "§ro §oMinecraft", + "§rr §rMinecraft" + ] + },{ + "type": "textbox", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §nfontSize§r (§6optional§r)", + "§ltype§r: Number", + "§ldefault§r: 9", + "§lillustrate§r: The font size. (Actually it's the height of the font)" + ] + }, + { + "type": "textbox", + "isCenter": true, + "stroke": 4294901760, + "fontSize": 5, + "content": [ + "§lDemo§r: 5", + "§nMinecraft Formatting", + "§r§00 §11 §22 §33", + "§44 §55 §66 §77", + "§88 §99 §aa §bb", + "§cc §dd §ee §ff", + "§r§0k §kMinecraft", + "§rl §lMinecraft", + "§rm §mMinecraft", + "§rn §nMinecraft", + "§ro §oMinecraft", + "§rr §rMinecraft" + ] + },{ + "type": "textbox", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §nfontColor§r (§6optional§r)", + "§ltype§r: Number", + "§ldefault§r: 4278190080", + "§lillustrate§r: The default color of the content. You can also set the colors with special symbols (provided by Minecraft).But maybe you need it sometimes." + ] + }, + { + "type": "textbox", + "isCenter": true, + "stroke": 4294901760, + "fontColor": 5, + "content": [ + "§lDemo§r: 4294901760 (0xFFFF0000)", + "§nMinecraft Formatting", + "§r§00 §11 §22 §33", + "§44 §55 §66 §77", + "§88 §99 §aa §bb", + "§cc §dd §ee §ff", + "§r§0k §kMinecraft", + "§rl §lMinecraft", + "§rm §mMinecraft", + "§rn §nMinecraft", + "§ro §oMinecraft", + "§rr §rMinecraft" + ] + },{ + "type": "textbox", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §nfill§r (§6optional§r)", + "§ltype§r: Number", + "§ldefault§r: 0", + "§lillustrate§r: The background color." + ] + }, + { + "type": "textbox", + "isCenter": true, + "stroke": 4294901760, + "fill": 4278190335, + "content": [ + "§lDemo§r: 4278190335 (0xFF0000FF)", + "§nMinecraft Formatting", + "§r§00 §11 §22 §33", + "§44 §55 §66 §77", + "§88 §99 §aa §bb", + "§cc §dd §ee §ff", + "§r§0k §kMinecraft", + "§rl §lMinecraft", + "§rm §mMinecraft", + "§rn §nMinecraft", + "§ro §oMinecraft", + "§rr §rMinecraft" + ] + },{ + "type": "textbox", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §nstroke§r (§6optional§r)", + "§ltype§r: Number", + "§ldefault§r: 0", + "§lillustrate§r: The border color." + ] + }, + { + "type": "textbox", + "isCenter": true, + "stroke": 4278190335, + "content": [ + "§lDemo§r: 4278190335 (0xFF0000FF)", + "§nMinecraft Formatting", + "§r§00 §11 §22 §33", + "§44 §55 §66 §77", + "§88 §99 §aa §bb", + "§cc §dd §ee §ff", + "§r§0k §kMinecraft", + "§rl §lMinecraft", + "§rm §mMinecraft", + "§rn §nMinecraft", + "§ro §oMinecraft", + "§rr §rMinecraft" + ] + },{ + "type": "textbox", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §nisCenter§r (§6optional§r)", + "§ltype§r: Boolean", + "§ldefault§r: false", + "§lillustrate§r: Text-align center." + ] + }, + { + "type": "textbox", + "isCenter": false, + "stroke": 4294901760, + "content": [ + "§lDemo§r: false", + "§nMinecraft Formatting", + "§r§00 §11 §22 §33", + "§44 §55 §66 §77", + "§88 §99 §aa §bb", + "§cc §dd §ee §ff", + "§r§0k §kMinecraft", + "§rl §lMinecraft", + "§rm §mMinecraft", + "§rn §nMinecraft", + "§ro §oMinecraft", + "§rr §rMinecraft" + ] + },{ + "type": "textbox", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §nisShadow§r (§6optional§r)", + "§ltype§r: Boolean", + "§ldefault§r: false", + "§lillustrate§r: Render shadow." + ] + }, + { + "type": "textbox", + "isCenter": true, + "stroke": 4294901760, + "isShadow": true, + "content": [ + "§lDemo§r: true", + "§nMinecraft Formatting", + "§r§00 §11 §22 §33", + "§44 §55 §66 §77", + "§88 §99 §aa §bb", + "§cc §dd §ee §ff", + "§r§0k §kMinecraft", + "§rl §lMinecraft", + "§rm §mMinecraft", + "§rn §nMinecraft", + "§ro §oMinecraft", + "§rr §rMinecraft" + ] + } + ], + "fixed": [] +} diff --git a/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_2_image.json b/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_2_image.json new file mode 100644 index 00000000000..fa1276130c4 --- /dev/null +++ b/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_2_image.json @@ -0,0 +1,80 @@ +{ + "section": "Guide Widget API", + "title": "Image Widget", + "stream": [ + { + "type": "textbox", + "content": [ + "In this section we'll learn how to add an §4§lImage§r. There are three different forms of image supported here: §4Url§r, §4Item§r, and §4ResourceLocation§r. Don't worry, it's easy", + "-------------------------------", + "§lWidget Type§r: §nimage§r", + "-------------------------------", + "§lJSON§r:", + "{", + " \"type\": \"image\",", + " \"form\": \"Item\",", + " \"source\": \"minecraft:ender_pearl\",", + " \"width\": 100,", + " \"height\": 100", + "}" + ] + }, { + "type": "textbox", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §nform§r (§4required§r)", + "§ltype§r: String", + "§lillustrate§r: It can only be set one of §Url§r, §4Item§r, or §4ResourceLocation§r.", + " \"url\" -- image url.", + " \"item\" -- The registered name of the Item in game.", + " \"resource\" -- The resource location." + ] + }, + { + "type": "textbox", + "isCenter": true, + "content": [ + "§lDemo§r: \"url\"" + ] + }, + { + "type": "image", + "form": "url", + "source": "https://i.pinimg.com/originals/38/9d/e7/389de7ca61163911e72d4adcaabe1433.gif", + "stroke": 4278190080, + "stroke_width": 2, + "width": 100, + "height": 100 + }, + { + "type": "textbox", + "isCenter": true, + "content": [ + "§lDemo§r: \"item\"" + ] + }, + { + "type": "image", + "form": "item", + "source": "minecraft:ender_pearl", + "width": 100, + "height": 100 + }, + { + "type": "textbox", + "isCenter": true, + "content": [ + "§lDemo§r: \"resource\"" + ] + }, + { + "type": "image", + "form": "resource", + "source": "textures/gui/icon/gregtech_logo.png", + "width": 100, + "height": 100 + } + ], + "fixed": [] +} From a52383ef6c4893ccc5ae599a1f4f91bcea4705d1 Mon Sep 17 00:00:00 2001 From: Yefancy Date: Thu, 29 Jul 2021 18:35:38 +0800 Subject: [PATCH 05/58] frame --- src/main/java/gregtech/api/gui/Widget.java | 4 + .../gui/widgets/guide/GuidePageWidget.java | 42 ++- .../gui/widgets/guide/GuideWidget.java | 35 ++ .../gui/widgets/guide/IGuideWidget.java | 1 + .../gui/widgets/guide/ImageWidget.java | 8 +- .../gui/widgets/guide/TextTreeWidget.java | 6 +- .../gregtech/api/util/interpolate/Eases.java | 24 ++ .../gregtech/api/util/interpolate/IEase.java | 5 + .../api/util/interpolate/Interpolator.java | 42 +++ .../guide/tutorials/api_0_guidepage.json | 118 ++++++- .../guide/tutorials/api_1_widget.json | 304 ++++++++++++++++++ .../terminal/guide/tutorials/api_2_image.json | 80 ----- ...{api_1_textbox.json => api_2_textbox.json} | 119 ++++--- .../terminal/guide/tutorials/api_3_image.json | 207 ++++++++++++ 14 files changed, 840 insertions(+), 155 deletions(-) create mode 100644 src/main/java/gregtech/api/util/interpolate/Eases.java create mode 100644 src/main/java/gregtech/api/util/interpolate/IEase.java create mode 100644 src/main/java/gregtech/api/util/interpolate/Interpolator.java create mode 100644 src/main/resources/assets/gregtech/terminal/guide/tutorials/api_1_widget.json delete mode 100644 src/main/resources/assets/gregtech/terminal/guide/tutorials/api_2_image.json rename src/main/resources/assets/gregtech/terminal/guide/tutorials/{api_1_textbox.json => api_2_textbox.json} (78%) create mode 100644 src/main/resources/assets/gregtech/terminal/guide/tutorials/api_3_image.json diff --git a/src/main/java/gregtech/api/gui/Widget.java b/src/main/java/gregtech/api/gui/Widget.java index 45f25a9fa13..550f38719e8 100644 --- a/src/main/java/gregtech/api/gui/Widget.java +++ b/src/main/java/gregtech/api/gui/Widget.java @@ -83,6 +83,10 @@ protected void setSelfPosition(Position selfPosition) { recomputePosition(); } + public Position getSelfPosition() { + return selfPosition; + } + protected void setSize(Size size) { Preconditions.checkNotNull(size, "size"); this.size = size; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java index 44b298de62b..efcc5110d43 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java @@ -9,6 +9,8 @@ import gregtech.api.util.Position; import gregtech.api.util.RenderUtil; import gregtech.api.util.Size; +import gregtech.api.util.interpolate.Eases; +import gregtech.api.util.interpolate.Interpolator; import javafx.geometry.Pos; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.util.math.MathHelper; @@ -19,6 +21,7 @@ public class GuidePageWidget extends AbstractWidgetGroup { private IGuiTexture background; private int scrollYOffset; private int maxHeight; + private Interpolator interpolator; public GuidePageWidget(int xPosition, int yPosition, int width, int height) { super(new Position(xPosition, yPosition), new Size(width, height)); @@ -35,8 +38,28 @@ protected void setScrollYOffset(int scrollYOffset) { int minY = this.scrollYOffset + getPosition().y; int maxY = minY + getSize().height; for (Widget widget : widgets) { - if (widget.getPosition().y < maxY && widget.getPosition().y + widget.getSize().height > minY) { - widget.setVisible(true); + widget.setVisible(widget.getPosition().y < maxY && widget.getPosition().y + widget.getSize().height > minY); + } + } + + public int getScrollYOffset() { + return scrollYOffset; + } + + @Override + public void updateScreen() { + if (interpolator != null) interpolator.update(); + super.updateScreen(); + } + + public void jumpToRef(String ref){ + if (interpolator != null && !interpolator.isFinish()) return; + for (Widget widget : widgets) { + if (widget instanceof IGuideWidget && ref.equals(((IGuideWidget) widget).getRef())) { + interpolator = new Interpolator(scrollYOffset, widget.getSelfPosition().y, 20, Eases.EaseQuadOut, (value)->{ + setScrollYOffset(value.intValue()); + }); + interpolator.start(); } } } @@ -71,13 +94,26 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender } GlStateManager.translate(0, -scrollYOffset, 0); RenderUtil.useScissor(position.x, position.y, size.width, size.height, ()->{ + int offsetY = mouseY + scrollYOffset; for (Widget widget : widgets) { if (widget.isVisible()) { - widget.drawInBackground(mouseX, mouseY, partialTicks, context); + widget.drawInBackground(mouseX, offsetY, partialTicks, context); } } GlStateManager.color(rColorForOverlay, gColorForOverlay, bColorForOverlay, 1.0F); }); GlStateManager.translate(0, scrollYOffset, 0); } + + @Override + public void drawInForeground(int mouseX, int mouseY) { + GlStateManager.translate(0, -scrollYOffset, 0); + super.drawInForeground(mouseX, mouseY + scrollYOffset); + GlStateManager.translate(0, scrollYOffset, 0); + } + + @Override + public boolean mouseClicked(int mouseX, int mouseY, int button) { + return super.mouseClicked(mouseX, mouseY + scrollYOffset, button); + } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java index 395c3f36e6c..d35062750d8 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java @@ -7,6 +7,10 @@ import gregtech.api.gui.Widget; import gregtech.api.util.Position; import gregtech.api.util.Size; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.item.ItemStack; + +import java.util.List; public abstract class GuideWidget extends Widget implements IGuideWidget { //config @@ -14,6 +18,8 @@ public abstract class GuideWidget extends Widget implements IGuideWidget { public int fill; public int stroke; public int stroke_width = 1; + public String link; + public List hover_text; private static final Gson GSON = new Gson(); protected transient GuidePageWidget page; @@ -26,6 +32,11 @@ public GuideWidget(){ super(Position.ORIGIN, Size.ZERO); } + @Override + public String getRef() { + return ref; + } + @Override public Widget createStreamWidget(int x, int y, int pageWidth, JsonObject config) { GuideWidget widget = GSON.fromJson(config, this.getClass()); @@ -55,6 +66,21 @@ public void setPage(GuidePageWidget page) { this.page = page; } + @Override + public void drawInForeground(int mouseX, int mouseY) { + if (link != null && isMouseOverElement(mouseX, mouseY)) { + Position position = getPosition(); + Size size = getSize(); + drawBorder(position.x, position.y, size.width, size.height, 0xff0000ff, stroke_width); + } + if (hover_text != null && isMouseOverElement(mouseX, mouseY)) { + int scrollYOffset = page.getScrollYOffset(); + GlStateManager.translate(0, scrollYOffset, 0); + drawHoveringText(ItemStack.EMPTY, hover_text, 100, mouseX, mouseY - scrollYOffset); + GlStateManager.translate(0, -scrollYOffset, 0); + } + } + @Override public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { Position position = getPosition(); @@ -66,4 +92,13 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender drawGradientRect(position.x, position.y, size.width, size.height, fill, fill); } } + + @Override + public boolean mouseClicked(int mouseX, int mouseY, int button) { + if (link != null && isMouseOverElement(mouseX, mouseY)) { + page.jumpToRef(link); + return true; + } + return false; + } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java index 9bec77e3724..4d2b3808367 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java @@ -7,4 +7,5 @@ public interface IGuideWidget { Widget createStreamWidget(int x, int y, int pageWidth, JsonObject config); Widget createFixedWidget(int x, int y, int width, int height, JsonObject config); void setPage(GuidePageWidget page); + String getRef(); } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java index f2f0da27cf9..b5a1d8127c0 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java @@ -1,6 +1,7 @@ package gregtech.api.terminal.gui.widgets.guide; import com.google.gson.JsonObject; +import gregtech.api.GTValues; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; import gregtech.api.gui.resources.IGuiTexture; @@ -9,7 +10,9 @@ import gregtech.api.gui.resources.URLTexture; import gregtech.api.util.Position; import gregtech.api.util.Size; +import net.minecraft.client.renderer.GlStateManager; import net.minecraft.item.Item; +import net.minecraft.util.ResourceLocation; public class ImageWidget extends GuideWidget{ //config @@ -38,13 +41,13 @@ protected Widget initStream(int x, int y, int pageWidth, JsonObject config) { protected Widget initFixed(int x, int y, int width, int height, JsonObject config) { switch (form) { case "url": - image = new URLTexture(source); + image = new URLTexture("https://i0.hdslb.com/bfs/article/bcd3d609c1899810113fdb90c8d0e1dd4aa8ed38.gif"); break; case "item": image = new ItemStackTexture(Item.getByNameOrId(source)); break; case "resource": - image = TextureArea.fullImage(source); + image = new TextureArea(new ResourceLocation(source), 0.0, 0.0, 1.0, 1.0); break; } return this; @@ -54,6 +57,7 @@ protected Widget initFixed(int x, int y, int width, int height, JsonObject confi public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { if (image != null) { super.drawInBackground(mouseX, mouseY, partialTicks,context); + GlStateManager.color(1,1,1,1); Position position = getPosition(); image.draw(position.x, position.y, width, height); } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java index d20a9a82ccb..ecd8db3fbad 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java @@ -132,13 +132,13 @@ public boolean mouseClicked(int mouseX, int mouseY, int button) { this.selected = node; onSelected.accept(node); } - } else if (list.contains(node.children.get(node.children.size() - 1))){ + } else if (node.children.size() > 0 && list.contains(node.children.get(0))){ for (TreeNode> child : node.children) { list.remove(child); } } else { - for (TreeNode> child : node.children) { - list.add(index + 1, child); + for (int i = 0; i < node.children.size(); i++) { + list.add(index + 1 + i, node.children.get(i)); } } playButtonClickSound(); diff --git a/src/main/java/gregtech/api/util/interpolate/Eases.java b/src/main/java/gregtech/api/util/interpolate/Eases.java new file mode 100644 index 00000000000..87f74763cb4 --- /dev/null +++ b/src/main/java/gregtech/api/util/interpolate/Eases.java @@ -0,0 +1,24 @@ +package gregtech.api.util.interpolate; + +public enum Eases implements IEase{ + EaseLinear(input-> input), + EaseQuadIn(input-> input * input), + EaseQuadInOut(input->{ + if((input /= 0.5f) < 1) { + return 0.5f * input * input; + } + return -0.5f * ((--input) * (input - 2) - 1); + }), + EaseQuadOut(input->-input * (input - 2)); + + + IEase ease; + + Eases(IEase ease){ + this.ease = ease; + } + @Override + public float getInterpolation(float t) { + return ease.getInterpolation(t); + } +} diff --git a/src/main/java/gregtech/api/util/interpolate/IEase.java b/src/main/java/gregtech/api/util/interpolate/IEase.java new file mode 100644 index 00000000000..cb4c02b0e4e --- /dev/null +++ b/src/main/java/gregtech/api/util/interpolate/IEase.java @@ -0,0 +1,5 @@ +package gregtech.api.util.interpolate; + +public interface IEase { + float getInterpolation(float t); +} diff --git a/src/main/java/gregtech/api/util/interpolate/Interpolator.java b/src/main/java/gregtech/api/util/interpolate/Interpolator.java new file mode 100644 index 00000000000..2eef08dea52 --- /dev/null +++ b/src/main/java/gregtech/api/util/interpolate/Interpolator.java @@ -0,0 +1,42 @@ +package gregtech.api.util.interpolate; + +import net.minecraft.util.ITickable; + +import java.util.function.Consumer; + +public class Interpolator implements ITickable { + float from; + float to; + int duration; + IEase ease; + Consumer callback; + + int tick = -1; + + public Interpolator(float from, float to, int duration, IEase ease, Consumer callback) { + this.from = from; + this.to = to; + this.duration = duration; + this.ease = ease; + this.callback = callback; + } + + public void reset() { + tick = -1; + } + + public void start() { + tick = 0; + } + + public boolean isFinish(){ + return tick == duration; + } + + @Override + public void update() { + if (tick < 0 || tick >= duration) return; + callback.accept(ease.getInterpolation(tick * 1.0f / duration) * (to - from) + from); + tick++; + } +} diff --git a/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_0_guidepage.json b/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_0_guidepage.json index 34873e69ca1..cc671653f25 100644 --- a/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_0_guidepage.json +++ b/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_0_guidepage.json @@ -5,7 +5,7 @@ { "type": "textbox", "content": [ - "In this section we'll learn how to write a guide page.", + "In this page we'll learn how to write a guide page.", "-------------------------------", "Let's take a look at an example config file for a guide page.", "§lJSON§r:", @@ -28,9 +28,121 @@ " \"content\": [\"TextBox widget\"]", " }", " ]", - "}" + "}", + "-------------------------------", + "§lContents§r" + ] + }, + { + "type": "textbox", + "link": "section", + "content": [ + " 1.§nsection§r" + ] + }, + { + "type": "textbox", + "link": "title", + "content": [ + " 2.§ntitle§r" + ] + }, + { + "type": "textbox", + "link": "stream", + "content": [ + " 3.§nstream§r" + ] + }, + { + "type": "textbox", + "link": "fixed", + "content": [ + " 4.§nfixed§r" + ] + }, + { + "type": "textbox", + "ref": "section", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §nsection§r (§4required§r)", + "§ltype§r: String", + "§lillustrate§r: Specifies which section of the application the page belongs to.", + "The application automatically merges pages of the same section name and builds a directory tree." + ] + }, + { + "type": "textbox", + "ref": "title", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §ntitle§r (§4required§r)", + "§ltype§r: String", + "§lillustrate§r: The page title." + ] + }, + { + "type": "textbox", + "ref": "stream", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §nstream§r (§4required§r)", + "§ltype§r: Array", + "§lillustrate§r: Widgets in streaming layout. You don't need to care the position and size of widgets in stream, all typography will be done automatically." + ] + }, + { + "type": "textbox", + "ref": "fixed", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §nfixed§r (§4required§r)", + "§ltype§r: Array", + "§lillustrate§r: Widgets in fixed layout. You need to specify the position and size of each widget." + ] + }, + { + "type": "textbox", + "isCenter": true, + "content": [ + "§lDemo§r: fixed and stream" + ] + }, + { + "type": "textbox", + "isCenter": true, + "hover_text": ["stream widget"], + "content": [ + "§nMinecraft Formatting", + "§r§00 §11 §22 §33", + "§44 §55 §66 §77", + "§88 §99 §aa §bb", + "§cc §dd §ee §ff", + "§r§0k §kMinecraft", + "§rl §lMinecraft", + "§rm §mMinecraft", + "§rn §nMinecraft", + "§ro §oMinecraft", + "§rr §rMinecraft" ] } ], - "fixed": [] + "fixed": [ + { + "type": "image", + "x": 30, + "y": 800, + "stroke": 4278190335, + "hover_text": ["fixed widget", "\"x\": 30","\"y\": 800","\"width\": 100","\"width\": 100"], + "form": "item", + "source": "minecraft:ender_pearl", + "width": 100, + "height": 100 + } + ] } diff --git a/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_1_widget.json b/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_1_widget.json new file mode 100644 index 00000000000..6ff3a760930 --- /dev/null +++ b/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_1_widget.json @@ -0,0 +1,304 @@ +{ + "section": "Guide Widget API", + "title": "Guide Widget", + "stream": [ + { + "type": "textbox", + "content": [ + "In this page we'll learn what is §4§lGuide Widget§r, and its public attributes.", + "Widgets are rendered in the Guide Page, which is the basis for your custom pages. §nTextbox§r, §nImage§r, etc", + "To use it, just add the related JSON code under the §l\"fixed\"§r or §l\"stream\"§r.", + "There are some attributes effects (styles) that are valid for all widgets", + "-------------------------------", + "§lJSON§r:", + "{", + " \"type\": \"type here\",", + " \"x\": 50,", + " \"y\": 100,", + " \"width\": 150,", + " \"height\": 40,", + " \"ref\": \"ref\",", + " \"stroke\": 0,", + " \"stroke_width\": 1,", + " \"fill\": 0,", + " \"link\": \"ref\"", + " \"hover_text\": [\"text here\"]", + "}", + "-------------------------------", + "§lContents§r" + ] + }, + { + "type": "textbox", + "link": "type", + "content": [ + " 1.§ntype§r" + ] + }, + { + "type": "textbox", + "link": "xywh", + "content": [ + " 2.§nx, y, width, height§r" + ] + }, + { + "type": "textbox", + "link": "ref", + "content": [ + " 3.§nref§r" + ] + }, + { + "type": "textbox", + "link": "fill", + "content": [ + " 4.§nfill§r" + ] + }, + { + "type": "textbox", + "link": "stroke", + "content": [ + " 5.§nstroke§r" + ] + }, + { + "type": "textbox", + "link": "stroke_width", + "content": [ + " 6.§nstroke_width§r" + ] + }, + { + "type": "textbox", + "link": "link", + "content": [ + " 7.§nlink§r" + ] + }, + { + "type": "textbox", + "link": "hover", + "content": [ + " 8.§nhover_text§r" + ] + }, + { + "type": "textbox", + "ref": "type", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §ntype§r (§4required§r)", + "§ltype§r: String", + "§lillustrate§r: This is the unique id of the widget. See the API documentation for each widget." + ] + }, + { + "type": "textbox", + "ref": "xywh", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §nx, y, width, height§r (§4optional§r)", + "§ltype§r: Integer", + "§lillustrate§r: The position and size of the widget. In a stream layout, you usually don't need to set it (the image widget needs to set width and height). Under fixed layout you must set these four attributes." + ] + }, + { + "type": "textbox", + "ref": "ref", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §nref§r (§4optional§r)", + "§ltype§r: String", + "§ldefault§r: null", + "§lillustrate§r: This is a tag of this widget. The ref should be unique on the same page." + ] + }, + { + "type": "textbox", + "ref": "fill", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §nfill§r (§6optional§r)", + "§ltype§r: Number", + "§ldefault§r: 0", + "§lillustrate§r: The background color." + ] + }, + { + "type": "textbox", + "isCenter": true, + "content": [ + "§lDemo§r: 4278190335 (0xFF0000FF)" + ] + }, + { + "type": "textbox", + "isCenter": true, + "fill": 4278190335, + "content": [ + "§nMinecraft Formatting", + "§r§00 §11 §22 §33", + "§44 §55 §66 §77", + "§88 §99 §aa §bb", + "§cc §dd §ee §ff", + "§r§0k §kMinecraft", + "§rl §lMinecraft", + "§rm §mMinecraft", + "§rn §nMinecraft", + "§ro §oMinecraft", + "§rr §rMinecraft" + ] + }, + { + "type": "textbox", + "ref": "stroke", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §nstroke§r (§6optional§r)", + "§ltype§r: Number", + "§ldefault§r: 0", + "§lillustrate§r: The border color." + ] + }, + { + "type": "textbox", + "isCenter": true, + "content": [ + "§lDemo§r: 4278190335 (0xFF0000FF)" + ] + }, + { + "type": "image", + "form": "item", + "source": "minecraft:ender_pearl", + "stroke": 4278190335, + "width": 50, + "height": 50 + }, + { + "type": "textbox", + "ref": "stroke_width", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §nstroke_width§r (§6optional§r)", + "§ltype§r: Number", + "§ldefault§r: 1", + "§lillustrate§r: The border width." + ] + }, + { + "type": "textbox", + "isCenter": true, + "content": [ + "§lDemo§r: 5" + ] + }, + { + "type": "image", + "form": "item", + "source": "minecraft:ender_pearl", + "stroke": 4278190335, + "stroke_width": 5, + "width": 50, + "height": 50 + }, + { + "type": "textbox", + "ref": "link", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §nlink§r (§6optional§r)", + "§ltype§r: String", + "§ldefault§r: null", + "§lillustrate§r: Click to jump to the specified location. Need to be used with ref, target is ref." + ] + }, + { + "type": "textbox", + "isCenter": true, + "content": [ + "§lDemo§r: \"P2\"" + ] + }, + { + "type": "textbox", + "isCenter": true, + "fill": 4286430975, + "hover_text": ["\"ref\": \"P1\""], + "ref": "P1", + "link": "P2", + "content": ["Click Me!"] + }, + { + "type": "textbox", + "content": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ] + }, + { + "type": "textbox", + "isCenter": true, + "content": [ + "§lDemo§r: \"P1\"" + ] + }, + { + "type": "textbox", + "isCenter": true, + "fill": 4286430975, + "hover_text": ["\"ref\": \"P2\""], + "ref": "P2", + "link": "P1", + "content": ["Click Me!"] + }, + { + "type": "textbox", + "ref": "hover", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §nhover_text§r (§6optional§r)", + "§ltype§r: Array", + "§ldefault§r: null", + "§lillustrate§r: Displays text when the mouse is over the widget." + ] + }, + { + "type": "textbox", + "isCenter": true, + "content": [ + "§lDemo§r: [\"THIS IS\",\"GT ICON\"]" + ] + }, + { + "type": "image", + "hover_text": ["THIS IS","GT ICON"], + "form": "resource", + "source": "gregtech:textures/gui/icon/gregtech_logo.png", + "width": 100, + "height": 100 + } + ], + "fixed": [] +} diff --git a/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_2_image.json b/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_2_image.json deleted file mode 100644 index fa1276130c4..00000000000 --- a/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_2_image.json +++ /dev/null @@ -1,80 +0,0 @@ -{ - "section": "Guide Widget API", - "title": "Image Widget", - "stream": [ - { - "type": "textbox", - "content": [ - "In this section we'll learn how to add an §4§lImage§r. There are three different forms of image supported here: §4Url§r, §4Item§r, and §4ResourceLocation§r. Don't worry, it's easy", - "-------------------------------", - "§lWidget Type§r: §nimage§r", - "-------------------------------", - "§lJSON§r:", - "{", - " \"type\": \"image\",", - " \"form\": \"Item\",", - " \"source\": \"minecraft:ender_pearl\",", - " \"width\": 100,", - " \"height\": 100", - "}" - ] - }, { - "type": "textbox", - "content": [ - "-------------------------------", - "", - "§lAttr§r: §nform§r (§4required§r)", - "§ltype§r: String", - "§lillustrate§r: It can only be set one of §Url§r, §4Item§r, or §4ResourceLocation§r.", - " \"url\" -- image url.", - " \"item\" -- The registered name of the Item in game.", - " \"resource\" -- The resource location." - ] - }, - { - "type": "textbox", - "isCenter": true, - "content": [ - "§lDemo§r: \"url\"" - ] - }, - { - "type": "image", - "form": "url", - "source": "https://i.pinimg.com/originals/38/9d/e7/389de7ca61163911e72d4adcaabe1433.gif", - "stroke": 4278190080, - "stroke_width": 2, - "width": 100, - "height": 100 - }, - { - "type": "textbox", - "isCenter": true, - "content": [ - "§lDemo§r: \"item\"" - ] - }, - { - "type": "image", - "form": "item", - "source": "minecraft:ender_pearl", - "width": 100, - "height": 100 - }, - { - "type": "textbox", - "isCenter": true, - "content": [ - "§lDemo§r: \"resource\"" - ] - }, - { - "type": "image", - "form": "resource", - "source": "textures/gui/icon/gregtech_logo.png", - "width": 100, - "height": 100 - } - ], - "fixed": [] -} diff --git a/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_1_textbox.json b/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_2_textbox.json similarity index 78% rename from src/main/resources/assets/gregtech/terminal/guide/tutorials/api_1_textbox.json rename to src/main/resources/assets/gregtech/terminal/guide/tutorials/api_2_textbox.json index 8f20574c947..416286361a7 100644 --- a/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_1_textbox.json +++ b/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_2_textbox.json @@ -1,11 +1,11 @@ { "section": "Guide Widget API", - "title": "TextBox Widget", + "title": "1. TextBox Widget", "stream": [ { "type": "textbox", "content": [ - "In this section we'll learn how to use the powerful §4§lTextBox§r, which is the most commonly used. So you should read the API documentation carefully.", + "In this page we'll learn how to use the powerful §4§lTextBox§r, which is the most commonly used. So you should read the API documentation carefully.", "-------------------------------", "§lWidget Type§r: §ntextbox§r", "-------------------------------", @@ -15,15 +15,59 @@ " \"space\": 1,", " \"fontSize\": 9,", " \"fontColor\": 4278190080,", - " \"fill\": 0,", - " \"stroke\": 0,", " \"isCenter\": false,", " \"isShadow\": false,", " \"content\": [\"content here!\"]", - "}" + "}", + "-------------------------------", + "§lContents§r" ] - }, { + }, + { "type": "textbox", + "link": "content", + "content": [ + " 1.§ncontent§r" + ] + }, + { + "type": "textbox", + "link": "space", + "content": [ + " 2.§nspace§r" + ] + }, + { + "type": "textbox", + "link": "fontSize", + "content": [ + " 3.§nfontSize§r" + ] + }, + { + "type": "textbox", + "link": "fontColor", + "content": [ + " 4.§nfontColor§r" + ] + }, + { + "type": "textbox", + "link": "isCenter", + "content": [ + " 5.§nisCenter§r" + ] + }, + { + "type": "textbox", + "link": "isShadow", + "content": [ + " 6.§nisShadow§r" + ] + }, + { + "type": "textbox", + "ref": "content", "content": [ "-------------------------------", "", @@ -53,6 +97,7 @@ }, { "type": "textbox", + "ref": "space", "content": [ "-------------------------------", "", @@ -83,6 +128,7 @@ ] },{ "type": "textbox", + "ref": "fontSize", "content": [ "-------------------------------", "", @@ -113,6 +159,7 @@ ] },{ "type": "textbox", + "ref": "fontColor", "content": [ "-------------------------------", "", @@ -141,67 +188,10 @@ "§ro §oMinecraft", "§rr §rMinecraft" ] - },{ - "type": "textbox", - "content": [ - "-------------------------------", - "", - "§lAttr§r: §nfill§r (§6optional§r)", - "§ltype§r: Number", - "§ldefault§r: 0", - "§lillustrate§r: The background color." - ] }, { "type": "textbox", - "isCenter": true, - "stroke": 4294901760, - "fill": 4278190335, - "content": [ - "§lDemo§r: 4278190335 (0xFF0000FF)", - "§nMinecraft Formatting", - "§r§00 §11 §22 §33", - "§44 §55 §66 §77", - "§88 §99 §aa §bb", - "§cc §dd §ee §ff", - "§r§0k §kMinecraft", - "§rl §lMinecraft", - "§rm §mMinecraft", - "§rn §nMinecraft", - "§ro §oMinecraft", - "§rr §rMinecraft" - ] - },{ - "type": "textbox", - "content": [ - "-------------------------------", - "", - "§lAttr§r: §nstroke§r (§6optional§r)", - "§ltype§r: Number", - "§ldefault§r: 0", - "§lillustrate§r: The border color." - ] - }, - { - "type": "textbox", - "isCenter": true, - "stroke": 4278190335, - "content": [ - "§lDemo§r: 4278190335 (0xFF0000FF)", - "§nMinecraft Formatting", - "§r§00 §11 §22 §33", - "§44 §55 §66 §77", - "§88 §99 §aa §bb", - "§cc §dd §ee §ff", - "§r§0k §kMinecraft", - "§rl §lMinecraft", - "§rm §mMinecraft", - "§rn §nMinecraft", - "§ro §oMinecraft", - "§rr §rMinecraft" - ] - },{ - "type": "textbox", + "ref": "isCenter", "content": [ "-------------------------------", "", @@ -231,6 +221,7 @@ ] },{ "type": "textbox", + "ref": "isShadow", "content": [ "-------------------------------", "", diff --git a/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_3_image.json b/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_3_image.json new file mode 100644 index 00000000000..0305b73fa87 --- /dev/null +++ b/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_3_image.json @@ -0,0 +1,207 @@ +{ + "section": "Guide Widget API", + "title": "2. Image Widget", + "stream": [ + { + "type": "textbox", + "content": [ + "In this page we'll learn how to add an §4§lImage§r. There are three different forms of image supported here: §4Url§r, §4Item§r, and §4ResourceLocation§r. Don't worry, it's easy", + "-------------------------------", + "§lWidget Type§r: §nimage§r", + "-------------------------------", + "§lJSON§r:", + "{", + " \"type\": \"image\",", + " \"form\": \"Item\",", + " \"source\": \"minecraft:ender_pearl\",", + " \"width\": 100,", + " \"height\": 100", + "}", + "-------------------------------", + "§lContents§r" + ] + }, + { + "type": "textbox", + "link": "form", + "content": [ + " 1.§nform§r" + ] + }, + { + "type": "textbox", + "link": "source", + "content": [ + " 2.§nsource§r" + ] + }, + { + "type": "textbox", + "link": "wh", + "content": [ + " 3.§nwidth, height§r" + ] + }, + { + "type": "textbox", + "ref": "form", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §nform§r (§4required§r)", + "§ltype§r: String", + "§lillustrate§r: It can only be set one of §4Url§r, §4Item§r, or §4ResourceLocation§r.", + " \"url\" -- image url.", + " \"item\" -- The registered name of the Item in game.", + " \"resource\" -- The resource location." + ] + }, + { + "type": "textbox", + "isCenter": true, + "content": [ + "§lDemo§r: \"url\"" + ] + }, + { + "type": "image", + "hover_text": ["https://z3.ax1x.com/2021/07/29/Wb4Djs.gif"], + "form": "url", + "source": "https://z3.ax1x.com/2021/07/29/Wb4Djs.gif", + "stroke": 4278190080, + "stroke_width": 2, + "width": 100, + "height": 100 + }, + { + "type": "textbox", + "isCenter": true, + "content": [ + "§lDemo§r: \"item\"" + ] + }, + { + "type": "image", + "hover_text": ["minecraft:ender_pearl"], + "form": "item", + "source": "minecraft:ender_pearl", + "width": 100, + "height": 100 + }, + { + "type": "textbox", + "isCenter": true, + "content": [ + "§lDemo§r: \"resource\"" + ] + }, + { + "type": "image", + "hover_text": ["gregtech:textures/gui/icon/coke_oven.png"], + "form": "resource", + "source": "gregtech:textures/gui/icon/coke_oven.png", + "width": 100, + "height": 100 + }, + { + "type": "textbox", + "ref": "source", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §nsource§r (§4required§r)", + "§ltype§r: String", + "§lillustrate§r: The source of the picture. The three images above correspond to the following sources:" + ] + }, + { + "type": "textbox", + "isCenter": true, + "content": [ + "§lDemo§r: \"https://z3.ax1x.com/2021/07/29/Wb4Djs.gif\"" + ] + }, + { + "type": "image", + "hover_text": ["https://z3.ax1x.com/2021/07/29/Wb4Djs.gif"], + "form": "url", + "source": "https://z3.ax1x.com/2021/07/29/Wb4Djs.gif", + "stroke": 4278190080, + "stroke_width": 2, + "width": 100, + "height": 100 + }, + { + "type": "textbox", + "isCenter": true, + "content": [ + "§lDemo§r: \"minecraft:ender_pearl\"" + ] + }, + { + "type": "image", + "hover_text": ["minecraft:ender_pearl"], + "form": "item", + "source": "minecraft:ender_pearl", + "width": 100, + "height": 100 + }, + { + "type": "textbox", + "isCenter": true, + "content": [ + "§lDemo§r: \"gregtech:textures/gui/icon/coke_oven.png\"" + ] + }, + { + "type": "image", + "hover_text": ["gregtech:textures/gui/icon/coke_oven.png"], + "form": "resource", + "source": "gregtech:textures/gui/icon/coke_oven.png", + "width": 100, + "height": 100 + }, + { + "type": "textbox", + "ref": "wh", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §nwidth, height§r (§4required§r)", + "§ltype§r: Integer", + "§lillustrate§r: The Size of the picture." + ] + }, + { + "type": "textbox", + "isCenter": true, + "content": [ + "§lDemo§r: \"50, 50\"" + ] + }, + { + "type": "image", + "hover_text": ["minecraft:ender_pearl"], + "form": "item", + "source": "minecraft:ender_pearl", + "width": 50, + "height": 50 + }, + { + "type": "textbox", + "isCenter": true, + "content": [ + "§lDemo§r: \"100, 50\"" + ] + }, + { + "type": "image", + "hover_text": ["minecraft:ender_pearl"], + "form": "item", + "source": "minecraft:ender_pearl", + "width": 100, + "height": 50 + } + ], + "fixed": [] +} From 7faa2fcdfc74f17dd3ce07d989bff5171efd2fcd Mon Sep 17 00:00:00 2001 From: Yefancy Date: Thu, 29 Jul 2021 23:51:46 +0800 Subject: [PATCH 06/58] os system --- .../java/gregtech/api/gui/GuiTextures.java | 3 + .../api/gui/widgets/AbstractWidgetGroup.java | 4 +- .../api/terminal/app/guide/GuideApp.java | 4 +- .../gui/widgets/TerminalMenuWidget.java | 54 ----------- .../gui/widgets/guide/GuidePageWidget.java | 6 +- .../gui/widgets/guide/TextTreeWidget.java | 2 +- .../gui/widgets/os/TerminalDesktopWidget.java | 13 +++ .../gui/widgets/os/TerminalMenuWidget.java | 91 ++++++++++++++++++ .../gui/widgets/os/TerminalOSWidget.java | 77 +++++++++++++++ .../api/util/interpolate/Interpolator.java | 35 ++++--- .../behaviors/GuideTerminalBehaviour.java | 12 ++- .../gui/terminal/terminal_background.png | Bin 25109 -> 398697 bytes .../textures/gui/terminal/terminal_frame.png | Bin 0 -> 24072 bytes .../textures/gui/terminal/terminal_menu.png | Bin 0 -> 2798 bytes 14 files changed, 223 insertions(+), 78 deletions(-) delete mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/TerminalMenuWidget.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalDesktopWidget.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalMenuWidget.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalOSWidget.java create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/terminal_frame.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/terminal_menu.png diff --git a/src/main/java/gregtech/api/gui/GuiTextures.java b/src/main/java/gregtech/api/gui/GuiTextures.java index 478df98aefc..c93d5fdb872 100644 --- a/src/main/java/gregtech/api/gui/GuiTextures.java +++ b/src/main/java/gregtech/api/gui/GuiTextures.java @@ -168,5 +168,8 @@ public class GuiTextures { public static final TextureArea MULTIBLOCK_CATEGORY = TextureArea.fullImage("textures/gui/icon/coke_oven.png"); //Terminal + public static final TextureArea TERMINAL_FRAME = TextureArea.fullImage("textures/gui/terminal/terminal_frame.png"); public static final TextureArea TERMINAL_BACKGROUND = TextureArea.fullImage("textures/gui/terminal/terminal_background.png"); + public static final TextureArea TERMINAL_MENU = TextureArea.fullImage("textures/gui/terminal/terminal_menu.png"); + } diff --git a/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java b/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java index 286c38be809..42b63d80cab 100644 --- a/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java +++ b/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java @@ -248,8 +248,8 @@ public boolean mouseWheelMove(int mouseX, int mouseY, int wheelDelta) { @Override public boolean mouseClicked(int mouseX, int mouseY, int button) { - for (Widget widget : widgets) { - if(widget.mouseClicked(mouseX, mouseY, button)) { + for (int i = widgets.size() - 1; i >= 0; i--) { + if(widgets.get(i).mouseClicked(mouseX, mouseY, button)) { return true; } } diff --git a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java index 4156d7a2abb..3fffd971337 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java @@ -39,7 +39,7 @@ public void loadApp(WidgetGroup group, boolean isClient) { pageWidget = null; if (isClient && getTree() != null) { group.addWidget( - new TextTreeWidget<>(0, 0, 100, 232, getTree(), leaf -> { + new TextTreeWidget<>(0, 0, 133, 232, getTree(), leaf -> { if (pageWidget != null) { group.removeWidget(pageWidget); } @@ -75,7 +75,7 @@ public static JsonObject getConfig(String fileName) { } private GuidePageWidget loadLeaf(TreeNode> leaf) { - GuidePageWidget page = new GuidePageWidget(100, 0, 200, 232); + GuidePageWidget page = new GuidePageWidget(133, 0, 200, 232); if (leaf.isLeaf() && leaf.content != null) { JsonObject config = leaf.content.getSecond(); // add title diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/TerminalMenuWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/TerminalMenuWidget.java deleted file mode 100644 index 673d6b5b7c8..00000000000 --- a/src/main/java/gregtech/api/terminal/gui/widgets/TerminalMenuWidget.java +++ /dev/null @@ -1,54 +0,0 @@ -package gregtech.api.terminal.gui.widgets; - -import gregtech.api.gui.IRenderContext; -import gregtech.api.gui.resources.IGuiTexture; -import gregtech.api.gui.widgets.AbstractWidgetGroup; -import gregtech.api.gui.widgets.WidgetGroup; -import gregtech.api.terminal.app.AbstractApplication; -import gregtech.api.util.Position; -import gregtech.api.util.Size; - -public class TerminalMenuWidget extends AbstractWidgetGroup { - private int appCount; - private IGuiTexture background; - private final WidgetGroup activeContent; - private CircleButtonWidget activeButton; - public TerminalMenuWidget(int xPosition, int yPosition, int width, int height) { - super(new Position(xPosition, yPosition), new Size(width, height)); - this.activeContent = new WidgetGroup(new Position(27,-19), new Size(300, 232)); - this.addWidget(activeContent); - } - - public TerminalMenuWidget setBackground(IGuiTexture background) { - this.background = background; - return this; - } - - public void addApp(AbstractApplication application){ - int x = this.getSize().width / 2; - int r = 12; - int y = appCount * (2 * r + 4) + r; - CircleButtonWidget button = new CircleButtonWidget(x,y,r).setIcon(application.getIcon()).setHoverText(application.getName()); - button.setClickListener(clickData -> { - if (button != activeButton) { - activeContent.clearAllWidgets(); - application.loadApp(activeContent, clickData.isClient); - if (activeButton != null) { - activeButton.setFillColors(0xffffffff); - } - activeButton = button; - activeButton.setFillColors(0xFFAAF1DB); - } - }); - this.addWidget(button); - appCount++; - } - - @Override - public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { - if( background != null) { - background.draw(this.getPosition().x, this.getPosition().y, this.getSize().width, this.getSize().height); - } - super.drawInBackground(mouseX, mouseY, partialTicks, context); - } -} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java index efcc5110d43..1cfaea846e4 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java @@ -56,9 +56,9 @@ public void jumpToRef(String ref){ if (interpolator != null && !interpolator.isFinish()) return; for (Widget widget : widgets) { if (widget instanceof IGuideWidget && ref.equals(((IGuideWidget) widget).getRef())) { - interpolator = new Interpolator(scrollYOffset, widget.getSelfPosition().y, 20, Eases.EaseQuadOut, (value)->{ - setScrollYOffset(value.intValue()); - }); + interpolator = new Interpolator(scrollYOffset, widget.getSelfPosition().y, 20, Eases.EaseQuadOut, + value-> setScrollYOffset(value.intValue()), + value-> interpolator = null); interpolator.start(); } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java index ecd8db3fbad..e7e96cdb565 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java @@ -79,7 +79,7 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender if (background != null) { background.draw(position.x, position.y, size.width, size.height); } else { - gregtech.api.gui.resources.RenderUtil.renderRect(position.x, position.y, size.width, size.height, 0, 0x8f000000); + drawGradientRect(position.x, position.y, size.width, size.height, 0x8f000000, 0x8f000000); } RenderUtil.useScissor(position.x, position.y, size.width, size.height, ()->{ FontRenderer fr = Minecraft.getMinecraft().fontRenderer; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalDesktopWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalDesktopWidget.java new file mode 100644 index 00000000000..ccdf5f1ede2 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalDesktopWidget.java @@ -0,0 +1,13 @@ +package gregtech.api.terminal.gui.widgets.os; + +import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.util.Position; +import gregtech.api.util.Size; + +public class TerminalDesktopWidget extends WidgetGroup { + private final TerminalOSWidget os; + public TerminalDesktopWidget(Position position, Size size, TerminalOSWidget os) { + super(position, size); + this.os = os; + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalMenuWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalMenuWidget.java new file mode 100644 index 00000000000..83f5209e4fb --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalMenuWidget.java @@ -0,0 +1,91 @@ +package gregtech.api.terminal.gui.widgets.os; + +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.terminal.app.AbstractApplication; +import gregtech.api.terminal.gui.widgets.CircleButtonWidget; +import gregtech.api.util.Position; +import gregtech.api.util.Size; +import gregtech.api.util.interpolate.Eases; +import gregtech.api.util.interpolate.Interpolator; +import net.minecraft.client.renderer.GlStateManager; + +public class TerminalMenuWidget extends WidgetGroup { + private Interpolator interpolator; + private int appCount; + private IGuiTexture background; + private CircleButtonWidget activeButton; + private final TerminalOSWidget os; + public boolean isHide; + + + public TerminalMenuWidget(Position position, Size size, TerminalOSWidget os) { + super(position, size); + this.os = os; + } + + public TerminalMenuWidget setBackground(IGuiTexture background) { + this.background = background; + return this; + } + + public void addApp(AbstractApplication application){ + int x = this.getSize().width / 2; + int r = 12; + int y = appCount * (2 * r + 4) + r + 20; + CircleButtonWidget button = new CircleButtonWidget(x,y,r).setIcon(application.getIcon()).setHoverText(application.getName()); + button.setClickListener(clickData -> { + if (button != activeButton) { + os.openApplication(application, clickData.isClient); + if (activeButton != null) { + activeButton.setFillColors(0xffffffff); + } + activeButton = button; + activeButton.setFillColors(0xFFAAF1DB); + } + }); + this.addWidget(button); + appCount++; + } + + public void hideMenu() { + if (!isHide && interpolator == null) { + int y = getSelfPosition().y; + interpolator = new Interpolator(getSelfPosition().x, getSelfPosition().x - getSize().width, 10, Eases.EaseLinear, + value-> setSelfPosition(new Position(value.intValue(), y)), + value-> interpolator = null); + interpolator.start(); + isHide = true; + } + } + + public void showMenu() { + if (isHide && interpolator == null) { + int y = getSelfPosition().y; + interpolator = new Interpolator(getSelfPosition().x, getSelfPosition().x + getSize().width, 10, Eases.EaseLinear, + value-> setSelfPosition(new Position(value.intValue(), y)), + value-> interpolator = null); + interpolator.start(); + isHide = false; + } + } + + @Override + public void updateScreen() { + if(interpolator != null) interpolator.update(); + super.updateScreen(); + } + + @Override + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + GlStateManager.color(1,1,1,0.5f); + if( background != null) { + background.draw(this.getPosition().x, this.getPosition().y, this.getSize().width, this.getSize().height); + } else { + drawGradientRect(this.getPosition().x, this.getPosition().y, this.getSize().width, this.getSize().height, 0xff000000, 0xff000000); + } + GlStateManager.color(1,1,1,1); + super.drawInBackground(mouseX, mouseY, partialTicks, context); + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalOSWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalOSWidget.java new file mode 100644 index 00000000000..24e531a82f8 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalOSWidget.java @@ -0,0 +1,77 @@ +package gregtech.api.terminal.gui.widgets.os; + +import gregtech.api.gui.GuiTextures; +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.widgets.AbstractWidgetGroup; +import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.terminal.app.AbstractApplication; +import gregtech.api.terminal.gui.widgets.CircleButtonWidget; +import gregtech.api.util.Position; +import gregtech.api.util.Size; +import gregtech.api.util.interpolate.Eases; +import gregtech.api.util.interpolate.Interpolator; +import javafx.application.Application; +import javafx.geometry.Pos; +import net.minecraft.client.renderer.GlStateManager; + +import java.util.ArrayList; +import java.util.List; + +public class TerminalOSWidget extends AbstractWidgetGroup { + private IGuiTexture background; + private final List apps; + private final TerminalMenuWidget menu; + private final TerminalDesktopWidget desktop; + + public TerminalOSWidget(int xPosition, int yPosition, int width, int height) { + super(new Position(xPosition, yPosition), new Size(width, height)); + this.apps = new ArrayList<>(); + this.desktop = new TerminalDesktopWidget(new Position(0,0), new Size(333, 232), this); + this.menu = new TerminalMenuWidget(new Position(0,0), new Size(35, 232), this).setBackground(GuiTextures.TERMINAL_MENU); + this.addWidget(desktop); + this.addWidget(menu); + } + + public TerminalOSWidget setBackground(IGuiTexture background) { + this.background = background; + return this; + } + + public void installApplication(AbstractApplication application){ + apps.add(application); + menu.addApp(application); + } + + public void openApplication(AbstractApplication application, boolean isClient) { + desktop.clearAllWidgets(); + application.loadApp(desktop, isClient); + } + + public void backToHome() { + } + + @Override + public boolean mouseClicked(int mouseX, int mouseY, int button) { + if (super.mouseClicked(mouseX, mouseY, button)) { + return true; + } else { + if (menu.isHide) { + menu.showMenu(); + } else { + menu.hideMenu(); + } + } + return true; + } + + @Override + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + if( background != null) { + background.draw(this.getPosition().x, this.getPosition().y, this.getSize().width, this.getSize().height); + } else { + drawGradientRect(this.getPosition().x, this.getPosition().y, this.getSize().width, this.getSize().height, -1, -1); + } + super.drawInBackground(mouseX, mouseY, partialTicks, context); + } +} diff --git a/src/main/java/gregtech/api/util/interpolate/Interpolator.java b/src/main/java/gregtech/api/util/interpolate/Interpolator.java index 2eef08dea52..7e73e7a8e58 100644 --- a/src/main/java/gregtech/api/util/interpolate/Interpolator.java +++ b/src/main/java/gregtech/api/util/interpolate/Interpolator.java @@ -1,32 +1,42 @@ package gregtech.api.util.interpolate; +import crafttweaker.IAction; +import gregtech.api.util.function.BooleanConsumer; import net.minecraft.util.ITickable; +import scala.Function; +import scala.swing.Action; import java.util.function.Consumer; public class Interpolator implements ITickable { - float from; - float to; - int duration; - IEase ease; - Consumer callback; + private final float from; + private final float to; + private final int duration; + private final IEase ease; + private final Consumer interpolate; + private final Consumer callback; - int tick = -1; + private int tick = 0; - public Interpolator(float from, float to, int duration, IEase ease, Consumer callback) { + public Interpolator(float from, float to, int duration, IEase ease, Consumer interpolate) { + this(from, to, duration, ease, interpolate, null); + } + + public Interpolator(float from, float to, int duration, IEase ease, Consumer interpolate, Consumer callback) { this.from = from; this.to = to; this.duration = duration; this.ease = ease; + this.interpolate = interpolate; this.callback = callback; } public void reset() { - tick = -1; + tick = 0; } public void start() { - tick = 0; + tick = 1; } public boolean isFinish(){ @@ -35,8 +45,11 @@ public boolean isFinish(){ @Override public void update() { - if (tick < 0 || tick >= duration) return; - callback.accept(ease.getInterpolation(tick * 1.0f / duration) * (to - from) + from); + if (tick < 1 || tick > duration) return; + if (tick == duration) { + callback.accept(ease.getInterpolation(tick * 1.0f / duration) * (to - from) + from); + } + interpolate.accept(ease.getInterpolation(tick * 1.0f / duration) * (to - from) + from); tick++; } } diff --git a/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java b/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java index 8cc400aa343..82d0d45dc11 100644 --- a/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java +++ b/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java @@ -2,11 +2,12 @@ import gregtech.api.gui.GuiTextures; import gregtech.api.gui.ModularUI; +import gregtech.api.gui.widgets.ImageWidget; import gregtech.api.items.gui.ItemUIFactory; import gregtech.api.items.gui.PlayerInventoryHolder; import gregtech.api.items.metaitem.stats.IItemBehaviour; import gregtech.api.terminal.TerminalBuilder; -import gregtech.api.terminal.gui.widgets.TerminalMenuWidget; +import gregtech.api.terminal.gui.widgets.os.TerminalOSWidget; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.util.ActionResult; @@ -34,10 +35,11 @@ public void addInformation(ItemStack itemStack, List lines) { @Override public ModularUI createUI(PlayerInventoryHolder holder, EntityPlayer entityPlayer) { - TerminalMenuWidget menu = new TerminalMenuWidget(15, 30, 24, 24); - TerminalBuilder.getApplications().forEach(menu::addApp); - return ModularUI.builder(GuiTextures.TERMINAL_BACKGROUND, 380, 256) - .widget(menu) + TerminalOSWidget os = new TerminalOSWidget(12, 11, 333, 232).setBackground(GuiTextures.TERMINAL_BACKGROUND); + TerminalBuilder.getApplications().forEach(os::installApplication); + return ModularUI.builder(GuiTextures.TERMINAL_FRAME, 380, 256) + .widget(os) + .widget(new ImageWidget(0, 0, 380, 256, GuiTextures.TERMINAL_FRAME)) .build(holder, entityPlayer); } } diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_background.png b/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_background.png index 3bb4031f9c1324203ff6cc74b891bdd4a13e2a3f..e7a6cf37cdbec068c9478bf130b6cc07667a4e1c 100644 GIT binary patch literal 398697 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
kx^}qa|^IO03d;Ftc|8;)t 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 tHo3?QDO7z`!Ew-J>Q|R{{ZX@#ajRX literal 25109 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_menu.png b/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_menu.png new file mode 100644 index 0000000000000000000000000000000000000000..3a2c78e329fbef69538d22bcf820558000b9b9ff GIT binary patch literal 2798 zcmeHJO^@3|81^EHXi+85N~l5{EEkDZF!qe?*cq#)Y@MYE!pmwKX_pgBX2yxNvB%i6 zn`AFYy&!HJxPU5g;(&yJdk>U9fVgphUjRbAaYT&sVYcn|gA~CdcLh`Peso@qekDndGk~CI9qhzt2FJo_4>D_eR1o8rk(jC z?eEFG_?>`?%p^<KAhzAtbsHkzg1&_u08s$Fz`^?RW2k5)OM;!wTgzDLEi^__7J+3=CKGew zn4%n72xDwP+p=w-5TKgnl1xEfU0gAActy*!kg3S^nvo2|fea0$ba8~NXlV0lX_GR{ znv%joCajM%2Qu2=ii2`I56-B?$2{Y?tP~bC*kUB4s7B%;)Xnle0hG0I+{8FhOO`bu zD!F;6j*G&cvj; zd<@PzMDozEp^X6afsOmfu5$*x*I+wPmObjA17NrWT)H%oJdr`DqiXg|d(nnOuB1|O`IUyzA7%J}`Q-jvSq*vtd(ZZiBkqbo+2*1B(|GV&| zC3HmcAy>WCGU}sPbr)JB#JWFM^R;6gYXw(rupT!3SG_bHoac(VRQ(xDc3;-Cr@!uX zHu}?BfByXA**oz0JKw+Z+uy(b_2mn{zkj*Ae&O!tvlqYn>6f*SNS~d4PaQaQ;M9Tt d$pN```_(faUt0g{tNI^lZ*!~j?X?eX{sU(co-zOc literal 0 HcmV?d00001 From 13c5c07ed3b1922b6d8017e8e4aca98e39fbd10f Mon Sep 17 00:00:00 2001 From: KilaBash Date: Fri, 30 Jul 2021 01:33:17 +0800 Subject: [PATCH 07/58] os --- .../java/gregtech/api/gui/GuiTextures.java | 2 + .../api/terminal/app/AbstractApplication.java | 15 +++-- .../api/terminal/app/guide/GuideApp.java | 13 ++-- .../api/terminal/app/guide/ItemGuideApp.java | 5 ++ .../app/guide/MultiBlockGuideApp.java | 5 ++ .../app/guide/SimpleMachineGuideApp.java | 5 ++ .../terminal/app/guide/TutorialGuideApp.java | 5 ++ .../gui/widgets/CircleButtonWidget.java | 2 +- .../gui/widgets/os/TerminalMenuWidget.java | 4 ++ .../gui/widgets/os/TerminalOSWidget.java | 57 ++++++++++++------ .../behaviors/GuideTerminalBehaviour.java | 3 + .../textures/gui/terminal/terminal_home.png | Bin 0 -> 2882 bytes 12 files changed, 86 insertions(+), 30 deletions(-) create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/terminal_home.png diff --git a/src/main/java/gregtech/api/gui/GuiTextures.java b/src/main/java/gregtech/api/gui/GuiTextures.java index c93d5fdb872..144a9418178 100644 --- a/src/main/java/gregtech/api/gui/GuiTextures.java +++ b/src/main/java/gregtech/api/gui/GuiTextures.java @@ -171,5 +171,7 @@ public class GuiTextures { public static final TextureArea TERMINAL_FRAME = TextureArea.fullImage("textures/gui/terminal/terminal_frame.png"); public static final TextureArea TERMINAL_BACKGROUND = TextureArea.fullImage("textures/gui/terminal/terminal_background.png"); public static final TextureArea TERMINAL_MENU = TextureArea.fullImage("textures/gui/terminal/terminal_menu.png"); + public static final TextureArea TERMINAL_HOME = TextureArea.fullImage("textures/gui/terminal/terminal_home.png"); + } diff --git a/src/main/java/gregtech/api/terminal/app/AbstractApplication.java b/src/main/java/gregtech/api/terminal/app/AbstractApplication.java index b1d2fd1ffaf..da6ecf8a6c2 100644 --- a/src/main/java/gregtech/api/terminal/app/AbstractApplication.java +++ b/src/main/java/gregtech/api/terminal/app/AbstractApplication.java @@ -1,14 +1,17 @@ package gregtech.api.terminal.app; -import gregtech.api.gui.Widget; import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.util.Position; +import gregtech.api.util.Size; +import net.minecraft.nbt.NBTTagCompound; -public abstract class AbstractApplication { +public abstract class AbstractApplication extends WidgetGroup { protected final String name; protected final IGuiTexture icon; public AbstractApplication (String name, IGuiTexture icon) { + super(Position.ORIGIN, new Size(333, 232)); this.name = name; this.icon = icon; } @@ -21,12 +24,14 @@ public IGuiTexture getIcon() { return icon; } - public void loadApp(WidgetGroup group, boolean isClient) { + public abstract AbstractApplication openApp(boolean isClient, NBTTagCompound nbt); - } + public void closeApp(boolean isClient, NBTTagCompound nbt) { - public void unloadApp(boolean isClient) { + } + public boolean isBackgroundApp() { + return false; } } diff --git a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java index 3fffd971337..b07663f570c 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java @@ -12,6 +12,7 @@ import gregtech.api.terminal.gui.widgets.guide.*; import gregtech.api.terminal.util.TreeNode; import net.minecraft.client.Minecraft; +import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.ResourceLocation; import net.minecraft.util.Tuple; @@ -34,20 +35,24 @@ public GuideApp(String name, IGuiTexture icon) { super(name, icon); } + protected abstract GuideApp createAPP(); + @Override - public void loadApp(WidgetGroup group, boolean isClient) { + public GuideApp openApp(boolean isClient, NBTTagCompound nbt) { + GuideApp app = createAPP(); pageWidget = null; if (isClient && getTree() != null) { - group.addWidget( + app.addWidget( new TextTreeWidget<>(0, 0, 133, 232, getTree(), leaf -> { if (pageWidget != null) { - group.removeWidget(pageWidget); + app.removeWidget(pageWidget); } pageWidget = loadLeaf(leaf); - group.addWidget(pageWidget); + app.addWidget(pageWidget); }, this::itemIcon, this::itemName).setNodeTexture(GuiTextures.BORDERED_BACKGROUND).setLeafTexture(GuiTextures.SLOT_DARKENED) ); } + return app; } protected IGuiTexture itemIcon(T item) { diff --git a/src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java index a79e4d4acc6..ab11a1f1a8a 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java @@ -23,6 +23,11 @@ public ItemGuideApp() { super("Items Machines", new ItemStackTexture(MetaItems.SCANNER.getStackForm())); } + @Override + protected GuideApp> createAPP() { + return new ItemGuideApp(); + } + @Override protected TreeNode, JsonObject>> getTree() { return ROOT; diff --git a/src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java index 311e0dbec03..a68f32b377f 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java @@ -28,6 +28,11 @@ protected TreeNode> getTree() { return ROOT; } + @Override + protected GuideApp createAPP() { + return new MultiBlockGuideApp(); + } + @Override protected IGuiTexture itemIcon(MetaTileEntity item) { return new ItemStackTexture(item.getStackForm()); diff --git a/src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java index 633e4943ad9..06cef73351e 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java @@ -28,6 +28,11 @@ protected TreeNode> getTree() { return ROOT; } + @Override + protected GuideApp createAPP() { + return new SimpleMachineGuideApp(); + } + @Override protected IGuiTexture itemIcon(MetaTileEntity item) { return new ItemStackTexture(item.getStackForm()); diff --git a/src/main/java/gregtech/api/terminal/app/guide/TutorialGuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/TutorialGuideApp.java index 32aad915681..4d1c0e8b361 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/TutorialGuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/TutorialGuideApp.java @@ -39,6 +39,11 @@ public TutorialGuideApp() { super("Tutorials", new ItemStackTexture(Items.PAPER)); } + @Override + protected GuideApp createAPP() { + return new TutorialGuideApp(); + } + @Override protected TreeNode> getTree() { return ROOT; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java index 9eadc58360f..1f79d1ab114 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java @@ -91,7 +91,7 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender @Override public void drawInForeground(int mouseX, int mouseY) { - if (this.isMouseOverElement(mouseX, mouseY)) { + if (hoverText != null && this.isMouseOverElement(mouseX, mouseY)) { this.drawHoveringText(ItemStack.EMPTY, Collections.singletonList(I18n.format(hoverText)), 300, mouseX, mouseY); } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalMenuWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalMenuWidget.java index 83f5209e4fb..b3b427d1c51 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalMenuWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalMenuWidget.java @@ -62,6 +62,10 @@ public void hideMenu() { public void showMenu() { if (isHide && interpolator == null) { + if (activeButton != null) { + activeButton.setFillColors(0xffffffff); + } + activeButton = null; int y = getSelfPosition().y; interpolator = new Interpolator(getSelfPosition().x, getSelfPosition().x + getSize().width, 10, Eases.EaseLinear, value-> setSelfPosition(new Position(value.intValue(), y)), diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalOSWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalOSWidget.java index 24e531a82f8..db7f1fa7aa6 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalOSWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalOSWidget.java @@ -2,12 +2,14 @@ import gregtech.api.gui.GuiTextures; import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.Widget; import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.widgets.AbstractWidgetGroup; import gregtech.api.gui.widgets.WidgetGroup; import gregtech.api.terminal.app.AbstractApplication; import gregtech.api.terminal.gui.widgets.CircleButtonWidget; import gregtech.api.util.Position; +import gregtech.api.util.RenderUtil; import gregtech.api.util.Size; import gregtech.api.util.interpolate.Eases; import gregtech.api.util.interpolate.Interpolator; @@ -18,17 +20,19 @@ import java.util.ArrayList; import java.util.List; +import static gregtech.api.gui.impl.ModularUIGui.*; + public class TerminalOSWidget extends AbstractWidgetGroup { private IGuiTexture background; - private final List apps; + private final List openedApps; private final TerminalMenuWidget menu; private final TerminalDesktopWidget desktop; public TerminalOSWidget(int xPosition, int yPosition, int width, int height) { super(new Position(xPosition, yPosition), new Size(width, height)); - this.apps = new ArrayList<>(); - this.desktop = new TerminalDesktopWidget(new Position(0,0), new Size(333, 232), this); - this.menu = new TerminalMenuWidget(new Position(0,0), new Size(35, 232), this).setBackground(GuiTextures.TERMINAL_MENU); + this.openedApps = new ArrayList<>(); + this.desktop = new TerminalDesktopWidget(Position.ORIGIN, new Size(333, 232), this); + this.menu = new TerminalMenuWidget(Position.ORIGIN, new Size(35, 232), this).setBackground(GuiTextures.TERMINAL_MENU); this.addWidget(desktop); this.addWidget(menu); } @@ -39,39 +43,52 @@ public TerminalOSWidget setBackground(IGuiTexture background) { } public void installApplication(AbstractApplication application){ - apps.add(application); menu.addApp(application); } public void openApplication(AbstractApplication application, boolean isClient) { - desktop.clearAllWidgets(); - application.loadApp(desktop, isClient); + for (AbstractApplication app : openedApps) { + if (app.getClass() == application.getClass()) { + app.setVisible(true); + return; + } + } + AbstractApplication app = application.openApp(isClient, null); + openedApps.add(app); + desktop.addWidget(app); + menu.hideMenu(); } - public void backToHome() { + public void closeApplication(AbstractApplication application, boolean isClient) { + desktop.removeWidget(application); + application.closeApp(isClient, null); } - @Override - public boolean mouseClicked(int mouseX, int mouseY, int button) { - if (super.mouseClicked(mouseX, mouseY, button)) { - return true; - } else { - if (menu.isHide) { - menu.showMenu(); + public void backToHome() { + List close = new ArrayList<>(); + for (AbstractApplication app : openedApps) { + if (app.isBackgroundApp()) { + app.setVisible(false); } else { - menu.hideMenu(); + close.add(app); + closeApplication(app, isClientSide()); } } - return true; + close.forEach(openedApps::remove); + menu.showMenu(); } @Override public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + Position position = getPosition(); + Size size = getSize(); if( background != null) { - background.draw(this.getPosition().x, this.getPosition().y, this.getSize().width, this.getSize().height); + background.draw(position.x, position.y, size.width, size.height); } else { - drawGradientRect(this.getPosition().x, this.getPosition().y, this.getSize().width, this.getSize().height, -1, -1); + drawGradientRect(position.x, position.y, size.width, size.height, -1, -1); } - super.drawInBackground(mouseX, mouseY, partialTicks, context); + RenderUtil.useScissor(position.x, position.y, size.width, size.height, ()->{ + super.drawInBackground(mouseX, mouseY, partialTicks, context); + }); } } diff --git a/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java b/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java index 82d0d45dc11..c4bbe83c2b7 100644 --- a/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java +++ b/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java @@ -7,6 +7,7 @@ import gregtech.api.items.gui.PlayerInventoryHolder; import gregtech.api.items.metaitem.stats.IItemBehaviour; import gregtech.api.terminal.TerminalBuilder; +import gregtech.api.terminal.gui.widgets.CircleButtonWidget; import gregtech.api.terminal.gui.widgets.os.TerminalOSWidget; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; @@ -36,10 +37,12 @@ public void addInformation(ItemStack itemStack, List lines) { @Override public ModularUI createUI(PlayerInventoryHolder holder, EntityPlayer entityPlayer) { TerminalOSWidget os = new TerminalOSWidget(12, 11, 333, 232).setBackground(GuiTextures.TERMINAL_BACKGROUND); + CircleButtonWidget home = new CircleButtonWidget(362, 126, 12).setIcon(GuiTextures.TERMINAL_HOME).setFillColors(0xff9197A5).setClickListener(clickData -> os.backToHome()); TerminalBuilder.getApplications().forEach(os::installApplication); return ModularUI.builder(GuiTextures.TERMINAL_FRAME, 380, 256) .widget(os) .widget(new ImageWidget(0, 0, 380, 256, GuiTextures.TERMINAL_FRAME)) + .widget(home) .build(holder, entityPlayer); } } diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_home.png b/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_home.png new file mode 100644 index 0000000000000000000000000000000000000000..18829fb5fb4f947145a60f6b4b348d962423dc5a GIT binary patch literal 2882 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 literal 0 HcmV?d00001 From b0de1d1a0c579abc26cb37624f2ce2f9da1b48b5 Mon Sep 17 00:00:00 2001 From: Yefancy Date: Sat, 31 Jul 2021 00:54:13 +0800 Subject: [PATCH 08/58] guideeditor --- .../java/gregtech/api/gui/GuiTextures.java | 2 +- src/main/java/gregtech/api/gui/Widget.java | 16 ++- .../api/gui/resources/ItemStackTexture.java | 1 + .../api/gui/resources/RenderUtil.java | 2 - .../onlinepictexture/PictureTexture.java | 10 +- .../api/gui/widgets/AbstractWidgetGroup.java | 28 ++-- .../api/terminal/TerminalBuilder.java | 1 + .../api/terminal/app/AbstractApplication.java | 80 ++++++++++- .../api/terminal/app/GuideEditorApp.java | 22 +++ .../api/terminal/app/guide/GuideApp.java | 80 +++-------- .../api/terminal/app/guide/ItemGuideApp.java | 5 - .../app/guide/MultiBlockGuideApp.java | 5 - .../app/guide/SimpleMachineGuideApp.java | 5 - .../terminal/app/guide/TutorialGuideApp.java | 5 - .../gui/widgets/CircleButtonWidget.java | 16 ++- .../gui/widgets/guide/GuideEditor.java | 12 ++ .../widgets/guide/GuideEditorPageWidget.java | 127 ++++++++++++++++++ .../gui/widgets/guide/GuidePageWidget.java | 121 ++++++++++++++++- .../gui/widgets/guide/GuideWidget.java | 56 ++++++++ .../gui/widgets/guide/IGuideWidget.java | 1 + .../gui/widgets/guide/ImageWidget.java | 12 +- .../gui/widgets/guide/TextBoxWidget.java | 16 ++- .../gui/widgets/os/TerminalDesktopWidget.java | 35 +++++ .../gui/widgets/os/TerminalMenuWidget.java | 80 +++++++---- .../gui/widgets/os/TerminalOSWidget.java | 118 +++++++++++++--- .../api/util/interpolate/Interpolator.java | 3 +- .../behaviors/GuideTerminalBehaviour.java | 10 +- .../gui/terminal/guide_editor/icon.png | Bin 0 -> 32504 bytes .../textures/gui/terminal/terminal_close.png | Bin 0 -> 1798 bytes .../textures/gui/terminal/terminal_home.png | Bin 2882 -> 1496 bytes .../gui/terminal/terminal_minimum.png | Bin 0 -> 1672 bytes .../gui/terminal/terminal_setting.png | Bin 0 -> 1712 bytes 32 files changed, 703 insertions(+), 166 deletions(-) create mode 100644 src/main/java/gregtech/api/terminal/app/GuideEditorApp.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditor.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditorPageWidget.java create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/guide_editor/icon.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/terminal_close.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/terminal_minimum.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/terminal_setting.png diff --git a/src/main/java/gregtech/api/gui/GuiTextures.java b/src/main/java/gregtech/api/gui/GuiTextures.java index 144a9418178..bcd8c7d543f 100644 --- a/src/main/java/gregtech/api/gui/GuiTextures.java +++ b/src/main/java/gregtech/api/gui/GuiTextures.java @@ -172,6 +172,6 @@ public class GuiTextures { public static final TextureArea TERMINAL_BACKGROUND = TextureArea.fullImage("textures/gui/terminal/terminal_background.png"); public static final TextureArea TERMINAL_MENU = TextureArea.fullImage("textures/gui/terminal/terminal_menu.png"); public static final TextureArea TERMINAL_HOME = TextureArea.fullImage("textures/gui/terminal/terminal_home.png"); - + public static final TextureArea TERMINAL_SETTING = TextureArea.fullImage("textures/gui/terminal/terminal_setting.png"); } diff --git a/src/main/java/gregtech/api/gui/Widget.java b/src/main/java/gregtech/api/gui/Widget.java index 550f38719e8..5fa87c073e1 100644 --- a/src/main/java/gregtech/api/gui/Widget.java +++ b/src/main/java/gregtech/api/gui/Widget.java @@ -45,6 +45,7 @@ public abstract class Widget { private transient Position position; private transient Size size; private transient boolean isVisible; + private transient boolean isActive; public Widget(Position selfPosition, Size size) { Preconditions.checkNotNull(selfPosition, "selfPosition"); @@ -53,6 +54,7 @@ public Widget(Position selfPosition, Size size) { this.size = size; this.position = this.parentPosition.add(selfPosition); this.isVisible = true; + this.isActive = true; } public Widget(int x, int y, int width, int height) { @@ -77,7 +79,7 @@ public void setParentPosition(Position parentPosition) { recomputePosition(); } - protected void setSelfPosition(Position selfPosition) { + public void setSelfPosition(Position selfPosition) { Preconditions.checkNotNull(selfPosition, "selfPosition"); this.selfPosition = selfPosition; recomputePosition(); @@ -87,7 +89,7 @@ public Position getSelfPosition() { return selfPosition; } - protected void setSize(Size size) { + public void setSize(Size size) { Preconditions.checkNotNull(size, "size"); this.size = size; onSizeUpdate(); @@ -109,13 +111,21 @@ public void setVisible(boolean visible) { isVisible = visible; } + public boolean isActive() { + return isActive; + } + + public void setActive(boolean active) { + isActive = active; + } + public Rectangle toRectangleBox() { Position pos = getPosition(); Size size = getSize(); return new Rectangle(pos.x, pos.y, size.width, size.height); } - private void recomputePosition() { + protected void recomputePosition() { this.position = this.parentPosition.add(selfPosition); onPositionUpdate(); } diff --git a/src/main/java/gregtech/api/gui/resources/ItemStackTexture.java b/src/main/java/gregtech/api/gui/resources/ItemStackTexture.java index 1bcdc7a461d..bed8d58cccf 100644 --- a/src/main/java/gregtech/api/gui/resources/ItemStackTexture.java +++ b/src/main/java/gregtech/api/gui/resources/ItemStackTexture.java @@ -26,6 +26,7 @@ public void draw(double x, double y, int width, int height) { GlStateManager.translate(x * 16 / width, y * 16 / height, 0); RenderItem renderItem = Minecraft.getMinecraft().getRenderItem(); renderItem.renderItemAndEffectIntoGUI(itemStack, 0, 0); + GlStateManager.enableAlpha(); GlStateManager.popMatrix(); RenderHelper.disableStandardItemLighting(); } diff --git a/src/main/java/gregtech/api/gui/resources/RenderUtil.java b/src/main/java/gregtech/api/gui/resources/RenderUtil.java index b0dce74f99b..cf8a28ab440 100644 --- a/src/main/java/gregtech/api/gui/resources/RenderUtil.java +++ b/src/main/java/gregtech/api/gui/resources/RenderUtil.java @@ -139,7 +139,6 @@ public static void renderCircle(float x, float y, float r, int color, int segmen } tessellator.draw(); GlStateManager.enableTexture2D(); - GlStateManager.disableBlend(); } public static void renderSector(float x, float y, float r, int color, int segments, int from, int to) { @@ -159,7 +158,6 @@ public static void renderSector(float x, float y, float r, int color, int segmen } tessellator.draw(); GlStateManager.enableTexture2D(); - GlStateManager.disableBlend(); } public static void renderRect(float x, float y, float width, float height, float z, int color) { diff --git a/src/main/java/gregtech/api/gui/resources/onlinepictexture/PictureTexture.java b/src/main/java/gregtech/api/gui/resources/onlinepictexture/PictureTexture.java index 268734fb623..82efb803fae 100644 --- a/src/main/java/gregtech/api/gui/resources/onlinepictexture/PictureTexture.java +++ b/src/main/java/gregtech/api/gui/resources/onlinepictexture/PictureTexture.java @@ -24,7 +24,7 @@ public void draw(double x, double y, int width, int height) { render((float)x, (float)y, 1, 1, 0, width, height, false, false); } - public void render(float x, float y, float ux, float uv, float rotation, float sizeX, float sizeY, boolean flippedX, boolean flippedY) { + public void render(float x, float y, float width, float height, float rotation, float scaleX, float scaleY, boolean flippedX, boolean flippedY) { this.beforeRender(); GlStateManager.color(1,1,1,1); GlStateManager.enableBlend(); @@ -35,16 +35,16 @@ public void render(float x, float y, float ux, float uv, float rotation, float s GlStateManager.pushMatrix(); GL11.glRotated(rotation, 0, 0, 1); GlStateManager.enableRescaleNormal(); - GL11.glScaled(sizeX, sizeY, 1); + GL11.glScaled(scaleX, scaleY, 1); GL11.glBegin(GL11.GL_POLYGON); GL11.glTexCoord3f(flippedY ? 1 : 0, flippedX ? 1 : 0, 0); GL11.glVertex3f(x, y, 0.01f); GL11.glTexCoord3f(flippedY ? 1 : 0, flippedX ? 0 : 1, 0); - GL11.glVertex3f(x, y + uv, 0.01f); + GL11.glVertex3f(x, y + height, 0.01f); GL11.glTexCoord3f(flippedY ? 0 : 1, flippedX ? 0 : 1, 0); - GL11.glVertex3f(x + ux, y + uv, 0.01f); + GL11.glVertex3f(x + width, y + height, 0.01f); GL11.glTexCoord3f(flippedY ? 0 : 1, flippedX ? 1 : 0, 0); - GL11.glVertex3f(x + ux, y, 0.01f); + GL11.glVertex3f(x + width, y, 0.01f); GL11.glEnd(); GlStateManager.popMatrix(); GlStateManager.disableRescaleNormal(); diff --git a/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java b/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java index 42b63d80cab..25f85dab8a1 100644 --- a/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java +++ b/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java @@ -21,7 +21,7 @@ public class AbstractWidgetGroup extends Widget implements IGhostIngredientTarget, IIngredientSlot { - protected final List widgets = new ArrayList<>(); + public final List widgets = new ArrayList<>(); private final WidgetGroupUIAccess groupUIAccess = new WidgetGroupUIAccess(); private final boolean isDynamicSized; private boolean initialized = false; @@ -206,14 +206,18 @@ public Object getIngredientOverMouse(int mouseX, int mouseY) { @Override public void detectAndSendChanges() { for (Widget widget : widgets) { - widget.detectAndSendChanges(); + if (widget.isActive()) { + widget.detectAndSendChanges(); + } } } @Override public void updateScreen() { for (Widget widget : widgets) { - widget.updateScreen(); + if (widget.isActive()) { + widget.updateScreen(); + } } } @@ -238,8 +242,9 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender @Override public boolean mouseWheelMove(int mouseX, int mouseY, int wheelDelta) { - for (Widget widget : widgets) { - if(widget.mouseWheelMove(mouseX, mouseY, wheelDelta)) { + for (int i = widgets.size() - 1; i >= 0; i--) { + Widget widget = widgets.get(i); + if(widget.isVisible() && widget.mouseWheelMove(mouseX, mouseY, wheelDelta)) { return true; } } @@ -249,7 +254,8 @@ public boolean mouseWheelMove(int mouseX, int mouseY, int wheelDelta) { @Override public boolean mouseClicked(int mouseX, int mouseY, int button) { for (int i = widgets.size() - 1; i >= 0; i--) { - if(widgets.get(i).mouseClicked(mouseX, mouseY, button)) { + Widget widget = widgets.get(i); + if(widget.isVisible() && widget.mouseClicked(mouseX, mouseY, button)) { return true; } } @@ -258,8 +264,9 @@ public boolean mouseClicked(int mouseX, int mouseY, int button) { @Override public boolean mouseDragged(int mouseX, int mouseY, int button, long timeDragged) { - for (Widget widget : widgets) { - if(widget.mouseDragged(mouseX, mouseY, button, timeDragged)) { + for (int i = widgets.size() - 1; i >= 0; i--) { + Widget widget = widgets.get(i); + if(widget.isVisible() && widget.mouseDragged(mouseX, mouseY, button, timeDragged)) { return true; } } @@ -268,8 +275,9 @@ public boolean mouseDragged(int mouseX, int mouseY, int button, long timeDragged @Override public boolean mouseReleased(int mouseX, int mouseY, int button) { - for (Widget widget : widgets) { - if(widget.mouseReleased(mouseX, mouseY, button)) { + for (int i = widgets.size() - 1; i >= 0; i--) { + Widget widget = widgets.get(i); + if(widget.isVisible() && widget.mouseReleased(mouseX, mouseY, button)) { return true; } } diff --git a/src/main/java/gregtech/api/terminal/TerminalBuilder.java b/src/main/java/gregtech/api/terminal/TerminalBuilder.java index fb667768b4c..38b4f0a0cb2 100644 --- a/src/main/java/gregtech/api/terminal/TerminalBuilder.java +++ b/src/main/java/gregtech/api/terminal/TerminalBuilder.java @@ -17,6 +17,7 @@ public static void init() { appRegister.add(new MultiBlockGuideApp()); appRegister.add(new ItemGuideApp()); appRegister.add(new TutorialGuideApp()); + appRegister.add(new GuideEditorApp()); } public static List getApplications() { diff --git a/src/main/java/gregtech/api/terminal/app/AbstractApplication.java b/src/main/java/gregtech/api/terminal/app/AbstractApplication.java index da6ecf8a6c2..d2431be8a34 100644 --- a/src/main/java/gregtech/api/terminal/app/AbstractApplication.java +++ b/src/main/java/gregtech/api/terminal/app/AbstractApplication.java @@ -1,14 +1,23 @@ package gregtech.api.terminal.app; +import gregtech.api.gui.IRenderContext; import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.widgets.WidgetGroup; import gregtech.api.util.Position; import gregtech.api.util.Size; +import gregtech.api.util.interpolate.Eases; +import gregtech.api.util.interpolate.Interpolator; +import javafx.geometry.Pos; +import net.minecraft.client.renderer.GlStateManager; import net.minecraft.nbt.NBTTagCompound; +import java.util.function.Consumer; + public abstract class AbstractApplication extends WidgetGroup { + protected Interpolator interpolator; protected final String name; protected final IGuiTexture icon; + private float scale; public AbstractApplication (String name, IGuiTexture icon) { super(Position.ORIGIN, new Size(333, 232)); @@ -24,14 +33,81 @@ public IGuiTexture getIcon() { return icon; } - public abstract AbstractApplication openApp(boolean isClient, NBTTagCompound nbt); + public abstract AbstractApplication createApp(boolean isClient, NBTTagCompound nbt); - public void closeApp(boolean isClient, NBTTagCompound nbt) { + public void maximizeApp(Consumer callback) { + this.scale = 0; + setVisible(true); + interpolator = new Interpolator(0, 1, 10, Eases.EaseLinear, + value-> scale = value.floatValue(), + value-> { + interpolator = null; + if (callback != null) { + callback.accept(this); + } + }); + interpolator.start(); + } + public void minimizeApp(Consumer callback) { + this.scale = 1; + interpolator = new Interpolator(1, 0, 10, Eases.EaseLinear, + value-> scale = value.floatValue(), + value-> { + setVisible(false); + interpolator = null; + if (callback != null) { + callback.accept(this); + } + }); + interpolator.start(); + } + + public void closeApp(boolean isClient, NBTTagCompound nbt) { } public boolean isBackgroundApp() { return false; } + @Override + public void updateScreen() { + if (interpolator != null) { + interpolator.update(); + } + super.updateScreen(); + } + + @Override + public void drawInForeground(int mouseX, int mouseY) { + if (scale == 0) { + return; + } if (scale != 1) { + GlStateManager.pushMatrix(); + GlStateManager.translate((this.gui.getScreenWidth() - this.gui.getScreenWidth() * scale) / 2, + (this.gui.getScreenHeight() - this.gui.getScreenHeight() * scale) / 2, 0); + GlStateManager.scale(scale, scale, 1); + super.drawInForeground(0, 0); + GlStateManager.popMatrix(); + } else { + super.drawInForeground(mouseX, mouseY); + } + } + + @Override + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + if (scale == 0) { + return; + }if (scale != 1) { + GlStateManager.pushMatrix(); + GlStateManager.translate((this.gui.getScreenWidth() - this.gui.getScreenWidth() * scale) / 2, + (this.gui.getScreenHeight() - this.gui.getScreenHeight() * scale) / 2, 0); + GlStateManager.scale(scale, scale, 1); + super.drawInBackground(0, 0, partialTicks, context); + GlStateManager.popMatrix(); + } else { + super.drawInBackground(mouseX, mouseY, partialTicks, context); + } + + } } diff --git a/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java b/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java new file mode 100644 index 00000000000..a61fdb88298 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java @@ -0,0 +1,22 @@ +package gregtech.api.terminal.app; + +import gregtech.api.gui.resources.TextureArea; +import gregtech.api.terminal.gui.widgets.guide.GuideEditor; +import gregtech.api.terminal.gui.widgets.guide.GuideEditorPageWidget; +import net.minecraft.nbt.NBTTagCompound; + +public class GuideEditorApp extends AbstractApplication{ + public static final TextureArea ICON = TextureArea.fullImage("textures/gui/terminal/guide_editor/icon.png"); + + public GuideEditorApp() { + super("Guide Editor", ICON); + } + + @Override + public AbstractApplication createApp(boolean isClient, NBTTagCompound nbt) { + GuideEditorApp app = new GuideEditorApp(); + app.addWidget(new GuideEditor(0, 0, 133, 232)); + app.addWidget(new GuideEditorPageWidget(133, 0, 200, 232)); + return app; + } +} diff --git a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java index b07663f570c..3c59b2a9146 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java @@ -25,34 +25,34 @@ import java.util.Map; public abstract class GuideApp extends AbstractApplication { - private static final Map REGISTER_WIDGETS = new HashMap<>(); - static { //register guide widgets - REGISTER_WIDGETS.put("textbox", new TextBoxWidget()); - REGISTER_WIDGETS.put("image", new ImageWidget()); - } private GuidePageWidget pageWidget; public GuideApp(String name, IGuiTexture icon) { super(name, icon); } - protected abstract GuideApp createAPP(); - @Override - public GuideApp openApp(boolean isClient, NBTTagCompound nbt) { - GuideApp app = createAPP(); - pageWidget = null; - if (isClient && getTree() != null) { - app.addWidget( - new TextTreeWidget<>(0, 0, 133, 232, getTree(), leaf -> { - if (pageWidget != null) { - app.removeWidget(pageWidget); - } - pageWidget = loadLeaf(leaf); - app.addWidget(pageWidget); - }, this::itemIcon, this::itemName).setNodeTexture(GuiTextures.BORDERED_BACKGROUND).setLeafTexture(GuiTextures.SLOT_DARKENED) - ); + public AbstractApplication createApp(boolean isClient, NBTTagCompound nbt) { + try { + GuideApp app = this.getClass().newInstance(); + if (isClient && getTree() != null) { + app.addWidget( + new TextTreeWidget<>(0, 0, 133, 232, getTree(), leaf -> { + if (app.pageWidget != null) { + app.removeWidget(pageWidget); + } + app.pageWidget = new GuidePageWidget(133, 0, 200, 232); + if (leaf.isLeaf() && leaf.content != null) { + app.pageWidget.loadJsonConfig(leaf.content.getSecond()); + } + app.addWidget(pageWidget); + }, this::itemIcon, this::itemName).setNodeTexture(GuiTextures.BORDERED_BACKGROUND).setLeafTexture(GuiTextures.SLOT_DARKENED) + ); + } + return app; + } catch (Exception e) { + e.printStackTrace(); } - return app; + return null; } protected IGuiTexture itemIcon(T item) { @@ -78,42 +78,4 @@ public static JsonObject getConfig(String fileName) { return null; } } - - private GuidePageWidget loadLeaf(TreeNode> leaf) { - GuidePageWidget page = new GuidePageWidget(133, 0, 200, 232); - if (leaf.isLeaf() && leaf.content != null) { - JsonObject config = leaf.content.getSecond(); - // add title - Widget title = new TextBoxWidget(5, 2, 190, - Collections.singletonList(config.get("title").getAsString()), - 0, 15, 0xffffffff, 0x6fff0000, 0xff000000, - true, true); - page.addWidget(title); - - // add stream widgets - if (config.has("stream")) { - int y = title.getSize().height + 10; - for (JsonElement element : config.getAsJsonArray("stream")) { - JsonObject widgetConfig = element.getAsJsonObject(); - Widget widget = REGISTER_WIDGETS.get(widgetConfig.get("type").getAsString()).createStreamWidget(5, y, 190, widgetConfig); - y += widget.getSize().height + 5; - page.addWidget(widget); - } - } - // add fixed widgets - if (config.has("fixed")) { - for (JsonElement element : config.getAsJsonArray("fixed")) { - JsonObject widgetConfig = element.getAsJsonObject(); - Widget widget = REGISTER_WIDGETS.get(widgetConfig.get("type").getAsString()).createFixedWidget( - widgetConfig.get("x").getAsInt(), - widgetConfig.get("y").getAsInt(), - widgetConfig.get("width").getAsInt(), - widgetConfig.get("height").getAsInt(), - widgetConfig); - page.addWidget(widget); - } - } - } - return page; - } } diff --git a/src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java index ab11a1f1a8a..a79e4d4acc6 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java @@ -23,11 +23,6 @@ public ItemGuideApp() { super("Items Machines", new ItemStackTexture(MetaItems.SCANNER.getStackForm())); } - @Override - protected GuideApp> createAPP() { - return new ItemGuideApp(); - } - @Override protected TreeNode, JsonObject>> getTree() { return ROOT; diff --git a/src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java index a68f32b377f..311e0dbec03 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java @@ -28,11 +28,6 @@ protected TreeNode> getTree() { return ROOT; } - @Override - protected GuideApp createAPP() { - return new MultiBlockGuideApp(); - } - @Override protected IGuiTexture itemIcon(MetaTileEntity item) { return new ItemStackTexture(item.getStackForm()); diff --git a/src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java index 06cef73351e..633e4943ad9 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java @@ -28,11 +28,6 @@ protected TreeNode> getTree() { return ROOT; } - @Override - protected GuideApp createAPP() { - return new SimpleMachineGuideApp(); - } - @Override protected IGuiTexture itemIcon(MetaTileEntity item) { return new ItemStackTexture(item.getStackForm()); diff --git a/src/main/java/gregtech/api/terminal/app/guide/TutorialGuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/TutorialGuideApp.java index 4d1c0e8b361..32aad915681 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/TutorialGuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/TutorialGuideApp.java @@ -39,11 +39,6 @@ public TutorialGuideApp() { super("Tutorials", new ItemStackTexture(Items.PAPER)); } - @Override - protected GuideApp createAPP() { - return new TutorialGuideApp(); - } - @Override protected TreeNode> getTree() { return ROOT; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java index 1f79d1ab114..ccce2bcc7b7 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java @@ -6,6 +6,7 @@ import gregtech.api.gui.resources.RenderUtil; import gregtech.api.util.Position; import gregtech.api.util.Size; +import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.resources.I18n; import net.minecraft.item.ItemStack; import net.minecraft.network.PacketBuffer; @@ -16,10 +17,12 @@ import java.util.function.Consumer; public class CircleButtonWidget extends Widget { + private final int border; private int hoverTick; private boolean isHover; private String hoverText; private IGuiTexture icon; + private final int iconSize; private Consumer onPressCallback; private final int[] colors = { new Color(146, 146, 146).getRGB(), @@ -27,8 +30,14 @@ public class CircleButtonWidget extends Widget { new Color(255, 255, 255).getRGB(), }; - public CircleButtonWidget(int x, int y, int r) { + public CircleButtonWidget(int x, int y, int r, int border, int iconSize) { super(new Position(x - r, y - r), new Size(2 * r, 2 * r)); + this.border = border; + this.iconSize = iconSize; + } + + public CircleButtonWidget(int x, int y) { + this(x, y, 12, 2, 16); } public CircleButtonWidget setIcon(IGuiTexture icon) { @@ -83,9 +92,10 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender if (isHover || hoverTick != 0) { RenderUtil.renderSector(x, y, r, colors[1], segments, 0, (int) (segments * ((hoverTick + partialTicks) / 8))); } - RenderUtil.renderCircle(x, y, r - 2, colors[2], segments); + RenderUtil.renderCircle(x, y, r - border, colors[2], segments); if (icon != null) { - icon.draw(x - 8, y - 8, 16, 16); + GlStateManager.color(1,1,1,1); + icon.draw(x - iconSize / 2f, y - iconSize / 2f, iconSize, iconSize); } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditor.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditor.java new file mode 100644 index 00000000000..3783f0c4631 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditor.java @@ -0,0 +1,12 @@ +package gregtech.api.terminal.gui.widgets.guide; + +import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.util.Position; +import gregtech.api.util.Size; + +public class GuideEditor extends WidgetGroup { + public String json; + public GuideEditor(int x, int y, int width, int height) { + super(new Position(x, y), new Size(width, height)); + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditorPageWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditorPageWidget.java new file mode 100644 index 00000000000..6e08ac29673 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditorPageWidget.java @@ -0,0 +1,127 @@ +package gregtech.api.terminal.gui.widgets.guide; + + +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; +import com.google.gson.*; +import gregtech.api.gui.Widget; +import gregtech.api.util.Position; +import gregtech.api.util.interpolate.Eases; +import gregtech.api.util.interpolate.Interpolator; + +public class GuideEditorPageWidget extends GuidePageWidget { + private final BiMap configMap; + + public GuideEditorPageWidget(int xPosition, int yPosition, int width, int height) { + super(xPosition, yPosition, width, height); + configMap = HashBiMap.create(); + setTitle("Template"); + } + + public String getJsonString() { + JsonObject json = new JsonObject(); + json.addProperty("section", ""); + json.addProperty("title", title.content.get(0)); + if (stream != null) { + JsonArray array = new JsonArray(); + json.add("stream", array); + stream.forEach(widget -> array.add(configMap.get(widget))); + } + if (fixed != null) { + JsonArray array = new JsonArray(); + json.add("fixed", array); + fixed.forEach(widget -> array.add(configMap.get(widget))); + } + return new Gson().toJson(json); + } + + public JsonObject addGuideWidget(IGuideWidget widget, boolean isFixed) { + int pageWidth = this.getSize().width; + JsonObject widgetConfig = widget.getTemplate(isFixed); + Widget guideWidget; + if (isFixed) { + guideWidget = widget.createFixedWidget(widgetConfig.get("x").getAsInt(), + widgetConfig.get("y").getAsInt(), + widgetConfig.get("width").getAsInt(), + widgetConfig.get("height").getAsInt(), + widgetConfig); + this.addWidget(guideWidget); + fixed.add(guideWidget); + } else { + int y = getStreamBottom(); + guideWidget = widget.createStreamWidget(5, y + 5, pageWidth - 5, widgetConfig); + this.addWidget(guideWidget); + stream.add(guideWidget); + } + configMap.put(guideWidget, widgetConfig); + return widgetConfig; + } + + + public void moveUp(Widget widget) { + int index = stream.indexOf(widget); + if (index > 0) { + Widget target = stream.get(index - 1); + if (interpolator == null) { + int offset = widget.getPosition().y - target.getPosition().y; + int y1 = widget.getSelfPosition().y; + int y2 = target.getSelfPosition().y; + interpolator = new Interpolator(0, offset, 10, Eases.EaseLinear, value->{ + widget.setSelfPosition(new Position(widget.getSelfPosition().x, y1 - value.intValue())); + target.setSelfPosition(new Position(target.getSelfPosition().x, y2 + value.intValue())); + }, value->{ + interpolator = null; + stream.remove(widget); + stream.add(index - 1, widget); + }).start(); + } + } + } + + public void moveDown(Widget widget) { + int index = stream.indexOf(widget); + if (index >= 0 && index < stream.size() - 1) { + Widget target = stream.get(index + 1); + if (interpolator == null) { + int offset = target.getPosition().y - widget.getPosition().y; + int y1 = widget.getSelfPosition().y; + int y2 = target.getSelfPosition().y; + interpolator = new Interpolator(0, offset, 10, Eases.EaseLinear, value->{ + widget.setSelfPosition(new Position(widget.getSelfPosition().x, y1 + value.intValue())); + target.setSelfPosition(new Position(target.getSelfPosition().x, y2 - value.intValue())); + }, value->{ + interpolator = null; + stream.remove(widget); + stream.add(index + 1, widget); + }).start(); + } + } + } + + @Override + public void removeWidget(Widget widget) { + int index = stream.indexOf(widget); + if (index >= 0) { + int offset = widget.getSize().height + 5; + for (int i = stream.size() - 1; i > index; i--) { + Widget bottom = stream.get(i); + bottom.setSelfPosition(new Position(bottom.getSelfPosition().x, bottom.getSelfPosition().y - offset)); + } + stream.remove(widget); + } else { + fixed.remove(widget); + } + super.removeWidget(widget); + configMap.remove(widget); + } + + @Override + public boolean mouseClicked(int mouseX, int mouseY, int button) { + return super.mouseClicked(mouseX, mouseY, button); + } + + @Override + public boolean mouseDragged(int mouseX, int mouseY, int button, long timeDragged) { + return super.mouseDragged(mouseX, mouseY, button, timeDragged); + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java index 1cfaea846e4..d5faa04a902 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java @@ -1,27 +1,39 @@ package gregtech.api.terminal.gui.widgets.guide; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; import gregtech.api.gui.resources.IGuiTexture; -import gregtech.api.gui.resources.URLTexture; -import gregtech.api.gui.widgets.AbstractWidgetGroup; +import gregtech.api.gui.widgets.WidgetGroup; import gregtech.api.util.Position; import gregtech.api.util.RenderUtil; import gregtech.api.util.Size; import gregtech.api.util.interpolate.Eases; import gregtech.api.util.interpolate.Interpolator; -import javafx.geometry.Pos; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.util.math.MathHelper; +import java.util.*; + import static gregtech.api.gui.impl.ModularUIGui.*; -public class GuidePageWidget extends AbstractWidgetGroup { +public class GuidePageWidget extends WidgetGroup { + public static final Map REGISTER_WIDGETS = new HashMap<>(); + static { //register guide widgets + REGISTER_WIDGETS.put("textbox", new TextBoxWidget()); + REGISTER_WIDGETS.put("image", new ImageWidget()); + } + protected TextBoxWidget title; + protected List stream; + protected List fixed; + private IGuiTexture background; private int scrollYOffset; private int maxHeight; - private Interpolator interpolator; + protected Interpolator interpolator; public GuidePageWidget(int xPosition, int yPosition, int width, int height) { super(new Position(xPosition, yPosition), new Size(width, height)); @@ -32,6 +44,101 @@ public GuidePageWidget setBackground(IGuiTexture background) { return this; } + public void setTitle(String config) { + int height = 0; + if (title != null) { + height = title.getSize().height; + removeWidget(title); + } + title = new TextBoxWidget(5, 2, 190, + Collections.singletonList(config), + 0, 15, 0xffffffff, 0x6fff0000, 0xff000000, + true, true); + this.addWidget(title); + if (stream != null) { + int offset = title.getSize().height - height; + if (offset != 0) { + for (Widget widget : stream) { + widget.setSelfPosition(new Position(widget.getSelfPosition().x, widget.getSelfPosition().y + offset)); + } + } + } + } + + public String loadJsonConfig(String config) { + try { + loadJsonConfig(new JsonParser().parse(config).getAsJsonObject()); + } catch (Exception e) { + this.clearAllWidgets(); + return e.getMessage(); + } + return null; + } + + public void loadJsonConfig(JsonObject config) { + int pageWidth = this.getSize().width; + // add title + setTitle(config.get("title").getAsString()); + + // add stream widgets + if (config.has("stream")) { + stream = new ArrayList<>(); + int y = title.getSize().height + 10; + for (JsonElement element : config.getAsJsonArray("stream")) { + JsonObject widgetConfig = element.getAsJsonObject(); + Widget widget = REGISTER_WIDGETS.get(widgetConfig.get("type").getAsString()).createStreamWidget(5, y, pageWidth - 5, widgetConfig); + y += widget.getSize().height + 5; + this.addWidget(widget); + stream.add(widget); + } + } + // add fixed widgets + if (config.has("fixed")) { + fixed = new ArrayList<>(); + for (JsonElement element : config.getAsJsonArray("fixed")) { + JsonObject widgetConfig = element.getAsJsonObject(); + Widget widget = REGISTER_WIDGETS.get(widgetConfig.get("type").getAsString()).createFixedWidget( + widgetConfig.get("x").getAsInt(), + widgetConfig.get("y").getAsInt(), + widgetConfig.get("width").getAsInt(), + widgetConfig.get("height").getAsInt(), + widgetConfig); + this.addWidget(widget); + fixed.add(widget); + } + } + } + + public void onSizeUpdate(Widget widget, Size oldSize) { + int offset = widget.getSize().height - oldSize.height; + maxHeight = Math.max(maxHeight, widget.getSize().height + widget.getPosition().y); + if (stream != null) { + int index = stream.indexOf(widget); + for (int i = stream.size() - 1; i > index; i--) { + Widget nextWidget = stream.get(i); + nextWidget.setSelfPosition(new Position(nextWidget.getSelfPosition().x, nextWidget.getSelfPosition().y + offset)); + } + } + } + + public void onPositionUpdate(Widget widget, Position oldPosition) { + if (oldPosition.y + widget.getSize().height == maxHeight) { + maxHeight = 0; + for (Widget widget1 : widgets) { + maxHeight = Math.max(maxHeight, widget1.getSize().height + widget1.getPosition().y); + } + } + } + + protected int getStreamBottom() { + if (stream!= null && stream.size() > 0) { + Widget widget = stream.get(stream.size() - 1); + return widget.getSize().height + widget.getPosition().y; + } else { + return title.getSize().height + 10; + } + } + protected void setScrollYOffset(int scrollYOffset) { if (scrollYOffset == this.scrollYOffset) return; this.scrollYOffset = scrollYOffset; @@ -77,7 +184,9 @@ public void addWidget(Widget widget) { public boolean mouseWheelMove(int mouseX, int mouseY, int wheelDelta) { if (this.isMouseOverElement(mouseX, mouseY, true)) { int moveDelta = -MathHelper.clamp(wheelDelta, -1, 1) * 5; - setScrollYOffset(MathHelper.clamp(scrollYOffset + moveDelta, 0, Math.max(maxHeight - getSize().height, 0))); + if (maxHeight - getSize().height > 0) { + setScrollYOffset(MathHelper.clamp(scrollYOffset + moveDelta, 0, maxHeight - getSize().height + 5)); + } return true; } return false; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java index d35062750d8..f5eed7a7d6b 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java @@ -1,15 +1,21 @@ package gregtech.api.terminal.gui.widgets.guide; import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.sun.istack.internal.Nullable; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; import gregtech.api.util.Position; import gregtech.api.util.Size; +import javafx.geometry.Pos; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.item.ItemStack; +import net.minecraftforge.fml.common.ObfuscationReflectionHelper; +import net.minecraftforge.fml.relauncher.ReflectionHelper; +import java.lang.reflect.Field; import java.util.List; public abstract class GuideWidget extends Widget implements IGuideWidget { @@ -32,6 +38,56 @@ public GuideWidget(){ super(Position.ORIGIN, Size.ZERO); } + public void updateValue(String field, JsonElement value) { + try { + Field f = this.getClass().getDeclaredField(field); + f.set(this, new Gson().fromJson(value, f.getType())); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public void setSize(Size size) { + Size oldSize = this.getSize(); + super.setSize(size); + if (page != null) { + page.onSizeUpdate(this, oldSize); + } + } + + @Override + protected void recomputePosition() { + Position oldPosition = getPosition(); + super.recomputePosition(); + if (page != null) { + page.onPositionUpdate(this, oldPosition); + } + } + + @Override + public void setSelfPosition(Position selfPosition) { + super.setSelfPosition(selfPosition); + } + + @Override + public JsonObject getTemplate(boolean isFixed) { + JsonObject template = new JsonObject(); + if (isFixed) { + template.addProperty("x", 0); + template.addProperty("y", 0); + template.addProperty("width", 100); + template.addProperty("height", 100); + } + template.addProperty("ref", ref); + template.addProperty("stroke", stroke); + template.addProperty("stroke_width", stroke_width); + template.addProperty("fill", fill); + template.addProperty("link", link); + template.add("hover_text", new Gson().toJsonTree(hover_text)); + return template; + } + @Override public String getRef() { return ref; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java index 4d2b3808367..938d7c6c32d 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java @@ -8,4 +8,5 @@ public interface IGuideWidget { Widget createFixedWidget(int x, int y, int width, int height, JsonObject config); void setPage(GuidePageWidget page); String getRef(); + JsonObject getTemplate(boolean isFixed); } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java index b5a1d8127c0..5decb203734 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java @@ -21,7 +21,17 @@ public class ImageWidget extends GuideWidget{ public int width; public int height; - public IGuiTexture image; + public transient IGuiTexture image; + + @Override + public JsonObject getTemplate(boolean isFixed) { + JsonObject template = super.getTemplate(isFixed); + template.addProperty("form", "item"); + template.addProperty("source", "minecraft:ender_pearl"); + template.addProperty("width", 100); + template.addProperty("height", 100); + return template; + } @Override public void updateScreen() { diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java index 7f0d67d3e0a..3e16cb2ad3f 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java @@ -1,5 +1,6 @@ package gregtech.api.terminal.gui.widgets.guide; +import com.google.gson.Gson; import com.google.gson.JsonObject; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; @@ -12,6 +13,7 @@ import net.minecraft.client.resources.I18n; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; public class TextBoxWidget extends GuideWidget { @@ -23,7 +25,7 @@ public class TextBoxWidget extends GuideWidget { public boolean isShadow = false; public boolean isCenter = false; - private List textLines; + private transient List textLines; public TextBoxWidget(int x, int y, int width, List content, int space, int fontSize, int fontColor, int fill, int stroke, boolean isCenter, boolean isShadow) { super(x, y, width, 0); @@ -40,6 +42,18 @@ public TextBoxWidget(int x, int y, int width, List content, int space, i public TextBoxWidget() {} + @Override + public JsonObject getTemplate(boolean isFixed) { + JsonObject template = super.getTemplate(isFixed); + template.addProperty("space", space); + template.addProperty("fontSize", fontSize); + template.addProperty("fontColor", fontColor); + template.addProperty("isCenter", isCenter); + template.addProperty("isShadow", isShadow); + template.add("content", new Gson().toJsonTree(Arrays.asList("this is", "textbox!"))); + return template; + } + @Override protected Widget initFixed(int x, int y, int width, int height, JsonObject config) { this.textLines = new ArrayList<>(); diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalDesktopWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalDesktopWidget.java index ccdf5f1ede2..ccff0af79b3 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalDesktopWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalDesktopWidget.java @@ -1,13 +1,48 @@ package gregtech.api.terminal.gui.widgets.os; import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.terminal.app.AbstractApplication; +import gregtech.api.terminal.gui.widgets.CircleButtonWidget; import gregtech.api.util.Position; import gregtech.api.util.Size; +import java.awt.*; + public class TerminalDesktopWidget extends WidgetGroup { private final TerminalOSWidget os; + private final WidgetGroup appDiv; + public TerminalDesktopWidget(Position position, Size size, TerminalOSWidget os) { super(position, size); this.os = os; + this.appDiv = new WidgetGroup(); + this.addWidget(appDiv); + } + + public void installApplication(AbstractApplication application){ + int r = 12; + int index = appDiv.widgets.size(); + int x = this.getSize().width / 2 + (3 * r) * (index - 3); + int y = (index / 7) * (3 * r) + 40; + CircleButtonWidget button = new CircleButtonWidget(x,y) + .setColors(new Color(146, 146, 146, 126).getRGB(), + new Color(105, 224, 216).getRGB(), + new Color(206, 206, 206).getRGB()) + .setIcon(application.getIcon()) + .setHoverText(application.getName()); + button.setClickListener(clickData -> { + os.openApplication(application, clickData.isClient); + }); + appDiv.addWidget(button); + } + + public void showDesktop() { + appDiv.setActive(true); + appDiv.setVisible(true); + } + + public void hideDesktop() { + appDiv.setActive(false); + appDiv.setVisible(false); } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalMenuWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalMenuWidget.java index b3b427d1c51..935ce7f4948 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalMenuWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalMenuWidget.java @@ -1,9 +1,9 @@ package gregtech.api.terminal.gui.widgets.os; +import gregtech.api.gui.GuiTextures; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.widgets.WidgetGroup; -import gregtech.api.terminal.app.AbstractApplication; import gregtech.api.terminal.gui.widgets.CircleButtonWidget; import gregtech.api.util.Position; import gregtech.api.util.Size; @@ -11,11 +11,11 @@ import gregtech.api.util.interpolate.Interpolator; import net.minecraft.client.renderer.GlStateManager; +import java.awt.*; + public class TerminalMenuWidget extends WidgetGroup { private Interpolator interpolator; - private int appCount; private IGuiTexture background; - private CircleButtonWidget activeButton; private final TerminalOSWidget os; public boolean isHide; @@ -23,6 +23,31 @@ public class TerminalMenuWidget extends WidgetGroup { public TerminalMenuWidget(Position position, Size size, TerminalOSWidget os) { super(position, size); this.os = os; + this.addWidget(new CircleButtonWidget(5, 10, 4, 1, 0) + .setColors(new Color(255, 255, 255, 0).getRGB(), + new Color(255, 255, 255).getRGB(), + new Color(239, 105, 105).getRGB()) + .setHoverText("close") + .setClickListener(this::close)); + this.addWidget(new CircleButtonWidget(15, 10, 4, 1, 0) + .setColors(new Color(255, 255, 255, 0).getRGB(), + new Color(255, 255, 255).getRGB(), + new Color(243, 217, 117).getRGB()) + .setHoverText("minimize") + .setClickListener(this::minimize)); + this.addWidget(new CircleButtonWidget(25, 10, 4, 1, 0) + .setColors(new Color(255, 255, 255, 0).getRGB(), + new Color(255, 255, 255).getRGB(), + new Color(154, 243, 122).getRGB()) + .setHoverText("maximize") + .setClickListener(this::maximize)); + this.addWidget(new CircleButtonWidget(15, 40, 10, 1, 14) + .setColors(new Color(255, 255, 255, 0).getRGB(), + new Color(255, 255, 255).getRGB(), + new Color(80, 80, 80).getRGB()) + .setHoverText("setting") + .setIcon(GuiTextures.TERMINAL_SETTING) + .setClickListener(this::setting)); } public TerminalMenuWidget setBackground(IGuiTexture background) { @@ -30,23 +55,20 @@ public TerminalMenuWidget setBackground(IGuiTexture background) { return this; } - public void addApp(AbstractApplication application){ - int x = this.getSize().width / 2; - int r = 12; - int y = appCount * (2 * r + 4) + r + 20; - CircleButtonWidget button = new CircleButtonWidget(x,y,r).setIcon(application.getIcon()).setHoverText(application.getName()); - button.setClickListener(clickData -> { - if (button != activeButton) { - os.openApplication(application, clickData.isClient); - if (activeButton != null) { - activeButton.setFillColors(0xffffffff); - } - activeButton = button; - activeButton.setFillColors(0xFFAAF1DB); - } - }); - this.addWidget(button); - appCount++; + public void close(ClickData clickData) { + os.closeApplication(os.focusApp, clickData.isClient); + } + + public void minimize(ClickData clickData) { + os.minimizeApplication(os.focusApp, clickData.isClient); + } + + public void maximize(ClickData clickData) { + + } + + public void setting(ClickData clickData) { + } public void hideMenu() { @@ -54,24 +76,26 @@ public void hideMenu() { int y = getSelfPosition().y; interpolator = new Interpolator(getSelfPosition().x, getSelfPosition().x - getSize().width, 10, Eases.EaseLinear, value-> setSelfPosition(new Position(value.intValue(), y)), - value-> interpolator = null); + value-> { + setVisible(false); + interpolator = null; + isHide = true; + }); interpolator.start(); - isHide = true; } } public void showMenu() { if (isHide && interpolator == null) { - if (activeButton != null) { - activeButton.setFillColors(0xffffffff); - } - activeButton = null; + setVisible(true); int y = getSelfPosition().y; interpolator = new Interpolator(getSelfPosition().x, getSelfPosition().x + getSize().width, 10, Eases.EaseLinear, value-> setSelfPosition(new Position(value.intValue(), y)), - value-> interpolator = null); + value-> { + interpolator = null; + isHide = false; + }); interpolator.start(); - isHide = false; } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalOSWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalOSWidget.java index db7f1fa7aa6..00589d4ca61 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalOSWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalOSWidget.java @@ -16,25 +16,33 @@ import javafx.application.Application; import javafx.geometry.Pos; import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import static gregtech.api.gui.impl.ModularUIGui.*; public class TerminalOSWidget extends AbstractWidgetGroup { private IGuiTexture background; - private final List openedApps; - private final TerminalMenuWidget menu; - private final TerminalDesktopWidget desktop; + public final List openedApps; + public AbstractApplication focusApp; + public final TerminalMenuWidget menu; + public final TerminalDesktopWidget desktop; + public List waitToRemoved; + private NBTTagCompound tabletNBT; - public TerminalOSWidget(int xPosition, int yPosition, int width, int height) { + public TerminalOSWidget(int xPosition, int yPosition, int width, int height, NBTTagCompound tabletNBT) { super(new Position(xPosition, yPosition), new Size(width, height)); this.openedApps = new ArrayList<>(); this.desktop = new TerminalDesktopWidget(Position.ORIGIN, new Size(333, 232), this); - this.menu = new TerminalMenuWidget(Position.ORIGIN, new Size(35, 232), this).setBackground(GuiTextures.TERMINAL_MENU); + this.menu = new TerminalMenuWidget(Position.ORIGIN, new Size(31, 232), this).setBackground(GuiTextures.TERMINAL_MENU); this.addWidget(desktop); this.addWidget(menu); + this.waitToRemoved = new ArrayList<>(); + this.tabletNBT = tabletNBT; } public TerminalOSWidget setBackground(IGuiTexture background) { @@ -43,39 +51,87 @@ public TerminalOSWidget setBackground(IGuiTexture background) { } public void installApplication(AbstractApplication application){ - menu.addApp(application); + desktop.installApplication(application); } public void openApplication(AbstractApplication application, boolean isClient) { + if (focusApp != null ) { + closeApplication(focusApp, isClient); + } for (AbstractApplication app : openedApps) { if (app.getClass() == application.getClass()) { - app.setVisible(true); + focusApp = app; + maximizeApplication(app, isClient); return; } } - AbstractApplication app = application.openApp(isClient, null); - openedApps.add(app); - desktop.addWidget(app); - menu.hideMenu(); + String name = application.getName(); + if (!tabletNBT.hasKey(name)) { + tabletNBT.setTag(name, new NBTTagCompound()); + } + AbstractApplication app = application.createApp(isClient, tabletNBT.getCompoundTag(application.getName())); + if (app != null) { + openedApps.add(app); + desktop.addWidget(app); + focusApp = app; + maximizeApplication(app, isClient); + } + } + + public void maximizeApplication(AbstractApplication application, boolean isClient) { + application.setActive(true); + if (isClient) { + application.maximizeApp(app->desktop.hideDesktop()); + if (!menu.isHide) { + menu.hideMenu(); + } + } + desktop.hideDesktop(); + } + + public void minimizeApplication(AbstractApplication application, boolean isClient) { + if (application != null) { + if (application.isBackgroundApp()) { + application.setActive(false); + } + if (isClient) { + application.minimizeApp(null); + } + if(focusApp == application) { + focusApp = null; + } + desktop.showDesktop(); + } } public void closeApplication(AbstractApplication application, boolean isClient) { - desktop.removeWidget(application); - application.closeApp(isClient, null); + if (application != null) { + String name = application.getName(); + if (!tabletNBT.hasKey(name)) { + tabletNBT.setTag(name, new NBTTagCompound()); + } + application.closeApp(isClient, tabletNBT.getCompoundTag(name)); + if (isClient) { + application.minimizeApp(waitToRemoved::add); + } else { + waitToRemoved.add(application); + } + openedApps.remove(application); + if(focusApp == application) { + focusApp = null; + } + desktop.showDesktop(); + } } - public void backToHome() { - List close = new ArrayList<>(); - for (AbstractApplication app : openedApps) { - if (app.isBackgroundApp()) { - app.setVisible(false); + public void homeTrigger(boolean isClient) { + if(isClient) { + if (menu.isHide) { + menu.showMenu(); } else { - close.add(app); - closeApplication(app, isClientSide()); + menu.hideMenu(); } } - close.forEach(openedApps::remove); - menu.showMenu(); } @Override @@ -91,4 +147,22 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender super.drawInBackground(mouseX, mouseY, partialTicks, context); }); } + + @Override + public void updateScreen() { + if (waitToRemoved.size() > 0) { + waitToRemoved.forEach(desktop::removeWidget); + } + waitToRemoved.clear(); + super.updateScreen(); + } + + @Override + public void detectAndSendChanges() { + if (waitToRemoved.size() > 0) { + waitToRemoved.forEach(desktop::removeWidget); + } + waitToRemoved.clear(); + super.detectAndSendChanges(); + } } diff --git a/src/main/java/gregtech/api/util/interpolate/Interpolator.java b/src/main/java/gregtech/api/util/interpolate/Interpolator.java index 7e73e7a8e58..2c79a927ad0 100644 --- a/src/main/java/gregtech/api/util/interpolate/Interpolator.java +++ b/src/main/java/gregtech/api/util/interpolate/Interpolator.java @@ -35,8 +35,9 @@ public void reset() { tick = 0; } - public void start() { + public Interpolator start() { tick = 1; + return this; } public boolean isFinish(){ diff --git a/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java b/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java index c4bbe83c2b7..a451c053d23 100644 --- a/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java +++ b/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java @@ -16,6 +16,7 @@ import net.minecraft.util.EnumHand; import net.minecraft.world.World; +import java.awt.*; import java.util.List; public class GuideTerminalBehaviour implements IItemBehaviour, ItemUIFactory { @@ -36,8 +37,13 @@ public void addInformation(ItemStack itemStack, List lines) { @Override public ModularUI createUI(PlayerInventoryHolder holder, EntityPlayer entityPlayer) { - TerminalOSWidget os = new TerminalOSWidget(12, 11, 333, 232).setBackground(GuiTextures.TERMINAL_BACKGROUND); - CircleButtonWidget home = new CircleButtonWidget(362, 126, 12).setIcon(GuiTextures.TERMINAL_HOME).setFillColors(0xff9197A5).setClickListener(clickData -> os.backToHome()); + TerminalOSWidget os = new TerminalOSWidget(12, 11, 333, 232, holder.getCurrentItem().getOrCreateSubCompound("terminal")) + .setBackground(GuiTextures.TERMINAL_BACKGROUND); + CircleButtonWidget home = new CircleButtonWidget(362, 126).setIcon(GuiTextures.TERMINAL_HOME) + .setColors(new Color(82, 97, 93, 255).getRGB(), + new Color(39, 232, 141).getRGB(), + 0xff9197A5) + .setClickListener(clickData -> os.homeTrigger(clickData.isClient)); TerminalBuilder.getApplications().forEach(os::installApplication); return ModularUI.builder(GuiTextures.TERMINAL_FRAME, 380, 256) .widget(os) diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/guide_editor/icon.png b/src/main/resources/assets/gregtech/textures/gui/terminal/guide_editor/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..d9f2047fd1a93b399b8b4bd26266a3e17f055add GIT binary patch literal 32504 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

ZF7ts5!GU< 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 delta 2855 zcmV+?3)uA73&IwVIDZOFX+uL$P-t&-Z*ypGa3D!TLm+T+Z)Rz1WdHzp+MQE(Sd;e_ zKHv9c4^~3h@UfR{fdC>StO&>uS)ve<0AYj>5y@A0LT~suv4>S3ILP<0Bm`DLLvaF4FK%)Nj?Pt*r}7;7Xa9z9H|HZ zjR63eC`Tj$K!3XcU{!%qECRs70HCZuA}$2Lt^t5qwlYTofV~9(c8*w(4?ti5fSE!p z%m5%b0suoE6U_r4Oaq`W(!b!TUvP!ENC5!A%azTSOVTqGxRuZvck=My;vwR~Y_URN z7by^C3FIQ2mzyIKNaq7g&I|wm8u`(|{y0C7=jP<$=6`1AZ142NqW){}Zz4V+@!$Tu zi~3=fuAC~28EsPoqkpK{9G%|Vj005J}`Hw&=0RYXHq~ibpyyzHQ zsFW8>#s~laM4*8xut5h5!4#~(4xGUqyucR%VSffhKnx_nJP<+#?5=i zx(HVZgM=}{CnA%mPqZa^68XeSVKGG0roJ=O`kZsA{w~!BzPm=q|!{oOVI>m_MObMbS zQlyj;N;PFaO^>2$gY-Gd%Qm(Z8eYv>2*=jns=cMJ`N4THx>VkjAF8G9M07`GWOnM|ey z)0dgZR4~^v8<}UA514ONSSt1^d=-((5|uiYR+WC0=c-gyb5%dpd8!Lkt5pxHURHgk zMpd&=yOjAR1s%ETak!GFdam@h^#)@rS0t$wXH+Irf)+G6c;?H29p+V6F6oj{!|o%K3xI)C?d3A#4A zQM!e?+jY>uuIoY)~6ln+%&eo6EMSt(&dHcAIVA6yg+*DbgwR zQ*PQZ?ELHs?3(Nb?K$>g_9gah_Rk&691wl!-G{dRHsl(}4 zXB%gsbDi@w7p6;)%MzD%mlsoQr;4X;pL)xc%+^yMd)ZNTI#eJ*$ zO)i@o$z8)e??LqN_gLa_%;TM>o2SC_kmoO6c3xRt`@J4dvz#WL)-Y|z+r(Soy~}%G zIzByR`p)SCKE^%*pMQFvhrXu1BHul}BYxI?nSKZSp8Grc%l(h|zu|fE7V%C6U;)7a z8@mESk|3$_Skm zS{wQ>%qC18))9_|&j{ZTes8AvOzF(F2#DZEY>2oYX&IRp`G0*BDJn9mF6vRVQ*?23 z_bk?|G6C?@kiR8rC z#65}Qa{}jVnlqf_npBo_W3J`gqPZ95>CVfZcRX1&S&)1zB2~Schd65~Cxg+yU zRz%j`tk2nT*)2JgoRplSQVnUAv@6#zwiHuJf`1l#y^yd_xUjR>xOiFd;3B_8 zyA~shQx|tGF!j;$ ztoK>JuYXFtYC+Y|hVTuo8}W_h8((co-gKdQYW0rIw9U%R12tha?OV*YtlRRTHly}> zoqt`+R{gE3x4zjX+Sb3_cYE^=gB=w+-tUy`ytONMS8KgRef4hA?t0jufM;t32jm~jej0UI&kHifN$EH?V5MBa9S!3!a?Q1 zC*P)gd*e{(q0YnH!_D8Bf4B7r>qvPk(mKC&tSzH$pgp0z@92!9ogH2sN4~fJe(y2k zV|B+hk5`_cohUu=`Q(C=R&z?UQbnZ;IU-!xL z-hbzhUGThc^dk3S+apRi!(|`JEz}0it z_}4C7pLxCS#_SunZYJFvxFx#v_;&W~7k3KoOx#_1k9e>AzS{lj2l@}{f3*IwWx#FV z_+Y?b&%;>{?+yuvp8k~o(}&^GN6bgnBY#FCjgOrl9~%uCz4Bzvli{bbrxVZ0epdf^ z>vOB;-~HnIOV3#R*zgPai_gEVd8zYq@2jb=I>#f&AH2?aJ@Kaet(_`g8%^e|9=1g zfaw4Lbua(`>RI+y?e7jKeZ#YO-C0B=b|K~#9!V*LOAKLaIzg@J*ALHqwfoThv| zdKstY2R1p3Oh|l2QtpS$%Rmb!2S7$CZ41_lNOMoP0YU;r;_DIuU(MP2{^002ovPDHLk FV1j^`c)|bx diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_minimum.png b/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_minimum.png new file mode 100644 index 0000000000000000000000000000000000000000..12f30a4c85399253c917b847a2d7df143aeb021c GIT binary patch literal 1672 zcmb7FONit|7|tRN>+Z}lAc%O`kVaY2N-F7e9>r#d+4MNmV8&*)VaMB4S5>;hbW+(Q zGu<->5xuymhrNn7?}9f$L|hMo7s0zA2y^iuxL2jO(w&a8yR)xAl1kNA-~auO`g6Ox zy}5GXwF{CYt#r29JL0`s-shLZ^YXnZ7O$7mt@m?Dy7+Q=pOe1$@>NNC@vo@2TkHn! zBEn-8Q{HFlBu)idlCG{zQcU()A@|uJN<8K7?|x9^h?jk*1BuV|CnAc{b2= z*L5{$Xodj<0^~nB| zDlA=^0V%0*=|MJ{8K*>JBNnry$OTrfvFVT(JRkDMP}j>37!aWig4)KJTH?4ikrx|> z!i_2*XQK1oQOdL(mh*#*u#H0@vr&4JB0poe;8~CJ(IQdZg=E?H+#o=mBrkA6 zSf}kNA~b3gQDlb1?PF#ETQ>=?ZPNhQ4IN;(m_o;KEW-&G``erxlm$@kpPvQFiQxEO zp6j%1$0Y<1(;~oSrV091-vOi*I)-f+2BiH3+k06gjw2qOW-V1w!D#7(wrosGEjloX z$$;Bz5@5BQkiw>Ius$h^epW|lE6PQNkE&yIgWak|qez~W4#K275}rcJT3}SErlT|B z@l2Mh{o^4Mq)(`lx%Hff#TaL7eIR1@lp53?Cq2i9PZs`ciJU8XRQN+R`~1SIkdPrx z22Au;O(|W`$}Tidi1u)V27 zf2Y&67heDHw(|Q|OWmKPSLmfiqw&qHU(SE}!MEp5PEMvj-M#zCZ~y)Ak+= kym9B^(zVsimAySly7%WQ`Ti37r~FrRHn!VeU*G%aKEp8%ZvX%Q literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_setting.png b/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_setting.png new file mode 100644 index 0000000000000000000000000000000000000000..6300ad91847721d5e04189a359743b9cdeda9fe6 GIT binary patch literal 1712 zcmb7FOKjXk7?8 z$pKnUaNq*HP;o<4;!+8OdMH%%fIC^um<@mM!p+)CN; zt)&*-TBFF<4!xot9AHThF+tQp)QdAbsA@xAEXVn@uBk(aSgUHa+@QMJTvk1vGPPWC z05xn=by3N1ATsR(stFBOhpui|02&xN*h1>~(xkQ25AaI;=-8J0s%l*!60Ga}e!tYW zN<8i820}=Orf!-*B0#no3o-z4wr|2vXBkbyM1(w6b4JqU>!PYjr6U)jq@aznahPPl z^Z`k9qXcu8hCrVdxMV%;4UPL$XFV3NSY#4w6xgK81<$(t4%Ef+O$KCWo6W+;u3Dm~ zFp-J*4e7=>AiJWo)@H)=6_)Y!l(P8^DRW=$O@h6Y5y8_I=eBv8%CtV^d#2@g7g5VX4mAIp6TS<&+0uPcCFD3rEz(yyqCmae!GehH{%t z+=w$lV#*rzswP8I3PT?g({>RuAs}U!fp*0X06}I25QeDjRstgkM()b}bxzmw0?7A| z&VtXWL)#CNsP_K1Rpc+v8C$REMR53C)j0Rik+= zFkc%_hr7h%zATUT_q$Az-la-L)-xW6K1o@vBV%`u8r1J3JtG@;7k+<<94We8_$@X2 z|Ami3Lc1jHFxgvmEq6uFyU-{h`mMPduI=bp6S!=H`LO7}@}ubBESA)%?9cf8mA$gJ zuQlqmR^`L*ue~;XNqv0J)lYtfFa7iWA4f0mf2aMqI4nM1&|dBT&^Y(mb$#l}jq>4B z=M|tn@Wsi~A8CKSaQ)=WS3lQk)2F|jTb&Bd{`T;h+2=3T=k_R1e|zDV*{i26{J6LK jr1H}n-lYTE@1A`wJ7ySP|Gqt&|5F Date: Sat, 31 Jul 2021 15:20:37 +0800 Subject: [PATCH 09/58] scrollpanelwidgetgroup --- src/main/java/gregtech/api/gui/Widget.java | 4 +- .../api/gui/resources/ColorRectTexture.java | 49 ++++ .../api/gui/widgets/ScrollableListWidget.java | 4 +- .../gregtech/api/gui/widgets/TabGroup.java | 4 +- .../api/terminal/app/GuideEditorApp.java | 18 +- .../api/terminal/app/guide/GuideApp.java | 11 +- .../widgets/ScrollablePanelWidgetGroup.java | 271 ++++++++++++++++++ .../gui/widgets/guide/GuideEditor.java | 19 ++ .../widgets/guide/GuideEditorPageWidget.java | 9 - .../gui/widgets/guide/GuidePageWidget.java | 96 +------ 10 files changed, 382 insertions(+), 103 deletions(-) create mode 100644 src/main/java/gregtech/api/gui/resources/ColorRectTexture.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/ScrollablePanelWidgetGroup.java diff --git a/src/main/java/gregtech/api/gui/Widget.java b/src/main/java/gregtech/api/gui/Widget.java index 5fa87c073e1..a2ca5d778c9 100644 --- a/src/main/java/gregtech/api/gui/Widget.java +++ b/src/main/java/gregtech/api/gui/Widget.java @@ -256,14 +256,14 @@ public List getNativeWidgets() { /** * Writes data to be sent to client's {@link #readUpdateInfo} */ - protected final void writeUpdateInfo(int id, Consumer packetBufferWriter) { + protected void writeUpdateInfo(int id, Consumer packetBufferWriter) { if (uiAccess != null && gui != null) { uiAccess.writeUpdateInfo(this, id, packetBufferWriter); } } @SideOnly(Side.CLIENT) - protected final void writeClientAction(int id, Consumer packetBufferWriter) { + protected void writeClientAction(int id, Consumer packetBufferWriter) { if (uiAccess != null) { uiAccess.writeClientAction(this, id, packetBufferWriter); } diff --git a/src/main/java/gregtech/api/gui/resources/ColorRectTexture.java b/src/main/java/gregtech/api/gui/resources/ColorRectTexture.java new file mode 100644 index 00000000000..d1b192f11b4 --- /dev/null +++ b/src/main/java/gregtech/api/gui/resources/ColorRectTexture.java @@ -0,0 +1,49 @@ +package gregtech.api.gui.resources; + +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; + +public class ColorRectTexture implements IGuiTexture{ + private final int color; + + public ColorRectTexture(int color) { + this.color = color; + } + + @Override + public void draw(double x, double y, int width, int height) { + double j; + double right = x + width; + double bottom = y + height; + if (x < right) { + j = x; + x = right; + right = j; + } + + if (y < bottom) { + j = y; + y = bottom; + bottom = j; + } + float f3 = (float)(color >> 24 & 255) / 255.0F; + float f = (float)(color >> 16 & 255) / 255.0F; + float f1 = (float)(color >> 8 & 255) / 255.0F; + float f2 = (float)(color & 255) / 255.0F; + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder bufferbuilder = tessellator.getBuffer(); + GlStateManager.enableBlend(); + GlStateManager.disableTexture2D(); + GlStateManager.tryBlendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO); + GlStateManager.color(f, f1, f2, f3); + bufferbuilder.begin(7, DefaultVertexFormats.POSITION); + bufferbuilder.pos(x, bottom, 0.0D).endVertex(); + bufferbuilder.pos(right, bottom, 0.0D).endVertex(); + bufferbuilder.pos(right, y, 0.0D).endVertex(); + bufferbuilder.pos(x, y, 0.0D).endVertex(); + tessellator.draw(); + GlStateManager.enableTexture2D(); + } +} diff --git a/src/main/java/gregtech/api/gui/widgets/ScrollableListWidget.java b/src/main/java/gregtech/api/gui/widgets/ScrollableListWidget.java index 61cc253c3af..fa72a4ca6af 100644 --- a/src/main/java/gregtech/api/gui/widgets/ScrollableListWidget.java +++ b/src/main/java/gregtech/api/gui/widgets/ScrollableListWidget.java @@ -85,7 +85,7 @@ public void drawInForeground(int mouseX, int mouseY) { } @Override - public void drawInBackground(int mouseX, int mouseY, IRenderContext context) { + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { //make sure mouse is not hovered on any element when outside of bounds if (!isPositionInsideScissor(mouseX, mouseY)) { mouseX = Integer.MAX_VALUE; @@ -107,7 +107,7 @@ public void drawInBackground(int mouseX, int mouseY, IRenderContext context) { drawGradientRect(scrollX + 1, scrollSliderY, paneSize - 2, scrollSliderHeight, 0xFF555555, 0xFF454545); RenderUtil.useScissor(position.x, position.y, size.width - paneSize, size.height, () -> - super.drawInBackground(finalMouseX, finalMouseY, context)); + super.drawInBackground(finalMouseX, finalMouseY, partialTicks, context)); GlStateManager.color(rColorForOverlay, gColorForOverlay, bColorForOverlay, 1.0F); } diff --git a/src/main/java/gregtech/api/gui/widgets/TabGroup.java b/src/main/java/gregtech/api/gui/widgets/TabGroup.java index d9741df338e..b18ee5089bf 100644 --- a/src/main/java/gregtech/api/gui/widgets/TabGroup.java +++ b/src/main/java/gregtech/api/gui/widgets/TabGroup.java @@ -68,8 +68,8 @@ public List getContainedWidgets(boolean includeHidden) { } @Override - public void drawInBackground(int mouseX, int mouseY, IRenderContext context) { - super.drawInBackground(mouseX, mouseY, context); + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + super.drawInBackground(mouseX, mouseY, partialTicks, context); this.tabListRenderer.renderTabs(getPosition(), tabInfos, sizes.getWidth(), sizes.getHeight(), selectedTabIndex); GlStateManager.color(rColorForOverlay, gColorForOverlay, bColorForOverlay, 1.0F); } diff --git a/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java b/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java index a61fdb88298..75fbbe49fea 100644 --- a/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java +++ b/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java @@ -4,6 +4,9 @@ import gregtech.api.terminal.gui.widgets.guide.GuideEditor; import gregtech.api.terminal.gui.widgets.guide.GuideEditorPageWidget; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.PacketBuffer; + +import java.util.function.Consumer; public class GuideEditorApp extends AbstractApplication{ public static final TextureArea ICON = TextureArea.fullImage("textures/gui/terminal/guide_editor/icon.png"); @@ -14,9 +17,16 @@ public GuideEditorApp() { @Override public AbstractApplication createApp(boolean isClient, NBTTagCompound nbt) { - GuideEditorApp app = new GuideEditorApp(); - app.addWidget(new GuideEditor(0, 0, 133, 232)); - app.addWidget(new GuideEditorPageWidget(133, 0, 200, 232)); - return app; + if (isClient) { + GuideEditorApp app = new GuideEditorApp(); + app.addWidget(new GuideEditor(0, 20, 133, 232)); + app.addWidget(new GuideEditorPageWidget(133, 0, 200, 232)); + return app; + } + return null; + } + + @Override + protected void writeClientAction(int id, Consumer packetBufferWriter) { } } diff --git a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java index 3c59b2a9146..dabcc3322a8 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java @@ -6,6 +6,7 @@ import gregtech.api.GTValues; import gregtech.api.gui.GuiTextures; import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.ColorRectTexture; import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.widgets.WidgetGroup; import gregtech.api.terminal.app.AbstractApplication; @@ -13,6 +14,7 @@ import gregtech.api.terminal.util.TreeNode; import net.minecraft.client.Minecraft; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.PacketBuffer; import net.minecraft.util.ResourceLocation; import net.minecraft.util.Tuple; @@ -23,6 +25,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.function.Consumer; public abstract class GuideApp extends AbstractApplication { private GuidePageWidget pageWidget; @@ -38,13 +41,13 @@ public AbstractApplication createApp(boolean isClient, NBTTagCompound nbt) { app.addWidget( new TextTreeWidget<>(0, 0, 133, 232, getTree(), leaf -> { if (app.pageWidget != null) { - app.removeWidget(pageWidget); + app.removeWidget(app.pageWidget); } app.pageWidget = new GuidePageWidget(133, 0, 200, 232); if (leaf.isLeaf() && leaf.content != null) { app.pageWidget.loadJsonConfig(leaf.content.getSecond()); } - app.addWidget(pageWidget); + app.addWidget(app.pageWidget); }, this::itemIcon, this::itemName).setNodeTexture(GuiTextures.BORDERED_BACKGROUND).setLeafTexture(GuiTextures.SLOT_DARKENED) ); } @@ -55,6 +58,10 @@ public AbstractApplication createApp(boolean isClient, NBTTagCompound nbt) { return null; } + @Override + protected void writeClientAction(int id, Consumer packetBufferWriter) { + } + protected IGuiTexture itemIcon(T item) { return null; } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/ScrollablePanelWidgetGroup.java b/src/main/java/gregtech/api/terminal/gui/widgets/ScrollablePanelWidgetGroup.java new file mode 100644 index 00000000000..245b12027ad --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/ScrollablePanelWidgetGroup.java @@ -0,0 +1,271 @@ +package gregtech.api.terminal.gui.widgets; + +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.util.Position; +import gregtech.api.util.RenderUtil; +import gregtech.api.util.Size; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.util.math.MathHelper; + +public class ScrollablePanelWidgetGroup extends WidgetGroup { + protected int scrollXOffset; + protected int scrollYOffset; + protected int xBarHeight; + protected int yBarWidth; + protected boolean draggable; + protected IGuiTexture background; + protected int maxHeight; + protected int maxWidth; + protected IGuiTexture xBarB; + protected IGuiTexture xBarF; + protected IGuiTexture yBarB; + protected IGuiTexture yBarF; + + private int lastMouseX; + private int lastMouseY; + private boolean draggedPanel; + private boolean draggedOnXScrollBar; + private boolean draggedOnYScrollBar; + + + public ScrollablePanelWidgetGroup(int x, int y, int width, int height) { + super(new Position(x, y), new Size(width, height)); + maxHeight = height; + maxWidth = width; + } + + public ScrollablePanelWidgetGroup availableXScrollBarHeight(int xBar) { + this.xBarHeight = xBar; + return this; + } + + public ScrollablePanelWidgetGroup availableYScrollBarWidth(int yBar) { + this.yBarWidth = yBar; + return this; + } + + public ScrollablePanelWidgetGroup setDraggable(boolean draggable) { + this.draggable = draggable; + return this; + } + + public ScrollablePanelWidgetGroup setBackground(IGuiTexture background) { + this.background = background; + return this; + } + + public ScrollablePanelWidgetGroup setXBarStyle(IGuiTexture background, IGuiTexture bar) { + this.xBarB = background; + this.xBarF = bar; + return this; + } + + public ScrollablePanelWidgetGroup setYBarStyle(IGuiTexture background, IGuiTexture bar) { + this.yBarB = background; + this.yBarF = bar; + return this; + } + + public int getScrollYOffset() { + return scrollYOffset; + } + + public int getScrollXOffset() { + return scrollXOffset; + } + + @Override + public void addWidget(Widget widget) { + maxHeight = Math.max(maxHeight, widget.getSize().height + widget.getSelfPosition().y); + maxWidth = Math.max(maxWidth, widget.getSize().width + widget.getSelfPosition().x); + super.addWidget(widget); + } + + @Override + public void removeWidget(Widget widget) { + super.removeWidget(widget); + computeMax(); + } + + @Override + public void clearAllWidgets() { + super.clearAllWidgets(); + computeMax(); + } + + @Override + public void setSize(Size size) { + super.setSize(size); + computeMax(); + } + + protected void computeMax() { + maxHeight = getSize().height; + maxWidth = getSize().width; + for (Widget widget : widgets) { + maxHeight = Math.max(maxHeight, widget.getSize().height + widget.getSelfPosition().y); + maxWidth = Math.max(maxWidth, widget.getSize().width + widget.getSelfPosition().x); + } + } + + protected int getMaxHeight() { + return maxHeight + xBarHeight; + } + + protected int getMaxWidth() { + return maxWidth + yBarWidth; + } + + protected void setScrollXOffset(int scrollXOffset) { + if (scrollXOffset == this.scrollXOffset) return; + this.scrollXOffset = scrollXOffset; + int minX = this.scrollXOffset + getPosition().x; + int maxX = minX + getSize().width; + for (Widget widget : widgets) { + widget.setVisible(widget.getPosition().x < maxX && widget.getPosition().x + widget.getSize().width > minX); + } + } + + protected void setScrollYOffset(int scrollYOffset) { + if (scrollYOffset == this.scrollYOffset) return; + this.scrollYOffset = scrollYOffset; + int minY = this.scrollYOffset + getPosition().y; + int maxY = minY + getSize().height; + for (Widget widget : widgets) { + widget.setVisible(widget.getPosition().y < maxY && widget.getPosition().y + widget.getSize().height > minY); + } + } + + private boolean isOnXScrollPane(int mouseX, int mouseY) { + Position pos = getPosition(); + Size size = getSize(); + return isMouseOver(pos.x, pos.y - xBarHeight, size.width, xBarHeight, mouseX, mouseY); + } + + private boolean isOnYScrollPane(int mouseX, int mouseY) { + Position pos = getPosition(); + Size size = getSize(); + return isMouseOver(pos.x + size.width - yBarWidth, pos.y, yBarWidth, size.height, mouseX, mouseY); + } + + @Override + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + Position position = getPosition(); + Size size = getSize(); + if (background != null) { + background.draw(position.x, position.y, size.width, size.height); + } + GlStateManager.translate(-scrollXOffset, -scrollYOffset, 0); + RenderUtil.useScissor(position.x, position.y, size.width - yBarWidth, size.height - xBarHeight, ()->{ + super.drawInBackground(mouseX +scrollXOffset, mouseY + scrollYOffset, partialTicks, context); + }); + GlStateManager.translate(scrollXOffset, scrollYOffset, 0); + if (xBarHeight > 0) { + if (xBarB != null) { + xBarB.draw(position.x, position.y - xBarHeight, size.width, xBarHeight); + } + if (xBarF != null) { + int barWidth = size.width / getMaxWidth(); + xBarF.draw(position.x + scrollXOffset, position.y - xBarHeight, barWidth, xBarHeight); + } + } + if (yBarWidth > 0) { + if (yBarB != null) { + yBarB.draw(position.x + size.width - yBarWidth, position.y, yBarWidth, size.height); + } + if (yBarF != null) { + int barHeight = (int) (size.height * 1.0f / getMaxHeight() * size.height); + yBarF.draw(position.x + size.width - yBarWidth, position.y + scrollYOffset * size.height * 1.0f / getMaxHeight(), yBarWidth, barHeight); + } + } + + } + + private void drawBar(Position position, Size size, int barSize, IGuiTexture barB, IGuiTexture barF, int anotherBarSize) { + if (barSize > 0) { + if (barB != null) { + barB.draw(position.x, position.y - barSize, size.width, barSize); + } + if (barF != null) { + int barWidth = (size.width + anotherBarSize) / getMaxWidth(); + barF.draw(position.x + scrollXOffset - barSize, position.y, barWidth, barSize); + } + } + } + + @Override + public void drawInForeground(int mouseX, int mouseY) { + GlStateManager.translate(-scrollXOffset, -scrollYOffset, 0); + super.drawInForeground(mouseX, mouseY + scrollYOffset); + GlStateManager.translate(scrollXOffset, scrollYOffset, 0); + } + + @Override + public boolean mouseClicked(int mouseX, int mouseY, int button) { + lastMouseX = mouseX; + lastMouseY = mouseY; + if (xBarHeight > 0 && isOnXScrollPane(mouseX, mouseY)) { + this.draggedOnXScrollBar = true; + return true; + } + else if (yBarWidth > 0 && isOnYScrollPane(mouseX, mouseY)) { + this.draggedOnYScrollBar = true; + return true; + } else if(isMouseOverElement(mouseX, mouseY)){ + if (super.mouseClicked(mouseX + scrollXOffset, mouseY + scrollYOffset, button)) { + return true; + } else if (draggable) { + this.draggedPanel = true; + return true; + } + } + return false; + } + + @Override + public boolean mouseWheelMove(int mouseX, int mouseY, int wheelDelta) { + if (this.isMouseOverElement(mouseX, mouseY, true)) { + if (super.mouseWheelMove(mouseX + scrollXOffset, mouseY + scrollYOffset, wheelDelta)) { + return true; + } + int moveDelta = -MathHelper.clamp(wheelDelta, -1, 1) * 5; + if (getMaxHeight() - getSize().height > 0) { + setScrollYOffset(MathHelper.clamp(scrollYOffset + moveDelta, 0, getMaxHeight() - getSize().height + 5)); + } + return true; + } + return false; + } + + @Override + public boolean mouseDragged(int mouseX, int mouseY, int button, long timeDragged) { + if (draggedOnXScrollBar) { + setScrollXOffset(MathHelper.clamp(scrollXOffset + (mouseX - lastMouseX) * getMaxWidth() / getSize().width, 0, Math.max(getMaxWidth() - getSize().width, 0))); + } else if (draggedOnYScrollBar) { + setScrollYOffset(MathHelper.clamp(scrollYOffset + (mouseY - lastMouseY) * getMaxHeight() / getSize().height, 0, Math.max(getMaxHeight() - getSize().height, 0))); + } else if (draggedPanel) { + setScrollXOffset(MathHelper.clamp(scrollXOffset + lastMouseX - mouseX, 0, Math.max(getMaxWidth() - yBarWidth - getSize().width, 0))); + setScrollYOffset(MathHelper.clamp(scrollYOffset + lastMouseY - mouseY, 0, Math.max(getMaxHeight() - xBarHeight - getSize().height, 0))); + } + lastMouseX = mouseX; + lastMouseY = mouseY; + return super.mouseDragged(mouseX + scrollXOffset, mouseY + scrollYOffset, button, timeDragged); + } + + @Override + public boolean mouseReleased(int mouseX, int mouseY, int button) { + if (draggedOnXScrollBar) { + draggedOnXScrollBar = false; + } else if (draggedOnYScrollBar) { + draggedOnYScrollBar = false; + } else if (draggedPanel) { + draggedPanel = false; + } else { + return super.mouseReleased(mouseX + scrollXOffset, mouseY + scrollYOffset, button); + } + return true; + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditor.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditor.java index 3783f0c4631..c937385b683 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditor.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditor.java @@ -1,12 +1,31 @@ package gregtech.api.terminal.gui.widgets.guide; +import gregtech.api.gui.widgets.AbstractWidgetGroup; +import gregtech.api.gui.widgets.LabelWidget; +import gregtech.api.gui.widgets.TabGroup; import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.gui.widgets.tab.ItemTabInfo; +import gregtech.api.terminal.gui.widgets.CircleButtonWidget; import gregtech.api.util.Position; import gregtech.api.util.Size; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; public class GuideEditor extends WidgetGroup { public String json; public GuideEditor(int x, int y, int width, int height) { super(new Position(x, y), new Size(width, height)); + TabGroup tabGroup = new TabGroup(TabGroup.TabLocation.HORIZONTAL_TOP_LEFT, Position.ORIGIN); + tabGroup.addTab(new ItemTabInfo("gregtech.machine.workbench.tab.workbench", new ItemStack(Blocks.CRAFTING_TABLE)), createItemListTab()); + tabGroup.addTab(new ItemTabInfo("gregtech.machine.workbench.tab.item_list", new ItemStack(Blocks.CHEST)), createItemListTab()); + this.addWidget(tabGroup); + } + + private AbstractWidgetGroup createItemListTab() { + WidgetGroup widgetGroup = new WidgetGroup(); + widgetGroup.addWidget(new LabelWidget(5, 20, "gregtech.machine.workbench.storage_note_1")); + widgetGroup.addWidget(new LabelWidget(5, 30, "gregtech.machine.workbench.storage_note_2")); + widgetGroup.addWidget(new CircleButtonWidget(10, 10)); + return widgetGroup; } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditorPageWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditorPageWidget.java index 6e08ac29673..0b216647e0b 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditorPageWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditorPageWidget.java @@ -115,13 +115,4 @@ public void removeWidget(Widget widget) { configMap.remove(widget); } - @Override - public boolean mouseClicked(int mouseX, int mouseY, int button) { - return super.mouseClicked(mouseX, mouseY, button); - } - - @Override - public boolean mouseDragged(int mouseX, int mouseY, int button, long timeDragged) { - return super.mouseDragged(mouseX, mouseY, button, timeDragged); - } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java index d5faa04a902..ab6f640e561 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java @@ -4,23 +4,19 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; -import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; -import gregtech.api.gui.resources.IGuiTexture; -import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.gui.resources.ColorRectTexture; +import gregtech.api.terminal.gui.widgets.ScrollablePanelWidgetGroup; import gregtech.api.util.Position; -import gregtech.api.util.RenderUtil; import gregtech.api.util.Size; import gregtech.api.util.interpolate.Eases; import gregtech.api.util.interpolate.Interpolator; -import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.util.math.MathHelper; +import java.awt.*; import java.util.*; +import java.util.List; -import static gregtech.api.gui.impl.ModularUIGui.*; - -public class GuidePageWidget extends WidgetGroup { +public class GuidePageWidget extends ScrollablePanelWidgetGroup { public static final Map REGISTER_WIDGETS = new HashMap<>(); static { //register guide widgets REGISTER_WIDGETS.put("textbox", new TextBoxWidget()); @@ -30,18 +26,15 @@ public class GuidePageWidget extends WidgetGroup { protected List stream; protected List fixed; - private IGuiTexture background; - private int scrollYOffset; - private int maxHeight; protected Interpolator interpolator; public GuidePageWidget(int xPosition, int yPosition, int width, int height) { - super(new Position(xPosition, yPosition), new Size(width, height)); - } - - public GuidePageWidget setBackground(IGuiTexture background) { - this.background = background; - return this; + super(xPosition, yPosition, width, height); + this.setBackground(new ColorRectTexture(-1)); + this.setDraggable(true); + this.availableYScrollBarWidth(4); + this.setYBarStyle(new ColorRectTexture(new Color(142, 142, 142).getRGB()) + , new ColorRectTexture(new Color(148, 226, 193).getRGB())); } public void setTitle(String config) { @@ -50,7 +43,7 @@ public void setTitle(String config) { height = title.getSize().height; removeWidget(title); } - title = new TextBoxWidget(5, 2, 190, + title = new TextBoxWidget(5, 2, this.getSize().width - yBarWidth - 10, Collections.singletonList(config), 0, 15, 0xffffffff, 0x6fff0000, 0xff000000, true, true); @@ -76,7 +69,7 @@ public String loadJsonConfig(String config) { } public void loadJsonConfig(JsonObject config) { - int pageWidth = this.getSize().width; + int pageWidth = this.getSize().width - yBarWidth; // add title setTitle(config.get("title").getAsString()); @@ -86,7 +79,7 @@ public void loadJsonConfig(JsonObject config) { int y = title.getSize().height + 10; for (JsonElement element : config.getAsJsonArray("stream")) { JsonObject widgetConfig = element.getAsJsonObject(); - Widget widget = REGISTER_WIDGETS.get(widgetConfig.get("type").getAsString()).createStreamWidget(5, y, pageWidth - 5, widgetConfig); + Widget widget = REGISTER_WIDGETS.get(widgetConfig.get("type").getAsString()).createStreamWidget(5, y, pageWidth - 10, widgetConfig); y += widget.getSize().height + 5; this.addWidget(widget); stream.add(widget); @@ -139,20 +132,6 @@ protected int getStreamBottom() { } } - protected void setScrollYOffset(int scrollYOffset) { - if (scrollYOffset == this.scrollYOffset) return; - this.scrollYOffset = scrollYOffset; - int minY = this.scrollYOffset + getPosition().y; - int maxY = minY + getSize().height; - for (Widget widget : widgets) { - widget.setVisible(widget.getPosition().y < maxY && widget.getPosition().y + widget.getSize().height > minY); - } - } - - public int getScrollYOffset() { - return scrollYOffset; - } - @Override public void updateScreen() { if (interpolator != null) interpolator.update(); @@ -173,56 +152,9 @@ public void jumpToRef(String ref){ @Override public void addWidget(Widget widget) { - maxHeight = Math.max(maxHeight, widget.getSize().height + widget.getPosition().y); super.addWidget(widget); if (widget instanceof IGuideWidget) { ((IGuideWidget) widget).setPage(this); } } - - @Override - public boolean mouseWheelMove(int mouseX, int mouseY, int wheelDelta) { - if (this.isMouseOverElement(mouseX, mouseY, true)) { - int moveDelta = -MathHelper.clamp(wheelDelta, -1, 1) * 5; - if (maxHeight - getSize().height > 0) { - setScrollYOffset(MathHelper.clamp(scrollYOffset + moveDelta, 0, maxHeight - getSize().height + 5)); - } - return true; - } - return false; - } - - @Override - public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { - Position position = getPosition(); - Size size = getSize(); - if (background != null) { - background.draw(position.x, position.y, size.width, size.height); - } else { - gregtech.api.gui.resources.RenderUtil.renderRect(position.x, position.y, size.width, size.height, 0, 0xffffffff); - } - GlStateManager.translate(0, -scrollYOffset, 0); - RenderUtil.useScissor(position.x, position.y, size.width, size.height, ()->{ - int offsetY = mouseY + scrollYOffset; - for (Widget widget : widgets) { - if (widget.isVisible()) { - widget.drawInBackground(mouseX, offsetY, partialTicks, context); - } - } - GlStateManager.color(rColorForOverlay, gColorForOverlay, bColorForOverlay, 1.0F); - }); - GlStateManager.translate(0, scrollYOffset, 0); - } - - @Override - public void drawInForeground(int mouseX, int mouseY) { - GlStateManager.translate(0, -scrollYOffset, 0); - super.drawInForeground(mouseX, mouseY + scrollYOffset); - GlStateManager.translate(0, scrollYOffset, 0); - } - - @Override - public boolean mouseClicked(int mouseX, int mouseY, int button) { - return super.mouseClicked(mouseX, mouseY + scrollYOffset, button); - } } From 7a65c9dda9abb489174489deaec33bb2e95e446f Mon Sep 17 00:00:00 2001 From: Yefancy Date: Mon, 2 Aug 2021 13:35:25 +0800 Subject: [PATCH 10/58] editor... --- .../java/gregtech/api/gui/GuiTextures.java | 4 + src/main/java/gregtech/api/gui/Widget.java | 6 + .../api/gui/resources/ColorRectTexture.java | 6 + .../api/gui/resources/RenderUtil.java | 1 + .../api/gui/resources/TextTexture.java | 31 ++ .../api/gui/widgets/ClickButtonWidget.java | 9 + .../api/gui/widgets/SimpleTextWidget.java | 22 ++ .../gregtech/api/gui/widgets/TabGroup.java | 21 +- .../api/gui/widgets/TextFieldWidget.java | 9 + .../gui/widgets/tab/IGuiTextureTabInfo.java | 36 +++ .../api/gui/widgets/tab/ITabInfo.java | 4 +- .../api/gui/widgets/tab/ItemTabInfo.java | 15 +- .../api/terminal/app/GuideEditorApp.java | 12 +- .../terminal/gui/CustomTabListRenderer.java | 41 +++ .../gregtech/api/terminal/gui/IDraggable.java | 9 + .../gui/widgets/CircleButtonWidget.java | 29 +- ...va => DraggableScrollableWidgetGroup.java} | 177 +++++++---- .../gui/widgets/RectButtonWidget.java | 40 +++ .../gui/widgets/TextEditorWidget.java | 127 ++++++++ .../gui/widgets/guide/GuideConfigEditor.java | 126 ++++++++ .../gui/widgets/guide/GuideEditor.java | 31 -- .../widgets/guide/GuideEditorPageWidget.java | 118 ------- .../widgets/guide/GuidePageEditorWidget.java | 297 ++++++++++++++++++ .../gui/widgets/guide/GuidePageWidget.java | 57 ++-- .../gui/widgets/guide/GuideWidget.java | 64 +++- .../gui/widgets/guide/IGuideWidget.java | 8 + .../gui/widgets/guide/ImageWidget.java | 40 ++- .../gui/widgets/guide/TextBoxWidget.java | 30 +- .../guide/congiurator/ConfiguratorWidget.java | 96 ++++++ .../guide/congiurator/NumberConfigurator.java | 57 ++++ .../guide/congiurator/StringConfigurator.java | 44 +++ .../congiurator/TextListConfigurator.java | 54 ++++ .../textures/gui/terminal/terminal_add.png | Bin 0 -> 2273 bytes .../textures/gui/terminal/terminal_delete.png | Bin 0 -> 1987 bytes .../textures/gui/terminal/terminal_down.png | Bin 0 -> 1903 bytes .../textures/gui/terminal/terminal_up.png | Bin 0 -> 1899 bytes 36 files changed, 1347 insertions(+), 274 deletions(-) create mode 100644 src/main/java/gregtech/api/gui/resources/TextTexture.java create mode 100644 src/main/java/gregtech/api/gui/widgets/tab/IGuiTextureTabInfo.java create mode 100644 src/main/java/gregtech/api/terminal/gui/CustomTabListRenderer.java create mode 100644 src/main/java/gregtech/api/terminal/gui/IDraggable.java rename src/main/java/gregtech/api/terminal/gui/widgets/{ScrollablePanelWidgetGroup.java => DraggableScrollableWidgetGroup.java} (52%) create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/RectButtonWidget.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/TextEditorWidget.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java delete mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditor.java delete mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditorPageWidget.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/ConfiguratorWidget.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/NumberConfigurator.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/StringConfigurator.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/TextListConfigurator.java create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/terminal_add.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/terminal_delete.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/terminal_down.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/terminal_up.png diff --git a/src/main/java/gregtech/api/gui/GuiTextures.java b/src/main/java/gregtech/api/gui/GuiTextures.java index bcd8c7d543f..0054bac88ac 100644 --- a/src/main/java/gregtech/api/gui/GuiTextures.java +++ b/src/main/java/gregtech/api/gui/GuiTextures.java @@ -173,5 +173,9 @@ public class GuiTextures { public static final TextureArea TERMINAL_MENU = TextureArea.fullImage("textures/gui/terminal/terminal_menu.png"); public static final TextureArea TERMINAL_HOME = TextureArea.fullImage("textures/gui/terminal/terminal_home.png"); public static final TextureArea TERMINAL_SETTING = TextureArea.fullImage("textures/gui/terminal/terminal_setting.png"); + public static final TextureArea TERMINAL_DELETE = TextureArea.fullImage("textures/gui/terminal/terminal_delete.png"); + public static final TextureArea TERMINAL_UP = TextureArea.fullImage("textures/gui/terminal/terminal_up.png"); + public static final TextureArea TERMINAL_DOWN = TextureArea.fullImage("textures/gui/terminal/terminal_down.png"); + public static final TextureArea TERMINAL_ADD = TextureArea.fullImage("textures/gui/terminal/terminal_add.png"); } diff --git a/src/main/java/gregtech/api/gui/Widget.java b/src/main/java/gregtech/api/gui/Widget.java index a2ca5d778c9..0e56ab4e111 100644 --- a/src/main/java/gregtech/api/gui/Widget.java +++ b/src/main/java/gregtech/api/gui/Widget.java @@ -85,6 +85,12 @@ public void setSelfPosition(Position selfPosition) { recomputePosition(); } + public Position addSelfPosition(int addX, int addY) { + this.selfPosition = new Position(selfPosition.x + addX, selfPosition.y + addY); + recomputePosition(); + return this.selfPosition; + } + public Position getSelfPosition() { return selfPosition; } diff --git a/src/main/java/gregtech/api/gui/resources/ColorRectTexture.java b/src/main/java/gregtech/api/gui/resources/ColorRectTexture.java index d1b192f11b4..8c1683cd0c7 100644 --- a/src/main/java/gregtech/api/gui/resources/ColorRectTexture.java +++ b/src/main/java/gregtech/api/gui/resources/ColorRectTexture.java @@ -5,6 +5,8 @@ import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import java.awt.*; + public class ColorRectTexture implements IGuiTexture{ private final int color; @@ -12,6 +14,10 @@ public ColorRectTexture(int color) { this.color = color; } + public ColorRectTexture(Color color) { + this.color = color.getRGB(); + } + @Override public void draw(double x, double y, int width, int height) { double j; diff --git a/src/main/java/gregtech/api/gui/resources/RenderUtil.java b/src/main/java/gregtech/api/gui/resources/RenderUtil.java index cf8a28ab440..f5033a12b73 100644 --- a/src/main/java/gregtech/api/gui/resources/RenderUtil.java +++ b/src/main/java/gregtech/api/gui/resources/RenderUtil.java @@ -139,6 +139,7 @@ public static void renderCircle(float x, float y, float r, int color, int segmen } tessellator.draw(); GlStateManager.enableTexture2D(); + GlStateManager.color(1,1,1,1); } public static void renderSector(float x, float y, float r, int color, int segments, int from, int to) { diff --git a/src/main/java/gregtech/api/gui/resources/TextTexture.java b/src/main/java/gregtech/api/gui/resources/TextTexture.java new file mode 100644 index 00000000000..04f20a4e37f --- /dev/null +++ b/src/main/java/gregtech/api/gui/resources/TextTexture.java @@ -0,0 +1,31 @@ +package gregtech.api.gui.resources; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.resources.I18n; +import net.minecraftforge.fml.common.FMLCommonHandler; + +public class TextTexture implements IGuiTexture{ + private final String text; + private final int color; + private final int textWidth; + + public TextTexture(String text) { + this.text = text; + this.color = 0xff000000; + textWidth = FMLCommonHandler.instance().getSide().isClient()? Minecraft.getMinecraft().fontRenderer.getStringWidth(text):0; + } + + public TextTexture(String text, int color) { + this.text = text; + this.color = color; + textWidth = FMLCommonHandler.instance().getSide().isClient()? Minecraft.getMinecraft().fontRenderer.getStringWidth(text):0; + } + + + @Override + public void draw(double x, double y, int width, int height) { + FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer; + fontRenderer.drawString(I18n.format(text), (float) (x + (width - textWidth) / 2), (float) (y + (height - fontRenderer.FONT_HEIGHT) / 2 + 2), color, false); + } +} diff --git a/src/main/java/gregtech/api/gui/widgets/ClickButtonWidget.java b/src/main/java/gregtech/api/gui/widgets/ClickButtonWidget.java index 390fb6de372..2e5aa16697a 100644 --- a/src/main/java/gregtech/api/gui/widgets/ClickButtonWidget.java +++ b/src/main/java/gregtech/api/gui/widgets/ClickButtonWidget.java @@ -24,6 +24,7 @@ public class ClickButtonWidget extends Widget { protected String displayText; protected int textColor = 0xFFFFFF; protected Consumer onPressCallback; + protected boolean shouldClientCallback; public ClickButtonWidget(int xPosition, int yPosition, int width, int height, String displayText, Consumer onPressed) { super(new Position(xPosition, yPosition), new Size(width, height)); @@ -31,6 +32,11 @@ public ClickButtonWidget(int xPosition, int yPosition, int width, int height, St this.onPressCallback = onPressed; } + public ClickButtonWidget setShouldClientCallback(boolean shouldClientCallback) { + this.shouldClientCallback = shouldClientCallback; + return this; + } + public ClickButtonWidget setButtonTexture(TextureArea buttonTexture) { this.buttonTexture = buttonTexture; return this; @@ -71,6 +77,9 @@ public boolean mouseClicked(int mouseX, int mouseY, int button) { protected void triggerButton() { ClickData clickData = new ClickData(Mouse.getEventButton(), isShiftDown(), isCtrlDown()); writeClientAction(1, clickData::writeToBuf); + if (shouldClientCallback) { + onPressCallback.accept(clickData); + } playButtonClickSound(); } diff --git a/src/main/java/gregtech/api/gui/widgets/SimpleTextWidget.java b/src/main/java/gregtech/api/gui/widgets/SimpleTextWidget.java index 6f63d926886..9b22ab31949 100644 --- a/src/main/java/gregtech/api/gui/widgets/SimpleTextWidget.java +++ b/src/main/java/gregtech/api/gui/widgets/SimpleTextWidget.java @@ -24,6 +24,7 @@ public class SimpleTextWidget extends Widget { protected int color; protected Supplier textSupplier; protected String lastText = ""; + protected boolean clientWidget; public SimpleTextWidget(int xPosition, int yPosition, String formatLocale, int color, Supplier textSupplier) { super(new Position(xPosition, yPosition), Size.ZERO); @@ -32,6 +33,14 @@ public SimpleTextWidget(int xPosition, int yPosition, String formatLocale, int c this.textSupplier = textSupplier; } + public SimpleTextWidget(int xPosition, int yPosition, String formatLocale, int color, Supplier textSupplier, boolean clientWidget) { + super(new Position(xPosition, yPosition), Size.ZERO); + this.color = color; + this.formatLocale = formatLocale; + this.textSupplier = textSupplier; + this.clientWidget = clientWidget; + } + public SimpleTextWidget(int xPosition, int yPosition, String formatLocale, Supplier textSupplier) { this(xPosition, yPosition, formatLocale, 0x404040, textSupplier); } @@ -45,6 +54,19 @@ private void updateSize() { } } + @Override + public void updateScreen() { + super.updateScreen(); + if (clientWidget && textSupplier != null) { + String newString = textSupplier.get(); + if (!newString.equals(lastText)) { + lastText = newString; + updateSize(); + } + lastText = newString; + } + } + @Override public void drawInBackground(int mouseX, int mouseY, IRenderContext context) { FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer; diff --git a/src/main/java/gregtech/api/gui/widgets/TabGroup.java b/src/main/java/gregtech/api/gui/widgets/TabGroup.java index b18ee5089bf..7c92191048a 100644 --- a/src/main/java/gregtech/api/gui/widgets/TabGroup.java +++ b/src/main/java/gregtech/api/gui/widgets/TabGroup.java @@ -19,6 +19,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.function.BiConsumer; import java.util.function.Supplier; import static gregtech.api.gui.impl.ModularUIGui.*; @@ -27,8 +28,14 @@ public class TabGroup extends AbstractWidgetGroup { private final List tabInfos = new ArrayList<>(); private final Map tabWidgets = new HashMap<>(); - private int selectedTabIndex = 0; + protected int selectedTabIndex = 0; private final TabListRenderer tabListRenderer; + private BiConsumer onTabChanged; + + public TabGroup(int x, int y, TabListRenderer tabListRenderer) { + super(new Position(x, y)); + this.tabListRenderer = tabListRenderer; + } public TabGroup(TabLocation tabLocation, Position position) { super(position); @@ -39,12 +46,18 @@ public TabGroup(TabLocation tabLocation) { this(tabLocation, Position.ORIGIN); } - public void addTab(ITabInfo tabInfo, AbstractWidgetGroup tabWidget) { + public TabGroup addTab(ITabInfo tabInfo, AbstractWidgetGroup tabWidget) { this.tabInfos.add(tabInfo); int tabIndex = tabInfos.size() - 1; this.tabWidgets.put(tabIndex, tabWidget); tabWidget.setVisible(tabIndex == selectedTabIndex); addWidget(tabWidget); + return this; + } + + public TabGroup setOnTabChanged(BiConsumer onTabChanged) { + this.onTabChanged = onTabChanged; + return this; } @Override @@ -104,9 +117,13 @@ public boolean mouseClicked(int mouseX, int mouseY, int button) { } private void setSelectedTab(int tabIndex) { + int old = selectedTabIndex; this.tabWidgets.get(selectedTabIndex).setVisible(false); this.tabWidgets.get(tabIndex).setVisible(true); this.selectedTabIndex = tabIndex; + if (this.onTabChanged != null) { + onTabChanged.accept(old, tabIndex); + } } @Override diff --git a/src/main/java/gregtech/api/gui/widgets/TextFieldWidget.java b/src/main/java/gregtech/api/gui/widgets/TextFieldWidget.java index 2ee4448526e..1cad2d7abc2 100644 --- a/src/main/java/gregtech/api/gui/widgets/TextFieldWidget.java +++ b/src/main/java/gregtech/api/gui/widgets/TextFieldWidget.java @@ -41,6 +41,15 @@ public TextFieldWidget(int xPosition, int yPosition, int width, int height, bool this.textResponder = textResponder; } + public void setCurrentString(String currentString) { + this.currentString = currentString; + this.textField.setText(currentString); + } + + public String getCurrentString() { + return this.textField.getText(); + } + @Override protected void onPositionUpdate() { if (isClientSide() && textField != null) { diff --git a/src/main/java/gregtech/api/gui/widgets/tab/IGuiTextureTabInfo.java b/src/main/java/gregtech/api/gui/widgets/tab/IGuiTextureTabInfo.java new file mode 100644 index 00000000000..e254d652605 --- /dev/null +++ b/src/main/java/gregtech/api/gui/widgets/tab/IGuiTextureTabInfo.java @@ -0,0 +1,36 @@ +package gregtech.api.gui.widgets.tab; + +import com.google.common.collect.Lists; +import gregtech.api.gui.resources.IGuiTexture; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.resources.I18n; +import net.minecraftforge.fml.client.config.GuiUtils; + +import static gregtech.api.gui.impl.ModularUIGui.*; + +public class IGuiTextureTabInfo implements ITabInfo { + private final IGuiTexture texture; + private final String nameLocale; + + public IGuiTextureTabInfo(IGuiTexture texture, String nameLocale) { + this.texture = texture; + this.nameLocale = nameLocale; + } + + @Override + public void renderTab(IGuiTexture tabTexture, int posX, int posY, int xSize, int ySize, boolean isSelected) { + tabTexture.draw(posX, posY, xSize, ySize); + texture.draw(posX, posY, xSize, ySize); + GlStateManager.color(rColorForOverlay, gColorForOverlay, bColorForOverlay, 1.0F); + } + + @Override + public void renderHoverText(int posX, int posY, int xSize, int ySize, int guiWidth, int guiHeight, boolean isSelected, int mouseX, int mouseY) { + String localizedText = I18n.format(nameLocale); + Minecraft mc = Minecraft.getMinecraft(); + ScaledResolution resolution = new ScaledResolution(mc); + GuiUtils.drawHoveringText(Lists.newArrayList(localizedText), mouseX, mouseY, resolution.getScaledWidth(), resolution.getScaledHeight(), -1, mc.fontRenderer); + } +} diff --git a/src/main/java/gregtech/api/gui/widgets/tab/ITabInfo.java b/src/main/java/gregtech/api/gui/widgets/tab/ITabInfo.java index f5c7c961745..28fb8daace7 100644 --- a/src/main/java/gregtech/api/gui/widgets/tab/ITabInfo.java +++ b/src/main/java/gregtech/api/gui/widgets/tab/ITabInfo.java @@ -1,10 +1,10 @@ package gregtech.api.gui.widgets.tab; -import gregtech.api.gui.resources.TextureArea; +import gregtech.api.gui.resources.IGuiTexture; public interface ITabInfo { - void renderTab(TextureArea tabTexture, int posX, int posY, int xSize, int ySize, boolean isSelected); + void renderTab(IGuiTexture tabTexture, int posX, int posY, int xSize, int ySize, boolean isSelected); void renderHoverText(int posX, int posY, int xSize, int ySize, int guiWidth, int guiHeight, boolean isSelected, int mouseX, int mouseY); diff --git a/src/main/java/gregtech/api/gui/widgets/tab/ItemTabInfo.java b/src/main/java/gregtech/api/gui/widgets/tab/ItemTabInfo.java index 71fd681b8a2..d8ff74a3f4e 100644 --- a/src/main/java/gregtech/api/gui/widgets/tab/ItemTabInfo.java +++ b/src/main/java/gregtech/api/gui/widgets/tab/ItemTabInfo.java @@ -1,6 +1,7 @@ package gregtech.api.gui.widgets.tab; import com.google.common.collect.Lists; +import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.resources.TextureArea; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.ScaledResolution; @@ -23,7 +24,7 @@ public ItemTabInfo(String nameLocale, ItemStack iconStack) { } @Override - public void renderTab(TextureArea tabTexture, int posX, int posY, int xSize, int ySize, boolean isSelected) { + public void renderTab(IGuiTexture tabTexture, int posX, int posY, int xSize, int ySize, boolean isSelected) { tabTexture.draw(posX, posY, xSize, ySize); GlStateManager.enableRescaleNormal(); RenderHelper.enableGUIStandardItemLighting(); @@ -35,10 +36,12 @@ public void renderTab(TextureArea tabTexture, int posX, int posY, int xSize, int @Override public void renderHoverText(int posX, int posY, int xSize, int ySize, int guiWidth, int guiHeight, boolean isSelected, int mouseX, int mouseY) { - String localizedText = I18n.format(nameLocale); - Minecraft mc = Minecraft.getMinecraft(); - ScaledResolution resolution = new ScaledResolution(mc); - GuiUtils.drawHoveringText(Lists.newArrayList(localizedText), mouseX, mouseY, - resolution.getScaledWidth(), resolution.getScaledHeight(), -1, mc.fontRenderer); + if (nameLocale != null) { + String localizedText = I18n.format(nameLocale); + Minecraft mc = Minecraft.getMinecraft(); + ScaledResolution resolution = new ScaledResolution(mc); + GuiUtils.drawHoveringText(Lists.newArrayList(localizedText), mouseX, mouseY, + resolution.getScaledWidth(), resolution.getScaledHeight(), -1, mc.fontRenderer); + } } } diff --git a/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java b/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java index 75fbbe49fea..9ecb104de8d 100644 --- a/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java +++ b/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java @@ -1,8 +1,8 @@ package gregtech.api.terminal.app; import gregtech.api.gui.resources.TextureArea; -import gregtech.api.terminal.gui.widgets.guide.GuideEditor; -import gregtech.api.terminal.gui.widgets.guide.GuideEditorPageWidget; +import gregtech.api.terminal.gui.widgets.guide.GuideConfigEditor; +import gregtech.api.terminal.gui.widgets.guide.GuidePageEditorWidget; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.PacketBuffer; @@ -19,8 +19,12 @@ public GuideEditorApp() { public AbstractApplication createApp(boolean isClient, NBTTagCompound nbt) { if (isClient) { GuideEditorApp app = new GuideEditorApp(); - app.addWidget(new GuideEditor(0, 20, 133, 232)); - app.addWidget(new GuideEditorPageWidget(133, 0, 200, 232)); + GuideConfigEditor configEditor = new GuideConfigEditor(0, 0, 133, 232); + GuidePageEditorWidget pageEditor = new GuidePageEditorWidget(133, 0, 200, 232); + configEditor.setGuidePageEditorWidget(pageEditor); + pageEditor.setGuideConfigEditor(configEditor); + app.addWidget(pageEditor); + app.addWidget(configEditor); return app; } return null; diff --git a/src/main/java/gregtech/api/terminal/gui/CustomTabListRenderer.java b/src/main/java/gregtech/api/terminal/gui/CustomTabListRenderer.java new file mode 100644 index 00000000000..c84cfd66220 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/CustomTabListRenderer.java @@ -0,0 +1,41 @@ +package gregtech.api.terminal.gui; + +import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.widgets.tab.ITabInfo; +import gregtech.api.gui.widgets.tab.TabListRenderer; +import gregtech.api.util.Position; + +import java.util.List; + +public class CustomTabListRenderer extends TabListRenderer { + private final IGuiTexture unSelected; + private final IGuiTexture selected; + private final int width; + private final int height; + + public CustomTabListRenderer(IGuiTexture unSelected, IGuiTexture selected, int width, int height){ + this.unSelected = unSelected; + this.selected = selected; + this.width = width; + this.height = height; + } + + @Override + public void renderTabs(Position offset, List tabInfos, int guiWidth, int guiHeight, int selectedTabIndex) { + int y = offset.y - height; + for (int i = 0; i < tabInfos.size(); i++) { + int x = offset.x + i * width; + if (selectedTabIndex == i && selected != null) { + tabInfos.get(i).renderTab(selected, x, y, width, height, true); + } + if (selectedTabIndex != i && unSelected != null) { + tabInfos.get(i).renderTab(unSelected, x, y, width, height, false); + } + } + } + + @Override + public int[] getTabPos(int guiWidth, int guiHeight, int tabIndex) { + return new int[]{width * guiWidth, -height, width, height}; + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/IDraggable.java b/src/main/java/gregtech/api/terminal/gui/IDraggable.java new file mode 100644 index 00000000000..1c38550638e --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/IDraggable.java @@ -0,0 +1,9 @@ +package gregtech.api.terminal.gui; + +public interface IDraggable { + boolean setDraggable(boolean isDraggable); + boolean allowDrag(int mouseX, int mouseY, int button); + default void startDrag(int mouseX, int mouseY) {} + default boolean dragging(int mouseX, int mouseY, int deltaX, int deltaY) {return true;} + default void endDrag(int mouseX, int mouseY) {} +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java index ccce2bcc7b7..47c89d0f085 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java @@ -17,14 +17,14 @@ import java.util.function.Consumer; public class CircleButtonWidget extends Widget { - private final int border; - private int hoverTick; - private boolean isHover; - private String hoverText; - private IGuiTexture icon; - private final int iconSize; - private Consumer onPressCallback; - private final int[] colors = { + protected int border; + protected int hoverTick; + protected boolean isHover; + protected String hoverText; + protected IGuiTexture icon; + protected final int iconSize; + protected Consumer onPressCallback; + protected final int[] colors = { new Color(146, 146, 146).getRGB(), new Color(39, 232, 141).getRGB(), new Color(255, 255, 255).getRGB(), @@ -57,7 +57,17 @@ public CircleButtonWidget setColors(int stroke, int strokeAnima, int fill) { return this; } - public CircleButtonWidget setFillColors(int fill) { + public CircleButtonWidget setStroke(int stroke) { + colors[0] = stroke; + return this; + } + + public CircleButtonWidget setStrokeAnima(int strokeAnima) { + colors[1] = strokeAnima; + return this; + } + + public CircleButtonWidget setFill(int fill) { colors[2] = fill; return this; } @@ -94,7 +104,6 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender } RenderUtil.renderCircle(x, y, r - border, colors[2], segments); if (icon != null) { - GlStateManager.color(1,1,1,1); icon.draw(x - iconSize / 2f, y - iconSize / 2f, iconSize, iconSize); } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/ScrollablePanelWidgetGroup.java b/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java similarity index 52% rename from src/main/java/gregtech/api/terminal/gui/widgets/ScrollablePanelWidgetGroup.java rename to src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java index 245b12027ad..eb45dd3d8c0 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/ScrollablePanelWidgetGroup.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java @@ -4,13 +4,13 @@ import gregtech.api.gui.Widget; import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.terminal.gui.IDraggable; import gregtech.api.util.Position; import gregtech.api.util.RenderUtil; import gregtech.api.util.Size; -import net.minecraft.client.renderer.GlStateManager; import net.minecraft.util.math.MathHelper; -public class ScrollablePanelWidgetGroup extends WidgetGroup { +public class DraggableScrollableWidgetGroup extends WidgetGroup { protected int scrollXOffset; protected int scrollYOffset; protected int xBarHeight; @@ -23,47 +23,49 @@ public class ScrollablePanelWidgetGroup extends WidgetGroup { protected IGuiTexture xBarF; protected IGuiTexture yBarB; protected IGuiTexture yBarF; + protected boolean focus; private int lastMouseX; private int lastMouseY; private boolean draggedPanel; private boolean draggedOnXScrollBar; private boolean draggedOnYScrollBar; + private Widget draggedWidget; - public ScrollablePanelWidgetGroup(int x, int y, int width, int height) { + public DraggableScrollableWidgetGroup(int x, int y, int width, int height) { super(new Position(x, y), new Size(width, height)); maxHeight = height; maxWidth = width; } - public ScrollablePanelWidgetGroup availableXScrollBarHeight(int xBar) { + public DraggableScrollableWidgetGroup setXScrollBarHeight(int xBar) { this.xBarHeight = xBar; return this; } - public ScrollablePanelWidgetGroup availableYScrollBarWidth(int yBar) { + public DraggableScrollableWidgetGroup setYScrollBarWidth(int yBar) { this.yBarWidth = yBar; return this; } - public ScrollablePanelWidgetGroup setDraggable(boolean draggable) { + public DraggableScrollableWidgetGroup setDraggable(boolean draggable) { this.draggable = draggable; return this; } - public ScrollablePanelWidgetGroup setBackground(IGuiTexture background) { + public DraggableScrollableWidgetGroup setBackground(IGuiTexture background) { this.background = background; return this; } - public ScrollablePanelWidgetGroup setXBarStyle(IGuiTexture background, IGuiTexture bar) { + public DraggableScrollableWidgetGroup setXBarStyle(IGuiTexture background, IGuiTexture bar) { this.xBarB = background; this.xBarF = bar; return this; } - public ScrollablePanelWidgetGroup setYBarStyle(IGuiTexture background, IGuiTexture bar) { + public DraggableScrollableWidgetGroup setYBarStyle(IGuiTexture background, IGuiTexture bar) { this.yBarB = background; this.yBarF = bar; return this; @@ -81,6 +83,7 @@ public int getScrollXOffset() { public void addWidget(Widget widget) { maxHeight = Math.max(maxHeight, widget.getSize().height + widget.getSelfPosition().y); maxWidth = Math.max(maxWidth, widget.getSize().width + widget.getSelfPosition().x); + widget.addSelfPosition(- scrollXOffset, - scrollYOffset); super.addWidget(widget); } @@ -103,11 +106,50 @@ public void setSize(Size size) { } protected void computeMax() { - maxHeight = getSize().height; - maxWidth = getSize().width; + int mh = 0; + int mw = 0; for (Widget widget : widgets) { - maxHeight = Math.max(maxHeight, widget.getSize().height + widget.getSelfPosition().y); - maxWidth = Math.max(maxWidth, widget.getSize().width + widget.getSelfPosition().x); + mh = Math.max(mh, widget.getSize().height + widget.getSelfPosition().y + scrollYOffset); + mw = Math.max(mw, widget.getSize().width + widget.getSelfPosition().x + scrollXOffset); + } + int offsetY = 0; + int offsetX = 0; + if (mh > getSize().height && mh < maxHeight) { + offsetY = maxHeight - mh; + maxHeight = mh; + if (scrollYOffset - offsetY < 0) { + offsetY = scrollYOffset; + } + scrollYOffset -= offsetY; + } else if (mh < getSize().height) { + offsetY = maxHeight - getSize().height; + maxHeight = getSize().height; + if (scrollYOffset - offsetY < 0) { + offsetY = scrollYOffset; + } + scrollYOffset -= offsetY; + } + if (mw > getSize().width && mw < maxWidth) { + offsetX = maxWidth - mw; + maxWidth = mw; + if (scrollXOffset - offsetX < 0) { + offsetX = scrollXOffset; + } + scrollXOffset -= offsetX; + }else if (mw < getSize().width) { + offsetX = maxWidth - getSize().width; + maxWidth = getSize().width; + if (scrollXOffset - offsetX < 0) { + offsetX = scrollXOffset; + } + scrollXOffset -= offsetX; + } + if (offsetX != 0 || offsetY != 0) { + for (Widget widget : widgets) { + Position newPos = widget.addSelfPosition(offsetX, offsetY); + widget.setVisible(newPos.x < getSize().width - yBarWidth && newPos.x + widget.getSize().width > 0); + widget.setVisible(newPos.y < getSize().height - xBarHeight && newPos.y + widget.getSize().height > 0); + } } } @@ -119,23 +161,31 @@ protected int getMaxWidth() { return maxWidth + yBarWidth; } + public int getWidgetBottomHeight() { + int y = 0; + for (Widget widget : widgets) { + y = Math.max(y, widget.getSize().height + widget.getSelfPosition().y); + } + return y; + } + protected void setScrollXOffset(int scrollXOffset) { if (scrollXOffset == this.scrollXOffset) return; + int offset = scrollXOffset - this.scrollXOffset; this.scrollXOffset = scrollXOffset; - int minX = this.scrollXOffset + getPosition().x; - int maxX = minX + getSize().width; for (Widget widget : widgets) { - widget.setVisible(widget.getPosition().x < maxX && widget.getPosition().x + widget.getSize().width > minX); + Position newPos = widget.addSelfPosition( - offset, 0); + widget.setVisible(newPos.x < getSize().width - yBarWidth && newPos.x + widget.getSize().width > 0); } } protected void setScrollYOffset(int scrollYOffset) { if (scrollYOffset == this.scrollYOffset) return; + int offset = scrollYOffset - this.scrollYOffset; this.scrollYOffset = scrollYOffset; - int minY = this.scrollYOffset + getPosition().y; - int maxY = minY + getSize().height; for (Widget widget : widgets) { - widget.setVisible(widget.getPosition().y < maxY && widget.getPosition().y + widget.getSize().height > minY); + Position newPos = widget.addSelfPosition(0, - offset); + widget.setVisible(newPos.y < getSize().height - xBarHeight && newPos.y + widget.getSize().height > 0); } } @@ -151,6 +201,10 @@ private boolean isOnYScrollPane(int mouseX, int mouseY) { return isMouseOver(pos.x + size.width - yBarWidth, pos.y, yBarWidth, size.height, mouseX, mouseY); } + protected boolean hookDrawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + return false; + } + @Override public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { Position position = getPosition(); @@ -158,11 +212,11 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender if (background != null) { background.draw(position.x, position.y, size.width, size.height); } - GlStateManager.translate(-scrollXOffset, -scrollYOffset, 0); RenderUtil.useScissor(position.x, position.y, size.width - yBarWidth, size.height - xBarHeight, ()->{ - super.drawInBackground(mouseX +scrollXOffset, mouseY + scrollYOffset, partialTicks, context); + if(!hookDrawInBackground(mouseX, mouseY, partialTicks, context)) { + super.drawInBackground(mouseX, mouseY, partialTicks, context); + } }); - GlStateManager.translate(scrollXOffset, scrollYOffset, 0); if (xBarHeight > 0) { if (xBarB != null) { xBarB.draw(position.x, position.y - xBarHeight, size.width, xBarHeight); @@ -181,26 +235,6 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender yBarF.draw(position.x + size.width - yBarWidth, position.y + scrollYOffset * size.height * 1.0f / getMaxHeight(), yBarWidth, barHeight); } } - - } - - private void drawBar(Position position, Size size, int barSize, IGuiTexture barB, IGuiTexture barF, int anotherBarSize) { - if (barSize > 0) { - if (barB != null) { - barB.draw(position.x, position.y - barSize, size.width, barSize); - } - if (barF != null) { - int barWidth = (size.width + anotherBarSize) / getMaxWidth(); - barF.draw(position.x + scrollXOffset - barSize, position.y, barWidth, barSize); - } - } - } - - @Override - public void drawInForeground(int mouseX, int mouseY) { - GlStateManager.translate(-scrollXOffset, -scrollYOffset, 0); - super.drawInForeground(mouseX, mouseY + scrollYOffset); - GlStateManager.translate(scrollXOffset, scrollYOffset, 0); } @Override @@ -209,18 +243,43 @@ public boolean mouseClicked(int mouseX, int mouseY, int button) { lastMouseY = mouseY; if (xBarHeight > 0 && isOnXScrollPane(mouseX, mouseY)) { this.draggedOnXScrollBar = true; + focus = true; return true; } else if (yBarWidth > 0 && isOnYScrollPane(mouseX, mouseY)) { this.draggedOnYScrollBar = true; + focus = true; return true; } else if(isMouseOverElement(mouseX, mouseY)){ - if (super.mouseClicked(mouseX + scrollXOffset, mouseY + scrollYOffset, button)) { + focus = true; + if (checkClickedDragged(mouseX, mouseY, button)) { return true; - } else if (draggable) { + } + if (draggable) { this.draggedPanel = true; return true; } + return false; + } else if (checkClickedDragged(mouseX, mouseY, button)) { + return true; + } + focus = false; + return false; + } + + private boolean checkClickedDragged(int mouseX, int mouseY, int button) { + draggedWidget = null; + for (int i = widgets.size() - 1; i >= 0; i--) { + Widget widget = widgets.get(i); + if(widget.isVisible()) { + if(widget.mouseClicked(mouseX, mouseY, button)) { + return true; + } else if (widget instanceof IDraggable && ((IDraggable) widget).allowDrag(mouseX, mouseY, button)) { + draggedWidget = widget; + ((IDraggable) widget).startDrag(mouseX, mouseY); + return true; + } + } } return false; } @@ -228,7 +287,7 @@ else if (yBarWidth > 0 && isOnYScrollPane(mouseX, mouseY)) { @Override public boolean mouseWheelMove(int mouseX, int mouseY, int wheelDelta) { if (this.isMouseOverElement(mouseX, mouseY, true)) { - if (super.mouseWheelMove(mouseX + scrollXOffset, mouseY + scrollYOffset, wheelDelta)) { + if (super.mouseWheelMove(mouseX, mouseY, wheelDelta)) { return true; } int moveDelta = -MathHelper.clamp(wheelDelta, -1, 1) * 5; @@ -237,22 +296,31 @@ public boolean mouseWheelMove(int mouseX, int mouseY, int wheelDelta) { } return true; } + focus = false; return false; } @Override public boolean mouseDragged(int mouseX, int mouseY, int button, long timeDragged) { + int deltaX = mouseX - lastMouseX; + int deltaY = mouseY - lastMouseY; + lastMouseX = mouseX; + lastMouseY = mouseY; if (draggedOnXScrollBar) { - setScrollXOffset(MathHelper.clamp(scrollXOffset + (mouseX - lastMouseX) * getMaxWidth() / getSize().width, 0, Math.max(getMaxWidth() - getSize().width, 0))); + setScrollXOffset(MathHelper.clamp(scrollXOffset + deltaX * getMaxWidth() / getSize().width, 0, Math.max(getMaxWidth() - getSize().width, 0))); + return true; } else if (draggedOnYScrollBar) { - setScrollYOffset(MathHelper.clamp(scrollYOffset + (mouseY - lastMouseY) * getMaxHeight() / getSize().height, 0, Math.max(getMaxHeight() - getSize().height, 0))); + setScrollYOffset(MathHelper.clamp(scrollYOffset + deltaY * getMaxHeight() / getSize().height, 0, Math.max(getMaxHeight() - getSize().height, 0))); + return true; + } else if (draggedWidget != null && ((IDraggable)draggedWidget).dragging(mouseX, mouseY, deltaX, deltaY)) { + draggedWidget.addSelfPosition(deltaX, deltaY); + return true; } else if (draggedPanel) { - setScrollXOffset(MathHelper.clamp(scrollXOffset + lastMouseX - mouseX, 0, Math.max(getMaxWidth() - yBarWidth - getSize().width, 0))); - setScrollYOffset(MathHelper.clamp(scrollYOffset + lastMouseY - mouseY, 0, Math.max(getMaxHeight() - xBarHeight - getSize().height, 0))); + setScrollXOffset(MathHelper.clamp(scrollXOffset - deltaX, 0, Math.max(getMaxWidth() - yBarWidth - getSize().width, 0))); + setScrollYOffset(MathHelper.clamp(scrollYOffset - deltaY, 0, Math.max(getMaxHeight() - xBarHeight - getSize().height, 0))); + return true; } - lastMouseX = mouseX; - lastMouseY = mouseY; - return super.mouseDragged(mouseX + scrollXOffset, mouseY + scrollYOffset, button, timeDragged); + return super.mouseDragged(mouseX, mouseY, button, timeDragged); } @Override @@ -261,10 +329,13 @@ public boolean mouseReleased(int mouseX, int mouseY, int button) { draggedOnXScrollBar = false; } else if (draggedOnYScrollBar) { draggedOnYScrollBar = false; + } else if (draggedWidget != null) { + ((IDraggable)draggedWidget).endDrag(mouseX, mouseY); + draggedWidget = null; } else if (draggedPanel) { draggedPanel = false; } else { - return super.mouseReleased(mouseX + scrollXOffset, mouseY + scrollYOffset, button); + return super.mouseReleased(mouseX, mouseY, button); } return true; } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/RectButtonWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/RectButtonWidget.java new file mode 100644 index 00000000000..b20460798a3 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/RectButtonWidget.java @@ -0,0 +1,40 @@ +package gregtech.api.terminal.gui.widgets; + +import gregtech.api.gui.IRenderContext; +import gregtech.api.util.Position; +import gregtech.api.util.Size; + +public class RectButtonWidget extends CircleButtonWidget{ + public RectButtonWidget(int x, int y, int width, int height) { + this(x, y, width, height,2); + } + + public RectButtonWidget(int x, int y, int width, int height, int border) { + super(x, y); + setSelfPosition(new Position(x, y)); + setSize(new Size(width, height)); + this.border = border; + } + + @Override + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + int x = this.getPosition().x; + int y = this.getPosition().y; + int width = this.getSize().width; + int height = this.getSize().height; + + drawSolidRect(x, y, width, height, colors[0]); + isHover = this.isMouseOverElement(mouseX, mouseY); + if (isHover || hoverTick != 0) { + float per = Math. min ((hoverTick + partialTicks) / 8, 1); + drawSolidRect(x, y, (int) (width * per), border, colors[1]); + drawSolidRect(x + width - border, y, border, (int) (height * per), colors[1]); + drawSolidRect((int) ((1 - per) * width) + x, y + height - border, (int) (width * per), border, colors[1]); + drawSolidRect(x, (int) ((1 - per) * height) + y, border, (int) (height * per), colors[1]); + } + drawSolidRect(x + border, y + border, width - 2 * border, height - 2 * border, colors[2]); + if (icon != null) { + icon.draw(x + border, y + border, width - 2 * border, height - 2 * border); + } + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/TextEditorWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/TextEditorWidget.java new file mode 100644 index 00000000000..c64b17c15d8 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/TextEditorWidget.java @@ -0,0 +1,127 @@ +package gregtech.api.terminal.gui.widgets; + +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.util.Position; +import gregtech.api.util.Size; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.util.ChatAllowedCharacters; +import net.minecraft.util.text.TextFormatting; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +import java.awt.*; +import java.util.function.Consumer; + +public class TextEditorWidget extends WidgetGroup { + private final TextPanelWidget textPanelWidget; + public TextEditorWidget(int x, int y, int width, int height, String text, Consumer stringUpdate) { + super(new Position(x, y), new Size(width, height)); + textPanelWidget = new TextPanelWidget(0, 10, width, height-10, text, stringUpdate); + this.addWidget(new RectButtonWidget(0, 0, 20, 10, 1).setFill(new Color(109, 229, 154, 141).getRGB()).setHoverText("update").setClickListener(d->{ + if (stringUpdate != null) { + stringUpdate.accept(textPanelWidget.content); + } + })); + this.addWidget(textPanelWidget); + } + + public TextEditorWidget setBackground(IGuiTexture background) { + textPanelWidget.setBackground(background); + return this; + } + + private static class TextPanelWidget extends DraggableScrollableWidgetGroup { + private final static int SPACE = 0; + private int updateCount; + private String content; + private int textHeight; + private final Consumer stringUpdate; + @SideOnly(Side.CLIENT) + private FontRenderer fontRenderer; + + public TextPanelWidget(int x, int y, int width, int height, String text, Consumer stringUpdate) { + super(x, y, width, height); + this.stringUpdate = stringUpdate; + this.content = text == null ? "" : text; + if (isClientSide()) { + fontRenderer = Minecraft.getMinecraft().fontRenderer; + textHeight = fontRenderer.getWordWrappedHeight(content, width - yBarWidth); + } + } + + @Override + protected int getMaxHeight() { + return textHeight + SPACE + xBarHeight; + } + + public void updateScreen() { + super.updateScreen(); + ++this.updateCount; + } + + @Override + public boolean keyTyped(char typedChar, int keyCode) { + if(!focus) return false; + if (GuiScreen.isKeyComboCtrlV(keyCode)) { + this.pageInsertIntoCurrent(GuiScreen.getClipboardString()); + } else { + switch(keyCode) { + case 14: + if (!content.isEmpty()) { + this.pageSetCurrent(content.substring(0, content.length() - 1)); + } + return true; + case 28: + case 156: + this.pageInsertIntoCurrent("\n"); + return true; + default: + if (ChatAllowedCharacters.isAllowedCharacter(typedChar)) { + this.pageInsertIntoCurrent(Character.toString(typedChar)); + } + } + } + return true; + } + + private void pageSetCurrent(String string) { + if (!content.equals(string)) { + content = string; + if(stringUpdate != null) { + stringUpdate.accept(content); + } + textHeight = this.fontRenderer.getWordWrappedHeight(content + "" + TextFormatting.BLACK + "_", this.getSize().width - yBarWidth); + } + } + + private void pageInsertIntoCurrent(String string) { + content += string; + if(stringUpdate != null) { + stringUpdate.accept(content); + } + textHeight = this.fontRenderer.getWordWrappedHeight(content + "" + TextFormatting.BLACK + "_", this.getSize().width - yBarWidth); + } + + @Override + protected boolean hookDrawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + String contentString = content; + if (focus) { + if (this.fontRenderer.getBidiFlag()) { + contentString += "_"; + } else if (this.updateCount / 6 % 2 == 0) { + contentString += TextFormatting.BLACK + "_"; + } else { + contentString += TextFormatting.GRAY + "_"; + } + } + this.fontRenderer.drawSplitString(contentString, getPosition().x, getPosition().y+ SPACE, getSize().width - yBarWidth, 0); + return true; + } + } +} + + diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java new file mode 100644 index 00000000000..0ceb0a5512b --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java @@ -0,0 +1,126 @@ +package gregtech.api.terminal.gui.widgets.guide; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import gregtech.api.gui.GuiTextures; +import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.ColorRectTexture; +import gregtech.api.gui.resources.TextTexture; +import gregtech.api.gui.widgets.LabelWidget; +import gregtech.api.gui.widgets.TabGroup; +import gregtech.api.gui.widgets.tab.IGuiTextureTabInfo; +import gregtech.api.terminal.gui.CustomTabListRenderer; +import gregtech.api.terminal.gui.widgets.CircleButtonWidget; +import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; +import gregtech.api.util.Size; + +import java.awt.*; +import java.util.Map; + +public class GuideConfigEditor extends TabGroup { + public String json; + private IGuideWidget selected; + private GuidePageEditorWidget pageEditor; + private final DraggableScrollableWidgetGroup widgetSelector; + private final DraggableScrollableWidgetGroup widgetConfigurator; + + public GuideConfigEditor(int x, int y, int width, int height) { + super(x, y + 10, new CustomTabListRenderer( + new ColorRectTexture(new Color(175, 0, 0, 131)), + new ColorRectTexture(new Color(246, 120, 120, 190)), 30, 10)); + setSize(new Size(width, height)); + widgetSelector = createWidgetSelector(); + widgetConfigurator = createConfigurator(); + this.addTab(new IGuiTextureTabInfo(new TextTexture("W", -1), "widget"), widgetSelector); + this.addTab(new IGuiTextureTabInfo(new TextTexture("C", -1), "config"), widgetConfigurator); + this.addWidget(new CircleButtonWidget(100, -5, 5, 1, 3) + .setColors(new Color(255, 255, 255, 0).getRGB(), + new Color(255, 255, 255).getRGB(), + new Color(0, 115, 255).getRGB()) + .setIcon(GuiTextures.TERMINAL_ADD) + .setHoverText("add stream") + .setClickListener(this::addStream)); + this.addWidget(new CircleButtonWidget(120, -5, 5, 1, 3) + .setColors(new Color(255, 255, 255, 0).getRGB(), + new Color(255, 255, 255).getRGB(), + new Color(113, 27, 217).getRGB()) + .setIcon(GuiTextures.TERMINAL_ADD) + .setHoverText("add fixed") + .setClickListener(this::addFixed)); + } + + public void setGuidePageEditorWidget(GuidePageEditorWidget pageEditor) { + this.pageEditor = pageEditor; + } + + private DraggableScrollableWidgetGroup createWidgetSelector() { + DraggableScrollableWidgetGroup group = new DraggableScrollableWidgetGroup(0, 0, getSize().width, getSize().height - 10) + .setBackground(new ColorRectTexture(new Color(246, 120, 120, 190))) + .setYScrollBarWidth(4) + .setYBarStyle(null, new ColorRectTexture(new Color(148, 226, 193))); + int y = 10; //133 + for (Map.Entry entry : GuidePageWidget.REGISTER_WIDGETS.entrySet()) { + IGuideWidget widgetTemplate = entry.getValue(); + JsonObject template = widgetTemplate.getTemplate(false); +// template.addProperty("stroke", 0xFF7CA1FF); + Widget guideWidget = widgetTemplate.createStreamWidget(5, y + 10, getSize().width - 14, template); + group.addWidget(new LabelWidget(getSize().width / 2 - 1, y, entry.getKey(), -1).setXCentered(true)); + y += guideWidget.getSize().height + 25; + group.addWidget(guideWidget); + } + return group; + } + + private DraggableScrollableWidgetGroup createConfigurator() { + return new DraggableScrollableWidgetGroup(0, 0, getSize().width, getSize().height - 10) + .setBackground(new ColorRectTexture(new Color(246, 120, 120, 190))) + .setYScrollBarWidth(4) + .setYBarStyle(null, new ColorRectTexture(new Color(148, 226, 193))); + } + + public void loadConfigurator(IGuideWidget widget, JsonObject config, boolean isFixed) { + widgetConfigurator.clearAllWidgets(); + if (widget != null) { + widget.loadConfigurator(widgetConfigurator, config, isFixed, attr->{ + widget.updateValue(attr, config.get(attr)); + }); + } + } + + private void addFixed(ClickData data) { + if (pageEditor != null && selected != null) { + selected.setStroke(0); + pageEditor.addGuideWidget(selected, true); + selected.setStroke(0xFF7CA1FF); + } + } + + private void addStream(ClickData data) { + if (pageEditor != null && selected != null) { + selected.setStroke(0); + pageEditor.addGuideWidget(selected, false); + selected.setStroke(0xFF7CA1FF); + } + } + + @Override + public boolean mouseClicked(int mouseX, int mouseY, int button) { + boolean flag = super.mouseClicked(mouseX, mouseY, button); + if (selectedTabIndex == 0 && widgetSelector != null) { + for (Widget widget : widgetSelector.widgets) { + if (widget.isMouseOverElement(mouseX, mouseY)) { + if (widget instanceof IGuideWidget) { + if (selected != null) { + selected.setStroke(0); + } + ((IGuideWidget) widget).setStroke(0xFF7CA1FF); + selected = (IGuideWidget) widget; + } + playButtonClickSound(); + return true; + } + } + } + return flag; + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditor.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditor.java deleted file mode 100644 index c937385b683..00000000000 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditor.java +++ /dev/null @@ -1,31 +0,0 @@ -package gregtech.api.terminal.gui.widgets.guide; - -import gregtech.api.gui.widgets.AbstractWidgetGroup; -import gregtech.api.gui.widgets.LabelWidget; -import gregtech.api.gui.widgets.TabGroup; -import gregtech.api.gui.widgets.WidgetGroup; -import gregtech.api.gui.widgets.tab.ItemTabInfo; -import gregtech.api.terminal.gui.widgets.CircleButtonWidget; -import gregtech.api.util.Position; -import gregtech.api.util.Size; -import net.minecraft.init.Blocks; -import net.minecraft.item.ItemStack; - -public class GuideEditor extends WidgetGroup { - public String json; - public GuideEditor(int x, int y, int width, int height) { - super(new Position(x, y), new Size(width, height)); - TabGroup tabGroup = new TabGroup(TabGroup.TabLocation.HORIZONTAL_TOP_LEFT, Position.ORIGIN); - tabGroup.addTab(new ItemTabInfo("gregtech.machine.workbench.tab.workbench", new ItemStack(Blocks.CRAFTING_TABLE)), createItemListTab()); - tabGroup.addTab(new ItemTabInfo("gregtech.machine.workbench.tab.item_list", new ItemStack(Blocks.CHEST)), createItemListTab()); - this.addWidget(tabGroup); - } - - private AbstractWidgetGroup createItemListTab() { - WidgetGroup widgetGroup = new WidgetGroup(); - widgetGroup.addWidget(new LabelWidget(5, 20, "gregtech.machine.workbench.storage_note_1")); - widgetGroup.addWidget(new LabelWidget(5, 30, "gregtech.machine.workbench.storage_note_2")); - widgetGroup.addWidget(new CircleButtonWidget(10, 10)); - return widgetGroup; - } -} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditorPageWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditorPageWidget.java deleted file mode 100644 index 0b216647e0b..00000000000 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditorPageWidget.java +++ /dev/null @@ -1,118 +0,0 @@ -package gregtech.api.terminal.gui.widgets.guide; - - -import com.google.common.collect.BiMap; -import com.google.common.collect.HashBiMap; -import com.google.gson.*; -import gregtech.api.gui.Widget; -import gregtech.api.util.Position; -import gregtech.api.util.interpolate.Eases; -import gregtech.api.util.interpolate.Interpolator; - -public class GuideEditorPageWidget extends GuidePageWidget { - private final BiMap configMap; - - public GuideEditorPageWidget(int xPosition, int yPosition, int width, int height) { - super(xPosition, yPosition, width, height); - configMap = HashBiMap.create(); - setTitle("Template"); - } - - public String getJsonString() { - JsonObject json = new JsonObject(); - json.addProperty("section", ""); - json.addProperty("title", title.content.get(0)); - if (stream != null) { - JsonArray array = new JsonArray(); - json.add("stream", array); - stream.forEach(widget -> array.add(configMap.get(widget))); - } - if (fixed != null) { - JsonArray array = new JsonArray(); - json.add("fixed", array); - fixed.forEach(widget -> array.add(configMap.get(widget))); - } - return new Gson().toJson(json); - } - - public JsonObject addGuideWidget(IGuideWidget widget, boolean isFixed) { - int pageWidth = this.getSize().width; - JsonObject widgetConfig = widget.getTemplate(isFixed); - Widget guideWidget; - if (isFixed) { - guideWidget = widget.createFixedWidget(widgetConfig.get("x").getAsInt(), - widgetConfig.get("y").getAsInt(), - widgetConfig.get("width").getAsInt(), - widgetConfig.get("height").getAsInt(), - widgetConfig); - this.addWidget(guideWidget); - fixed.add(guideWidget); - } else { - int y = getStreamBottom(); - guideWidget = widget.createStreamWidget(5, y + 5, pageWidth - 5, widgetConfig); - this.addWidget(guideWidget); - stream.add(guideWidget); - } - configMap.put(guideWidget, widgetConfig); - return widgetConfig; - } - - - public void moveUp(Widget widget) { - int index = stream.indexOf(widget); - if (index > 0) { - Widget target = stream.get(index - 1); - if (interpolator == null) { - int offset = widget.getPosition().y - target.getPosition().y; - int y1 = widget.getSelfPosition().y; - int y2 = target.getSelfPosition().y; - interpolator = new Interpolator(0, offset, 10, Eases.EaseLinear, value->{ - widget.setSelfPosition(new Position(widget.getSelfPosition().x, y1 - value.intValue())); - target.setSelfPosition(new Position(target.getSelfPosition().x, y2 + value.intValue())); - }, value->{ - interpolator = null; - stream.remove(widget); - stream.add(index - 1, widget); - }).start(); - } - } - } - - public void moveDown(Widget widget) { - int index = stream.indexOf(widget); - if (index >= 0 && index < stream.size() - 1) { - Widget target = stream.get(index + 1); - if (interpolator == null) { - int offset = target.getPosition().y - widget.getPosition().y; - int y1 = widget.getSelfPosition().y; - int y2 = target.getSelfPosition().y; - interpolator = new Interpolator(0, offset, 10, Eases.EaseLinear, value->{ - widget.setSelfPosition(new Position(widget.getSelfPosition().x, y1 + value.intValue())); - target.setSelfPosition(new Position(target.getSelfPosition().x, y2 - value.intValue())); - }, value->{ - interpolator = null; - stream.remove(widget); - stream.add(index + 1, widget); - }).start(); - } - } - } - - @Override - public void removeWidget(Widget widget) { - int index = stream.indexOf(widget); - if (index >= 0) { - int offset = widget.getSize().height + 5; - for (int i = stream.size() - 1; i > index; i--) { - Widget bottom = stream.get(i); - bottom.setSelfPosition(new Position(bottom.getSelfPosition().x, bottom.getSelfPosition().y - offset)); - } - stream.remove(widget); - } else { - fixed.remove(widget); - } - super.removeWidget(widget); - configMap.remove(widget); - } - -} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java new file mode 100644 index 00000000000..7c1b6995cc2 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java @@ -0,0 +1,297 @@ +package gregtech.api.terminal.gui.widgets.guide; + + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import gregtech.api.gui.GuiTextures; +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.Widget; +import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.terminal.gui.IDraggable; +import gregtech.api.terminal.gui.widgets.CircleButtonWidget; +import gregtech.api.util.Position; +import gregtech.api.util.Size; +import gregtech.api.util.interpolate.Eases; +import gregtech.api.util.interpolate.Interpolator; +import net.minecraft.client.renderer.GlStateManager; + +import java.awt.*; +import java.util.HashMap; +import java.util.Map; + +import static gregtech.api.gui.impl.ModularUIGui.*; + +public class GuidePageEditorWidget extends GuidePageWidget { + private final Map configMap; + private Widget selected; + private final WidgetGroup toolButtons; + private GuideConfigEditor configEditor; + + public GuidePageEditorWidget(int xPosition, int yPosition, int width, int height) { + super(xPosition, yPosition, width, height); + this.setDraggable(false); + configMap = new HashMap<>(); + setTitle("Template"); + toolButtons = new WidgetGroup(Position.ORIGIN, Size.ZERO); + toolButtons.setVisible(false); + toolButtons.addWidget(new CircleButtonWidget(-20, -4, 8, 1, 12) + .setColors(new Color(255, 255, 255, 0).getRGB(), + new Color(88, 198, 88).getRGB(), + new Color(158, 238, 124).getRGB()) + .setIcon(GuiTextures.TERMINAL_UP) + .setHoverText("up") + .setClickListener(this::moveUp)); + toolButtons.addWidget(new CircleButtonWidget(0, -4, 8, 1, 12) + .setColors(new Color(255, 255, 255, 0).getRGB(), + new Color(255, 217, 0).getRGB(), + new Color(243, 217, 117).getRGB()) + .setIcon(GuiTextures.TERMINAL_DOWN) + .setHoverText("down") + .setClickListener(this::moveDown)); + toolButtons.addWidget(new CircleButtonWidget(20, -4, 8, 1, 12) + .setColors(new Color(255, 255, 255, 0).getRGB(), + new Color(238, 46, 46).getRGB(), + new Color(238, 116, 116).getRGB()) + .setIcon(GuiTextures.TERMINAL_DELETE) + .setHoverText("delete") + .setClickListener(this::delete)); + addWidget(toolButtons); + } + + public void setGuideConfigEditor(GuideConfigEditor configEditor) { + this.configEditor = configEditor; + } + + private void setToolButton(int x, int y, int width, int height) { + toolButtons.setVisible(true); + toolButtons.setSelfPosition(new Position(x + width / 2, y)); + } + + private void delete(ClickData clickData) { + removeWidget(selected); + selected = null; + configEditor.loadConfigurator(null, null, true); + toolButtons.setSelfPosition(new Position(0, 0)); + toolButtons.setVisible(false); + } + + private void moveUp(ClickData clickData) { + moveUp(selected); + } + + private void moveDown(ClickData clickData) { + moveDown(selected); + } + + public String getJsonString() { + JsonObject json = new JsonObject(); + json.addProperty("section", ""); + json.addProperty("title", title.content.get(0)); + JsonArray array = new JsonArray(); + json.add("stream", array); + stream.forEach(widget -> array.add(configMap.get(widget))); + + JsonArray array2 = new JsonArray(); + json.add("fixed", array2); + fixed.forEach(widget -> array2.add(configMap.get(widget))); + + return new Gson().toJson(json); + } + + public JsonObject addGuideWidget(IGuideWidget widget, boolean isFixed) { + int pageWidth = this.getSize().width - 5; + JsonObject widgetConfig = widget.getTemplate(isFixed); + Widget guideWidget; + if (isFixed) { + int width = widgetConfig.get("width").getAsInt(); + int height = widgetConfig.get("height").getAsInt(); + + guideWidget = widget.createFixedWidget( + (pageWidth - width) / 2 + 5, + this.scrollYOffset + (this.getSize().height - height) / 2, + width, + height, + widgetConfig); + fixed.add(guideWidget); + this.addWidget(guideWidget); + } else { + int y = getStreamBottom(); + guideWidget = widget.createStreamWidget(5, y + 5, pageWidth, widgetConfig); + stream.add(guideWidget); + this.addWidget(guideWidget); + } + configMap.put(guideWidget, widgetConfig); + return widgetConfig; + } + + + public void moveUp(Widget widget) { + int index = stream.indexOf(widget); + if (index > 0) { + Widget target = stream.get(index - 1); + if (interpolator == null) { + int offsetD = 5 + widget.getSize().height; + int offsetU = widget.getPosition().y - target.getPosition().y; + int y1 = widget.getSelfPosition().y; + int y2 = target.getSelfPosition().y; + interpolator = new Interpolator(0, 1, 10, Eases.EaseLinear, value->{ + widget.setSelfPosition(new Position(widget.getSelfPosition().x, (int) (y1 - value.floatValue() * offsetU))); + target.setSelfPosition(new Position(target.getSelfPosition().x, (int) (y2 + value.floatValue() * offsetD))); + if (widget == selected) { + setToolButton(selected.getSelfPosition().x, selected.getSelfPosition().y, selected.getSize().width, selected.getSize().height); + } + widget.setVisible(widget.getSelfPosition().y < scrollYOffset + getSize().height && widget.getSelfPosition().y + widget.getSize().height > 0); + target.setVisible(target.getSelfPosition().y < scrollYOffset + getSize().height && target.getSelfPosition().y + target.getSize().height > 0); + }, value->{ + interpolator = null; + stream.remove(widget); + stream.add(index - 1, widget); + }).start(); + } + } + } + + public void moveDown(Widget widget) { + int index = stream.indexOf(widget); + if (index >= 0 && index < stream.size() - 1) { + Widget target = stream.get(index + 1); + if (interpolator == null) { + int offsetD = 5 + target.getSize().height; + int offsetU = target.getPosition().y - widget.getPosition().y; + int y1 = widget.getSelfPosition().y; + int y2 = target.getSelfPosition().y; + interpolator = new Interpolator(0, 1, 10, Eases.EaseLinear, value->{ + widget.setSelfPosition(new Position(widget.getSelfPosition().x, (int) (y1 + value.floatValue() * offsetD))); + target.setSelfPosition(new Position(target.getSelfPosition().x, (int) (y2 - value.floatValue() * offsetU))); + if (widget == selected) { + setToolButton(selected.getSelfPosition().x, selected.getSelfPosition().y, selected.getSize().width, selected.getSize().height); + } + widget.setVisible(widget.getSelfPosition().y < getSize().height - xBarHeight && widget.getSelfPosition().y + widget.getSize().height > 0); + target.setVisible(target.getSelfPosition().y < getSize().height - xBarHeight && target.getSelfPosition().y + target.getSize().height > 0); + }, value->{ + interpolator = null; + stream.remove(widget); + stream.add(index + 1, widget); + }).start(); + } + } + } + + @Override + protected void setScrollYOffset(int scrollYOffset) { + if (scrollYOffset == this.scrollYOffset) return; + int offset = scrollYOffset - this.scrollYOffset; + this.scrollYOffset = scrollYOffset; + for (Widget widget : widgets) { + Position newPos = widget.addSelfPosition(0, -offset); + if (widget != toolButtons) { + widget.setVisible(newPos.y < getSize().height - xBarHeight && newPos.y + widget.getSize().height > 0); + } + } + } + + @Override + public void removeWidget(Widget widget) { + int index = stream.indexOf(widget); + if (index >= 0) { + int offset = widget.getSize().height + 5; + for (int i = stream.size() - 1; i > index; i--) { + Widget bottom = stream.get(i); + Position newPos = bottom.addSelfPosition(0, -offset); + bottom.setVisible(newPos.y < getSize().height - xBarHeight && newPos.y + widget.getSize().height > 0); + } + stream.remove(widget); + } else { + fixed.remove(widget); + } + super.removeWidget(widget); + configMap.remove(widget); + } + + @Override + public boolean mouseClicked(int mouseX, int mouseY, int button) { + boolean flag = false; + for (Widget widget : fixed) { + if (widget.isMouseOverElement(mouseX, mouseY)) { + if (widget instanceof IGuideWidget && widget != selected) { + configEditor.loadConfigurator((IGuideWidget) widget, configMap.get(widget), true); + selected = widget; + setToolButton(selected.getSelfPosition().x, selected.getSelfPosition().y, selected.getSize().width, selected.getSize().height); + } + playButtonClickSound(); + flag = true; + break; + } + } + for (Widget widget : stream) { + if (widget.isMouseOverElement(mouseX, mouseY)) { + if (widget instanceof IGuideWidget && widget != selected) { + configEditor.loadConfigurator((IGuideWidget) widget, configMap.get(widget), false); + selected = widget; + setToolButton(selected.getSelfPosition().x, selected.getSelfPosition().y, selected.getSize().width, selected.getSize().height); + } + playButtonClickSound(); + flag = true; + break; + } + } + if (super.mouseClicked(mouseX, mouseY, button)) { + return true; + } + return flag; + } + + @Override + protected boolean hookDrawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + Position position = getPosition(); + Size size = getSize(); + for (Widget widget : widgets) { + if (widget != toolButtons && widget.isVisible()) { + widget.drawInBackground(mouseX, mouseY, partialTicks, context); + if (widget.isMouseOverElement(mouseX, mouseY)) { + if (widget != selected) { + Position pos = widget.getPosition(); + Size s = widget.getSize(); + if (stream.contains(widget)) { + drawSolidRect(position.x, pos.y, size.width - yBarWidth, s.height, 0x6f000000); + } else { + drawSolidRect(pos.x, pos.y, s.width, s.height, 0x6f000000); + } + } + } + } + } + if (selected != null) { + Position pos = selected.getPosition(); + Size s = selected.getSize(); + if (stream.contains(selected)) { + drawSolidRect(position.x, pos.y, size.width - yBarWidth, s.height, 0x6f0000ff); + } else { + drawSolidRect(pos.x, pos.y, s.width, s.height, 0x6f0000ff); + } + } + if(toolButtons.isVisible()) { + toolButtons.drawInBackground(mouseX, mouseY, partialTicks, context); + } + GlStateManager.color(rColorForOverlay, gColorForOverlay, bColorForOverlay, 1.0F); + return true; + } + + @Override + public boolean mouseDragged(int mouseX, int mouseY, int button, long timeDragged) { + if (super.mouseDragged(mouseX, mouseY, button, timeDragged)) { + setToolButton(selected.getSelfPosition().x, selected.getSelfPosition().y, selected.getSize().width, selected.getSize().height); + return true; + } + return false; + } + + @Override + public void addWidget(Widget widget) { + super.addWidget(widget); + if(fixed.contains(widget) && widget instanceof IDraggable) { + ((IDraggable) widget).setDraggable(true); + } + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java index ab6f640e561..e952b622d61 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java @@ -6,7 +6,7 @@ import com.google.gson.JsonParser; import gregtech.api.gui.Widget; import gregtech.api.gui.resources.ColorRectTexture; -import gregtech.api.terminal.gui.widgets.ScrollablePanelWidgetGroup; +import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; import gregtech.api.util.Position; import gregtech.api.util.Size; import gregtech.api.util.interpolate.Eases; @@ -16,25 +16,27 @@ import java.util.*; import java.util.List; -public class GuidePageWidget extends ScrollablePanelWidgetGroup { +public class GuidePageWidget extends DraggableScrollableWidgetGroup { public static final Map REGISTER_WIDGETS = new HashMap<>(); static { //register guide widgets - REGISTER_WIDGETS.put("textbox", new TextBoxWidget()); - REGISTER_WIDGETS.put("image", new ImageWidget()); + REGISTER_WIDGETS.put(TextBoxWidget.NAME, new TextBoxWidget()); + REGISTER_WIDGETS.put(ImageWidget.NAME, new ImageWidget()); } protected TextBoxWidget title; - protected List stream; - protected List fixed; + protected List stream = new ArrayList<>(); + protected List fixed = new ArrayList<>(); +// protected int pageWdith; protected Interpolator interpolator; public GuidePageWidget(int xPosition, int yPosition, int width, int height) { super(xPosition, yPosition, width, height); - this.setBackground(new ColorRectTexture(-1)); - this.setDraggable(true); - this.availableYScrollBarWidth(4); - this.setYBarStyle(new ColorRectTexture(new Color(142, 142, 142).getRGB()) - , new ColorRectTexture(new Color(148, 226, 193).getRGB())); + this.setBackground(new ColorRectTexture(-1)) + .setDraggable(true) + .setYScrollBarWidth(4) + .setYBarStyle(new ColorRectTexture(new Color(142, 142, 142)), + new ColorRectTexture(new Color(148, 226, 193))); + } public void setTitle(String config) { @@ -48,12 +50,10 @@ public void setTitle(String config) { 0, 15, 0xffffffff, 0x6fff0000, 0xff000000, true, true); this.addWidget(title); - if (stream != null) { - int offset = title.getSize().height - height; - if (offset != 0) { - for (Widget widget : stream) { - widget.setSelfPosition(new Position(widget.getSelfPosition().x, widget.getSelfPosition().y + offset)); - } + int offset = title.getSize().height - height; + if (offset != 0) { + for (Widget widget : stream) { + widget.addSelfPosition(0, offset); } } } @@ -81,8 +81,8 @@ public void loadJsonConfig(JsonObject config) { JsonObject widgetConfig = element.getAsJsonObject(); Widget widget = REGISTER_WIDGETS.get(widgetConfig.get("type").getAsString()).createStreamWidget(5, y, pageWidth - 10, widgetConfig); y += widget.getSize().height + 5; - this.addWidget(widget); stream.add(widget); + this.addWidget(widget); } } // add fixed widgets @@ -96,21 +96,20 @@ public void loadJsonConfig(JsonObject config) { widgetConfig.get("width").getAsInt(), widgetConfig.get("height").getAsInt(), widgetConfig); - this.addWidget(widget); fixed.add(widget); + this.addWidget(widget); } } } public void onSizeUpdate(Widget widget, Size oldSize) { int offset = widget.getSize().height - oldSize.height; - maxHeight = Math.max(maxHeight, widget.getSize().height + widget.getPosition().y); - if (stream != null) { - int index = stream.indexOf(widget); - for (int i = stream.size() - 1; i > index; i--) { - Widget nextWidget = stream.get(i); - nextWidget.setSelfPosition(new Position(nextWidget.getSelfPosition().x, nextWidget.getSelfPosition().y + offset)); - } + maxHeight = Math.max(maxHeight, widget.getSize().height + widget.getSelfPosition().y); + int index = stream.indexOf(widget); + if (index < 0) return; + for (int i = stream.size() - 1; i > index; i--) { + Widget nextWidget = stream.get(i); + nextWidget.addSelfPosition(0, offset); } } @@ -118,7 +117,7 @@ public void onPositionUpdate(Widget widget, Position oldPosition) { if (oldPosition.y + widget.getSize().height == maxHeight) { maxHeight = 0; for (Widget widget1 : widgets) { - maxHeight = Math.max(maxHeight, widget1.getSize().height + widget1.getPosition().y); + maxHeight = Math.max(maxHeight, widget1.getSize().height + widget1.getSelfPosition().y); } } } @@ -126,7 +125,7 @@ public void onPositionUpdate(Widget widget, Position oldPosition) { protected int getStreamBottom() { if (stream!= null && stream.size() > 0) { Widget widget = stream.get(stream.size() - 1); - return widget.getSize().height + widget.getPosition().y; + return widget.getSize().height + widget.getSelfPosition().y; } else { return title.getSize().height + 10; } @@ -142,7 +141,7 @@ public void jumpToRef(String ref){ if (interpolator != null && !interpolator.isFinish()) return; for (Widget widget : widgets) { if (widget instanceof IGuideWidget && ref.equals(((IGuideWidget) widget).getRef())) { - interpolator = new Interpolator(scrollYOffset, widget.getSelfPosition().y, 20, Eases.EaseQuadOut, + interpolator = new Interpolator(scrollYOffset, widget.getSelfPosition().y + scrollYOffset, 20, Eases.EaseQuadOut, value-> setScrollYOffset(value.intValue()), value-> interpolator = null); interpolator.start(); diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java index f5eed7a7d6b..3e7f4b2d930 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java @@ -1,24 +1,26 @@ package gregtech.api.terminal.gui.widgets.guide; import com.google.gson.Gson; -import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.sun.istack.internal.Nullable; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; +import gregtech.api.terminal.gui.IDraggable; +import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; +import gregtech.api.terminal.gui.widgets.guide.congiurator.NumberConfigurator; +import gregtech.api.terminal.gui.widgets.guide.congiurator.StringConfigurator; +import gregtech.api.terminal.gui.widgets.guide.congiurator.TextListConfigurator; import gregtech.api.util.Position; import gregtech.api.util.Size; -import javafx.geometry.Pos; -import net.minecraft.client.renderer.GlStateManager; import net.minecraft.item.ItemStack; -import net.minecraftforge.fml.common.ObfuscationReflectionHelper; -import net.minecraftforge.fml.relauncher.ReflectionHelper; import java.lang.reflect.Field; +import java.util.ArrayList; import java.util.List; +import java.util.function.Consumer; -public abstract class GuideWidget extends Widget implements IGuideWidget { +public abstract class GuideWidget extends Widget implements IGuideWidget, IDraggable { //config public String ref; public int fill; @@ -28,6 +30,7 @@ public abstract class GuideWidget extends Widget implements IGuideWidget { public List hover_text; private static final Gson GSON = new Gson(); + public boolean allowDrag; protected transient GuidePageWidget page; public GuideWidget(int x, int y, int width, int height) { @@ -38,15 +41,28 @@ public GuideWidget(){ super(Position.ORIGIN, Size.ZERO); } + public abstract String getRegistryName(); + public void updateValue(String field, JsonElement value) { try { - Field f = this.getClass().getDeclaredField(field); - f.set(this, new Gson().fromJson(value, f.getType())); + Field f = this.getClass().getField(field); + if (value.isJsonNull()) { // default + f.set(this, f.get(GuidePageWidget.REGISTER_WIDGETS.get(getRegistryName()))); + } else { + f.set(this, new Gson().fromJson(value, f.getType())); + } } catch (Exception e) { e.printStackTrace(); } } + + + @Override + public void setStroke(int color) { + this.stroke = color; + } + @Override public void setSize(Size size) { Size oldSize = this.getSize(); @@ -88,6 +104,14 @@ public JsonObject getTemplate(boolean isFixed) { return template; } + @Override + public void loadConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, boolean isFixed, Consumer needUpdate) { + group.addWidget(new NumberConfigurator(5, group.getWidgetBottomHeight() + 5, config, "stroke_width").setOnUpdated(needUpdate)); + group.addWidget(new StringConfigurator(5, group.getWidgetBottomHeight() + 5, config, "ref", "").setOnUpdated(needUpdate)); + group.addWidget(new StringConfigurator(5, group.getWidgetBottomHeight() + 5, config, "link", "").setOnUpdated(needUpdate)); + group.addWidget(new TextListConfigurator(5, group.getWidgetBottomHeight() + 5, 40, config, "hover_text", true).setOnUpdated(needUpdate)); + } + @Override public String getRef() { return ref; @@ -129,11 +153,12 @@ public void drawInForeground(int mouseX, int mouseY) { Size size = getSize(); drawBorder(position.x, position.y, size.width, size.height, 0xff0000ff, stroke_width); } - if (hover_text != null && isMouseOverElement(mouseX, mouseY)) { - int scrollYOffset = page.getScrollYOffset(); - GlStateManager.translate(0, scrollYOffset, 0); - drawHoveringText(ItemStack.EMPTY, hover_text, 100, mouseX, mouseY - scrollYOffset); - GlStateManager.translate(0, -scrollYOffset, 0); + if ((hover_text != null || link != null) && isMouseOverElement(mouseX, mouseY)) { + List tooltip = hover_text == null ? new ArrayList<>() : new ArrayList<>(hover_text); + if (link != null) { + tooltip.add("§9Ctrl+Click§r §e(" + link + ")§r"); + } + drawHoveringText(ItemStack.EMPTY, tooltip, 100, mouseX, mouseY); } } @@ -151,10 +176,21 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender @Override public boolean mouseClicked(int mouseX, int mouseY, int button) { - if (link != null && isMouseOverElement(mouseX, mouseY)) { + if (link != null && isMouseOverElement(mouseX, mouseY) && isCtrlDown()) { page.jumpToRef(link); return true; } return false; } + + @Override + public boolean allowDrag(int mouseX, int mouseY, int button) { + return allowDrag && isMouseOverElement(mouseX, mouseY); + } + + @Override + public boolean setDraggable(boolean isDraggable) { + allowDrag = isDraggable; + return allowDrag; + } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java index 938d7c6c32d..f8ad46d95d4 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java @@ -1,12 +1,20 @@ package gregtech.api.terminal.gui.widgets.guide; +import com.google.gson.JsonElement; import com.google.gson.JsonObject; import gregtech.api.gui.Widget; +import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; + +import java.util.function.Consumer; public interface IGuideWidget { Widget createStreamWidget(int x, int y, int pageWidth, JsonObject config); Widget createFixedWidget(int x, int y, int width, int height, JsonObject config); void setPage(GuidePageWidget page); + void updateValue(String field, JsonElement value); String getRef(); JsonObject getTemplate(boolean isFixed); + void loadConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, boolean isFixed, Consumer needUpdate); + void setStroke(int color); } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java index 5decb203734..cc6c1fcb991 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java @@ -1,5 +1,6 @@ package gregtech.api.terminal.gui.widgets.guide; +import com.google.gson.JsonElement; import com.google.gson.JsonObject; import gregtech.api.GTValues; import gregtech.api.gui.IRenderContext; @@ -8,13 +9,19 @@ import gregtech.api.gui.resources.ItemStackTexture; import gregtech.api.gui.resources.TextureArea; import gregtech.api.gui.resources.URLTexture; +import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; +import gregtech.api.terminal.gui.widgets.guide.congiurator.NumberConfigurator; +import gregtech.api.terminal.gui.widgets.guide.congiurator.StringConfigurator; import gregtech.api.util.Position; import gregtech.api.util.Size; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.item.Item; import net.minecraft.util.ResourceLocation; +import java.util.function.Consumer; + public class ImageWidget extends GuideWidget{ + public final static String NAME = "image"; //config public String form; public String source; @@ -23,16 +30,41 @@ public class ImageWidget extends GuideWidget{ public transient IGuiTexture image; + @Override + public String getRegistryName() { + return NAME; + } + + @Override + public void updateValue(String field, JsonElement value) { + super.updateValue(field, value); + if (field.equals("width") || field.equals("height")) { + this.setSelfPosition(new Position(getSelfPosition().x - (width - getSize().width) / 2, getSelfPosition().y)); + this.setSize(new Size(width, height)); + } + if (field.equals("form") || field.equals("source")) { + initFixed(0,0,0,0,null); + } + } + @Override public JsonObject getTemplate(boolean isFixed) { JsonObject template = super.getTemplate(isFixed); template.addProperty("form", "item"); template.addProperty("source", "minecraft:ender_pearl"); - template.addProperty("width", 100); - template.addProperty("height", 100); + template.addProperty("width", 50); + template.addProperty("height", 50); return template; } + @Override + public void loadConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, boolean isFixed, Consumer needUpdate) { + super.loadConfigurator(group, config, isFixed, needUpdate); + group.addWidget(new StringConfigurator(5, group.getWidgetBottomHeight() + 5, config, "source").setOnUpdated(needUpdate)); + group.addWidget(new NumberConfigurator(5, group.getWidgetBottomHeight() + 5, config, "width").setOnUpdated(needUpdate)); + group.addWidget(new NumberConfigurator(5, group.getWidgetBottomHeight() + 5, config, "height").setOnUpdated(needUpdate)); + } + @Override public void updateScreen() { if (image != null) { @@ -51,7 +83,7 @@ protected Widget initStream(int x, int y, int pageWidth, JsonObject config) { protected Widget initFixed(int x, int y, int width, int height, JsonObject config) { switch (form) { case "url": - image = new URLTexture("https://i0.hdslb.com/bfs/article/bcd3d609c1899810113fdb90c8d0e1dd4aa8ed38.gif"); + image = new URLTexture(source); break; case "item": image = new ItemStackTexture(Item.getByNameOrId(source)); @@ -69,7 +101,7 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender super.drawInBackground(mouseX, mouseY, partialTicks,context); GlStateManager.color(1,1,1,1); Position position = getPosition(); - image.draw(position.x, position.y, width, height); + image.draw(position.x, position.y, getSize().width, getSize().height); } } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java index 3e16cb2ad3f..b38066bd686 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java @@ -1,10 +1,14 @@ package gregtech.api.terminal.gui.widgets.guide; import com.google.gson.Gson; +import com.google.gson.JsonElement; import com.google.gson.JsonObject; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; import gregtech.api.gui.resources.RenderUtil; +import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; +import gregtech.api.terminal.gui.widgets.guide.congiurator.NumberConfigurator; +import gregtech.api.terminal.gui.widgets.guide.congiurator.TextListConfigurator; import gregtech.api.util.Position; import gregtech.api.util.Size; import net.minecraft.client.Minecraft; @@ -15,8 +19,11 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.function.Consumer; public class TextBoxWidget extends GuideWidget { + public final static String NAME = "textbox"; + // config public List content; public int space = 1; @@ -42,6 +49,19 @@ public TextBoxWidget(int x, int y, int width, List content, int space, i public TextBoxWidget() {} + @Override + public String getRegistryName() { + return NAME; + } + + @Override + public void updateValue(String field, JsonElement value) { + super.updateValue(field, value); + if (field.equals("space") || field.equals("fontSize") || field.equals("content")) { + initFixed(getSelfPosition().x, getSelfPosition().y, getSize().width, getSize().height, null); + } + } + @Override public JsonObject getTemplate(boolean isFixed) { JsonObject template = super.getTemplate(isFixed); @@ -50,10 +70,18 @@ public JsonObject getTemplate(boolean isFixed) { template.addProperty("fontColor", fontColor); template.addProperty("isCenter", isCenter); template.addProperty("isShadow", isShadow); - template.add("content", new Gson().toJsonTree(Arrays.asList("this is", "textbox!"))); + template.add("content", new Gson().toJsonTree(Arrays.asList("this is a", "textbox!"))); return template; } + @Override + public void loadConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, boolean isFixed, Consumer needUpdate) { + super.loadConfigurator(group, config, isFixed, needUpdate); + group.addWidget(new NumberConfigurator(5, group.getWidgetBottomHeight() + 5, config, "space", 1).setOnUpdated(needUpdate)); + group.addWidget(new NumberConfigurator(5, group.getWidgetBottomHeight() + 5, config, "fontSize", 9).setOnUpdated(needUpdate)); + group.addWidget(new TextListConfigurator(5, group.getWidgetBottomHeight() + 5, 200, config, "content", false).setOnUpdated(needUpdate)); + } + @Override protected Widget initFixed(int x, int y, int width, int height, JsonObject config) { this.textLines = new ArrayList<>(); diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/ConfiguratorWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/ConfiguratorWidget.java new file mode 100644 index 00000000000..6ad16d559b9 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/ConfiguratorWidget.java @@ -0,0 +1,96 @@ +package gregtech.api.terminal.gui.widgets.guide.congiurator; + +import com.google.gson.JsonElement; +import com.google.gson.JsonNull; +import com.google.gson.JsonObject; +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.widgets.LabelWidget; +import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.util.Position; +import net.minecraft.client.Minecraft; +import net.minecraft.item.ItemStack; + +import java.util.Collections; +import java.util.function.Consumer; + +public class ConfiguratorWidget extends WidgetGroup { + protected String name; + protected boolean canDefault; + protected boolean isDefault; + protected JsonObject config; + + private int nameWidth; + private Consumer onUpdated; + + public ConfiguratorWidget(int x, int y, JsonObject config, String name, boolean canDefault) { + super(new Position(x, y)); + this.name = name; + this.canDefault = canDefault; + this.config = config; + if (canDefault && config.get(name).isJsonNull()) { + isDefault = true; + } + this.addWidget(new LabelWidget(0, 2, name, -1)); + if (isClientSide()) { + nameWidth = Minecraft.getMinecraft().fontRenderer.getStringWidth(name); + } + } + + public ConfiguratorWidget setOnUpdated(Consumer onUpdated) { + this.onUpdated = onUpdated; + return this; + } + + protected void update(){ + if (onUpdated != null) { + onUpdated.accept(name); + } + } + + @Override + public void drawInForeground(int mouseX, int mouseY) { + int x = getPosition().x; + int y = getPosition().y; + if (canDefault && isMouseOver(x + nameWidth + 4, y + 4, 5, 5, mouseX, mouseY)) { + drawHoveringText(ItemStack.EMPTY, Collections.singletonList("default the value"), 100, mouseX, mouseY); + } + super.drawInForeground(mouseX, mouseY); + } + + @Override + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + int x = getPosition().x; + int y = getPosition().y; + drawSolidRect(x, y, this.getSize().width, 1, -1); + if (canDefault) { + drawBorder(x + nameWidth + 4, y + 4, 5, 5, 0xff000000, 1); + if (isDefault) { + drawSolidRect(x + nameWidth + 5, y + 5, 3, 3, 0xff000000); + } + } + super.drawInBackground(mouseX, mouseY, partialTicks, context); + } + + @Override + public boolean mouseClicked(int mouseX, int mouseY, int button) { + int x = getPosition().x; + int y = getPosition().y; + if (!isDefault && super.mouseClicked(mouseX, mouseY, button)) { + return true; + } + if (canDefault && isMouseOver(x + nameWidth + 4, y + 4, 5, 5, mouseX, mouseY)) { + isDefault = !isDefault; + if (isDefault) { + config.addProperty(name, (String) null); + update(); + onDefault(); + } + playButtonClickSound(); + return true; + } + return false; + } + + protected void onDefault() { + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/NumberConfigurator.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/NumberConfigurator.java new file mode 100644 index 00000000000..cb52f8f9ead --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/NumberConfigurator.java @@ -0,0 +1,57 @@ +package gregtech.api.terminal.gui.widgets.guide.congiurator; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import gregtech.api.gui.GuiTextures; +import gregtech.api.gui.resources.TextTexture; +import gregtech.api.gui.widgets.ImageWidget; +import gregtech.api.gui.widgets.SimpleTextWidget; +import gregtech.api.terminal.gui.widgets.RectButtonWidget; + +public class NumberConfigurator extends ConfiguratorWidget{ + private int defaultValue; + + public NumberConfigurator(int x, int y, JsonObject config, String name) { + super(x, y, config, name, false); + init(0); + } + + public NumberConfigurator(int x, int y, JsonObject config, String name, int defaultValue) { + super(x, y, config, name, true); + init(defaultValue); + } + + private void init(int defaultValue){ + this.defaultValue = defaultValue; + this.addWidget(new RectButtonWidget(0, 11, 20, 20) + .setClickListener(data -> adjustTransferRate(data.isShiftClick ? -100 : -10)) + .setIcon(new TextTexture("-10"))); + this.addWidget(new RectButtonWidget(96, 11, 20, 20) + .setClickListener(data -> adjustTransferRate(data.isShiftClick ? +100 : +10)) + .setIcon(new TextTexture("+10"))); + this.addWidget(new RectButtonWidget(20, 11, 20, 20) + .setClickListener(data -> adjustTransferRate(data.isShiftClick ? -5 : -1)) + .setIcon(new TextTexture("-1"))); + this.addWidget(new RectButtonWidget(76, 11, 20, 20) + .setClickListener(data -> adjustTransferRate(data.isShiftClick ? +5 : +1)) + .setIcon(new TextTexture("+1"))); + this.addWidget(new ImageWidget(40, 11, 36, 20, GuiTextures.DISPLAY)); + this.addWidget(new SimpleTextWidget(58, 21, "", 0xFFFFFF, () -> { + JsonElement element = config.get(name); + if (element.isJsonNull()) { + return Integer.toString(defaultValue); + } + return element.getAsString(); + }, true)); + } + + private void adjustTransferRate(int added) { + JsonElement element = config.get(name); + int num = defaultValue; + if (!element.isJsonNull()) { + num = element.getAsInt(); + } + config.addProperty(name, num + added); + update(); + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/StringConfigurator.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/StringConfigurator.java new file mode 100644 index 00000000000..b4589dfdfd0 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/StringConfigurator.java @@ -0,0 +1,44 @@ +package gregtech.api.terminal.gui.widgets.guide.congiurator; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import gregtech.api.gui.resources.TextTexture; +import gregtech.api.gui.widgets.TextFieldWidget; +import gregtech.api.terminal.gui.widgets.RectButtonWidget; + +public class StringConfigurator extends ConfiguratorWidget{ + private String defaultValue = ""; + private TextFieldWidget textFieldWidget; + + public StringConfigurator(int x, int y, JsonObject config, String name) { + super(x, y, config, name, false); + init(); + textFieldWidget.setCurrentString(config.get(name).isJsonNull() ? defaultValue : config.get(name).getAsString()); + } + + public StringConfigurator(int x, int y, JsonObject config, String name, String defaultValue) { + super(x, y, config, name, true); + this.defaultValue = defaultValue; + init(); + textFieldWidget.setCurrentString(config.get(name).isJsonNull() ? defaultValue : config.get(name).getAsString()); + } + + private void init() { + this.addWidget(new RectButtonWidget(76, 11, 40, 20) + .setClickListener(data -> updateString()) + .setIcon(new TextTexture("Update"))); + textFieldWidget = new TextFieldWidget(0, 11, 76, 20, true, null, null) + .setValidator(s->true); + this.addWidget(textFieldWidget); + } + + private void updateString() { + config.addProperty(name, textFieldWidget.getCurrentString()); + update(); + } + + @Override + protected void onDefault() { + textFieldWidget.setCurrentString(defaultValue); + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/TextListConfigurator.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/TextListConfigurator.java new file mode 100644 index 00000000000..9645c440241 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/TextListConfigurator.java @@ -0,0 +1,54 @@ +package gregtech.api.terminal.gui.widgets.guide.congiurator; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import gregtech.api.gui.resources.ColorRectTexture; +import gregtech.api.terminal.gui.widgets.TextEditorWidget; + +import java.util.List; + +public class TextListConfigurator extends ConfiguratorWidget{ +// private TextEditorWidget textEditorWidget; + public TextListConfigurator(int x, int y, int height, JsonObject config, String name, boolean canDefault) { + super(x, y, config, name, canDefault); + JsonElement element = config.get(name); + if (element.isJsonNull()) { + init(height, ""); + } else { + List init = new Gson().fromJson(element, List.class); + StringBuilder s = new StringBuilder(); + for (int i = 0; i < init.size(); i++) { + s.append(init.get(i)); + if(i != init.size() - 1) { + s.append('\n'); + } + } + init(height, s.toString()); + } + } + +// public TextListConfigurator(int x, int y, int height, JsonObject config, String name, String defaultS) { +// super(x, y, config, name, false); +// StringBuilder s = new StringBuilder(); +// for (int i = 0; i < defaultS.size(); i++) { +// s.append(defaultS.get(i)); +// if(i != defaultS.size() - 1) { +// s.append('\n'); +// } +// } +// init(height, s.toString()); +// } + + private void init(int height, String init) { + this.addWidget(new TextEditorWidget(0, 11, 116, height, init, this::updateTextList).setBackground(new ColorRectTexture(-1))); + } + + private void updateTextList(String saved) { + JsonArray array = new JsonArray(); + array.add(saved); + config.add(name, array); + update(); + } +} diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_add.png b/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_add.png new file mode 100644 index 0000000000000000000000000000000000000000..dfaabb5e2c2f77b84aa60c6b7331f074505ac6b0 GIT binary patch literal 2273 zcmb_e3v3f*9KSI#$9Oo9Fd!Qo2Pz=fd$xByS0=QBb<#0Mb@M^wdiS-fYkTGH)^?K+ z#AS*&C37OrC4(%A;G)7nT?BaqjAM~8oDXCg$V>>3DFnyEfM2_=jyD>cdw$>Ve*fS9 z|NXx2>x#mHxx>@Ory&S3+@5DEg7@_3nVJHx6E9pB;cZAT?^z8&hCUQMlaO^A#v(|{ zPOq~>FLBHhB*kwKWyJ*y5q}V(5hOb&5)`E}prbC}@dhkdPs<(*^~x5k*ytb~K`SWr z=2fa-L1lqcsw|VtGL|zF&5j6=zz=j0jre^5O^8^q7_R`Iqs;_{#vpo`1)CKOh?Y1C zQLCZ?)Mzl_62;OeXEsnK(oC~6P@1GTg5(H_!AVLWO#)*^<39{WQ)RbMWSbL@1>Y=K zsjdeFf(VDhhA?ALR1ZO!&1Qn637W3r31(T}D9R zyvS0x#IqdkVr3pTag32+NY2c$rvC43ic}soK=k{*xgaYNJDBF?g`%mRi6 zG7tI_zg0LZ7~w(nd-mT8kC#L$6$2gs*H!}i@2T9MC;K$sl*+Bs@Bd1Lh%Tso-Xd82n1l2RJheNWL?{jAW7|Z+bkzv)A-KbK*tm5)q85r z^3^9-P5iu6Gk)eho$^N=z`}C^8A3ncjo~{p6qfh?*To4==sq2|cqS_4?*PU)e`@KhoT(j>=VRRiT!)r?$TP;OnROj8WB- zcK75I=bvc#?v+#gfyMLck}C>7qBBQiNr&5(4LhG(_QjW7`FnFSwXPmw;rHN^l5I&d zma&d$V^;ESN#mr|*z%$`rr1CBum7pDa~JDaS+J$9X{4>HcVmIWc8TlCnvh>RrS`qn zO~?_S>BZ2?mdnE0C4*8n28uUzbZouaP1|dO$6m5$9-3&Ahkf09T1S>#V-C3fDA$y? z+wvRJZ1Y2*rU@x~vwrCvS2HKOtLtF-iL~F_$4V&~8QtxX>}x0XIU1T*cWmGO^O&v) znJAX?+8TSAV~exs!sQo`ldVtIpX=G&oPvJ7+fZluc0=#glGV*u-dy`>D{`?iYZ*C= zOZukXgUo21J*{~}>i+cOJJ+_kBlU+iKj(iqqk2-9Gm!^Z;hpP}k;c(YXO2ETGiA+R z3o|awY^h24@zEXU5u~-d_OyOwP$X^JwngcK&zi>XN=AIgmtH*c*>7y>AY>`B{`7*MjtN;K2 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_delete.png b/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_delete.png new file mode 100644 index 0000000000000000000000000000000000000000..e5af7a69b06e9655b7dce5cebc0fe75b8da56ec7 GIT binary patch literal 1987 zcmb_dZD<@t7~Te2YfVJdqEscz2E@|N?auDrevz|HZqMel7ejKIG(~Z4clK_{-OjqZ zm%9W+Y}GVi17azn1(8M(e-u;{N(*B3pGu|pS*n&I_Ma_?h$zI_`!Y?_55;9aW@nyx z-{*bbXJ+O{hIjOA*tCIRn4avAIZD5`#LxP5^xgaG5~80Q{h?hU!`yUR{H$SKIdmt( ztoy*tPec>BorXm!31pK3PSh(tMKetQwz`k3DIBo{Ty(t@cj4HF9P8RCZakS2a()_@ z+@aY3kIfF}t=TC{x4CWiv;B308mQn1vGq#X3ype;YuGhtJMQK=wgHKzQrtl7ke$el zuxS!tHknX>1!a*{^#oJ|U6i-7q5xH1PUZSlB_E7*%diiI7lUm_6+OXLcsJHwYa zpsCH}IzCqAQmJ%Ygi&UihS5sMs^~C3<70jlhol-5XUXkfpB!k zAe+sk6{sr;5EHOLHMi&H5NcTzquA{Vo@9a&?^)i$13O=kY&XNxFG956EzVivSK+XDIrI(+SVQp zT)G@ldAZe?l}#+;;1Un^m1^eQT8x(SIB)lh&3iZplE&>(*$ z>LHrGI&lr@7-AIz=%@nF961SSF%hkVY|B^@v8~~D;FlAZjU>HcTeJV3cq=7V33)|K z_g0?!@1b0uCYu~rgmU@v`@cfr;|;Z`EqX*CUIdEj~Ai7666drH;(@_z4^~O)_ytn#fin<&$qsP^yksvQpbP%V`1Rf_VZ`HIq`ni z?mhb!7c%D;*Uo>|?cCej#hm@&_kHl3eo|iOd--UV`?~u5tuGxv_{PQ8UR?i3X47sn zZ%%&l=!NY!Sf^fn(>;Cm_AUK`+8Jio)EZ_lJfM~azTJPi`q;)v@9@&nPI7S`yztE4 R{LS$(o6QWHM+TqR^EcG+g&hC@ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_down.png b/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_down.png new file mode 100644 index 0000000000000000000000000000000000000000..99441b8e0b17caad32ce466214a4bb227350a699 GIT binary patch literal 1903 zcmb_dONbmr817YA)|H6F91<@!or8+jbX9jxzsMwRdS7@!-LW;NupAoFoRkC^-tjpx`ZN^}O6{HV?(7AJtV~{r~s> z_5D@vHyfu8EIzv^Nz#G(N_ACypDvz-dGUVkkH4_^Jdv!N$t3B?XNqS|`uLN>k~IHi z*jmrm{a0PWqY|dP%}RqP5ok#|c4ClVvcYn>%{pORQGWaC8$}LjMLAvep`UoH8?J1p zY;C*IBHJ6pp~{Kl^09#{3`8u)@*wKPnLDT`BfG9>7u~8Nk0AL*MOi8w%Ikhp_IS$V za>)b)8JcW4C1gTJGhUW8h%6OaD$)T&E;L=;ktdfTyrnd7SF6htU*fN#bn`rMRkh#m zm->2%ryUhJj-x_N)ifXwARERx9)LJII<-(`8A-z=4|yyX7IB+z<`qRS9fuGlGqZ6v zNs~yJI>3pFO0WoN1f*n!OE%Nq$T=k{>#>N%c_y%EhE2LW=UJEE$MkIYE(apDzCZJ^ zFPA8qxybU`mIz~#kbTivYnU)~m1TT0C9Jk3XdW%1Nn9^wIOl1L^WJo!np4WM=gBXe z4r9vu*^9g2tcr71Q8cI_04<=y7J_cscA@n1wXU1_pK@TEuK?M0b!w9CJFq%E@LS zfMWi*7APme#y|8N9oodO+ki3)1FRWsU}Itdi&_xc79=PjQ){oKp(sb(+ikUAMTJF6 z(~%8z9keObfz1pZIBlB&&Co2Wi`%xeLi8gYxhr8NR(Lomqc!%{q}2=Mk#t;4ijt@( zq|gGR%A`BoCm)aGc{0D>Wy0tKR5JFS@gVQxlr42c?jE8+^?uYdy!Bw>Hg*_d76T}- zpjbnr3>-r&f?*icV7kVr&8C6hOWbhF;zm=={(It+l#nitJ521Ys`B4Mc{ELqIqnJN z-tzmuLQ#tib*wFQuk1!+yEb33h@&pCqZiHDQ6he3hY^cKmQr!lT(u8eZ!| z{lT@hvy0!tg&)2kzuvj{;hoP8?fkfN9{lp&#dn)m9=r6^@`bnMcb@+`yY0>O&)xX0 zHvIGE>o=~?*{he242~aMs42fUUTIvFsu#{)_OH!<4{rZ-_@na&Z=FjX&%7%?-@3GX Qq&O1mwMO;xlW*?)4IT?w2mk;8 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_up.png b/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_up.png new file mode 100644 index 0000000000000000000000000000000000000000..7325b52ab4fcec7ccc50ea1172f07d38ff8c3fdd GIT binary patch literal 1899 zcmb_dONbmr814v$7+o;Lfbn9}0pB%U{q8O@F1ypa*+FNsOa`(d!d6#R&on#T)pqyp z%r2tfMS|oYIVqkz{5IihvtwAF&Gw847O(sss9 zZ7+Ao_B!#XGW)cAe29dBm=#za#{DEm!@4rEi$uHZRuy>!Dc0-CTe{teV{MD6SQKU#!2ZKRv zVAOclRW;A^RH&=E4g><^TS2yt4OP4Y>a zM8eb|PF1Z2%aBGuN-A8sk@ZK;DN$LU#Vjdufz>K(+T#V!d;BJ*tKsV$h}5=Pm5)8S z#Bt>!FBUdM7?XtTiOxG)DO1}l=NlPe3!8%Gu`-$zH8O?^o^?3yPZw%sN?C3+Wyg zTQDUkx6f9P2(ux(=Kz_hUk9K+NB4u}p&Xjq}kEUGybo0C~2$`SW>S}j>oVbReI z&4q>m0tyY_GSdKF;4+|_x3~vH1HdVo5&J(rP+T^e3BB6z&Gxw2SW*0yD`R+dtSs!0I_x=NGQZbL(7w+pE@y)Yey?*G2M_)U9`PVDw zzr8Cx>BCRITfFqbx%1z@NiSYrf9BdxKOP Date: Tue, 3 Aug 2021 14:35:20 +0800 Subject: [PATCH 11/58] bool, color, common selectors --- src/main/java/gregtech/api/gui/Widget.java | 90 +++++- .../api/gui/resources/RenderUtil.java | 109 -------- .../api/gui/widgets/AbstractWidgetGroup.java | 5 +- .../gregtech/api/gui/widgets/ImageWidget.java | 5 +- .../gregtech/api/gui/widgets/LabelWidget.java | 11 +- .../api/gui/widgets/TextFieldWidget.java | 74 ++++- .../gui/widgets/CircleButtonWidget.java | 7 +- .../api/terminal/gui/widgets/ColorWidget.java | 262 ++++++++++++++++++ .../DraggableScrollableWidgetGroup.java | 5 +- .../gui/widgets/RectButtonWidget.java | 91 +++++- .../terminal/gui/widgets/SelectorWidget.java | 118 ++++++++ .../widgets/guide/GuidePageEditorWidget.java | 6 +- .../gui/widgets/guide/GuideWidget.java | 11 +- .../gui/widgets/guide/ImageWidget.java | 10 +- .../gui/widgets/guide/TextBoxWidget.java | 10 +- .../gui/widgets/guide/TextTreeWidget.java | 6 +- .../configurator/BooleanConfigurator.java | 43 +++ .../guide/configurator/ColorConfigurator.java | 34 +++ .../ConfiguratorWidget.java | 28 +- .../NumberConfigurator.java | 38 ++- .../configurator/SelectorConfigurator.java | 49 ++++ .../StringConfigurator.java | 17 +- .../TextListConfigurator.java | 18 +- 23 files changed, 855 insertions(+), 192 deletions(-) create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/ColorWidget.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/SelectorWidget.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/BooleanConfigurator.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ColorConfigurator.java rename src/main/java/gregtech/api/terminal/gui/widgets/guide/{congiurator => configurator}/ConfiguratorWidget.java (74%) rename src/main/java/gregtech/api/terminal/gui/widgets/guide/{congiurator => configurator}/NumberConfigurator.java (53%) create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/SelectorConfigurator.java rename src/main/java/gregtech/api/terminal/gui/widgets/guide/{congiurator => configurator}/StringConfigurator.java (67%) rename src/main/java/gregtech/api/terminal/gui/widgets/guide/{congiurator => configurator}/TextListConfigurator.java (63%) diff --git a/src/main/java/gregtech/api/gui/Widget.java b/src/main/java/gregtech/api/gui/Widget.java index 0e56ab4e111..aecde19dcbf 100644 --- a/src/main/java/gregtech/api/gui/Widget.java +++ b/src/main/java/gregtech/api/gui/Widget.java @@ -1,6 +1,7 @@ package gregtech.api.gui; import com.google.common.base.Preconditions; +import gregtech.api.gui.resources.RenderUtil; import gregtech.api.gui.widgets.WidgetUIAccess; import gregtech.api.util.Position; import gregtech.api.util.Size; @@ -8,10 +9,8 @@ import net.minecraft.client.audio.PositionedSoundRecord; import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.gui.Gui; -import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.client.renderer.OpenGlHelper; -import net.minecraft.client.renderer.RenderHelper; -import net.minecraft.client.renderer.RenderItem; +import net.minecraft.client.renderer.*; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.client.util.ITooltipFlag; import net.minecraft.init.SoundEvents; import net.minecraft.item.ItemStack; @@ -29,6 +28,7 @@ import java.util.List; import java.util.function.Consumer; import java.util.function.Supplier; +import org.lwjgl.opengl.GL11; /** * Widget is functional element of ModularUI @@ -365,8 +365,88 @@ protected static void drawSolidRect(int x, int y, int width, int height, int col @SideOnly(Side.CLIENT) protected static void drawGradientRect(int x, int y, int width, int height, int startColor, int endColor) { - GuiUtils.drawGradientRect(0, x, y, x + width, y + height, startColor, endColor); + drawGradientRect(x, y, width, height, startColor, endColor, false); + } + + @SideOnly(Side.CLIENT) + public static void drawGradientRect(float x, float y, float width, float height, int startColor, int endColor, boolean horizontal) { + float startAlpha = (float) (startColor >> 24 & 255) / 255.0F; + float startRed = (float) (startColor >> 16 & 255) / 255.0F; + float startGreen = (float) (startColor >> 8 & 255) / 255.0F; + float startBlue = (float) (startColor & 255) / 255.0F; + float endAlpha = (float) (endColor >> 24 & 255) / 255.0F; + float endRed = (float) (endColor >> 16 & 255) / 255.0F; + float endGreen = (float) (endColor >> 8 & 255) / 255.0F; + float endBlue = (float) (endColor & 255) / 255.0F; + GlStateManager.disableTexture2D(); GlStateManager.enableBlend(); + GlStateManager.disableAlpha(); + GlStateManager.tryBlendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO); + GlStateManager.shadeModel(GL11.GL_SMOOTH); + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder buffer = tessellator.getBuffer(); + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR); + if (horizontal) { + buffer.pos(x + width, y, 0).color(endRed, endGreen, endBlue, endAlpha).endVertex(); + buffer.pos(x, y, 0).color(startRed, startGreen, startBlue, startAlpha).endVertex(); + buffer.pos(x, y + height, 0).color(startRed, startGreen, startBlue, startAlpha).endVertex(); + buffer.pos(x + width, y + height, 0).color(endRed, endGreen, endBlue, endAlpha).endVertex(); + tessellator.draw(); + } else { + buffer.pos(x + width, y, 0).color(startRed, startGreen, startBlue, startAlpha).endVertex(); + buffer.pos(x, y, 0).color(startRed, startGreen, startBlue, startAlpha).endVertex(); + buffer.pos(x, y + height, 0).color(endRed, endGreen, endBlue, endAlpha).endVertex(); + buffer.pos(x + width, y + height, 0).color(endRed, endGreen, endBlue, endAlpha).endVertex(); + tessellator.draw(); + } + GlStateManager.shadeModel(GL11.GL_FLAT); + GlStateManager.enableAlpha(); + GlStateManager.enableTexture2D(); + } + + @SideOnly(Side.CLIENT) + public static void setColor(int color) { // ARGB + GlStateManager.color((color >> 16 & 255) / 255.0F, + (color >> 8 & 255) / 255.0F, + (color & 255) / 255.0F, + (color >> 24 & 255) / 255.0F); + } + + @SideOnly(Side.CLIENT) + public static void renderCircle(float x, float y, float r, int color, int segments) { + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder bufferbuilder = tessellator.getBuffer(); + GlStateManager.enableBlend(); + GlStateManager.disableTexture2D(); + GlStateManager.tryBlendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO); + setColor(color); + bufferbuilder.begin(GL11.GL_POLYGON, DefaultVertexFormats.POSITION); + for (int i = 0; i < segments; i++) { + bufferbuilder.pos(x + r * Math.cos(-2 * Math.PI * i / segments), y + r * Math.sin(-2 * Math.PI * i / segments), 0.0D).endVertex(); + } + tessellator.draw(); + GlStateManager.enableTexture2D(); + GlStateManager.color(1,1,1,1); + } + + @SideOnly(Side.CLIENT) + public static void renderSector(float x, float y, float r, int color, int segments, int from, int to) { + if (from > to || from < 0) return; + if(to > segments) to = segments; + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder bufferbuilder = tessellator.getBuffer(); + GlStateManager.enableBlend(); + GlStateManager.disableTexture2D(); + GlStateManager.tryBlendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO); + setColor(color); + bufferbuilder.begin(GL11.GL_TRIANGLES, DefaultVertexFormats.POSITION); + for (int i = from; i < to; i++) { + bufferbuilder.pos(x + r * Math.cos(-2 * Math.PI * i / segments), y + r * Math.sin(-2 * Math.PI * i / segments), 0.0D).endVertex(); + bufferbuilder.pos(x + r * Math.cos(-2 * Math.PI * (i + 1) / segments), y + r * Math.sin(-2 * Math.PI * (i + 1) / segments), 0.0D).endVertex(); + bufferbuilder.pos(x, y, 0.0D).endVertex(); + } + tessellator.draw(); + GlStateManager.enableTexture2D(); } @SideOnly(Side.CLIENT) diff --git a/src/main/java/gregtech/api/gui/resources/RenderUtil.java b/src/main/java/gregtech/api/gui/resources/RenderUtil.java index f5033a12b73..63960272bdc 100644 --- a/src/main/java/gregtech/api/gui/resources/RenderUtil.java +++ b/src/main/java/gregtech/api/gui/resources/RenderUtil.java @@ -107,113 +107,4 @@ private static void drawFluidTexture(double xCoord, double yCoord, TextureAtlasS buffer.pos(xCoord, yCoord + maskTop, zLevel).tex(uMin, vMin).endVertex(); tessellator.draw(); } - - public static void renderItemOverLay(float x, float y, float z, float scale, ItemStack itemStack) { - net.minecraft.client.renderer.RenderHelper.enableStandardItemLighting(); - GlStateManager.pushMatrix(); - GlStateManager.scale(scale, scale, 0.0001f); - GlStateManager.translate(x * 16, y * 16, z * 16); - RenderItem renderItem = Minecraft.getMinecraft().getRenderItem(); - renderItem.renderItemAndEffectIntoGUI(itemStack, 0, 0 ); - GlStateManager.popMatrix(); - net.minecraft.client.renderer.RenderHelper.disableStandardItemLighting(); - } - - public static void setColor(int color) { // ARGB - GlStateManager.color((color >> 16 & 255) / 255.0F, - (color >> 8 & 255) / 255.0F, - (color & 255) / 255.0F, - (color >> 24 & 255) / 255.0F); - } - - public static void renderCircle(float x, float y, float r, int color, int segments) { - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder bufferbuilder = tessellator.getBuffer(); - GlStateManager.enableBlend(); - GlStateManager.disableTexture2D(); - GlStateManager.tryBlendFuncSeparate(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ZERO); - setColor(color); - bufferbuilder.begin(GL11.GL_POLYGON, DefaultVertexFormats.POSITION); - for (int i = 0; i < segments; i++) { - bufferbuilder.pos(x + r * Math.cos(-2 * Math.PI * i / segments), y + r * Math.sin(-2 * Math.PI * i / segments), 0.0D).endVertex(); - } - tessellator.draw(); - GlStateManager.enableTexture2D(); - GlStateManager.color(1,1,1,1); - } - - public static void renderSector(float x, float y, float r, int color, int segments, int from, int to) { - if (from > to || from < 0) return; - if(to > segments) to = segments; - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder bufferbuilder = tessellator.getBuffer(); - GlStateManager.enableBlend(); - GlStateManager.disableTexture2D(); - GlStateManager.tryBlendFuncSeparate(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ZERO); - setColor(color); - bufferbuilder.begin(GL11.GL_TRIANGLES, DefaultVertexFormats.POSITION); - for (int i = from; i < to; i++) { - bufferbuilder.pos(x + r * Math.cos(-2 * Math.PI * i / segments), y + r * Math.sin(-2 * Math.PI * i / segments), 0.0D).endVertex(); - bufferbuilder.pos(x + r * Math.cos(-2 * Math.PI * (i + 1) / segments), y + r * Math.sin(-2 * Math.PI * (i + 1) / segments), 0.0D).endVertex(); - bufferbuilder.pos(x, y, 0.0D).endVertex(); - } - tessellator.draw(); - GlStateManager.enableTexture2D(); - } - - public static void renderRect(float x, float y, float width, float height, float z, int color) { - renderGradientRect(x, y, width, height, z, color, color, false); - } - - public static void renderGradientRect(float x, float y, float width, float height, float z, int startColor, int endColor, boolean horizontal) { - float startAlpha = (float) (startColor >> 24 & 255) / 255.0F; - float startRed = (float) (startColor >> 16 & 255) / 255.0F; - float startGreen = (float) (startColor >> 8 & 255) / 255.0F; - float startBlue = (float) (startColor & 255) / 255.0F; - float endAlpha = (float) (endColor >> 24 & 255) / 255.0F; - float endRed = (float) (endColor >> 16 & 255) / 255.0F; - float endGreen = (float) (endColor >> 8 & 255) / 255.0F; - float endBlue = (float) (endColor & 255) / 255.0F; - GlStateManager.disableTexture2D(); - GlStateManager.enableBlend(); - GlStateManager.disableAlpha(); - GlStateManager.tryBlendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO); - GlStateManager.shadeModel(GL11.GL_SMOOTH); - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder buffer = tessellator.getBuffer(); - buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR); - if (horizontal) { - buffer.pos(x + width, y, z).color(endRed, endGreen, endBlue, endAlpha).endVertex(); - buffer.pos(x, y, z).color(startRed, startGreen, startBlue, startAlpha).endVertex(); - buffer.pos(x, y + height, z).color(startRed, startGreen, startBlue, startAlpha).endVertex(); - buffer.pos(x + width, y + height, z).color(endRed, endGreen, endBlue, endAlpha).endVertex(); - tessellator.draw(); - } else { - buffer.pos(x + width, y, z).color(startRed, startGreen, startBlue, startAlpha).endVertex(); - buffer.pos(x, y, z).color(startRed, startGreen, startBlue, startAlpha).endVertex(); - buffer.pos(x, y + height, z).color(endRed, endGreen, endBlue, endAlpha).endVertex(); - buffer.pos(x + width, y + height, z).color(endRed, endGreen, endBlue, endAlpha).endVertex(); - tessellator.draw(); - } - GlStateManager.shadeModel(GL11.GL_FLAT); - GlStateManager.disableBlend(); - GlStateManager.enableAlpha(); - GlStateManager.enableTexture2D(); - } - - public static void renderTextureArea(TextureArea textureArea, float x, float y, float width, float height, float z) { - double imageU = textureArea.offsetX; - double imageV = textureArea.offsetY; - double imageWidth = textureArea.imageWidth; - double imageHeight = textureArea.imageHeight; - Minecraft.getMinecraft().renderEngine.bindTexture(textureArea.imageLocation); - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder bufferbuilder = tessellator.getBuffer(); - bufferbuilder.begin(7, DefaultVertexFormats.POSITION_TEX); - bufferbuilder.pos(x, y + height, z).tex(imageU, imageV + imageHeight).endVertex(); - bufferbuilder.pos(x + width, y + height, z).tex(imageU + imageWidth, imageV + imageHeight).endVertex(); - bufferbuilder.pos(x + width, y, z).tex(imageU + imageWidth, imageV).endVertex(); - bufferbuilder.pos(x, y, z).tex(imageU, imageV).endVertex(); - tessellator.draw(); - } } diff --git a/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java b/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java index 25f85dab8a1..1c7042b01c7 100644 --- a/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java +++ b/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java @@ -286,8 +286,9 @@ public boolean mouseReleased(int mouseX, int mouseY, int button) { @Override public boolean keyTyped(char charTyped, int keyCode) { - for (Widget widget : widgets) { - if(widget.keyTyped(charTyped, keyCode)) { + for (int i = widgets.size() - 1; i >= 0; i--) { + Widget widget = widgets.get(i); + if(widget.isVisible() && widget.keyTyped(charTyped, keyCode)) { return true; } } diff --git a/src/main/java/gregtech/api/gui/widgets/ImageWidget.java b/src/main/java/gregtech/api/gui/widgets/ImageWidget.java index 7f1cb903702..c6f5af688b9 100644 --- a/src/main/java/gregtech/api/gui/widgets/ImageWidget.java +++ b/src/main/java/gregtech/api/gui/widgets/ImageWidget.java @@ -2,6 +2,7 @@ import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.resources.TextureArea; import gregtech.api.util.Position; import gregtech.api.util.Size; @@ -16,7 +17,7 @@ public class ImageWidget extends Widget { - protected TextureArea area; + protected IGuiTexture area; private BooleanSupplier predicate; private boolean isVisible = true; @@ -25,7 +26,7 @@ public ImageWidget(int xPosition, int yPosition, int width, int height) { super(new Position(xPosition, yPosition), new Size(width, height)); } - public ImageWidget(int xPosition, int yPosition, int width, int height, TextureArea area) { + public ImageWidget(int xPosition, int yPosition, int width, int height, IGuiTexture area) { this(xPosition, yPosition, width, height); this.area = area; } diff --git a/src/main/java/gregtech/api/gui/widgets/LabelWidget.java b/src/main/java/gregtech/api/gui/widgets/LabelWidget.java index 520f33a9240..dc582bba3d2 100644 --- a/src/main/java/gregtech/api/gui/widgets/LabelWidget.java +++ b/src/main/java/gregtech/api/gui/widgets/LabelWidget.java @@ -21,6 +21,7 @@ public class LabelWidget extends Widget { protected String text; protected Object[] formatting; private int color; + private boolean dropShadow; public LabelWidget(int xPosition, int yPosition, String text, Object... formatting) { this(xPosition, yPosition, text, 0x404040, formatting); @@ -38,6 +39,11 @@ public LabelWidget(int xPosition, int yPosition, String text, int color, Object[ recomputeSize(); } + public LabelWidget setShadow(boolean dropShadow){ + this.dropShadow = dropShadow; + return this; + } + private String getResultText() { return I18n.format(text, formatting); } @@ -65,10 +71,9 @@ public void drawInBackground(int mouseX, int mouseY, IRenderContext context) { FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer; Position pos = getPosition(); if (!xCentered) { - fontRenderer.drawString(resultText, pos.x, pos.y, color); + fontRenderer.drawString(resultText, pos.x, pos.y, color, dropShadow); } else { - fontRenderer.drawString(resultText, - pos.x - fontRenderer.getStringWidth(resultText) / 2, pos.y, color); + fontRenderer.drawString(resultText, pos.x - fontRenderer.getStringWidth(resultText) / 2.0f, pos.y, color, dropShadow); } GlStateManager.color(rColorForOverlay, gColorForOverlay, bColorForOverlay, 1.0F); } diff --git a/src/main/java/gregtech/api/gui/widgets/TextFieldWidget.java b/src/main/java/gregtech/api/gui/widgets/TextFieldWidget.java index 1cad2d7abc2..68aff5b092c 100644 --- a/src/main/java/gregtech/api/gui/widgets/TextFieldWidget.java +++ b/src/main/java/gregtech/api/gui/widgets/TextFieldWidget.java @@ -2,6 +2,7 @@ import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.util.MCGuiUtil; import gregtech.api.util.Position; import gregtech.api.util.Size; @@ -23,15 +24,23 @@ public class TextFieldWidget extends Widget { protected int maxStringLength = 32; protected Predicate textValidator; - protected final Supplier textSupplier; - protected final Consumer textResponder; + protected Supplier textSupplier; + protected Consumer textResponder; protected String currentString; + private IGuiTexture background; + private boolean enableBackground; + private boolean isClient; public TextFieldWidget(int xPosition, int yPosition, int width, int height, boolean enableBackground, Supplier textSupplier, Consumer textResponder) { super(new Position(xPosition, yPosition), new Size(width, height)); if (isClientSide()) { + this.enableBackground = enableBackground; FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer; - this.textField = new GuiTextField(0, fontRenderer, xPosition, yPosition, width, height); + if (enableBackground) { + this.textField = new GuiTextField(0, fontRenderer, xPosition, yPosition, width, height); + } else { + this.textField = new GuiTextField(0, fontRenderer, xPosition + 1, yPosition + (height - fontRenderer.FONT_HEIGHT) / 2 + 1, width - 2, height); + } this.textField.setCanLoseFocus(true); this.textField.setEnableBackgroundDrawing(enableBackground); this.textField.setMaxStringLength(maxStringLength); @@ -41,6 +50,34 @@ public TextFieldWidget(int xPosition, int yPosition, int width, int height, bool this.textResponder = textResponder; } + public TextFieldWidget(int xPosition, int yPosition, int width, int height, IGuiTexture background, Supplier textSupplier, Consumer textResponder) { + super(new Position(xPosition, yPosition), new Size(width, height)); + if (isClientSide()) { + this.enableBackground = false; + FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer; + this.textField = new GuiTextField(0, fontRenderer, xPosition + 1, yPosition + (height - fontRenderer.FONT_HEIGHT) / 2 + 1, width - 2, height); + this.textField.setCanLoseFocus(true); + this.textField.setEnableBackgroundDrawing(false); + this.textField.setMaxStringLength(maxStringLength); + this.textField.setGuiResponder(MCGuiUtil.createTextFieldResponder(this::onTextChanged)); + } + this.background = background; + this.textSupplier = textSupplier; + this.textResponder = textResponder; + } + + public TextFieldWidget setTextSupplier(Supplier textSupplier, boolean isClient) { + this.isClient = isClient; + this.textSupplier = textSupplier; + return this; + } + + public TextFieldWidget setTextResponder(Consumer textResponder, boolean isClient) { + this.isClient = isClient; + this.textResponder = textResponder; + return this; + } + public void setCurrentString(String currentString) { this.currentString = currentString; this.textField.setText(currentString); @@ -53,26 +90,37 @@ public String getCurrentString() { @Override protected void onPositionUpdate() { if (isClientSide() && textField != null) { + FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer; Position position = getPosition(); + Size size = getSize(); GuiTextField textField = this.textField; - textField.x = position.x; - textField.y = position.y; + textField.x = enableBackground ? position.x : position.x + 1; + textField.y = enableBackground ? position.y : position.y + (size.height - fontRenderer.FONT_HEIGHT) / 2 + 1; } } @Override protected void onSizeUpdate() { if (isClientSide() && textField != null) { + FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer; + Position position = getPosition(); Size size = getSize(); GuiTextField textField = this.textField; - textField.width = size.width; + textField.width = enableBackground ? size.width : size.width - 2; textField.height = size.height; + textField.y = enableBackground ? position.y : position.y + (getSize().height - fontRenderer.FONT_HEIGHT) / 2 + 1; + } } @Override public void drawInBackground(int mouseX, int mouseY, IRenderContext context) { super.drawInBackground(mouseX, mouseY, context); + if (background != null) { + Position position = getPosition(); + Size size = getSize(); + background.draw(position.x, position.y, size.width, size.height); + } this.textField.drawTextBox(); } @@ -86,6 +134,14 @@ public boolean keyTyped(char charTyped, int keyCode) { return this.textField.textboxKeyTyped(charTyped, keyCode); } + @Override + public void updateScreen() { + if (textSupplier != null && isClient) { + this.currentString = textSupplier.get(); + this.textField.setText(currentString); + } + } + @Override public void detectAndSendChanges() { super.detectAndSendChanges(); @@ -106,7 +162,11 @@ public void readUpdateInfo(int id, PacketBuffer buffer) { protected void onTextChanged(String newTextString) { if (textValidator.test(newTextString)) { - writeClientAction(1, buffer -> buffer.writeString(newTextString)); + if (isClient && textResponder != null) { + textResponder.accept(newTextString); + } else { + writeClientAction(1, buffer -> buffer.writeString(newTextString)); + } } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java index 47c89d0f085..4b84b6707ab 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java @@ -15,6 +15,7 @@ import java.awt.*; import java.util.Collections; import java.util.function.Consumer; +import java.util.function.Supplier; public class CircleButtonWidget extends Widget { protected int border; @@ -97,12 +98,12 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender int y = this.getPosition().y + r; int segments = 24; - RenderUtil.renderCircle(x, y, r, colors[0], segments); + renderCircle(x, y, r, colors[0], segments); isHover = this.isMouseOverElement(mouseX, mouseY); if (isHover || hoverTick != 0) { - RenderUtil.renderSector(x, y, r, colors[1], segments, 0, (int) (segments * ((hoverTick + partialTicks) / 8))); + renderSector(x, y, r, colors[1], segments, 0, (int) (segments * ((hoverTick + partialTicks) / 8))); } - RenderUtil.renderCircle(x, y, r - border, colors[2], segments); + renderCircle(x, y, r - border, colors[2], segments); if (icon != null) { icon.draw(x - iconSize / 2f, y - iconSize / 2f, iconSize, iconSize); } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/ColorWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/ColorWidget.java new file mode 100644 index 00000000000..2f9580e405a --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/ColorWidget.java @@ -0,0 +1,262 @@ +package gregtech.api.terminal.gui.widgets; + +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.ColorRectTexture; +import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.widgets.TextFieldWidget; +import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.util.Position; +import gregtech.api.util.Size; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.math.MathHelper; + +import java.util.function.Consumer; +import java.util.function.Supplier; + +public class ColorWidget extends WidgetGroup { + private int red = 255; + private int green = 255; + private int blue = 255; + private int alpha = 255; + private Consumer onColorChanged; + private final int barWidth; + private final int barHeight; + private final CircleButtonWidget redButton; + private final CircleButtonWidget greenButton; + private final CircleButtonWidget blueButton; + private final CircleButtonWidget alphaButton; + private int lastMouseX; + private CircleButtonWidget dragged; + private Supplier colorSupplier; + private boolean isClient; + + public ColorWidget(int x, int y, int barWidth, int barHeight){ + super(new Position(x, y), new Size(barWidth + 35, 3 * (barHeight + 5) + 10)); + this.barWidth = barWidth; + this.barHeight= barHeight; + IGuiTexture textFieldBackground = new ColorRectTexture(0x9f000000); + TextFieldWidget redField = new TextFieldWidget(barWidth + 5, 0, 30, barHeight, textFieldBackground, null, null) + .setTextResponder((t) -> setRed(t.isEmpty()? 0 : Integer.parseInt(t)), true) + .setTextSupplier(() -> Integer.toString(red), true) + .setValidator(this::checkValid); + TextFieldWidget greenField = new TextFieldWidget(barWidth + 5, barHeight + 5, 30, barHeight, textFieldBackground, null, null) + .setTextResponder((t) -> setGreen(t.isEmpty()? 0 : Integer.parseInt(t)), true) + .setTextSupplier(() -> Integer.toString(green), true) + .setValidator(this::checkValid); + TextFieldWidget blueField = new TextFieldWidget(barWidth + 5, (barHeight + 5) * 2, 30, barHeight, textFieldBackground, null, null) + .setTextResponder((t) -> setBlue(t.isEmpty()? 0 : Integer.parseInt(t)), true) + .setTextSupplier(() -> Integer.toString(blue), true) + .setValidator(this::checkValid); + TextFieldWidget alphaField = new TextFieldWidget(barWidth + 5, (barHeight + 5) * 3, 30, barHeight, textFieldBackground, null, null) + .setTextResponder((t) -> setAlpha(t.isEmpty()? 0 : Integer.parseInt(t)), true) + .setTextSupplier(() -> Integer.toString(alpha), true) + .setValidator(this::checkValid); + this.addWidget(redField); + this.addWidget(greenField); + this.addWidget(blueField); + this.addWidget(alphaField); + redButton = new CircleButtonWidget(barWidth, barHeight / 2, 4, 1, 0).setFill(0xffff0000).setStrokeAnima(-1); + greenButton = new CircleButtonWidget(barWidth, barHeight / 2 + barHeight + 5, 4, 1, 0).setFill(0xff00ff00).setStrokeAnima(-1); + blueButton = new CircleButtonWidget(barWidth, barHeight / 2 + 2 * (barHeight + 5), 4, 1, 0).setFill(0xff0000ff).setStrokeAnima(-1); + alphaButton = new CircleButtonWidget(barWidth, barHeight / 2 + 3 * (barHeight + 5), 4, 1, 0).setFill(-1).setStrokeAnima(-1); + this.addWidget(redButton); + this.addWidget(greenButton); + this.addWidget(blueButton); + this.addWidget(alphaButton); + } + + public ColorWidget setOnColorChanged(Consumer onColorChanged) { + this.onColorChanged = onColorChanged; + return this; + } + + public ColorWidget setColorSupplier(Supplier colorSupplier, boolean isClient) { + this.colorSupplier = colorSupplier; + this.isClient = isClient; + return this; + } + + @Override + public void detectAndSendChanges() { + super.detectAndSendChanges(); + if (!isClient && colorSupplier!= null) { + int c = colorSupplier.get(); + int r = (c & 0x00ff0000) >> 16; + int g = (c & 0x0000ff00) >> 8; + int b = (c & 0x000000ff); + int a = (c & 0xff000000) >> 24; + if (r != red || g != green || b != blue || a ==alpha) { + setRed(r); + setGreen(g); + setBlue(b); + setAlpha(a); + writeUpdateInfo(2, buffer -> buffer.writeInt(c)); + } + } + } + + @Override + public void updateScreen() { + super.updateScreen(); + if (isClient && colorSupplier!= null) { + int c = colorSupplier.get(); + int r = (c & 0x00ff0000) >> 16; + int g = (c & 0x0000ff00) >> 8; + int b = (c & 0x000000ff); + int a = (c & 0xff000000) >> 24; + if (r != red || g != green || b != blue || a ==alpha) { + setRed(r); + setGreen(g); + setBlue(b); + setAlpha(a); + writeClientAction(2, buffer -> buffer.writeInt(c)); + } + } + } + + @Override + public void readUpdateInfo(int id, PacketBuffer buffer) { + handleColor(id, buffer); + } + + private void handleColor(int id, PacketBuffer buffer) { + if (id == 2) { + int c = buffer.readInt(); + int r = (c & 0x00ff0000) >> 16; + int g = (c & 0x0000ff00) >> 8; + int b = (c & 0x000000ff); + int a = (c & 0xff000000) >> 24; + if (r != red || g != green || b != blue || a ==alpha) { + setRed(r); + setGreen(g); + setBlue(b); + setAlpha(a); + } + } + } + + @Override + public void handleClientAction(int id, PacketBuffer buffer) { + handleColor(id, buffer); + } + + private void setRed(int red) { + if (this.red != red) { + this.red = red; + redButton.setSelfPosition(new Position(red * barWidth / 255 - 4, redButton.getSelfPosition().y)); + if (onColorChanged != null) { + onColorChanged.accept((alpha << 24) | (red << 16) | (green << 8) | (blue)); + } + } + } + + private void setGreen(int green) { + if (this.green != green) { + this.green = green; + greenButton.setSelfPosition(new Position(green * barWidth / 255 - 4, greenButton.getSelfPosition().y)); + if (onColorChanged != null) { + onColorChanged.accept((alpha << 24) | (red << 16) | (green << 8) | (blue)); + } + } + } + + private void setBlue(int blue) { + if (this.blue != blue) { + this.blue = blue; + blueButton.setSelfPosition(new Position(blue * barWidth / 255 - 4, blueButton.getSelfPosition().y)); + if (onColorChanged != null) { + onColorChanged.accept((alpha << 24) | (red << 16) | (green << 8) | (blue)); + } + } + } + + private void setAlpha(int alpha) { + if (this.alpha != alpha) { + this.alpha = alpha; + alphaButton.setSelfPosition(new Position(alpha * barWidth / 255 - 4, alphaButton.getSelfPosition().y)); + if (onColorChanged != null) { + onColorChanged.accept((alpha << 24) | (red << 16) | (green << 8) | (blue)); + } + } + } + + private boolean checkValid(String input) { + if (input.length() > 3) return false; + if (input.isEmpty()) return true; + try { + int value = Integer.parseInt(input); + if(value >= 0 && value <= 255) { + return true; + } + } catch (Exception e) { + return false; + } + return false; + } + + @Override + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + int x = getPosition().x; + int y = getPosition().y; + drawGradientRect(x, y + 2, barWidth, 5, 0xFF000000, 0xFFFF0000, true); + drawGradientRect(x, y + barHeight + 5 + 2, barWidth, 5, 0xFF000000, 0xFF00ff00, true); + drawGradientRect(x, y + 2 * (barHeight + 5) + 2, barWidth, 5, 0xFF000000, 0xFF0000ff, true); + drawGradientRect(x, y + 3 * (barHeight + 5) + 2, barWidth, 5, (0) | (red << 16) | (green << 8) | (blue), (255 << 24) | (red << 16) | (green << 8) | (blue), true); + super.drawInBackground(mouseX, mouseY, partialTicks, context); + } + + @Override + public boolean mouseClicked(int mouseX, int mouseY, int button) { + lastMouseX = mouseX; + dragged = null; + if (redButton.isMouseOverElement(mouseX, mouseY)) { + dragged = redButton; + return true; + } else if (greenButton.isMouseOverElement(mouseX, mouseY)) { + dragged = greenButton; + return true; + } else if (blueButton.isMouseOverElement(mouseX, mouseY)) { + dragged = blueButton; + return true; + } else if (alphaButton.isMouseOverElement(mouseX, mouseY)) { + dragged = alphaButton; + return true; + } + boolean flag = false; + for (int i = widgets.size() - 1; i >= 0; i--) { + Widget widget = widgets.get(i); + if(widget.isVisible() && widget.mouseClicked(mouseX, mouseY, button)) { + flag = true; + } + } + return flag; + } + + @Override + public boolean mouseDragged(int mouseX, int mouseY, int button, long timeDragged) { + int xDelta = mouseX - lastMouseX; + lastMouseX = mouseX; + if (dragged != null) { + int newX = MathHelper.clamp(dragged.getSelfPosition().x + 4 + xDelta, 0, barWidth); + if (dragged == redButton) { + setRed(newX * 255 / barWidth); + } else if (dragged == greenButton) { + setGreen(newX * 255 / barWidth); + } else if (dragged == blueButton) { + setBlue(newX * 255 / barWidth); + } else if (dragged == alphaButton) { + setAlpha(newX * 255 / barWidth); + } + dragged.setSelfPosition(new Position(newX - 4, dragged.getSelfPosition().y)); + return true; + } + return super.mouseDragged(mouseX, mouseY, button, timeDragged); + } + + @Override + public boolean mouseReleased(int mouseX, int mouseY, int button) { + dragged = null; + return super.mouseReleased(mouseX, mouseY, button); + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java b/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java index eb45dd3d8c0..ec0c752e39d 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java @@ -96,7 +96,10 @@ public void removeWidget(Widget widget) { @Override public void clearAllWidgets() { super.clearAllWidgets(); - computeMax(); + maxHeight = getSize().height; + maxWidth = getSize().width; + scrollXOffset = 0; + scrollYOffset = 0; } @Override diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/RectButtonWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/RectButtonWidget.java index b20460798a3..a4060c2986e 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/RectButtonWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/RectButtonWidget.java @@ -1,10 +1,23 @@ package gregtech.api.terminal.gui.widgets; import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.util.Position; import gregtech.api.util.Size; +import net.minecraft.network.PacketBuffer; +import org.lwjgl.input.Mouse; + +import java.util.function.BiConsumer; +import java.util.function.Supplier; public class RectButtonWidget extends CircleButtonWidget{ + private IGuiTexture pressedIcon; + private BiConsumer onPressed; + private boolean isPressed; + private Supplier supplier; + private boolean isClient; + + public RectButtonWidget(int x, int y, int width, int height) { this(x, y, width, height,2); } @@ -16,6 +29,78 @@ public RectButtonWidget(int x, int y, int width, int height, int border) { this.border = border; } + public RectButtonWidget setToggleButton(IGuiTexture pressedIcon, BiConsumer onPressed) { + this.pressedIcon = pressedIcon; + this.onPressed = onPressed; + return this; + } + + public RectButtonWidget setValueSupplier(boolean isClient, Supplier supplier) { + this.isClient = isClient; + this.supplier = supplier; + return this; + } + + @Override + public void updateScreen() { + super.updateScreen(); + if (isClient && supplier != null) { + isPressed = supplier.get(); + } + } + + @Override + public void detectAndSendChanges() { + if (!isClient && supplier != null) { + if(supplier.get() != isPressed) { + isPressed = !isPressed; + writeUpdateInfo(1, buffer -> buffer.writeBoolean(isPressed)); + } + } + } + + @Override + public void readUpdateInfo(int id, PacketBuffer buffer) { + if (id == 1) { + isPressed = buffer.readBoolean(); + } + } + + @Override + public boolean mouseClicked(int mouseX, int mouseY, int button) { + if (onPressed == null) { + return super.mouseClicked(mouseX, mouseY, button); + } else { + if (isMouseOverElement(mouseX, mouseY)) { + isPressed = !isPressed; + ClickData clickData = new ClickData(Mouse.getEventButton(), isShiftDown(), isCtrlDown(), false); + writeClientAction(1, buffer -> { + clickData.writeToBuf(buffer); + buffer.writeBoolean(isPressed); + }); + playButtonClickSound(); + onPressed.accept(new ClickData(Mouse.getEventButton(), isShiftDown(), isCtrlDown(), true), isPressed); + return true; + } + return false; + } + } + + @Override + public void handleClientAction(int id, PacketBuffer buffer) { + if (onPressed == null) { + super.handleClientAction(id, buffer); + } else { + if (id == 1) { + ClickData clickData = ClickData.readFromBuf(buffer); + isPressed = buffer.readBoolean(); + if (onPressCallback != null) { + onPressed.accept(clickData, isPressed); + } + } + } + } + @Override public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { int x = this.getPosition().x; @@ -33,7 +118,11 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender drawSolidRect(x, (int) ((1 - per) * height) + y, border, (int) (height * per), colors[1]); } drawSolidRect(x + border, y + border, width - 2 * border, height - 2 * border, colors[2]); - if (icon != null) { + if (isPressed) { + if (pressedIcon != null) { + pressedIcon.draw(x + border, y + border, width - 2 * border, height - 2 * border); + } + } else if (icon != null) { icon.draw(x + border, y + border, width - 2 * border, height - 2 * border); } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/SelectorWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/SelectorWidget.java new file mode 100644 index 00000000000..6f8b0efbef2 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/SelectorWidget.java @@ -0,0 +1,118 @@ +package gregtech.api.terminal.gui.widgets; + +import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.widgets.SimpleTextWidget; +import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.util.Position; +import gregtech.api.util.Size; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.network.PacketBuffer; + +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Supplier; + +public class SelectorWidget extends WidgetGroup { + protected RectButtonWidget button; + protected List candidates; + protected boolean isShow; + private IGuiTexture background; + private Consumer onChanged; + private boolean isUp; + private final int fontColor; + + public SelectorWidget(int x, int y, int width, int height, List candidates, int fontColor, Supplier supplier, boolean isClient) { + super(new Position(x, y), new Size(width, height)); + this.button = new RectButtonWidget(0,0,width,height); + this.candidates = candidates; + this.fontColor = fontColor; + button.setClickListener(d->isShow = !isShow); + this.addWidget(button); + this.addWidget(new SimpleTextWidget(width / 2, height / 2, "", fontColor, supplier, isClient)); + } + + public SelectorWidget setIsUp(boolean isUp) { + this.isUp = isUp; + return this; + } + + public SelectorWidget setOnChanged(Consumer onChanged) { + this.onChanged = onChanged; + return this; + } + + public SelectorWidget setColors(int stroke, int anima, int fill) { + button.setColors(stroke, anima, fill); + return this; + } + + public SelectorWidget setButtonBackground(IGuiTexture guiTexture) { + button.setIcon(guiTexture); + return this; + } + + public SelectorWidget setBackground(IGuiTexture background) { + this.background = background; + return this; + } + + @Override + public void drawInForeground(int mouseX, int mouseY) { + super.drawInForeground(mouseX, mouseY); + if(isShow) { + int x = getPosition().x; + int width = getSize().width; + int height = getSize().height; + int y = (isUp ? -candidates.size(): (candidates.size() + 1)) * height + getPosition().y; + for (String candidate : candidates) { + if (background != null) { + background.draw(x, y, width, height); + } else { + drawSolidRect(x, y, width, height, 0xAA000000); + } + FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer; + fontRenderer.drawString(candidate, x + 4, y + (height - fontRenderer.FONT_HEIGHT) / 2 + 1, fontColor); + y += height; + } + y = (isUp ? -candidates.size(): (candidates.size() + 1)) * height + getPosition().y; + for (String ignored : candidates) { + if (isMouseOver(x, y, width, height, mouseX, mouseY)) { + drawBorder(x, y, width, height, -1, 1); + } + y += height; + } + } + } + + @Override + public boolean mouseClicked(int mouseX, int mouseY, int button) { + if (isShow) { + int x = getPosition().x; + int width = getSize().width; + int height = getSize().height; + int y = (isUp ? -candidates.size(): (candidates.size() + 1)) * height + getPosition().y; + for (String candidate : candidates) { + if (isMouseOver(x, y, width, height, mouseX, mouseY)) { + if (onChanged != null) { + onChanged.accept(candidate); + } + writeClientAction(2, buffer -> buffer.writeString(candidate)); + } + y += height; + } + } + isShow = false; + return super.mouseClicked(mouseX, mouseY, button); + } + + @Override + public void handleClientAction(int id, PacketBuffer buffer) { + super.handleClientAction(id, buffer); + if (id == 2) { + if (onChanged != null) { + onChanged.accept(buffer.readString(Short.MAX_VALUE)); + } + } + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java index 7c1b6995cc2..0f61ead4b95 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java @@ -100,7 +100,7 @@ public String getJsonString() { } public JsonObject addGuideWidget(IGuideWidget widget, boolean isFixed) { - int pageWidth = this.getSize().width - 5; + int pageWidth = this.getSize().width - yBarWidth; JsonObject widgetConfig = widget.getTemplate(isFixed); Widget guideWidget; if (isFixed) { @@ -117,7 +117,7 @@ public JsonObject addGuideWidget(IGuideWidget widget, boolean isFixed) { this.addWidget(guideWidget); } else { int y = getStreamBottom(); - guideWidget = widget.createStreamWidget(5, y + 5, pageWidth, widgetConfig); + guideWidget = widget.createStreamWidget(5, y + 5, pageWidth - 10, widgetConfig); stream.add(guideWidget); this.addWidget(guideWidget); } @@ -280,7 +280,7 @@ protected boolean hookDrawInBackground(int mouseX, int mouseY, float partialTick @Override public boolean mouseDragged(int mouseX, int mouseY, int button, long timeDragged) { - if (super.mouseDragged(mouseX, mouseY, button, timeDragged)) { + if (super.mouseDragged(mouseX, mouseY, button, timeDragged) && toolButtons.isVisible()) { setToolButton(selected.getSelfPosition().x, selected.getSelfPosition().y, selected.getSize().width, selected.getSize().height); return true; } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java index 3e7f4b2d930..9dfe19aaab1 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java @@ -8,9 +8,10 @@ import gregtech.api.gui.Widget; import gregtech.api.terminal.gui.IDraggable; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; -import gregtech.api.terminal.gui.widgets.guide.congiurator.NumberConfigurator; -import gregtech.api.terminal.gui.widgets.guide.congiurator.StringConfigurator; -import gregtech.api.terminal.gui.widgets.guide.congiurator.TextListConfigurator; +import gregtech.api.terminal.gui.widgets.guide.configurator.ColorConfigurator; +import gregtech.api.terminal.gui.widgets.guide.configurator.NumberConfigurator; +import gregtech.api.terminal.gui.widgets.guide.configurator.StringConfigurator; +import gregtech.api.terminal.gui.widgets.guide.configurator.TextListConfigurator; import gregtech.api.util.Position; import gregtech.api.util.Size; import net.minecraft.item.ItemStack; @@ -106,7 +107,9 @@ public JsonObject getTemplate(boolean isFixed) { @Override public void loadConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, boolean isFixed, Consumer needUpdate) { - group.addWidget(new NumberConfigurator(5, group.getWidgetBottomHeight() + 5, config, "stroke_width").setOnUpdated(needUpdate)); + group.addWidget(new ColorConfigurator(5, group.getWidgetBottomHeight() + 5, config, "fill", 0).setOnUpdated(needUpdate)); + group.addWidget(new ColorConfigurator(5, group.getWidgetBottomHeight() + 5, config, "stroke", 0).setOnUpdated(needUpdate)); + group.addWidget(new NumberConfigurator(5, group.getWidgetBottomHeight() + 5, config, "stroke_width", 1).setOnUpdated(needUpdate)); group.addWidget(new StringConfigurator(5, group.getWidgetBottomHeight() + 5, config, "ref", "").setOnUpdated(needUpdate)); group.addWidget(new StringConfigurator(5, group.getWidgetBottomHeight() + 5, config, "link", "").setOnUpdated(needUpdate)); group.addWidget(new TextListConfigurator(5, group.getWidgetBottomHeight() + 5, 40, config, "hover_text", true).setOnUpdated(needUpdate)); diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java index cc6c1fcb991..6bfe5b8aaed 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java @@ -2,7 +2,6 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import gregtech.api.GTValues; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; import gregtech.api.gui.resources.IGuiTexture; @@ -10,14 +9,16 @@ import gregtech.api.gui.resources.TextureArea; import gregtech.api.gui.resources.URLTexture; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; -import gregtech.api.terminal.gui.widgets.guide.congiurator.NumberConfigurator; -import gregtech.api.terminal.gui.widgets.guide.congiurator.StringConfigurator; +import gregtech.api.terminal.gui.widgets.guide.configurator.NumberConfigurator; +import gregtech.api.terminal.gui.widgets.guide.configurator.SelectorConfigurator; +import gregtech.api.terminal.gui.widgets.guide.configurator.StringConfigurator; import gregtech.api.util.Position; import gregtech.api.util.Size; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.item.Item; import net.minecraft.util.ResourceLocation; +import java.util.Arrays; import java.util.function.Consumer; public class ImageWidget extends GuideWidget{ @@ -39,7 +40,7 @@ public String getRegistryName() { public void updateValue(String field, JsonElement value) { super.updateValue(field, value); if (field.equals("width") || field.equals("height")) { - this.setSelfPosition(new Position(getSelfPosition().x - (width - getSize().width) / 2, getSelfPosition().y)); + this.addSelfPosition(- (width - getSize().width) / 2, 0); this.setSize(new Size(width, height)); } if (field.equals("form") || field.equals("source")) { @@ -60,6 +61,7 @@ public JsonObject getTemplate(boolean isFixed) { @Override public void loadConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, boolean isFixed, Consumer needUpdate) { super.loadConfigurator(group, config, isFixed, needUpdate); + group.addWidget(new SelectorConfigurator(5, group.getWidgetBottomHeight() + 5, config, "form", Arrays.asList("url", "item", "resource")).setOnUpdated(needUpdate)); group.addWidget(new StringConfigurator(5, group.getWidgetBottomHeight() + 5, config, "source").setOnUpdated(needUpdate)); group.addWidget(new NumberConfigurator(5, group.getWidgetBottomHeight() + 5, config, "width").setOnUpdated(needUpdate)); group.addWidget(new NumberConfigurator(5, group.getWidgetBottomHeight() + 5, config, "height").setOnUpdated(needUpdate)); diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java index b38066bd686..cb7a8fdc126 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java @@ -5,10 +5,11 @@ import com.google.gson.JsonObject; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; -import gregtech.api.gui.resources.RenderUtil; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; -import gregtech.api.terminal.gui.widgets.guide.congiurator.NumberConfigurator; -import gregtech.api.terminal.gui.widgets.guide.congiurator.TextListConfigurator; +import gregtech.api.terminal.gui.widgets.guide.configurator.BooleanConfigurator; +import gregtech.api.terminal.gui.widgets.guide.configurator.ColorConfigurator; +import gregtech.api.terminal.gui.widgets.guide.configurator.NumberConfigurator; +import gregtech.api.terminal.gui.widgets.guide.configurator.TextListConfigurator; import gregtech.api.util.Position; import gregtech.api.util.Size; import net.minecraft.client.Minecraft; @@ -79,6 +80,9 @@ public void loadConfigurator(DraggableScrollableWidgetGroup group, JsonObject co super.loadConfigurator(group, config, isFixed, needUpdate); group.addWidget(new NumberConfigurator(5, group.getWidgetBottomHeight() + 5, config, "space", 1).setOnUpdated(needUpdate)); group.addWidget(new NumberConfigurator(5, group.getWidgetBottomHeight() + 5, config, "fontSize", 9).setOnUpdated(needUpdate)); + group.addWidget(new ColorConfigurator(5, group.getWidgetBottomHeight() + 5, config, "fontColor", 0xff000000).setOnUpdated(needUpdate)); + group.addWidget(new BooleanConfigurator(5, group.getWidgetBottomHeight() + 5, config, "isShadow", false).setOnUpdated(needUpdate)); + group.addWidget(new BooleanConfigurator(5, group.getWidgetBottomHeight() + 5, config, "isCenter", false).setOnUpdated(needUpdate)); group.addWidget(new TextListConfigurator(5, group.getWidgetBottomHeight() + 5, 200, config, "content", false).setOnUpdated(needUpdate)); } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java index e7e96cdb565..da993835380 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java @@ -96,7 +96,7 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender if (leafTexture != null) { leafTexture.draw(position.x, y, size.width, ITEM_HEIGHT); } else { - gregtech.api.gui.resources.RenderUtil.renderRect(position.x, y, size.width, ITEM_HEIGHT, 0, 0xffff0000); + drawSolidRect(position.x, y, size.width, ITEM_HEIGHT, 0xffff0000); } if (node.content != null) { String nameS = nameSupplier.apply(node.content.getFirst()); @@ -110,11 +110,11 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender if (nodeTexture != null) { nodeTexture.draw(position.x, y, size.width, ITEM_HEIGHT); } else { - gregtech.api.gui.resources.RenderUtil.renderRect(position.x, y, size.width, ITEM_HEIGHT, 0, 0xffffff00); + drawSolidRect(position.x, y, size.width, ITEM_HEIGHT, 0xffffff00); } } if (node == selected) { - gregtech.api.gui.resources.RenderUtil.renderRect(position.x, y, size.width, ITEM_HEIGHT, 0, 0x7f000000); + drawSolidRect(position.x, y, size.width, ITEM_HEIGHT, 0x7f000000); } fr.drawString(I18n.format(name), x, y + 2, 0xff000000); } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/BooleanConfigurator.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/BooleanConfigurator.java new file mode 100644 index 00000000000..2b4c4ae2ca8 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/BooleanConfigurator.java @@ -0,0 +1,43 @@ +package gregtech.api.terminal.gui.widgets.guide.configurator; + +import com.google.gson.JsonObject; +import gregtech.api.gui.GuiTextures; +import gregtech.api.gui.resources.ColorRectTexture; +import gregtech.api.terminal.gui.widgets.RectButtonWidget; + +import java.awt.*; + +public class BooleanConfigurator extends ConfiguratorWidget{ + private boolean defaultValue; + + public BooleanConfigurator(int x, int y, JsonObject config, String name) { + super(x, y, config, name, false); + init(); + } + + public BooleanConfigurator(int x, int y, JsonObject config, String name, boolean defaultValue) { + super(x, y, config, name, true); + this.defaultValue = defaultValue; + init(); + } + + private void init(){ + this.addWidget(new RectButtonWidget(0, 15, 10, 10, 2) + .setToggleButton(new ColorRectTexture(new Color(198, 198, 198).getRGB()), (c, p)-> update(p)) + .setValueSupplier(true, ()->{ + if(config.get(name).isJsonNull()) { + return defaultValue; + } + return config.get(name).getAsBoolean(); + }) + .setColors(new Color(0, 0, 0, 74).getRGB(), + new Color(128, 255, 128).getRGB(), + new Color(255, 255, 255, 0).getRGB()) + .setIcon(new ColorRectTexture(new Color(0, 0, 0, 74).getRGB()))); + } + + private void update(boolean bool) { + config.addProperty(name, bool); + update(); + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ColorConfigurator.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ColorConfigurator.java new file mode 100644 index 00000000000..f52019325ec --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ColorConfigurator.java @@ -0,0 +1,34 @@ +package gregtech.api.terminal.gui.widgets.guide.configurator; + +import com.google.gson.JsonObject; +import gregtech.api.terminal.gui.widgets.ColorWidget; + +public class ColorConfigurator extends ConfiguratorWidget{ + private int defaultValue; + + public ColorConfigurator(int x, int y, JsonObject config, String name, int defaultValue) { + super(x, y, config, name, true); + this.defaultValue = defaultValue; + init(); + } + + public ColorConfigurator(int x, int y, JsonObject config, String name) { + super(x, y, config, name, false); + init(); + } + + private void init(){ + this.addWidget(new ColorWidget(0, 15, 85, 10).setColorSupplier(()->{ + if(config.get(name).isJsonNull()) { + return defaultValue; + } + return config.get(name).getAsInt(); + },true).setOnColorChanged(this::update)); + } + + private void update(int color) { + config.addProperty(name, color); + update(); + } + +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/ConfiguratorWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ConfiguratorWidget.java similarity index 74% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/ConfiguratorWidget.java rename to src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ConfiguratorWidget.java index 6ad16d559b9..42b25898006 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/ConfiguratorWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ConfiguratorWidget.java @@ -1,7 +1,5 @@ -package gregtech.api.terminal.gui.widgets.guide.congiurator; +package gregtech.api.terminal.gui.widgets.guide.configurator; -import com.google.gson.JsonElement; -import com.google.gson.JsonNull; import com.google.gson.JsonObject; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.widgets.LabelWidget; @@ -30,7 +28,7 @@ public ConfiguratorWidget(int x, int y, JsonObject config, String name, boolean if (canDefault && config.get(name).isJsonNull()) { isDefault = true; } - this.addWidget(new LabelWidget(0, 2, name, -1)); + this.addWidget(new LabelWidget(0, 4, name, -1).setShadow(true)); if (isClientSide()) { nameWidth = Minecraft.getMinecraft().fontRenderer.getStringWidth(name); } @@ -51,10 +49,12 @@ protected void update(){ public void drawInForeground(int mouseX, int mouseY) { int x = getPosition().x; int y = getPosition().y; - if (canDefault && isMouseOver(x + nameWidth + 4, y + 4, 5, 5, mouseX, mouseY)) { - drawHoveringText(ItemStack.EMPTY, Collections.singletonList("default the value"), 100, mouseX, mouseY); + if (canDefault && isMouseOver(x + nameWidth + 4, y + 6, 5, 5, mouseX, mouseY)) { + drawHoveringText(ItemStack.EMPTY, Collections.singletonList("default value"), 100, mouseX, mouseY); + } + if (!isDefault) { + super.drawInForeground(mouseX, mouseY); } - super.drawInForeground(mouseX, mouseY); } @Override @@ -63,12 +63,18 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender int y = getPosition().y; drawSolidRect(x, y, this.getSize().width, 1, -1); if (canDefault) { - drawBorder(x + nameWidth + 4, y + 4, 5, 5, 0xff000000, 1); + drawBorder(x + nameWidth + 4, y + 6, 5, 5, -1, 1); if (isDefault) { - drawSolidRect(x + nameWidth + 5, y + 5, 3, 3, 0xff000000); + drawSolidRect(x + nameWidth + 5, y + 7, 3, 3, -1); } } - super.drawInBackground(mouseX, mouseY, partialTicks, context); + if (canDefault && isDefault) { + super.drawInBackground(-100, -100, partialTicks, context); + drawSolidRect(x, y + 15, this.getSize().width, this.getSize().height - 15, 0x99000000); + } else { + super.drawInBackground(mouseX, mouseY, partialTicks, context); + } + } @Override @@ -78,7 +84,7 @@ public boolean mouseClicked(int mouseX, int mouseY, int button) { if (!isDefault && super.mouseClicked(mouseX, mouseY, button)) { return true; } - if (canDefault && isMouseOver(x + nameWidth + 4, y + 4, 5, 5, mouseX, mouseY)) { + if (canDefault && isMouseOver(x + nameWidth + 4, y + 6, 5, 5, mouseX, mouseY)) { isDefault = !isDefault; if (isDefault) { config.addProperty(name, (String) null); diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/NumberConfigurator.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/NumberConfigurator.java similarity index 53% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/NumberConfigurator.java rename to src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/NumberConfigurator.java index cb52f8f9ead..58c4c8fb059 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/NumberConfigurator.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/NumberConfigurator.java @@ -1,13 +1,16 @@ -package gregtech.api.terminal.gui.widgets.guide.congiurator; +package gregtech.api.terminal.gui.widgets.guide.configurator; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import gregtech.api.gui.GuiTextures; +import gregtech.api.gui.resources.ColorRectTexture; import gregtech.api.gui.resources.TextTexture; import gregtech.api.gui.widgets.ImageWidget; import gregtech.api.gui.widgets.SimpleTextWidget; import gregtech.api.terminal.gui.widgets.RectButtonWidget; +import java.awt.*; + public class NumberConfigurator extends ConfiguratorWidget{ private int defaultValue; @@ -23,20 +26,33 @@ public NumberConfigurator(int x, int y, JsonObject config, String name, int defa private void init(int defaultValue){ this.defaultValue = defaultValue; - this.addWidget(new RectButtonWidget(0, 11, 20, 20) + int y = 15; + this.addWidget(new RectButtonWidget(0, y, 20, 20) + .setColors(new Color(0, 0, 0, 74).getRGB(), + new Color(128, 255, 128).getRGB(), + new Color(255, 255, 255, 0).getRGB()) .setClickListener(data -> adjustTransferRate(data.isShiftClick ? -100 : -10)) - .setIcon(new TextTexture("-10"))); - this.addWidget(new RectButtonWidget(96, 11, 20, 20) + .setIcon(new TextTexture("-10", -1))); + this.addWidget(new RectButtonWidget(96, y, 20, 20) + .setColors(new Color(0, 0, 0, 74).getRGB(), + new Color(128, 255, 128).getRGB(), + new Color(255, 255, 255, 0).getRGB()) .setClickListener(data -> adjustTransferRate(data.isShiftClick ? +100 : +10)) - .setIcon(new TextTexture("+10"))); - this.addWidget(new RectButtonWidget(20, 11, 20, 20) + .setIcon(new TextTexture("+10", -1))); + this.addWidget(new RectButtonWidget(20, y, 20, 20) + .setColors(new Color(0, 0, 0, 74).getRGB(), + new Color(128, 255, 128).getRGB(), + new Color(255, 255, 255, 0).getRGB()) .setClickListener(data -> adjustTransferRate(data.isShiftClick ? -5 : -1)) - .setIcon(new TextTexture("-1"))); - this.addWidget(new RectButtonWidget(76, 11, 20, 20) + .setIcon(new TextTexture("-1", -1))); + this.addWidget(new RectButtonWidget(76, y, 20, 20) + .setColors(new Color(0, 0, 0, 74).getRGB(), + new Color(128, 255, 128).getRGB(), + new Color(255, 255, 255, 0).getRGB()) .setClickListener(data -> adjustTransferRate(data.isShiftClick ? +5 : +1)) - .setIcon(new TextTexture("+1"))); - this.addWidget(new ImageWidget(40, 11, 36, 20, GuiTextures.DISPLAY)); - this.addWidget(new SimpleTextWidget(58, 21, "", 0xFFFFFF, () -> { + .setIcon(new TextTexture("+1", -1))); + this.addWidget(new ImageWidget(40, y, 36, 20, new ColorRectTexture(0x9f000000))); + this.addWidget(new SimpleTextWidget(58, 25, "", 0xFFFFFF, () -> { JsonElement element = config.get(name); if (element.isJsonNull()) { return Integer.toString(defaultValue); diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/SelectorConfigurator.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/SelectorConfigurator.java new file mode 100644 index 00000000000..eaeec766e7f --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/SelectorConfigurator.java @@ -0,0 +1,49 @@ +package gregtech.api.terminal.gui.widgets.guide.configurator; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import gregtech.api.gui.GuiTextures; +import gregtech.api.gui.resources.TextTexture; +import gregtech.api.gui.widgets.ImageWidget; +import gregtech.api.gui.widgets.SimpleTextWidget; +import gregtech.api.terminal.gui.widgets.RectButtonWidget; +import gregtech.api.terminal.gui.widgets.SelectorWidget; + +import java.awt.*; +import java.util.List; + +public class SelectorConfigurator extends ConfiguratorWidget{ + private final List candidates; + private String defaultValue; + public SelectorConfigurator(int x, int y, JsonObject config, String name, List candidates, String defaultValue) { + super(x, y, config, name, true); + this.defaultValue = defaultValue; + this.candidates = candidates; + init(); + } + + public SelectorConfigurator(int x, int y, JsonObject config, String name, List candidates) { + super(x, y, config, name, false); + this.candidates = candidates; + init(); + } + + private void init(){ + this.addWidget(new SelectorWidget(0, 15, 80, 20, candidates, -1, ()->{ + if(config.get(name).isJsonNull()) { + return defaultValue; + } + return config.get(name).getAsString(); + }, true) + .setColors(new Color(0, 0, 0, 74).getRGB(), + new Color(128, 255, 128).getRGB(), + new Color(255, 255, 255, 0).getRGB()) + .setIsUp(true) + .setOnChanged(this::updateValue)); + } + + private void updateValue(String selected) { + config.addProperty(name, selected); + update(); + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/StringConfigurator.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/StringConfigurator.java similarity index 67% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/StringConfigurator.java rename to src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/StringConfigurator.java index b4589dfdfd0..3ffba684148 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/StringConfigurator.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/StringConfigurator.java @@ -1,11 +1,14 @@ -package gregtech.api.terminal.gui.widgets.guide.congiurator; +package gregtech.api.terminal.gui.widgets.guide.configurator; -import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import gregtech.api.gui.resources.ColorRectTexture; +import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.resources.TextTexture; import gregtech.api.gui.widgets.TextFieldWidget; import gregtech.api.terminal.gui.widgets.RectButtonWidget; +import java.awt.*; + public class StringConfigurator extends ConfiguratorWidget{ private String defaultValue = ""; private TextFieldWidget textFieldWidget; @@ -24,10 +27,14 @@ public StringConfigurator(int x, int y, JsonObject config, String name, String d } private void init() { - this.addWidget(new RectButtonWidget(76, 11, 40, 20) + this.addWidget(new RectButtonWidget(76, 15, 40, 20) + .setColors(new Color(0, 0, 0, 74).getRGB(), + new Color(128, 255, 128).getRGB(), + new Color(255, 255, 255, 0).getRGB()) .setClickListener(data -> updateString()) - .setIcon(new TextTexture("Update"))); - textFieldWidget = new TextFieldWidget(0, 11, 76, 20, true, null, null) + .setIcon(new TextTexture("Update", -1))); + textFieldWidget = new TextFieldWidget(0, 15, 76, 20, new ColorRectTexture(0x9f000000), null, null) + .setMaxStringLength(Integer.MAX_VALUE) .setValidator(s->true); this.addWidget(textFieldWidget); } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/TextListConfigurator.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/TextListConfigurator.java similarity index 63% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/TextListConfigurator.java rename to src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/TextListConfigurator.java index 9645c440241..9ec086e11f3 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/TextListConfigurator.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/TextListConfigurator.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.gui.widgets.guide.congiurator; +package gregtech.api.terminal.gui.widgets.guide.configurator; import com.google.gson.Gson; import com.google.gson.JsonArray; @@ -10,7 +10,7 @@ import java.util.List; public class TextListConfigurator extends ConfiguratorWidget{ -// private TextEditorWidget textEditorWidget; + public TextListConfigurator(int x, int y, int height, JsonObject config, String name, boolean canDefault) { super(x, y, config, name, canDefault); JsonElement element = config.get(name); @@ -29,20 +29,8 @@ public TextListConfigurator(int x, int y, int height, JsonObject config, String } } -// public TextListConfigurator(int x, int y, int height, JsonObject config, String name, String defaultS) { -// super(x, y, config, name, false); -// StringBuilder s = new StringBuilder(); -// for (int i = 0; i < defaultS.size(); i++) { -// s.append(defaultS.get(i)); -// if(i != defaultS.size() - 1) { -// s.append('\n'); -// } -// } -// init(height, s.toString()); -// } - private void init(int height, String init) { - this.addWidget(new TextEditorWidget(0, 11, 116, height, init, this::updateTextList).setBackground(new ColorRectTexture(-1))); + this.addWidget(new TextEditorWidget(0, 15, 116, height, init, this::updateTextList).setBackground(new ColorRectTexture(0xA3FFFFFF))); } private void updateTextList(String saved) { From 879671fb09b3adb794e380189328a860c5cd74ff Mon Sep 17 00:00:00 2001 From: Yefancy Date: Tue, 3 Aug 2021 22:00:12 +0800 Subject: [PATCH 12/58] CustomDragSizePos --- .../api/terminal/app/GuideEditorApp.java | 2 +- .../api/terminal/app/guide/GuideApp.java | 2 +- .../gregtech/api/terminal/gui/IDraggable.java | 1 - .../gui/widgets/CustomPositionSizeWidget.java | 211 ++++++++++++++++++ .../DraggableScrollableWidgetGroup.java | 14 +- .../widgets/guide/GuidePageEditorWidget.java | 116 ++++++---- .../gui/widgets/guide/GuidePageWidget.java | 19 +- .../gui/widgets/guide/GuideWidget.java | 41 ++-- .../gui/widgets/guide/IGuideWidget.java | 4 + .../gui/widgets/guide/ImageWidget.java | 28 +-- .../gui/widgets/guide/TextBoxWidget.java | 14 +- 11 files changed, 349 insertions(+), 103 deletions(-) create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/CustomPositionSizeWidget.java diff --git a/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java b/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java index 9ecb104de8d..a5bbbc889d0 100644 --- a/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java +++ b/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java @@ -20,7 +20,7 @@ public AbstractApplication createApp(boolean isClient, NBTTagCompound nbt) { if (isClient) { GuideEditorApp app = new GuideEditorApp(); GuideConfigEditor configEditor = new GuideConfigEditor(0, 0, 133, 232); - GuidePageEditorWidget pageEditor = new GuidePageEditorWidget(133, 0, 200, 232); + GuidePageEditorWidget pageEditor = new GuidePageEditorWidget(133, 0, 200, 232, 5); configEditor.setGuidePageEditorWidget(pageEditor); pageEditor.setGuideConfigEditor(configEditor); app.addWidget(pageEditor); diff --git a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java index dabcc3322a8..67568dc5fcf 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java @@ -43,7 +43,7 @@ public AbstractApplication createApp(boolean isClient, NBTTagCompound nbt) { if (app.pageWidget != null) { app.removeWidget(app.pageWidget); } - app.pageWidget = new GuidePageWidget(133, 0, 200, 232); + app.pageWidget = new GuidePageWidget(133, 0, 200, 232, 5); if (leaf.isLeaf() && leaf.content != null) { app.pageWidget.loadJsonConfig(leaf.content.getSecond()); } diff --git a/src/main/java/gregtech/api/terminal/gui/IDraggable.java b/src/main/java/gregtech/api/terminal/gui/IDraggable.java index 1c38550638e..5366276a536 100644 --- a/src/main/java/gregtech/api/terminal/gui/IDraggable.java +++ b/src/main/java/gregtech/api/terminal/gui/IDraggable.java @@ -1,7 +1,6 @@ package gregtech.api.terminal.gui; public interface IDraggable { - boolean setDraggable(boolean isDraggable); boolean allowDrag(int mouseX, int mouseY, int button); default void startDrag(int mouseX, int mouseY) {} default boolean dragging(int mouseX, int mouseY, int deltaX, int deltaY) {return true;} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/CustomPositionSizeWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/CustomPositionSizeWidget.java new file mode 100644 index 00000000000..4868795681e --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/CustomPositionSizeWidget.java @@ -0,0 +1,211 @@ +package gregtech.api.terminal.gui.widgets; + +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.Widget; +import gregtech.api.terminal.gui.IDraggable; +import gregtech.api.util.Position; +import gregtech.api.util.Size; +import javafx.geometry.Pos; + +import java.util.function.BiConsumer; + +public class CustomPositionSizeWidget extends Widget implements IDraggable { + private Widget controlled; + private final int borderColor; + private final int hoverColor; + private final int border; + private boolean dragUp; + private boolean dragDown; + private boolean dragLeft; + private boolean dragRight; + private boolean dragPos; + + private BiConsumer onUpdated; + + + public CustomPositionSizeWidget(Widget controlled, int borderColor, int hoverColor, int border) { + super(controlled.getSelfPosition(), controlled.getSize()); + this.controlled = controlled; + this.borderColor = borderColor; + this.hoverColor = hoverColor; + this.border = border; + } + + public CustomPositionSizeWidget(int borderColor, int hoverColor, int border) { + super(Position.ORIGIN, Size.ZERO); + this.borderColor = borderColor; + this.hoverColor = hoverColor; + this.border = border; + } + + public CustomPositionSizeWidget setControlled(Widget controlled) { + this.controlled = controlled; + if (controlled != null) { + this.setSelfPosition(controlled.getSelfPosition()); + this.setSize(controlled.getSize()); + } + return this; + } + + public Widget getControlled() { + return controlled; + } + + public CustomPositionSizeWidget setOnUpdated(BiConsumer onUpdated) { + this.onUpdated = onUpdated; + return this; + } + + @Override + public void updateScreen() { + if (controlled != null) { + Position pos = controlled.getSelfPosition(); + Size size = controlled.getSize(); + if (!this.getSelfPosition().equals(pos)) { + this.setSelfPosition(pos); + } + if (this.getSize().equals(size)) { + this.setSize(size); + } + } + } + + @Override + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + if (controlled == null) return; + int x = controlled.getPosition().x; + int y = controlled.getPosition().y; + int width = controlled.getSize().width; + int height = controlled.getSize().height; + + boolean hoverUp = false; + boolean hoverDown = false; + boolean hoverLeft = false; + boolean hoverRight = false; + // UP + if (isMouseOver(x, y, width / 5, border, mouseX, mouseY) || + isMouseOver(x + width * 2 / 5, y, width / 5, border, mouseX, mouseY) || + isMouseOver(x + width * 4 / 5, y, width / 5, border, mouseX, mouseY) || + isMouseOver(x, y, border, height / 5, mouseX, mouseY) || + isMouseOver(x + width - border, y, border, height / 5, mouseX, mouseY)) { + hoverUp = true; + } + if (isMouseOver(x, y + height - border, width / 5, border, mouseX, mouseY) || + isMouseOver(x + width * 2 / 5, y + height - border, width / 5, border, mouseX, mouseY) || + isMouseOver(x + width * 4 / 5, y + height - border, width / 5, border, mouseX, mouseY) || + isMouseOver(x, y + height * 4 / 5, border, height / 5, mouseX, mouseY) || + isMouseOver(x + width - border, y + height * 4 / 5, border, height / 5, mouseX, mouseY)) { + hoverDown = true; + } + if (isMouseOver(x, y, border, height / 5, mouseX, mouseY) || + isMouseOver(x, y + height * 2 / 5, border, height / 5, mouseX, mouseY) || + isMouseOver(x, y + height * 4 / 5, border, height / 5, mouseX, mouseY) || + isMouseOver(x, y, width / 5, border, mouseX, mouseY) || + isMouseOver(x, y + height - border, width / 5, border, mouseX, mouseY)) { + hoverLeft = true; + } + if (isMouseOver(x + width - border, y, border, height / 5, mouseX, mouseY) || + isMouseOver(x + width - border, y + height * 2 / 5, border, height / 5, mouseX, mouseY) || + isMouseOver(x + width - border, y + height * 4 / 5, border, height / 5, mouseX, mouseY) || + isMouseOver(x + width * 4 / 5, y, width / 5, border, mouseX, mouseY) || + isMouseOver(x + width * 4 / 5, y + height - border, width / 5, border, mouseX, mouseY)) { + hoverRight = true; + } + drawSolidRect(x, y, width / 5, border, hoverUp ? hoverColor : borderColor); + drawSolidRect(x + width * 2 / 5, y, width / 5, border, hoverUp ? hoverColor : borderColor); + drawSolidRect(x + width * 4 / 5, y, width / 5, border, hoverUp ? hoverColor : borderColor); + // DOWN + drawSolidRect(x, y + height - border, width / 5, border, hoverDown ? hoverColor : borderColor); + drawSolidRect(x + width * 2 / 5, y + height - border, width / 5, border, hoverDown ? hoverColor : borderColor); + drawSolidRect(x + width * 4 / 5, y + height - border, width / 5, border, hoverDown ? hoverColor : borderColor); + // LEFT + drawSolidRect(x, y, border, height / 5, hoverLeft ? hoverColor : borderColor); + drawSolidRect(x, y + height * 2 / 5, border, height / 5, hoverLeft ? hoverColor : borderColor); + drawSolidRect(x, y + height * 4 / 5, border, height / 5, hoverLeft ? hoverColor : borderColor); + // RIGHT + drawSolidRect(x + width - border, y, border, height / 5, hoverRight ? hoverColor : borderColor); + drawSolidRect(x + width - border, y + height * 2 / 5, border, height / 5, hoverRight ? hoverColor : borderColor); + drawSolidRect(x + width - border, y + height * 4 / 5, border, height / 5, hoverRight ? hoverColor : borderColor); + } + + @Override + public boolean allowDrag(int mouseX, int mouseY, int button) { + if (controlled == null) return false; + int x = controlled.getPosition().x; + int y = controlled.getPosition().y; + int width = controlled.getSize().width; + int height = controlled.getSize().height; + if (isMouseOver(x, y, width, height, mouseX, mouseY)) { + // UP + dragUp = isMouseOver(x, y, width / 5, border, mouseX, mouseY) || + isMouseOver(x + width * 2 / 5, y, width / 5, border, mouseX, mouseY) || + isMouseOver(x + width * 4 / 5, y, width / 5, border, mouseX, mouseY) || + isMouseOver(x, y, border, height / 5, mouseX, mouseY) || + isMouseOver(x + width - border, y, border, height / 5, mouseX, mouseY); + // DOWN + dragDown = isMouseOver(x, y + height - border, width / 5, border, mouseX, mouseY) || + isMouseOver(x + width * 2 / 5, y + height - border, width / 5, border, mouseX, mouseY) || + isMouseOver(x + width * 4 / 5, y + height - border, width / 5, border, mouseX, mouseY) || + isMouseOver(x, y + height * 4 / 5, border, height / 5, mouseX, mouseY) || + isMouseOver(x + width - border, y + height * 4 / 5, border, height / 5, mouseX, mouseY); + // LEFT + dragLeft = isMouseOver(x, y, border, height / 5, mouseX, mouseY) || + isMouseOver(x, y + height * 2 / 5, border, height / 5, mouseX, mouseY) || + isMouseOver(x, y + height * 4 / 5, border, height / 5, mouseX, mouseY) || + isMouseOver(x, y, width / 5, border, mouseX, mouseY) || + isMouseOver(x, y + height - border, width / 5, border, mouseX, mouseY); + // RIGHT + dragRight = isMouseOver(x + width - border, y, border, height / 5, mouseX, mouseY) || + isMouseOver(x + width - border, y + height * 2 / 5, border, height / 5, mouseX, mouseY) || + isMouseOver(x + width - border, y + height * 4 / 5, border, height / 5, mouseX, mouseY) || + isMouseOver(x + width * 4 / 5, y, width / 5, border, mouseX, mouseY) || + isMouseOver(x + width * 4 / 5, y + height - border, width / 5, border, mouseX, mouseY); + dragPos = !dragUp && !dragDown && !dragLeft && !dragRight; + return true; + } + return false; + } + + @Override + public boolean dragging(int mouseX, int mouseY, int deltaX, int deltaY) { + if (controlled == null) return false; + int width = controlled.getSize().width; + int height = controlled.getSize().height; + int addX = 0, addY = 0; + if (!dragPos) { + if (dragUp) { + addY = deltaY; + height -= deltaY; + } + if (dragDown) { + height += deltaY; + } + if (dragLeft) { + addX = deltaX; + width -= deltaX; + } + if (dragRight) { + width += deltaX; + } + controlled.addSelfPosition(addX, addY); + controlled.setSize(new Size(width, height)); + } else { + controlled.addSelfPosition(deltaX, deltaY); + } + if (onUpdated != null) { + onUpdated.accept(controlled.getSelfPosition(), controlled.getSize()); + } + this.setSelfPosition(controlled.getSelfPosition()); + this.setSize(controlled.getSize()); + return false; + } + + @Override + public void endDrag(int mouseX, int mouseY) { + dragDown = false; + dragUp = false; + dragLeft = false; + dragRight = false; + dragPos = false; + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java b/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java index ec0c752e39d..8ceea9e6414 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java @@ -280,7 +280,7 @@ private boolean checkClickedDragged(int mouseX, int mouseY, int button) { } else if (widget instanceof IDraggable && ((IDraggable) widget).allowDrag(mouseX, mouseY, button)) { draggedWidget = widget; ((IDraggable) widget).startDrag(mouseX, mouseY); - return true; + return false; } } } @@ -294,8 +294,8 @@ public boolean mouseWheelMove(int mouseX, int mouseY, int wheelDelta) { return true; } int moveDelta = -MathHelper.clamp(wheelDelta, -1, 1) * 5; - if (getMaxHeight() - getSize().height > 0) { - setScrollYOffset(MathHelper.clamp(scrollYOffset + moveDelta, 0, getMaxHeight() - getSize().height + 5)); + if (getMaxHeight() - getSize().height > 0 || scrollYOffset > getMaxHeight() - getSize().height) { + setScrollYOffset(MathHelper.clamp(scrollYOffset + moveDelta, 0, getMaxHeight() - getSize().height)); } return true; } @@ -309,11 +309,11 @@ public boolean mouseDragged(int mouseX, int mouseY, int button, long timeDragged int deltaY = mouseY - lastMouseY; lastMouseX = mouseX; lastMouseY = mouseY; - if (draggedOnXScrollBar) { - setScrollXOffset(MathHelper.clamp(scrollXOffset + deltaX * getMaxWidth() / getSize().width, 0, Math.max(getMaxWidth() - getSize().width, 0))); + if (draggedOnXScrollBar && (getMaxWidth() - getSize().width > 0 || scrollYOffset > getMaxWidth() - getSize().width)) { + setScrollXOffset(MathHelper.clamp(scrollXOffset + deltaX * getMaxWidth() / getSize().width, 0, getMaxWidth() - getSize().width)); return true; - } else if (draggedOnYScrollBar) { - setScrollYOffset(MathHelper.clamp(scrollYOffset + deltaY * getMaxHeight() / getSize().height, 0, Math.max(getMaxHeight() - getSize().height, 0))); + } else if (draggedOnYScrollBar && (getMaxHeight() - getSize().height > 0 || scrollYOffset > getMaxHeight() - getSize().height)) { + setScrollYOffset(MathHelper.clamp(scrollYOffset + deltaY * getMaxHeight() / getSize().height, 0, getMaxHeight() - getSize().height)); return true; } else if (draggedWidget != null && ((IDraggable)draggedWidget).dragging(mouseX, mouseY, deltaX, deltaY)) { draggedWidget.addSelfPosition(deltaX, deltaY); diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java index 0f61ead4b95..293e128d34f 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java @@ -8,8 +8,8 @@ import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; import gregtech.api.gui.widgets.WidgetGroup; -import gregtech.api.terminal.gui.IDraggable; import gregtech.api.terminal.gui.widgets.CircleButtonWidget; +import gregtech.api.terminal.gui.widgets.CustomPositionSizeWidget; import gregtech.api.util.Position; import gregtech.api.util.Size; import gregtech.api.util.interpolate.Eases; @@ -26,13 +26,15 @@ public class GuidePageEditorWidget extends GuidePageWidget { private final Map configMap; private Widget selected; private final WidgetGroup toolButtons; + private final CustomPositionSizeWidget customPositionSizeWidget; private GuideConfigEditor configEditor; - public GuidePageEditorWidget(int xPosition, int yPosition, int width, int height) { - super(xPosition, yPosition, width, height); + public GuidePageEditorWidget(int xPosition, int yPosition, int width, int height, int margin) { + super(xPosition, yPosition, width, height, margin); this.setDraggable(false); configMap = new HashMap<>(); setTitle("Template"); + customPositionSizeWidget = new CustomPositionSizeWidget(0xff0000ff, 0xffff0000, 2).setOnUpdated(this::onPosSizeChanged); toolButtons = new WidgetGroup(Position.ORIGIN, Size.ZERO); toolButtons.setVisible(false); toolButtons.addWidget(new CircleButtonWidget(-20, -4, 8, 1, 12) @@ -56,23 +58,33 @@ public GuidePageEditorWidget(int xPosition, int yPosition, int width, int height .setIcon(GuiTextures.TERMINAL_DELETE) .setHoverText("delete") .setClickListener(this::delete)); + addWidget(customPositionSizeWidget); addWidget(toolButtons); } + private void onPosSizeChanged(Position pos, Size size) { + if (customPositionSizeWidget.getControlled() instanceof IGuideWidget) { + ((IGuideWidget) customPositionSizeWidget.getControlled()).onFixedPositionSizeChanged(pos, size); + } + toolButtons.setSelfPosition(new Position(pos.x + size.width / 2, pos.y)); + } + public void setGuideConfigEditor(GuideConfigEditor configEditor) { this.configEditor = configEditor; } - private void setToolButton(int x, int y, int width, int height) { + private void setToolButton(Widget widget) { + customPositionSizeWidget.setControlled(widget); toolButtons.setVisible(true); - toolButtons.setSelfPosition(new Position(x + width / 2, y)); + toolButtons.setSelfPosition(new Position(widget.getSelfPosition().x + widget.getSize().width / 2, widget.getSelfPosition().y)); } private void delete(ClickData clickData) { removeWidget(selected); selected = null; configEditor.loadConfigurator(null, null, true); - toolButtons.setSelfPosition(new Position(0, 0)); + toolButtons.setSelfPosition(new Position(-scrollYOffset, -scrollYOffset)); + customPositionSizeWidget.setControlled(null); toolButtons.setVisible(false); } @@ -100,7 +112,8 @@ public String getJsonString() { } public JsonObject addGuideWidget(IGuideWidget widget, boolean isFixed) { - int pageWidth = this.getSize().width - yBarWidth; + int pageWidth = getPageWidth(); + int margin = getMargin(); JsonObject widgetConfig = widget.getTemplate(isFixed); Widget guideWidget; if (isFixed) { @@ -117,7 +130,7 @@ public JsonObject addGuideWidget(IGuideWidget widget, boolean isFixed) { this.addWidget(guideWidget); } else { int y = getStreamBottom(); - guideWidget = widget.createStreamWidget(5, y + 5, pageWidth - 10, widgetConfig); + guideWidget = widget.createStreamWidget(margin, y + 5, pageWidth - 2 * margin, widgetConfig); stream.add(guideWidget); this.addWidget(guideWidget); } @@ -139,7 +152,7 @@ public void moveUp(Widget widget) { widget.setSelfPosition(new Position(widget.getSelfPosition().x, (int) (y1 - value.floatValue() * offsetU))); target.setSelfPosition(new Position(target.getSelfPosition().x, (int) (y2 + value.floatValue() * offsetD))); if (widget == selected) { - setToolButton(selected.getSelfPosition().x, selected.getSelfPosition().y, selected.getSize().width, selected.getSize().height); + setToolButton(selected); } widget.setVisible(widget.getSelfPosition().y < scrollYOffset + getSize().height && widget.getSelfPosition().y + widget.getSize().height > 0); target.setVisible(target.getSelfPosition().y < scrollYOffset + getSize().height && target.getSelfPosition().y + target.getSize().height > 0); @@ -165,7 +178,7 @@ public void moveDown(Widget widget) { widget.setSelfPosition(new Position(widget.getSelfPosition().x, (int) (y1 + value.floatValue() * offsetD))); target.setSelfPosition(new Position(target.getSelfPosition().x, (int) (y2 - value.floatValue() * offsetU))); if (widget == selected) { - setToolButton(selected.getSelfPosition().x, selected.getSelfPosition().y, selected.getSize().width, selected.getSize().height); + setToolButton(selected); } widget.setVisible(widget.getSelfPosition().y < getSize().height - xBarHeight && widget.getSelfPosition().y + widget.getSize().height > 0); target.setVisible(target.getSelfPosition().y < getSize().height - xBarHeight && target.getSelfPosition().y + target.getSize().height > 0); @@ -211,34 +224,36 @@ public void removeWidget(Widget widget) { @Override public boolean mouseClicked(int mouseX, int mouseY, int button) { + if (super.mouseClicked(mouseX, mouseY, button)) { + return true; + } boolean flag = false; for (Widget widget : fixed) { if (widget.isMouseOverElement(mouseX, mouseY)) { if (widget instanceof IGuideWidget && widget != selected) { configEditor.loadConfigurator((IGuideWidget) widget, configMap.get(widget), true); selected = widget; - setToolButton(selected.getSelfPosition().x, selected.getSelfPosition().y, selected.getSize().width, selected.getSize().height); + setToolButton(selected); } playButtonClickSound(); flag = true; break; } } - for (Widget widget : stream) { - if (widget.isMouseOverElement(mouseX, mouseY)) { - if (widget instanceof IGuideWidget && widget != selected) { - configEditor.loadConfigurator((IGuideWidget) widget, configMap.get(widget), false); - selected = widget; - setToolButton(selected.getSelfPosition().x, selected.getSelfPosition().y, selected.getSize().width, selected.getSize().height); + if (!flag) { + for (Widget widget : stream) { + if (widget.isMouseOverElement(mouseX, mouseY)) { + if (widget instanceof IGuideWidget && widget != selected) { + configEditor.loadConfigurator((IGuideWidget) widget, configMap.get(widget), false); + selected = widget; + setToolButton(selected); + } + playButtonClickSound(); + flag = true; + break; } - playButtonClickSound(); - flag = true; - break; } } - if (super.mouseClicked(mouseX, mouseY, button)) { - return true; - } return flag; } @@ -246,8 +261,18 @@ public boolean mouseClicked(int mouseX, int mouseY, int button) { protected boolean hookDrawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { Position position = getPosition(); Size size = getSize(); - for (Widget widget : widgets) { - if (widget != toolButtons && widget.isVisible()) { + if(title.isVisible()) { + title.drawInBackground(mouseX, mouseY, partialTicks, context); + } + for (Widget widget : stream) { + if (widget.isVisible()) { + widget.drawInBackground(mouseX, mouseY, partialTicks, context); + } + } + + boolean flag = false; + for (Widget widget : fixed) { + if (widget.isVisible()) { widget.drawInBackground(mouseX, mouseY, partialTicks, context); if (widget.isMouseOverElement(mouseX, mouseY)) { if (widget != selected) { @@ -255,23 +280,40 @@ protected boolean hookDrawInBackground(int mouseX, int mouseY, float partialTick Size s = widget.getSize(); if (stream.contains(widget)) { drawSolidRect(position.x, pos.y, size.width - yBarWidth, s.height, 0x6f000000); + } else { drawSolidRect(pos.x, pos.y, s.width, s.height, 0x6f000000); } } + flag = true; } } } - if (selected != null) { - Position pos = selected.getPosition(); - Size s = selected.getSize(); - if (stream.contains(selected)) { - drawSolidRect(position.x, pos.y, size.width - yBarWidth, s.height, 0x6f0000ff); - } else { - drawSolidRect(pos.x, pos.y, s.width, s.height, 0x6f0000ff); + if (!flag) { + for (Widget widget : stream) { + if (widget.isVisible() && widget != selected && widget.isMouseOverElement(mouseX, mouseY)) { + Position pos = widget.getPosition(); + Size s = widget.getSize(); + if (stream.contains(widget)) { + drawSolidRect(position.x, pos.y, size.width - yBarWidth, s.height, 0x6f000000); + } else { + drawSolidRect(pos.x, pos.y, s.width, s.height, 0x6f000000); + } + } } } + + if (selected != null) { +// Position pos = selected.getPosition(); +// Size s = selected.getSize(); +// if (stream.contains(selected)) { +// drawSolidRect(position.x, pos.y, size.width - yBarWidth, s.height, 0x6f0000ff); +// } else { +// drawSolidRect(pos.x, pos.y, s.width, s.height, 0x6f0000ff); +// } + } if(toolButtons.isVisible()) { + customPositionSizeWidget.drawInBackground(mouseX, mouseY, partialTicks, context); toolButtons.drawInBackground(mouseX, mouseY, partialTicks, context); } GlStateManager.color(rColorForOverlay, gColorForOverlay, bColorForOverlay, 1.0F); @@ -281,17 +323,9 @@ protected boolean hookDrawInBackground(int mouseX, int mouseY, float partialTick @Override public boolean mouseDragged(int mouseX, int mouseY, int button, long timeDragged) { if (super.mouseDragged(mouseX, mouseY, button, timeDragged) && toolButtons.isVisible()) { - setToolButton(selected.getSelfPosition().x, selected.getSelfPosition().y, selected.getSize().width, selected.getSize().height); + setToolButton(selected); return true; } return false; } - - @Override - public void addWidget(Widget widget) { - super.addWidget(widget); - if(fixed.contains(widget) && widget instanceof IDraggable) { - ((IDraggable) widget).setDraggable(true); - } - } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java index e952b622d61..6ad34a1117e 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java @@ -25,12 +25,12 @@ public class GuidePageWidget extends DraggableScrollableWidgetGroup { protected TextBoxWidget title; protected List stream = new ArrayList<>(); protected List fixed = new ArrayList<>(); -// protected int pageWdith; - protected Interpolator interpolator; + private final int margin; - public GuidePageWidget(int xPosition, int yPosition, int width, int height) { + public GuidePageWidget(int xPosition, int yPosition, int width, int height, int margin) { super(xPosition, yPosition, width, height); + this.margin = margin; this.setBackground(new ColorRectTexture(-1)) .setDraggable(true) .setYScrollBarWidth(4) @@ -39,6 +39,14 @@ public GuidePageWidget(int xPosition, int yPosition, int width, int height) { } + public int getPageWidth() { + return this.getSize().width - yBarWidth; + } + + public int getMargin() { + return margin; + } + public void setTitle(String config) { int height = 0; if (title != null) { @@ -69,7 +77,8 @@ public String loadJsonConfig(String config) { } public void loadJsonConfig(JsonObject config) { - int pageWidth = this.getSize().width - yBarWidth; + int pageWidth = getPageWidth(); + int margin = getMargin(); // add title setTitle(config.get("title").getAsString()); @@ -79,7 +88,7 @@ public void loadJsonConfig(JsonObject config) { int y = title.getSize().height + 10; for (JsonElement element : config.getAsJsonArray("stream")) { JsonObject widgetConfig = element.getAsJsonObject(); - Widget widget = REGISTER_WIDGETS.get(widgetConfig.get("type").getAsString()).createStreamWidget(5, y, pageWidth - 10, widgetConfig); + Widget widget = REGISTER_WIDGETS.get(widgetConfig.get("type").getAsString()).createStreamWidget(margin, y, pageWidth - 2 * margin, widgetConfig); y += widget.getSize().height + 5; stream.add(widget); this.addWidget(widget); diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java index 9dfe19aaab1..2111f319a7a 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java @@ -3,10 +3,8 @@ import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import com.sun.istack.internal.Nullable; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; -import gregtech.api.terminal.gui.IDraggable; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; import gregtech.api.terminal.gui.widgets.guide.configurator.ColorConfigurator; import gregtech.api.terminal.gui.widgets.guide.configurator.NumberConfigurator; @@ -21,7 +19,7 @@ import java.util.List; import java.util.function.Consumer; -public abstract class GuideWidget extends Widget implements IGuideWidget, IDraggable { +public abstract class GuideWidget extends Widget implements IGuideWidget { //config public String ref; public int fill; @@ -31,7 +29,7 @@ public abstract class GuideWidget extends Widget implements IGuideWidget, IDragg public List hover_text; private static final Gson GSON = new Gson(); - public boolean allowDrag; + private transient boolean isFixed; protected transient GuidePageWidget page; public GuideWidget(int x, int y, int width, int height) { @@ -52,12 +50,24 @@ public void updateValue(String field, JsonElement value) { } else { f.set(this, new Gson().fromJson(value, f.getType())); } + if (isFixed) { + initFixed(); + } else { + initStream(); + } } catch (Exception e) { e.printStackTrace(); } } + public boolean isFixed() { + return isFixed; + } + @Override + public void onFixedPositionSizeChanged(Position position, Size size) { + this.initFixed(); + } @Override public void setStroke(int color) { @@ -123,24 +133,26 @@ public String getRef() { @Override public Widget createStreamWidget(int x, int y, int pageWidth, JsonObject config) { GuideWidget widget = GSON.fromJson(config, this.getClass()); + widget.isFixed = false; widget.setSelfPosition(new Position(x, y)); widget.setSize(new Size(pageWidth, 0)); - return widget.initStream(x, y, pageWidth, config); + return widget.initStream(); } @Override public Widget createFixedWidget(int x, int y, int width, int height, JsonObject config) { GuideWidget widget = GSON.fromJson(config, this.getClass()); + widget.isFixed = true; widget.setSelfPosition(new Position(x, y)); widget.setSize(new Size(width, height)); - return widget.initFixed(x, y, width, height, config); + return widget.initFixed(); } - protected Widget initStream(int x, int y, int pageWidth, @Nullable JsonObject config) { - return initFixed(x, y, pageWidth, 0, config); + protected Widget initStream() { + return initFixed(); } - protected Widget initFixed(int x, int y, int width, int height, @Nullable JsonObject config) { + protected Widget initFixed() { return this; } @@ -185,15 +197,4 @@ public boolean mouseClicked(int mouseX, int mouseY, int button) { } return false; } - - @Override - public boolean allowDrag(int mouseX, int mouseY, int button) { - return allowDrag && isMouseOverElement(mouseX, mouseY); - } - - @Override - public boolean setDraggable(boolean isDraggable) { - allowDrag = isDraggable; - return allowDrag; - } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java index f8ad46d95d4..25f10636c6a 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java @@ -4,7 +4,10 @@ import com.google.gson.JsonObject; import gregtech.api.gui.Widget; import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.terminal.gui.IDraggable; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; +import gregtech.api.util.Position; +import gregtech.api.util.Size; import java.util.function.Consumer; @@ -17,4 +20,5 @@ public interface IGuideWidget { JsonObject getTemplate(boolean isFixed); void loadConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, boolean isFixed, Consumer needUpdate); void setStroke(int color); + void onFixedPositionSizeChanged(Position position, Size size); } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java index 6bfe5b8aaed..e9162a24121 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java @@ -1,6 +1,5 @@ package gregtech.api.terminal.gui.widgets.guide; -import com.google.gson.JsonElement; import com.google.gson.JsonObject; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; @@ -36,18 +35,6 @@ public String getRegistryName() { return NAME; } - @Override - public void updateValue(String field, JsonElement value) { - super.updateValue(field, value); - if (field.equals("width") || field.equals("height")) { - this.addSelfPosition(- (width - getSize().width) / 2, 0); - this.setSize(new Size(width, height)); - } - if (field.equals("form") || field.equals("source")) { - initFixed(0,0,0,0,null); - } - } - @Override public JsonObject getTemplate(boolean isFixed) { JsonObject template = super.getTemplate(isFixed); @@ -75,14 +62,23 @@ public void updateScreen() { } @Override - protected Widget initStream(int x, int y, int pageWidth, JsonObject config) { + protected Widget initStream() { + int pageWidth = getSize().width; + int x = getSelfPosition().x; + int y = getSelfPosition().y; + if (page != null) { + x = page.getMargin(); + pageWidth = page.getPageWidth() - 2 * x; + } this.setSelfPosition(new Position(x + (pageWidth - width) / 2, y)); this.setSize(new Size(width, height)); - return super.initStream(x, y, pageWidth, config); + return initFixed(); } @Override - protected Widget initFixed(int x, int y, int width, int height, JsonObject config) { + protected Widget initFixed() { + width = getSize().width; + height = getSize().height; switch (form) { case "url": image = new URLTexture(source); diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java index cb7a8fdc126..e6c2d7be156 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java @@ -45,7 +45,7 @@ public TextBoxWidget(int x, int y, int width, List content, int space, i this.stroke = stroke; this.isCenter = isCenter; this.isShadow = isShadow; - this.initFixed(x, y, width, 0, null); + this.initFixed(); } public TextBoxWidget() {} @@ -55,14 +55,6 @@ public String getRegistryName() { return NAME; } - @Override - public void updateValue(String field, JsonElement value) { - super.updateValue(field, value); - if (field.equals("space") || field.equals("fontSize") || field.equals("content")) { - initFixed(getSelfPosition().x, getSelfPosition().y, getSize().width, getSize().height, null); - } - } - @Override public JsonObject getTemplate(boolean isFixed) { JsonObject template = super.getTemplate(isFixed); @@ -87,12 +79,12 @@ public void loadConfigurator(DraggableScrollableWidgetGroup group, JsonObject co } @Override - protected Widget initFixed(int x, int y, int width, int height, JsonObject config) { + protected Widget initFixed() { this.textLines = new ArrayList<>(); FontRenderer font = Minecraft.getMinecraft().fontRenderer; this.space = Math.max(space, 0); this.fontSize = Math.max(fontSize, 1); - int wrapWidth = width * font.FONT_HEIGHT / fontSize; + int wrapWidth = getSize().width * font.FONT_HEIGHT / fontSize; if (content != null) { for (String textLine : content) { this.textLines.addAll(font.listFormattedStringToWidth(I18n.format(textLine), wrapWidth)); From 76781eef5d1dad235cfa52e6d7426f8b94bd0fb3 Mon Sep 17 00:00:00 2001 From: Yefancy Date: Wed, 4 Aug 2021 13:09:14 +0800 Subject: [PATCH 13/58] details --- .../api/terminal/gui/widgets/ColorWidget.java | 76 +++++++----- .../gui/widgets/CustomPositionSizeWidget.java | 109 +++++++++--------- .../gui/widgets/TextEditorWidget.java | 2 +- .../gui/widgets/guide/GuideConfigEditor.java | 78 ++++++++++--- .../widgets/guide/GuidePageEditorWidget.java | 54 ++++++--- .../gui/widgets/guide/GuidePageWidget.java | 10 +- .../gui/widgets/guide/GuideWidget.java | 50 +++++--- .../gui/widgets/guide/IGuideWidget.java | 4 +- .../gui/widgets/guide/ImageWidget.java | 15 ++- .../gui/widgets/guide/TextBoxWidget.java | 10 +- 10 files changed, 262 insertions(+), 146 deletions(-) diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/ColorWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/ColorWidget.java index 2f9580e405a..58b88ed577a 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/ColorWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/ColorWidget.java @@ -37,19 +37,39 @@ public ColorWidget(int x, int y, int barWidth, int barHeight){ this.barHeight= barHeight; IGuiTexture textFieldBackground = new ColorRectTexture(0x9f000000); TextFieldWidget redField = new TextFieldWidget(barWidth + 5, 0, 30, barHeight, textFieldBackground, null, null) - .setTextResponder((t) -> setRed(t.isEmpty()? 0 : Integer.parseInt(t)), true) + .setTextResponder((t) -> { + setRed(t.isEmpty()? 0 : Integer.parseInt(t)); + if (onColorChanged != null) { + onColorChanged.accept((alpha << 24) | (red << 16) | (green << 8) | (blue)); + } + }, true) .setTextSupplier(() -> Integer.toString(red), true) .setValidator(this::checkValid); TextFieldWidget greenField = new TextFieldWidget(barWidth + 5, barHeight + 5, 30, barHeight, textFieldBackground, null, null) - .setTextResponder((t) -> setGreen(t.isEmpty()? 0 : Integer.parseInt(t)), true) + .setTextResponder((t) -> { + setGreen(t.isEmpty()? 0 : Integer.parseInt(t)); + if (onColorChanged != null) { + onColorChanged.accept((alpha << 24) | (red << 16) | (green << 8) | (blue)); + } + }, true) .setTextSupplier(() -> Integer.toString(green), true) .setValidator(this::checkValid); TextFieldWidget blueField = new TextFieldWidget(barWidth + 5, (barHeight + 5) * 2, 30, barHeight, textFieldBackground, null, null) - .setTextResponder((t) -> setBlue(t.isEmpty()? 0 : Integer.parseInt(t)), true) + .setTextResponder((t) -> { + setBlue(t.isEmpty()? 0 : Integer.parseInt(t)); + if (onColorChanged != null) { + onColorChanged.accept((alpha << 24) | (red << 16) | (green << 8) | (blue)); + } + }, true) .setTextSupplier(() -> Integer.toString(blue), true) .setValidator(this::checkValid); TextFieldWidget alphaField = new TextFieldWidget(barWidth + 5, (barHeight + 5) * 3, 30, barHeight, textFieldBackground, null, null) - .setTextResponder((t) -> setAlpha(t.isEmpty()? 0 : Integer.parseInt(t)), true) + .setTextResponder((t) -> { + setAlpha(t.isEmpty()? 0 : Integer.parseInt(t)); + if (onColorChanged != null) { + onColorChanged.accept((alpha << 24) | (red << 16) | (green << 8) | (blue)); + } + }, true) .setTextSupplier(() -> Integer.toString(alpha), true) .setValidator(this::checkValid); this.addWidget(redField); @@ -82,11 +102,11 @@ public void detectAndSendChanges() { super.detectAndSendChanges(); if (!isClient && colorSupplier!= null) { int c = colorSupplier.get(); - int r = (c & 0x00ff0000) >> 16; - int g = (c & 0x0000ff00) >> 8; + int r = (c & 0x00ff0000) >>> 16; + int g = (c & 0x0000ff00) >>> 8; int b = (c & 0x000000ff); - int a = (c & 0xff000000) >> 24; - if (r != red || g != green || b != blue || a ==alpha) { + int a = (c & 0xff000000) >>> 24; + if (r != red || g != green || b != blue || a !=alpha) { setRed(r); setGreen(g); setBlue(b); @@ -101,11 +121,11 @@ public void updateScreen() { super.updateScreen(); if (isClient && colorSupplier!= null) { int c = colorSupplier.get(); - int r = (c & 0x00ff0000) >> 16; - int g = (c & 0x0000ff00) >> 8; + int r = (c & 0x00ff0000) >>> 16; + int g = (c & 0x0000ff00) >>> 8; int b = (c & 0x000000ff); - int a = (c & 0xff000000) >> 24; - if (r != red || g != green || b != blue || a ==alpha) { + int a = (c & 0xff000000) >>> 24; + if (r != red || g != green || b != blue || a != alpha) { setRed(r); setGreen(g); setBlue(b); @@ -123,15 +143,18 @@ public void readUpdateInfo(int id, PacketBuffer buffer) { private void handleColor(int id, PacketBuffer buffer) { if (id == 2) { int c = buffer.readInt(); - int r = (c & 0x00ff0000) >> 16; - int g = (c & 0x0000ff00) >> 8; + int r = (c & 0x00ff0000) >>> 16; + int g = (c & 0x0000ff00) >>> 8; int b = (c & 0x000000ff); - int a = (c & 0xff000000) >> 24; - if (r != red || g != green || b != blue || a ==alpha) { + int a = (c & 0xff000000) >>> 24; + if (r != red || g != green || b != blue || a != alpha) { setRed(r); setGreen(g); setBlue(b); setAlpha(a); + if (onColorChanged != null) { + onColorChanged.accept((alpha << 24) | (red << 16) | (green << 8) | (blue)); + } } } } @@ -145,9 +168,6 @@ private void setRed(int red) { if (this.red != red) { this.red = red; redButton.setSelfPosition(new Position(red * barWidth / 255 - 4, redButton.getSelfPosition().y)); - if (onColorChanged != null) { - onColorChanged.accept((alpha << 24) | (red << 16) | (green << 8) | (blue)); - } } } @@ -155,9 +175,6 @@ private void setGreen(int green) { if (this.green != green) { this.green = green; greenButton.setSelfPosition(new Position(green * barWidth / 255 - 4, greenButton.getSelfPosition().y)); - if (onColorChanged != null) { - onColorChanged.accept((alpha << 24) | (red << 16) | (green << 8) | (blue)); - } } } @@ -165,9 +182,6 @@ private void setBlue(int blue) { if (this.blue != blue) { this.blue = blue; blueButton.setSelfPosition(new Position(blue * barWidth / 255 - 4, blueButton.getSelfPosition().y)); - if (onColorChanged != null) { - onColorChanged.accept((alpha << 24) | (red << 16) | (green << 8) | (blue)); - } } } @@ -175,9 +189,6 @@ private void setAlpha(int alpha) { if (this.alpha != alpha) { this.alpha = alpha; alphaButton.setSelfPosition(new Position(alpha * barWidth / 255 - 4, alphaButton.getSelfPosition().y)); - if (onColorChanged != null) { - onColorChanged.accept((alpha << 24) | (red << 16) | (green << 8) | (blue)); - } } } @@ -199,9 +210,9 @@ private boolean checkValid(String input) { public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { int x = getPosition().x; int y = getPosition().y; - drawGradientRect(x, y + 2, barWidth, 5, 0xFF000000, 0xFFFF0000, true); - drawGradientRect(x, y + barHeight + 5 + 2, barWidth, 5, 0xFF000000, 0xFF00ff00, true); - drawGradientRect(x, y + 2 * (barHeight + 5) + 2, barWidth, 5, 0xFF000000, 0xFF0000ff, true); + drawGradientRect(x, y + 2, barWidth, 5, (255 << 24) | (0) | (green << 8) | (blue), (255 << 24) | (255 << 16) | (green << 8) | (blue), true); + drawGradientRect(x, y + barHeight + 5 + 2, barWidth, 5, (255 << 24) | (red << 16) | (0) | (blue), (255 << 24) | (red << 16) | (255 << 8) | (blue), true); + drawGradientRect(x, y + 2 * (barHeight + 5) + 2, barWidth, 5, (255 << 24) | (red << 16) | (green << 8) | (0), (255 << 24) | (red << 16) | (green << 8) | (255), true); drawGradientRect(x, y + 3 * (barHeight + 5) + 2, barWidth, 5, (0) | (red << 16) | (green << 8) | (blue), (255 << 24) | (red << 16) | (green << 8) | (blue), true); super.drawInBackground(mouseX, mouseY, partialTicks, context); } @@ -248,6 +259,9 @@ public boolean mouseDragged(int mouseX, int mouseY, int button, long timeDragged } else if (dragged == alphaButton) { setAlpha(newX * 255 / barWidth); } + if (onColorChanged != null) { + onColorChanged.accept((alpha << 24) | (red << 16) | (green << 8) | (blue)); + } dragged.setSelfPosition(new Position(newX - 4, dragged.getSelfPosition().y)); return true; } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/CustomPositionSizeWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/CustomPositionSizeWidget.java index 4868795681e..6bd708f2e5b 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/CustomPositionSizeWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/CustomPositionSizeWidget.java @@ -70,6 +70,38 @@ public void updateScreen() { } } + private boolean hoverUp(int x, int y, int width, int height, int mouseX, int mouseY) { + return isMouseOver(x, y, width / 5, border, mouseX, mouseY) || + isMouseOver(x + width * 2 / 5, y, width / 5, border, mouseX, mouseY) || + isMouseOver(x + width * 4 / 5, y, width / 5, border, mouseX, mouseY) || + isMouseOver(x, y, border, height / 5, mouseX, mouseY) || + isMouseOver(x + width - border, y, border, height / 5, mouseX, mouseY); + } + + private boolean hoverDown(int x, int y, int width, int height, int mouseX, int mouseY) { + return isMouseOver(x, y + height - border, width / 5, border, mouseX, mouseY) || + isMouseOver(x + width * 2 / 5, y + height - border, width / 5, border, mouseX, mouseY) || + isMouseOver(x + width * 4 / 5, y + height - border, width / 5, border, mouseX, mouseY) || + isMouseOver(x, y + height * 4 / 5, border, height / 5, mouseX, mouseY) || + isMouseOver(x + width - border, y + height * 4 / 5, border, height / 5, mouseX, mouseY); + } + + private boolean hoverLeft(int x, int y, int width, int height, int mouseX, int mouseY) { + return isMouseOver(x, y, border, height / 5, mouseX, mouseY) || + isMouseOver(x, y + height * 2 / 5, border, height / 5, mouseX, mouseY) || + isMouseOver(x, y + height * 4 / 5, border, height / 5, mouseX, mouseY) || + isMouseOver(x, y, width / 5, border, mouseX, mouseY) || + isMouseOver(x, y + height - border, width / 5, border, mouseX, mouseY); + } + + private boolean hoverRight(int x, int y, int width, int height, int mouseX, int mouseY) { + return isMouseOver(x + width - border, y, border, height / 5, mouseX, mouseY) || + isMouseOver(x + width - border, y + height * 2 / 5, border, height / 5, mouseX, mouseY) || + isMouseOver(x + width - border, y + height * 4 / 5, border, height / 5, mouseX, mouseY) || + isMouseOver(x + width * 4 / 5, y, width / 5, border, mouseX, mouseY) || + isMouseOver(x + width * 4 / 5, y + height - border, width / 5, border, mouseX, mouseY); + } + @Override public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { if (controlled == null) return; @@ -83,83 +115,52 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender boolean hoverLeft = false; boolean hoverRight = false; // UP - if (isMouseOver(x, y, width / 5, border, mouseX, mouseY) || - isMouseOver(x + width * 2 / 5, y, width / 5, border, mouseX, mouseY) || - isMouseOver(x + width * 4 / 5, y, width / 5, border, mouseX, mouseY) || - isMouseOver(x, y, border, height / 5, mouseX, mouseY) || - isMouseOver(x + width - border, y, border, height / 5, mouseX, mouseY)) { + if (dragUp || hoverUp(x, y, width, height, mouseX, mouseY)) { hoverUp = true; } - if (isMouseOver(x, y + height - border, width / 5, border, mouseX, mouseY) || - isMouseOver(x + width * 2 / 5, y + height - border, width / 5, border, mouseX, mouseY) || - isMouseOver(x + width * 4 / 5, y + height - border, width / 5, border, mouseX, mouseY) || - isMouseOver(x, y + height * 4 / 5, border, height / 5, mouseX, mouseY) || - isMouseOver(x + width - border, y + height * 4 / 5, border, height / 5, mouseX, mouseY)) { + if (dragDown || hoverDown(x, y, width, height, mouseX, mouseY)) { hoverDown = true; } - if (isMouseOver(x, y, border, height / 5, mouseX, mouseY) || - isMouseOver(x, y + height * 2 / 5, border, height / 5, mouseX, mouseY) || - isMouseOver(x, y + height * 4 / 5, border, height / 5, mouseX, mouseY) || - isMouseOver(x, y, width / 5, border, mouseX, mouseY) || - isMouseOver(x, y + height - border, width / 5, border, mouseX, mouseY)) { + if (dragLeft || hoverLeft(x, y, width, height, mouseX, mouseY)) { hoverLeft = true; } - if (isMouseOver(x + width - border, y, border, height / 5, mouseX, mouseY) || - isMouseOver(x + width - border, y + height * 2 / 5, border, height / 5, mouseX, mouseY) || - isMouseOver(x + width - border, y + height * 4 / 5, border, height / 5, mouseX, mouseY) || - isMouseOver(x + width * 4 / 5, y, width / 5, border, mouseX, mouseY) || - isMouseOver(x + width * 4 / 5, y + height - border, width / 5, border, mouseX, mouseY)) { + if (dragRight || hoverRight(x, y, width, height, mouseX, mouseY)) { hoverRight = true; } - drawSolidRect(x, y, width / 5, border, hoverUp ? hoverColor : borderColor); - drawSolidRect(x + width * 2 / 5, y, width / 5, border, hoverUp ? hoverColor : borderColor); - drawSolidRect(x + width * 4 / 5, y, width / 5, border, hoverUp ? hoverColor : borderColor); + // UP + drawSolidRect(x, y, width / 5, border, hoverUp && !hoverRight ? hoverColor : borderColor); + drawSolidRect(x + width * 2 / 5, y, width / 5, border, hoverUp && !hoverLeft && !hoverRight ? hoverColor : borderColor); + drawSolidRect(x + width * 4 / 5, y, width / 5, border, hoverUp && !hoverLeft ? hoverColor : borderColor); // DOWN - drawSolidRect(x, y + height - border, width / 5, border, hoverDown ? hoverColor : borderColor); - drawSolidRect(x + width * 2 / 5, y + height - border, width / 5, border, hoverDown ? hoverColor : borderColor); - drawSolidRect(x + width * 4 / 5, y + height - border, width / 5, border, hoverDown ? hoverColor : borderColor); + drawSolidRect(x, y + height - border, width / 5, border, hoverDown && !hoverRight ? hoverColor : borderColor); + drawSolidRect(x + width * 2 / 5, y + height - border, width / 5, border, hoverDown && !hoverLeft && !hoverRight ? hoverColor : borderColor); + drawSolidRect(x + width * 4 / 5, y + height - border, width / 5, border, hoverDown && !hoverLeft ? hoverColor : borderColor); // LEFT - drawSolidRect(x, y, border, height / 5, hoverLeft ? hoverColor : borderColor); - drawSolidRect(x, y + height * 2 / 5, border, height / 5, hoverLeft ? hoverColor : borderColor); - drawSolidRect(x, y + height * 4 / 5, border, height / 5, hoverLeft ? hoverColor : borderColor); + drawSolidRect(x, y, border, height / 5, hoverLeft && !hoverDown ? hoverColor : borderColor); + drawSolidRect(x, y + height * 2 / 5, border, height / 5, hoverLeft && !hoverDown && !hoverUp ? hoverColor : borderColor); + drawSolidRect(x, y + height * 4 / 5, border, height / 5, hoverLeft && !hoverUp ? hoverColor : borderColor); // RIGHT - drawSolidRect(x + width - border, y, border, height / 5, hoverRight ? hoverColor : borderColor); - drawSolidRect(x + width - border, y + height * 2 / 5, border, height / 5, hoverRight ? hoverColor : borderColor); - drawSolidRect(x + width - border, y + height * 4 / 5, border, height / 5, hoverRight ? hoverColor : borderColor); + drawSolidRect(x + width - border, y, border, height / 5, hoverRight && !hoverDown ? hoverColor : borderColor); + drawSolidRect(x + width - border, y + height * 2 / 5, border, height / 5, hoverRight && !hoverDown && !hoverUp ? hoverColor : borderColor); + drawSolidRect(x + width - border, y + height * 4 / 5, border, height / 5, hoverRight && !hoverUp ? hoverColor : borderColor); } @Override public boolean allowDrag(int mouseX, int mouseY, int button) { - if (controlled == null) return false; + if (controlled == null || !isActive()) return false; int x = controlled.getPosition().x; int y = controlled.getPosition().y; int width = controlled.getSize().width; int height = controlled.getSize().height; if (isMouseOver(x, y, width, height, mouseX, mouseY)) { // UP - dragUp = isMouseOver(x, y, width / 5, border, mouseX, mouseY) || - isMouseOver(x + width * 2 / 5, y, width / 5, border, mouseX, mouseY) || - isMouseOver(x + width * 4 / 5, y, width / 5, border, mouseX, mouseY) || - isMouseOver(x, y, border, height / 5, mouseX, mouseY) || - isMouseOver(x + width - border, y, border, height / 5, mouseX, mouseY); + dragUp = hoverUp(x, y, width, height, mouseX, mouseY); // DOWN - dragDown = isMouseOver(x, y + height - border, width / 5, border, mouseX, mouseY) || - isMouseOver(x + width * 2 / 5, y + height - border, width / 5, border, mouseX, mouseY) || - isMouseOver(x + width * 4 / 5, y + height - border, width / 5, border, mouseX, mouseY) || - isMouseOver(x, y + height * 4 / 5, border, height / 5, mouseX, mouseY) || - isMouseOver(x + width - border, y + height * 4 / 5, border, height / 5, mouseX, mouseY); + dragDown = hoverDown(x, y, width, height, mouseX, mouseY); // LEFT - dragLeft = isMouseOver(x, y, border, height / 5, mouseX, mouseY) || - isMouseOver(x, y + height * 2 / 5, border, height / 5, mouseX, mouseY) || - isMouseOver(x, y + height * 4 / 5, border, height / 5, mouseX, mouseY) || - isMouseOver(x, y, width / 5, border, mouseX, mouseY) || - isMouseOver(x, y + height - border, width / 5, border, mouseX, mouseY); + dragLeft = hoverLeft(x, y, width, height, mouseX, mouseY); // RIGHT - dragRight = isMouseOver(x + width - border, y, border, height / 5, mouseX, mouseY) || - isMouseOver(x + width - border, y + height * 2 / 5, border, height / 5, mouseX, mouseY) || - isMouseOver(x + width - border, y + height * 4 / 5, border, height / 5, mouseX, mouseY) || - isMouseOver(x + width * 4 / 5, y, width / 5, border, mouseX, mouseY) || - isMouseOver(x + width * 4 / 5, y + height - border, width / 5, border, mouseX, mouseY); + dragRight = hoverRight(x, y, width, height, mouseX, mouseY); dragPos = !dragUp && !dragDown && !dragLeft && !dragRight; return true; } @@ -168,7 +169,7 @@ public boolean allowDrag(int mouseX, int mouseY, int button) { @Override public boolean dragging(int mouseX, int mouseY, int deltaX, int deltaY) { - if (controlled == null) return false; + if (controlled == null || !isActive()) return false; int width = controlled.getSize().width; int height = controlled.getSize().height; int addX = 0, addY = 0; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/TextEditorWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/TextEditorWidget.java index c64b17c15d8..e719f2422c4 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/TextEditorWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/TextEditorWidget.java @@ -118,7 +118,7 @@ protected boolean hookDrawInBackground(int mouseX, int mouseY, float partialTick contentString += TextFormatting.GRAY + "_"; } } - this.fontRenderer.drawSplitString(contentString, getPosition().x, getPosition().y+ SPACE, getSize().width - yBarWidth, 0); + this.fontRenderer.drawSplitString(contentString, getPosition().x, getPosition().y + SPACE, getSize().width - yBarWidth, 0); return true; } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java index 0ceb0a5512b..5de5d4214aa 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java @@ -1,17 +1,19 @@ package gregtech.api.terminal.gui.widgets.guide; -import com.google.gson.JsonElement; import com.google.gson.JsonObject; import gregtech.api.gui.GuiTextures; import gregtech.api.gui.Widget; import gregtech.api.gui.resources.ColorRectTexture; import gregtech.api.gui.resources.TextTexture; +import gregtech.api.gui.widgets.ImageWidget; import gregtech.api.gui.widgets.LabelWidget; import gregtech.api.gui.widgets.TabGroup; +import gregtech.api.gui.widgets.TextFieldWidget; import gregtech.api.gui.widgets.tab.IGuiTextureTabInfo; import gregtech.api.terminal.gui.CustomTabListRenderer; import gregtech.api.terminal.gui.widgets.CircleButtonWidget; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; +import gregtech.api.terminal.gui.widgets.TextEditorWidget; import gregtech.api.util.Size; import java.awt.*; @@ -23,36 +25,81 @@ public class GuideConfigEditor extends TabGroup { private GuidePageEditorWidget pageEditor; private final DraggableScrollableWidgetGroup widgetSelector; private final DraggableScrollableWidgetGroup widgetConfigurator; + private final CircleButtonWidget[] addButton; public GuideConfigEditor(int x, int y, int width, int height) { super(x, y + 10, new CustomTabListRenderer( new ColorRectTexture(new Color(175, 0, 0, 131)), new ColorRectTexture(new Color(246, 120, 120, 190)), 30, 10)); setSize(new Size(width, height)); + addButton = new CircleButtonWidget[2]; widgetSelector = createWidgetSelector(); widgetConfigurator = createConfigurator(); - this.addTab(new IGuiTextureTabInfo(new TextTexture("W", -1), "widget"), widgetSelector); - this.addTab(new IGuiTextureTabInfo(new TextTexture("C", -1), "config"), widgetConfigurator); - this.addWidget(new CircleButtonWidget(100, -5, 5, 1, 3) + this.addTab(new IGuiTextureTabInfo(new TextTexture("P", -1), "Page Config"), createPageConfig()); + this.addTab(new IGuiTextureTabInfo(new TextTexture("W", -1), "Widgets Box"), widgetSelector); + this.addTab(new IGuiTextureTabInfo(new TextTexture("C", -1), "Widget Config"), widgetConfigurator); + this.setOnTabChanged((oldIndex, newIndex)->{ + if (newIndex == 1) { + addButton[0].setVisible(true); + addButton[1].setVisible(true); + } else { + addButton[0].setVisible(false); + addButton[1].setVisible(false); + } + }); +// addButton[0] = new CircleButtonWidget(100, -5, 5, 1, 3) +// .setColors(new Color(255, 255, 255, 0).getRGB(), +// new Color(255, 255, 255).getRGB(), +// new Color(146, 253, 118).getRGB()) +// .setIcon(GuiTextures.TERMINAL_ADD) +// .setHoverText("add stream") +// .setClickListener(this::getJson); + addButton[0] = new CircleButtonWidget(115, 15, 8, 1, 8) .setColors(new Color(255, 255, 255, 0).getRGB(), new Color(255, 255, 255).getRGB(), new Color(0, 115, 255).getRGB()) .setIcon(GuiTextures.TERMINAL_ADD) .setHoverText("add stream") - .setClickListener(this::addStream)); - this.addWidget(new CircleButtonWidget(120, -5, 5, 1, 3) + .setClickListener(this::addStream); + addButton[1] = new CircleButtonWidget(115, 35, 8, 1, 8) .setColors(new Color(255, 255, 255, 0).getRGB(), new Color(255, 255, 255).getRGB(), new Color(113, 27, 217).getRGB()) .setIcon(GuiTextures.TERMINAL_ADD) .setHoverText("add fixed") - .setClickListener(this::addFixed)); + .setClickListener(this::addFixed); + this.addWidget(addButton[0]); + this.addWidget(addButton[1]); } public void setGuidePageEditorWidget(GuidePageEditorWidget pageEditor) { this.pageEditor = pageEditor; } + private DraggableScrollableWidgetGroup createPageConfig() { + DraggableScrollableWidgetGroup group = new DraggableScrollableWidgetGroup(0, 0, getSize().width, getSize().height - 10) + .setBackground(new ColorRectTexture(new Color(246, 120, 120, 190))) + .setYScrollBarWidth(4) + .setYBarStyle(null, new ColorRectTexture(new Color(148, 226, 193))); + group.addWidget(new LabelWidget(5, 5, "section", -1).setShadow(true)); + group.addWidget(new TextFieldWidget(5, 15, 116, 20, new ColorRectTexture(0x9f000000), null, null) + .setTextResponder(s->{ + if (pageEditor != null) { + pageEditor.setSection(s); + } + }, true) + .setMaxStringLength(Integer.MAX_VALUE) + .setValidator(s->true)); + group.addWidget(new ImageWidget(5, 48,116, 1, new ColorRectTexture(-1))); + group.addWidget(new LabelWidget(5, 55, "title", -1).setShadow(true)); + group.addWidget(new TextEditorWidget(5, 65, 116, 40, "Template", s->{ + if (pageEditor != null) { + pageEditor.setTitle(s); + } + }).setBackground(new ColorRectTexture(0xA3FFFFFF))); + return group; + } + private DraggableScrollableWidgetGroup createWidgetSelector() { DraggableScrollableWidgetGroup group = new DraggableScrollableWidgetGroup(0, 0, getSize().width, getSize().height - 10) .setBackground(new ColorRectTexture(new Color(246, 120, 120, 190))) @@ -62,9 +109,8 @@ private DraggableScrollableWidgetGroup createWidgetSelector() { for (Map.Entry entry : GuidePageWidget.REGISTER_WIDGETS.entrySet()) { IGuideWidget widgetTemplate = entry.getValue(); JsonObject template = widgetTemplate.getTemplate(false); -// template.addProperty("stroke", 0xFF7CA1FF); Widget guideWidget = widgetTemplate.createStreamWidget(5, y + 10, getSize().width - 14, template); - group.addWidget(new LabelWidget(getSize().width / 2 - 1, y, entry.getKey(), -1).setXCentered(true)); + group.addWidget(new LabelWidget(getSize().width / 2 - 1, y - 3, entry.getKey(), -1).setXCentered(true).setShadow(true)); y += guideWidget.getSize().height + 25; group.addWidget(guideWidget); } @@ -78,12 +124,16 @@ private DraggableScrollableWidgetGroup createConfigurator() { .setYBarStyle(null, new ColorRectTexture(new Color(148, 226, 193))); } - public void loadConfigurator(IGuideWidget widget, JsonObject config, boolean isFixed) { + public void loadConfigurator(IGuideWidget widget) { widgetConfigurator.clearAllWidgets(); if (widget != null) { - widget.loadConfigurator(widgetConfigurator, config, isFixed, attr->{ - widget.updateValue(attr, config.get(attr)); - }); + widget.loadConfigurator(widgetConfigurator, widget.getConfig(), widget.isFixed(), widget::updateValue); + } + } + + private void getJson(ClickData data) { + if(pageEditor != null) { + System.out.println(pageEditor.getJsonString()); } } @@ -106,7 +156,7 @@ private void addStream(ClickData data) { @Override public boolean mouseClicked(int mouseX, int mouseY, int button) { boolean flag = super.mouseClicked(mouseX, mouseY, button); - if (selectedTabIndex == 0 && widgetSelector != null) { + if (selectedTabIndex == 1 && widgetSelector != null) { for (Widget widget : widgetSelector.widgets) { if (widget.isMouseOverElement(mouseX, mouseY)) { if (widget instanceof IGuideWidget) { diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java index 293e128d34f..bdf2b1dfb59 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java @@ -17,22 +17,19 @@ import net.minecraft.client.renderer.GlStateManager; import java.awt.*; -import java.util.HashMap; -import java.util.Map; import static gregtech.api.gui.impl.ModularUIGui.*; public class GuidePageEditorWidget extends GuidePageWidget { - private final Map configMap; private Widget selected; private final WidgetGroup toolButtons; private final CustomPositionSizeWidget customPositionSizeWidget; private GuideConfigEditor configEditor; + private String section = "default"; public GuidePageEditorWidget(int xPosition, int yPosition, int width, int height, int margin) { super(xPosition, yPosition, width, height, margin); this.setDraggable(false); - configMap = new HashMap<>(); setTitle("Template"); customPositionSizeWidget = new CustomPositionSizeWidget(0xff0000ff, 0xffff0000, 2).setOnUpdated(this::onPosSizeChanged); toolButtons = new WidgetGroup(Position.ORIGIN, Size.ZERO); @@ -62,9 +59,31 @@ public GuidePageEditorWidget(int xPosition, int yPosition, int width, int height addWidget(toolButtons); } + public void setSection(String section) { + this.section = section; + } + private void onPosSizeChanged(Position pos, Size size) { - if (customPositionSizeWidget.getControlled() instanceof IGuideWidget) { - ((IGuideWidget) customPositionSizeWidget.getControlled()).onFixedPositionSizeChanged(pos, size); + Widget widget = customPositionSizeWidget.getControlled(); + if (widget instanceof IGuideWidget && ((IGuideWidget) widget).isFixed()) { + JsonObject config = ((IGuideWidget) widget).getConfig(); + if (config.has("x")) { + config.addProperty("x", pos.x + scrollXOffset); + ((IGuideWidget) widget).updateValue("x"); + } + if (config.has("y")) { + config.addProperty("y", pos.y + scrollYOffset); + ((IGuideWidget) widget).updateValue("y"); + } + if (config.has("width")) { + config.addProperty("width", size.width); + ((IGuideWidget) widget).updateValue("width"); + } + if (config.has("height")) { + config.addProperty("height", size.height); + ((IGuideWidget) widget).updateValue("height"); + } + ((IGuideWidget) widget).onFixedPositionSizeChanged(pos, size); } toolButtons.setSelfPosition(new Position(pos.x + size.width / 2, pos.y)); } @@ -75,6 +94,7 @@ public void setGuideConfigEditor(GuideConfigEditor configEditor) { private void setToolButton(Widget widget) { customPositionSizeWidget.setControlled(widget); + customPositionSizeWidget.setActive(!(widget instanceof IGuideWidget) || ((IGuideWidget) widget).isFixed()); toolButtons.setVisible(true); toolButtons.setSelfPosition(new Position(widget.getSelfPosition().x + widget.getSize().width / 2, widget.getSelfPosition().y)); } @@ -82,7 +102,7 @@ private void setToolButton(Widget widget) { private void delete(ClickData clickData) { removeWidget(selected); selected = null; - configEditor.loadConfigurator(null, null, true); + configEditor.loadConfigurator(null); toolButtons.setSelfPosition(new Position(-scrollYOffset, -scrollYOffset)); customPositionSizeWidget.setControlled(null); toolButtons.setVisible(false); @@ -98,15 +118,23 @@ private void moveDown(ClickData clickData) { public String getJsonString() { JsonObject json = new JsonObject(); - json.addProperty("section", ""); + json.addProperty("section", section); json.addProperty("title", title.content.get(0)); JsonArray array = new JsonArray(); json.add("stream", array); - stream.forEach(widget -> array.add(configMap.get(widget))); + stream.forEach(widget -> { + if (widget instanceof IGuideWidget) { + array.add(((IGuideWidget) widget).getConfig()); + } + }); JsonArray array2 = new JsonArray(); json.add("fixed", array2); - fixed.forEach(widget -> array2.add(configMap.get(widget))); + fixed.forEach(widget -> { + if (widget instanceof IGuideWidget) { + array2.add(((IGuideWidget) widget).getConfig()); + } + }); return new Gson().toJson(json); } @@ -134,7 +162,6 @@ public JsonObject addGuideWidget(IGuideWidget widget, boolean isFixed) { stream.add(guideWidget); this.addWidget(guideWidget); } - configMap.put(guideWidget, widgetConfig); return widgetConfig; } @@ -219,7 +246,6 @@ public void removeWidget(Widget widget) { fixed.remove(widget); } super.removeWidget(widget); - configMap.remove(widget); } @Override @@ -231,7 +257,7 @@ public boolean mouseClicked(int mouseX, int mouseY, int button) { for (Widget widget : fixed) { if (widget.isMouseOverElement(mouseX, mouseY)) { if (widget instanceof IGuideWidget && widget != selected) { - configEditor.loadConfigurator((IGuideWidget) widget, configMap.get(widget), true); + configEditor.loadConfigurator((IGuideWidget) widget); selected = widget; setToolButton(selected); } @@ -244,7 +270,7 @@ public boolean mouseClicked(int mouseX, int mouseY, int button) { for (Widget widget : stream) { if (widget.isMouseOverElement(mouseX, mouseY)) { if (widget instanceof IGuideWidget && widget != selected) { - configEditor.loadConfigurator((IGuideWidget) widget, configMap.get(widget), false); + configEditor.loadConfigurator((IGuideWidget) widget); selected = widget; setToolButton(selected); } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java index 6ad34a1117e..61669ee62d3 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java @@ -48,16 +48,22 @@ public int getMargin() { } public void setTitle(String config) { + int x = 5; + int y = 2; + int width = this.getSize().width - yBarWidth - 10; int height = 0; if (title != null) { height = title.getSize().height; + x = title.getSelfPosition().x; + y = title.getSelfPosition().y; removeWidget(title); } - title = new TextBoxWidget(5, 2, this.getSize().width - yBarWidth - 10, + title = new TextBoxWidget(5, 2, width, Collections.singletonList(config), 0, 15, 0xffffffff, 0x6fff0000, 0xff000000, true, true); this.addWidget(title); + title.setSelfPosition(new Position(x, y)); int offset = title.getSize().height - height; if (offset != 0) { for (Widget widget : stream) { @@ -126,7 +132,7 @@ public void onPositionUpdate(Widget widget, Position oldPosition) { if (oldPosition.y + widget.getSize().height == maxHeight) { maxHeight = 0; for (Widget widget1 : widgets) { - maxHeight = Math.max(maxHeight, widget1.getSize().height + widget1.getSelfPosition().y); + maxHeight = Math.max(maxHeight, widget1.getSize().height + widget1.getSelfPosition().y + scrollYOffset); } } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java index 2111f319a7a..1d6cfa26d20 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java @@ -31,6 +31,7 @@ public abstract class GuideWidget extends Widget implements IGuideWidget { private static final Gson GSON = new Gson(); private transient boolean isFixed; protected transient GuidePageWidget page; + protected transient JsonObject config; public GuideWidget(int x, int y, int width, int height) { super(x, y, width, height); @@ -42,24 +43,32 @@ public GuideWidget(){ public abstract String getRegistryName(); - public void updateValue(String field, JsonElement value) { - try { - Field f = this.getClass().getField(field); - if (value.isJsonNull()) { // default - f.set(this, f.get(GuidePageWidget.REGISTER_WIDGETS.get(getRegistryName()))); - } else { - f.set(this, new Gson().fromJson(value, f.getType())); + public void updateValue(String field) { + if (config != null && config.has(field)) { + try { + Field f = this.getClass().getField(field); + JsonElement value = config.get(field); + if (value.isJsonNull()) { // default + f.set(this, f.get(GuidePageWidget.REGISTER_WIDGETS.get(getRegistryName()))); + } else { + f.set(this, new Gson().fromJson(value, f.getType())); + } + if (isFixed) { + initFixed(); + } else { + initStream(); + } + } catch (Exception e) { } - if (isFixed) { - initFixed(); - } else { - initStream(); - } - } catch (Exception e) { - e.printStackTrace(); } } + @Override + public JsonObject getConfig() { + return config; + } + + @Override public boolean isFixed() { return isFixed; } @@ -100,17 +109,18 @@ public void setSelfPosition(Position selfPosition) { @Override public JsonObject getTemplate(boolean isFixed) { JsonObject template = new JsonObject(); + template.addProperty("type", getRegistryName()); if (isFixed) { template.addProperty("x", 0); template.addProperty("y", 0); template.addProperty("width", 100); template.addProperty("height", 100); } - template.addProperty("ref", ref); - template.addProperty("stroke", stroke); - template.addProperty("stroke_width", stroke_width); - template.addProperty("fill", fill); - template.addProperty("link", link); + template.addProperty("ref", (String) null); + template.addProperty("stroke", (String) null); + template.addProperty("stroke_width", (String) null); + template.addProperty("fill", (String) null); + template.addProperty("link", (String) null); template.add("hover_text", new Gson().toJsonTree(hover_text)); return template; } @@ -136,6 +146,7 @@ public Widget createStreamWidget(int x, int y, int pageWidth, JsonObject config) widget.isFixed = false; widget.setSelfPosition(new Position(x, y)); widget.setSize(new Size(pageWidth, 0)); + widget.config = config; return widget.initStream(); } @@ -145,6 +156,7 @@ public Widget createFixedWidget(int x, int y, int width, int height, JsonObject widget.isFixed = true; widget.setSelfPosition(new Position(x, y)); widget.setSize(new Size(width, height)); + widget.config = config; return widget.initFixed(); } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java index 25f10636c6a..bbdb75acb2c 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java @@ -12,10 +12,12 @@ import java.util.function.Consumer; public interface IGuideWidget { + JsonObject getConfig(); + boolean isFixed(); Widget createStreamWidget(int x, int y, int pageWidth, JsonObject config); Widget createFixedWidget(int x, int y, int width, int height, JsonObject config); void setPage(GuidePageWidget page); - void updateValue(String field, JsonElement value); + void updateValue(String field); String getRef(); JsonObject getTemplate(boolean isFixed); void loadConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, boolean isFixed, Consumer needUpdate); diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java index e9162a24121..ccdee1f6ace 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java @@ -50,8 +50,10 @@ public void loadConfigurator(DraggableScrollableWidgetGroup group, JsonObject co super.loadConfigurator(group, config, isFixed, needUpdate); group.addWidget(new SelectorConfigurator(5, group.getWidgetBottomHeight() + 5, config, "form", Arrays.asList("url", "item", "resource")).setOnUpdated(needUpdate)); group.addWidget(new StringConfigurator(5, group.getWidgetBottomHeight() + 5, config, "source").setOnUpdated(needUpdate)); - group.addWidget(new NumberConfigurator(5, group.getWidgetBottomHeight() + 5, config, "width").setOnUpdated(needUpdate)); - group.addWidget(new NumberConfigurator(5, group.getWidgetBottomHeight() + 5, config, "height").setOnUpdated(needUpdate)); + if (!isFixed) { + group.addWidget(new NumberConfigurator(5, group.getWidgetBottomHeight() + 5, config, "width").setOnUpdated(needUpdate)); + group.addWidget(new NumberConfigurator(5, group.getWidgetBottomHeight() + 5, config, "height").setOnUpdated(needUpdate)); + } } @Override @@ -61,6 +63,11 @@ public void updateScreen() { } } + @Override + public void onFixedPositionSizeChanged(Position position, Size size) { + super.onFixedPositionSizeChanged(position, size); + } + @Override protected Widget initStream() { int pageWidth = getSize().width; @@ -71,14 +78,12 @@ protected Widget initStream() { pageWidth = page.getPageWidth() - 2 * x; } this.setSelfPosition(new Position(x + (pageWidth - width) / 2, y)); - this.setSize(new Size(width, height)); return initFixed(); } @Override protected Widget initFixed() { - width = getSize().width; - height = getSize().height; + this.setSize(new Size(width, height)); switch (form) { case "url": image = new URLTexture(source); diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java index e6c2d7be156..02eb98e8e9e 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java @@ -58,11 +58,11 @@ public String getRegistryName() { @Override public JsonObject getTemplate(boolean isFixed) { JsonObject template = super.getTemplate(isFixed); - template.addProperty("space", space); - template.addProperty("fontSize", fontSize); - template.addProperty("fontColor", fontColor); - template.addProperty("isCenter", isCenter); - template.addProperty("isShadow", isShadow); + template.addProperty("space", (String) null); + template.addProperty("fontSize", (String) null); + template.addProperty("fontColor", (String) null); + template.addProperty("isCenter", (String) null); + template.addProperty("isShadow", (String) null); template.add("content", new Gson().toJsonTree(Arrays.asList("this is a", "textbox!"))); return template; } From 4eee9946a767882423234cf87494af9b1b5a8f32 Mon Sep 17 00:00:00 2001 From: Yefancy Date: Wed, 4 Aug 2021 23:13:01 +0800 Subject: [PATCH 14/58] translate + metaitem + simple machine --- src/main/java/gregtech/api/GregTechAPI.java | 17 +- .../gregtech/api/gui/widgets/LabelWidget.java | 1 - .../gregtech/api/items/metaitem/MetaItem.java | 15 ++ .../api/terminal/app/guide/GuideApp.java | 8 +- .../api/terminal/app/guide/ItemGuideApp.java | 49 +++- .../app/guide/MultiBlockGuideApp.java | 42 ++- .../app/guide/SimpleMachineGuideApp.java | 39 ++- .../terminal/app/guide/TutorialGuideApp.java | 41 ++- .../DraggableScrollableWidgetGroup.java | 1 + .../gui/widgets/TextEditorWidget.java | 243 ++++++++++++++++-- .../gui/widgets/guide/GuideConfigEditor.java | 43 +++- .../widgets/guide/GuidePageEditorWidget.java | 5 + .../gui/widgets/guide/GuideWidget.java | 1 + .../gui/widgets/guide/IGuideWidget.java | 3 - .../gui/widgets/guide/ImageWidget.java | 1 + .../gui/widgets/guide/TextTreeWidget.java | 20 +- .../configurator/TextListConfigurator.java | 10 +- .../{ => en_us}/api_0_guidepage.json | 0 .../tutorials/{ => en_us}/api_1_widget.json | 0 .../tutorials/{ => en_us}/api_2_textbox.json | 0 .../tutorials/{ => en_us}/api_3_image.json | 0 .../textures/gui/widget/formatting.png | Bin 0 -> 1890 bytes .../gregtech/textures/gui/widget/palette.png | Bin 0 -> 1921 bytes 23 files changed, 450 insertions(+), 89 deletions(-) rename src/main/resources/assets/gregtech/terminal/guide/tutorials/{ => en_us}/api_0_guidepage.json (100%) rename src/main/resources/assets/gregtech/terminal/guide/tutorials/{ => en_us}/api_1_widget.json (100%) rename src/main/resources/assets/gregtech/terminal/guide/tutorials/{ => en_us}/api_2_textbox.json (100%) rename src/main/resources/assets/gregtech/terminal/guide/tutorials/{ => en_us}/api_3_image.json (100%) create mode 100644 src/main/resources/assets/gregtech/textures/gui/widget/formatting.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/widget/palette.png diff --git a/src/main/java/gregtech/api/GregTechAPI.java b/src/main/java/gregtech/api/GregTechAPI.java index b20965d1667..2bb8bb9c81c 100644 --- a/src/main/java/gregtech/api/GregTechAPI.java +++ b/src/main/java/gregtech/api/GregTechAPI.java @@ -4,6 +4,7 @@ import gregtech.api.metatileentity.MetaTileEntity; import gregtech.api.metatileentity.multiblock.MultiblockControllerBase; import gregtech.api.terminal.app.guide.MultiBlockGuideApp; +import gregtech.api.terminal.app.guide.SimpleMachineGuideApp; import gregtech.api.unification.OreDictUnifier; import gregtech.api.unification.material.Materials; import gregtech.api.unification.material.type.DustMaterial; @@ -14,6 +15,8 @@ import gregtech.api.util.IBlockOre; import gregtech.common.items.MetaItems; import gregtech.common.metatileentities.electric.multiblockpart.MetaTileEntityMultiblockPart; +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.I18n; import net.minecraft.util.ResourceLocation; import java.util.HashMap; @@ -36,7 +39,19 @@ public class GregTechAPI { public static T registerMetaTileEntity(int id, T sampleMetaTileEntity) { META_TILE_ENTITY_REGISTRY.register(id, sampleMetaTileEntity.metaTileEntityId, sampleMetaTileEntity); if (sampleMetaTileEntity instanceof MultiblockControllerBase || sampleMetaTileEntity instanceof MetaTileEntityMultiblockPart) { - MultiBlockGuideApp.registerMultiBlock(sampleMetaTileEntity); + MultiBlockGuideApp.registerMultiBlock(sampleMetaTileEntity, "default"); + } else { + SimpleMachineGuideApp.registerSimpleMachine(sampleMetaTileEntity, "default"); + } + return sampleMetaTileEntity; + } + + public static T registerMetaTileEntity(int id, T sampleMetaTileEntity, String section) { + META_TILE_ENTITY_REGISTRY.register(id, sampleMetaTileEntity.metaTileEntityId, sampleMetaTileEntity); + if (sampleMetaTileEntity instanceof MultiblockControllerBase || sampleMetaTileEntity instanceof MetaTileEntityMultiblockPart) { + MultiBlockGuideApp.registerMultiBlock(sampleMetaTileEntity, section); + } else { + SimpleMachineGuideApp.registerSimpleMachine(sampleMetaTileEntity, section); } return sampleMetaTileEntity; } diff --git a/src/main/java/gregtech/api/gui/widgets/LabelWidget.java b/src/main/java/gregtech/api/gui/widgets/LabelWidget.java index dc582bba3d2..cf75cb77523 100644 --- a/src/main/java/gregtech/api/gui/widgets/LabelWidget.java +++ b/src/main/java/gregtech/api/gui/widgets/LabelWidget.java @@ -4,7 +4,6 @@ import gregtech.api.gui.Widget; import gregtech.api.util.Position; import gregtech.api.util.Size; -import gregtech.common.ConfigHolder; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.renderer.GlStateManager; diff --git a/src/main/java/gregtech/api/items/metaitem/MetaItem.java b/src/main/java/gregtech/api/items/metaitem/MetaItem.java index 99793608c8f..cf8505a7003 100644 --- a/src/main/java/gregtech/api/items/metaitem/MetaItem.java +++ b/src/main/java/gregtech/api/items/metaitem/MetaItem.java @@ -18,6 +18,7 @@ import gregtech.api.items.gui.PlayerInventoryHolder; import gregtech.api.items.metaitem.stats.*; import gregtech.api.recipes.ingredients.IntCircuitIngredient; +import gregtech.api.terminal.app.guide.ItemGuideApp; import gregtech.api.unification.OreDictUnifier; import gregtech.api.unification.material.type.Material; import gregtech.api.unification.ore.OrePrefix; @@ -220,6 +221,20 @@ public final T addItem(int metaValue, String unlocalizedName) { } metaItems.put((short) metaValue, metaValueItem); names.put(unlocalizedName, metaValueItem); + ItemGuideApp.registerItem(metaValueItem, "default"); + return metaValueItem; + } + + public final T addItem(int metaValue, String unlocalizedName, String section) { + Validate.inclusiveBetween(0, Short.MAX_VALUE - 1, metaValue + metaItemOffset, "MetaItem ID should be in range from 0 to Short.MAX_VALUE-1"); + T metaValueItem = constructMetaValueItem((short) metaValue, unlocalizedName); + if (metaItems.containsKey((short) metaValue)) { + T registeredItem = metaItems.get((short) metaValue); + throw new IllegalArgumentException(String.format("MetaId %d is already occupied by item %s (requested by item %s)", metaValue, registeredItem.unlocalizedName, unlocalizedName)); + } + metaItems.put((short) metaValue, metaValueItem); + names.put(unlocalizedName, metaValueItem); + ItemGuideApp.registerItem(metaValueItem, section); return metaValueItem; } diff --git a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java index 67568dc5fcf..63bde426b50 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java @@ -45,7 +45,10 @@ public AbstractApplication createApp(boolean isClient, NBTTagCompound nbt) { } app.pageWidget = new GuidePageWidget(133, 0, 200, 232, 5); if (leaf.isLeaf() && leaf.content != null) { - app.pageWidget.loadJsonConfig(leaf.content.getSecond()); + JsonObject page = getPage(leaf.content); + if (page != null) { + app.pageWidget.loadJsonConfig(page); + } } app.addWidget(app.pageWidget); }, this::itemIcon, this::itemName).setNodeTexture(GuiTextures.BORDERED_BACKGROUND).setLeafTexture(GuiTextures.SLOT_DARKENED) @@ -70,8 +73,9 @@ protected String itemName(T item) { return null; } + protected abstract JsonObject getPage(T item); - protected abstract TreeNode> getTree(); + protected abstract TreeNode getTree(); public static JsonObject getConfig(String fileName) { try { diff --git a/src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java index a79e4d4acc6..56d01160792 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java @@ -1,34 +1,71 @@ package gregtech.api.terminal.app.guide; import com.google.gson.JsonObject; +import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.resources.ItemStackTexture; import gregtech.api.items.metaitem.MetaItem; import gregtech.api.metatileentity.MetaTileEntity; import gregtech.api.terminal.util.TreeNode; import gregtech.common.items.MetaItems; +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.Language; import net.minecraft.util.Tuple; import net.minecraftforge.fml.common.FMLCommonHandler; -public class ItemGuideApp extends GuideApp> { - private static TreeNode, JsonObject>> ROOT; +import java.util.HashMap; +import java.util.Map; + +public class ItemGuideApp extends GuideApp.MetaValueItem> { + private static TreeNode.MetaValueItem> ROOT; + private static Map.MetaValueItem, JsonObject> MAP; + private static Language language; + private static JsonObject DEFAULT; static { if (FMLCommonHandler.instance().getSide().isClient()) { ROOT = new TreeNode<>(0,"root"); DEFAULT = getConfig("terminal/guide/items/default.json"); + MAP = new HashMap<>(); } } public ItemGuideApp() { - super("Items Machines", new ItemStackTexture(MetaItems.SCANNER.getStackForm())); + super("Items", new ItemStackTexture(MetaItems.SCANNER.getStackForm())); } @Override - protected TreeNode, JsonObject>> getTree() { - return ROOT; + protected IGuiTexture itemIcon(MetaItem.MetaValueItem item) { + return new ItemStackTexture(item.getStackForm()); + } + + @Override + protected JsonObject getPage(MetaItem.MetaValueItem item) { + Language currentLanguage = Minecraft.getMinecraft().getLanguageManager().getCurrentLanguage(); + if (!currentLanguage.equals(language)) { + language = currentLanguage; + MAP.clear(); + } + if (!MAP.containsKey(item)) { + JsonObject config = getConfig("terminal/guide/items/" + currentLanguage.getLanguageCode() + "/" + item.unlocalizedName + ".json"); + if (config == null && !currentLanguage.getLanguageCode().equals("en_us")) { + config = getConfig("terminal/guide/items/" + "en_us/" + item.unlocalizedName + ".json"); + } + MAP.put(item, config); + } + if (MAP.get(item) == null) { + return DEFAULT; + } + return MAP.get(item); } - public static void registerItem(MetaTileEntity mte) { + @Override + protected TreeNode.MetaValueItem> getTree() { + return ROOT; + } + public static void registerItem(MetaItem.MetaValueItem item, String section) { + if (FMLCommonHandler.instance().getSide().isClient()) { + ROOT.getOrCreateChild(section).addContent(String.format("metaitem.%s.name", item.unlocalizedName), item); + } } } diff --git a/src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java index 311e0dbec03..3324866003d 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java @@ -6,16 +6,25 @@ import gregtech.api.metatileentity.MetaTileEntity; import gregtech.api.terminal.util.TreeNode; import gregtech.common.metatileentities.MetaTileEntities; +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.Language; import net.minecraft.util.Tuple; import net.minecraftforge.fml.common.FMLCommonHandler; +import java.util.HashMap; +import java.util.Map; + public class MultiBlockGuideApp extends GuideApp { - private static TreeNode> ROOT; + private static TreeNode ROOT; + private static Map MAP; + private static Language language; + private static JsonObject DEFAULT; static { if (FMLCommonHandler.instance().getSide().isClient()) { ROOT = new TreeNode<>(0, "root"); DEFAULT = getConfig("terminal/guide/multiblocks/default.json"); + MAP = new HashMap<>(); } } @@ -24,7 +33,7 @@ public MultiBlockGuideApp() { } @Override - protected TreeNode> getTree() { + protected TreeNode getTree() { return ROOT; } @@ -33,14 +42,29 @@ protected IGuiTexture itemIcon(MetaTileEntity item) { return new ItemStackTexture(item.getStackForm()); } - public static void registerMultiBlock(MetaTileEntity mte) { - if (FMLCommonHandler.instance().getSide().isClient()) { - JsonObject config = getConfig("terminal/guide/multiblocks/" + mte.metaTileEntityId.getPath() + ".json"); - if (config == null) { - ROOT.getOrCreateChild("default").addContent(mte.getMetaFullName(), new Tuple<>(mte, DEFAULT)); - } else { - ROOT.getOrCreateChild(config.get("section").getAsString()).addContent(mte.getMetaFullName(), new Tuple<>(mte, config)); + @Override + protected JsonObject getPage(MetaTileEntity mte) { + Language currentLanguage = Minecraft.getMinecraft().getLanguageManager().getCurrentLanguage(); + if (!currentLanguage.equals(language)) { + language = currentLanguage; + MAP.clear(); + } + if (!MAP.containsKey(mte)) { + JsonObject config = getConfig("terminal/guide/multiblocks/" + currentLanguage.getLanguageCode() + "/" + mte.metaTileEntityId.getPath() + ".json"); + if (config == null && !currentLanguage.getLanguageCode().equals("en_us")) { + config = getConfig("terminal/guide/multiblocks/" + "en_us/" + mte.metaTileEntityId.getPath() + ".json"); } + MAP.put(mte, config); + } + if (MAP.get(mte) == null) { + return DEFAULT; + } + return MAP.get(mte); + } + + public static void registerMultiBlock(MetaTileEntity mte, String section) { + if (FMLCommonHandler.instance().getSide().isClient()) { + ROOT.getOrCreateChild(section).addContent(mte.getMetaFullName(), mte); } } diff --git a/src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java index 633e4943ad9..1447f5cce7f 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java @@ -6,16 +6,25 @@ import gregtech.api.metatileentity.MetaTileEntity; import gregtech.api.terminal.util.TreeNode; import gregtech.common.metatileentities.MetaTileEntities; +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.Language; import net.minecraft.util.Tuple; import net.minecraftforge.fml.common.FMLCommonHandler; +import java.util.HashMap; +import java.util.Map; + public class SimpleMachineGuideApp extends GuideApp { - private static TreeNode> ROOT; + private static TreeNode ROOT; + private static Map MAP; + private static Language language; + private static JsonObject DEFAULT; static { if (FMLCommonHandler.instance().getSide().isClient()) { ROOT = new TreeNode<>(0,"root"); DEFAULT = getConfig("terminal/guide/simplemachines/default.json"); + MAP = new HashMap<>(); } } @@ -24,7 +33,7 @@ public SimpleMachineGuideApp() { } @Override - protected TreeNode> getTree() { + protected TreeNode getTree() { return ROOT; } @@ -33,14 +42,26 @@ protected IGuiTexture itemIcon(MetaTileEntity item) { return new ItemStackTexture(item.getStackForm()); } - public static void registerSimpleMachine(MetaTileEntity mte) { - if (FMLCommonHandler.instance().getSide().isClient()) { - JsonObject config = getConfig("terminal/guide/simplemachines/" + mte.metaTileEntityId.getPath() + ".json"); - if (config == null) { - ROOT.getOrCreateChild("default").addContent(mte.getMetaFullName(), new Tuple<>(mte, DEFAULT)); - } else { - ROOT.getOrCreateChild(config.get("section").getAsString()).addContent(mte.getMetaFullName(), new Tuple<>(mte, config)); + @Override + protected JsonObject getPage(MetaTileEntity mte) { + Language currentLanguage = Minecraft.getMinecraft().getLanguageManager().getCurrentLanguage(); + if (!currentLanguage.equals(language)) { + language = currentLanguage; + MAP.clear(); + } + if (!MAP.containsKey(mte)) { + JsonObject config = getConfig("terminal/guide/simplemachines/" + currentLanguage.getLanguageCode() + "/" + mte.metaTileEntityId.getPath() + ".json"); + if (config == null && !currentLanguage.getLanguageCode().equals("en_us")) { + config = getConfig("terminal/guide/simplemachines/" + "en_us/" + mte.metaTileEntityId.getPath() + ".json"); } + MAP.put(mte, config); + } + return MAP.get(mte); + } + + public static void registerSimpleMachine(MetaTileEntity mte, String section) { + if (FMLCommonHandler.instance().getSide().isClient()) { + ROOT.getOrCreateChild(section).addContent(mte.getMetaFullName(), mte); } } } diff --git a/src/main/java/gregtech/api/terminal/app/guide/TutorialGuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/TutorialGuideApp.java index 32aad915681..da723eb8f9d 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/TutorialGuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/TutorialGuideApp.java @@ -3,7 +3,10 @@ import com.google.gson.JsonObject; import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.resources.ItemStackTexture; +import gregtech.api.metatileentity.MetaTileEntity; import gregtech.api.terminal.util.TreeNode; +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.Language; import net.minecraft.init.Items; import net.minecraft.util.Tuple; import net.minecraftforge.fml.common.FMLCommonHandler; @@ -12,22 +15,29 @@ import java.io.IOException; import java.io.InputStreamReader; import java.net.URL; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; + +public class TutorialGuideApp extends GuideApp { + private static TreeNode ROOT; + private static Map MAP; + private static Language language; -public class TutorialGuideApp extends GuideApp { - private static TreeNode> ROOT; static { if (FMLCommonHandler.instance().getSide().isClient()) { ROOT = new TreeNode<>(0,"root"); + MAP = new HashMap<>(); try { - URL folder = ClassLoader.getSystemClassLoader().getResource("assets/gregtech/terminal/guide/tutorials"); + URL folder = ClassLoader.getSystemClassLoader().getResource("assets/gregtech/terminal/guide/tutorials/en_us"); if (folder != null) { new BufferedReader(new InputStreamReader(folder.openStream())).lines().forEach(file->{ - JsonObject config = getConfig("terminal/guide/tutorials/" + file); + JsonObject config = getConfig("terminal/guide/tutorials/en_us/" + file); if (config != null) { - ROOT.getOrCreateChild(config.get("section").getAsString()).addContent(config.get("title").getAsString(), new Tuple<>(null, config)); + ROOT.getOrCreateChild(config.get("section").getAsString()).addContent(config.get("title").getAsString(), file); + MAP.put(file, config); } }); - } } catch (IOException e) { e.printStackTrace(); @@ -40,7 +50,24 @@ public TutorialGuideApp() { } @Override - protected TreeNode> getTree() { + protected JsonObject getPage(String file) { + Language currentLanguage = Minecraft.getMinecraft().getLanguageManager().getCurrentLanguage(); + if (!currentLanguage.equals(language)) { + language = currentLanguage; + MAP.clear(); + } + if (!MAP.containsKey(file)) { + JsonObject config = getConfig("terminal/guide/tutorials/" + currentLanguage.getLanguageCode() + "/" + file); + if (config == null && !currentLanguage.getLanguageCode().equals("en_us")) { + config = getConfig("terminal/guide/tutorials/" + "en_us/" + file); + } + MAP.put(file, config); + } + return MAP.get(file); + } + + @Override + protected TreeNode getTree() { return ROOT; } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java b/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java index 8ceea9e6414..a00cfa35efe 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java @@ -184,6 +184,7 @@ protected void setScrollXOffset(int scrollXOffset) { protected void setScrollYOffset(int scrollYOffset) { if (scrollYOffset == this.scrollYOffset) return; + if (scrollYOffset < 0) scrollYOffset = 0; int offset = scrollYOffset - this.scrollYOffset; this.scrollYOffset = scrollYOffset; for (Widget widget : widgets) { diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/TextEditorWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/TextEditorWidget.java index e719f2422c4..98622a29dbe 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/TextEditorWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/TextEditorWidget.java @@ -2,6 +2,7 @@ import gregtech.api.gui.IRenderContext; import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.resources.TextureArea; import gregtech.api.gui.widgets.WidgetGroup; import gregtech.api.util.Position; import gregtech.api.util.Size; @@ -13,20 +14,24 @@ import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; -import java.awt.*; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class TextEditorWidget extends WidgetGroup { + private static final TextureArea PALETTE = TextureArea.fullImage("textures/gui/widget/palette.png"); + private static final TextureArea STYLE = TextureArea.fullImage("textures/gui/widget/formatting.png"); private final TextPanelWidget textPanelWidget; - public TextEditorWidget(int x, int y, int width, int height, String text, Consumer stringUpdate) { - super(new Position(x, y), new Size(width, height)); - textPanelWidget = new TextPanelWidget(0, 10, width, height-10, text, stringUpdate); - this.addWidget(new RectButtonWidget(0, 0, 20, 10, 1).setFill(new Color(109, 229, 154, 141).getRGB()).setHoverText("update").setClickListener(d->{ - if (stringUpdate != null) { - stringUpdate.accept(textPanelWidget.content); - } - })); + + public TextEditorWidget(int x, int y, int width, int height, String initText,Consumer stringUpdate, boolean allowToolBox) { + super(new Position(x, y), new Size(Math.max(width, allowToolBox ? 80 : width), Math.max(height, allowToolBox ? 32 : height))); + textPanelWidget = new TextPanelWidget(0, 32, Math.max(width, allowToolBox ? 80 : width), Math.max(height, allowToolBox ? 32 : height) - 32, initText, stringUpdate); this.addWidget(textPanelWidget); + if (allowToolBox) { + initToolBox(); + } } public TextEditorWidget setBackground(IGuiTexture background) { @@ -34,14 +39,69 @@ public TextEditorWidget setBackground(IGuiTexture background) { return this; } + @Override + public void setActive(boolean active) { + super.setActive(active); + textPanelWidget.setActive(active); + } + + private void initToolBox() { + TextFormatting[] formatting = TextFormatting.values(); + // palette + for (int y = 0; y < 4; y++) { + for (int x = 0; x < 4; x++) { + TextFormatting colorFormatting = formatting[y * 4 + x]; + this.addWidget(new RectButtonWidget(x * 8, y * 8, 8, 8, 1) + .setToggleButton(PALETTE.getSubArea(0.5 + x * 0.125, y * 0.25, 0.125, 0.25), + (cd, pressed)-> { + if (pressed) { + textPanelWidget.addFormatting(colorFormatting); + } else { + textPanelWidget.removeFormatting(colorFormatting); + } + }) + .setValueSupplier(true, ()-> colorFormatting == textPanelWidget.getFrontColorFormatting()) + .setIcon(PALETTE.getSubArea(x * 0.125, y * 0.25, 0.125, 0.25)) + .setColors(0, -1, 0)); + } + } + // style + for (int y = 0; y < 2; y++) { + for (int x = 0; x < 3; x++) { + TextFormatting styleFormatting = formatting[16 + y * 3 + x]; + if (styleFormatting == TextFormatting.RESET) return; + this.addWidget(new RectButtonWidget(x * 16 + 32, y * 16, 16, 16, 1) + .setToggleButton(STYLE.getSubArea(0.5 + x * 1.0 / 6, y * 0.5, 1.0 / 6, 0.5), + (cd, pressed)-> { + if (pressed) { + textPanelWidget.addFormatting(styleFormatting); + } else { + textPanelWidget.removeFormatting(styleFormatting); + } + }) + .setValueSupplier(true, ()-> textPanelWidget.getFrontStyleFormatting().contains(styleFormatting)) + .setIcon(STYLE.getSubArea(x * 1.0 / 6, y * 0.5, 1.0 / 6, 0.5)) + .setColors(0, -1, 0)); + } + } + } + private static class TextPanelWidget extends DraggableScrollableWidgetGroup { - private final static int SPACE = 0; - private int updateCount; - private String content; - private int textHeight; - private final Consumer stringUpdate; + public final static int SPACE = 0; + public int updateCount; + public String content; + public int textHeight; + public final Consumer stringUpdate; + public TextFormatting frontColor; + public List frontStyle; + @SideOnly(Side.CLIENT) - private FontRenderer fontRenderer; + public FontRenderer fontRenderer; + @SideOnly(Side.CLIENT) + private static final Pattern R_CODE_PATTERN = Pattern.compile("(?i)§[R]"); + @SideOnly(Side.CLIENT) + private static final Pattern COLOR_CODE_PATTERN = Pattern.compile("(?i)§[0-9A-F]"); + public TextPanelWidget(int x, int y, int width, int height, String text, Consumer stringUpdate) { super(x, y, width, height); @@ -50,11 +110,13 @@ public TextPanelWidget(int x, int y, int width, int height, String text, Consume if (isClientSide()) { fontRenderer = Minecraft.getMinecraft().fontRenderer; textHeight = fontRenderer.getWordWrappedHeight(content, width - yBarWidth); + frontColor = null; + frontStyle = new ArrayList<>(); } } @Override - protected int getMaxHeight() { + public int getMaxHeight() { return textHeight + SPACE + xBarHeight; } @@ -65,32 +127,156 @@ public void updateScreen() { @Override public boolean keyTyped(char typedChar, int keyCode) { - if(!focus) return false; + if(!focus || !isActive()) return false; if (GuiScreen.isKeyComboCtrlV(keyCode)) { this.pageInsertIntoCurrent(GuiScreen.getClipboardString()); + findFrontFormatting(); } else { switch(keyCode) { case 14: if (!content.isEmpty()) { this.pageSetCurrent(content.substring(0, content.length() - 1)); } - return true; + break; case 28: case 156: this.pageInsertIntoCurrent("\n"); - return true; + break; default: if (ChatAllowedCharacters.isAllowedCharacter(typedChar)) { this.pageInsertIntoCurrent(Character.toString(typedChar)); } } } + if (getMaxHeight() > getSize().height) { + setScrollYOffset(getMaxHeight() - getSize().height); + } else { + setScrollYOffset(0); + } return true; } - private void pageSetCurrent(String string) { + private static TextFormatting lookAheadChars(final String content, int index) { + if (index > 1 && content.charAt(index - 2) == '§') { + int t = content.charAt(index - 1); + if ('0' <= t && t <= '9'){ + return TextFormatting.values()[t - '0']; + } else if ('a' <= t && t <= 'f'){ + return TextFormatting.values()[t - 'a' + 10]; + } else if ('k' <= t && t <= 'o') { + return TextFormatting.values()[t - 'k' + 16]; + } else if (t == 'r') { + return TextFormatting.values()[21]; + } + } + return null; + } + + public static String cleanUpFormatting(final String content) { + Set removed = new HashSet<>(); + Matcher marcher = R_CODE_PATTERN.matcher(content); + while (marcher.find()) { + int index = marcher.start(); + while (index > 1) { + TextFormatting ahead = lookAheadChars(content, index); + if (ahead != null) { + removed.add(index - 2); + } else { + break; + } + index -= 2; + } + } + marcher = COLOR_CODE_PATTERN.matcher(content); + while (marcher.find()) { + int index = marcher.start(); + while (index > 1) { + TextFormatting ahead = lookAheadChars(content, index); + if (ahead == null) { + break; + } else if (TextFormatting.RESET != ahead){ + if (!removed.add(index - 2)) { + break; + } + } else { + break; + } + index -= 2; + } + } + StringBuilder builder = new StringBuilder(); + AtomicInteger start = new AtomicInteger(); + removed.stream().sorted().forEach(remove->{ + builder.append(content, start.get(), remove); + start.set(remove + 2); + }); + builder.append(content, start.get(), content.length()); + return builder.toString(); + } + + private void findFrontFormatting() { + int lastReset = content.lastIndexOf("§r"); + int lastColor = -1; + frontColor = null; + frontStyle.clear(); + for (TextFormatting value : TextFormatting.values()) { + int index = content.lastIndexOf(value.toString()); + if (index > lastReset) { + if (value.isColor()) { + if (index > lastColor) { + lastColor = index; + frontColor = value; + } + } else if (value.isFancyStyling() && index > lastColor) { + frontStyle.add(value); + } + } + } + } + + public void addFormatting(TextFormatting formatting) { + if (formatting.isColor()) { + frontColor = formatting; + pageInsertIntoCurrent(formatting.toString()); + for (TextFormatting style : frontStyle) { + pageInsertIntoCurrent(style.toString()); + } + } else if (formatting.isFancyStyling()){ + if (frontStyle.contains(formatting)) { + return; + } + frontStyle.add(formatting); + pageInsertIntoCurrent(formatting.toString()); + } + } + + public void removeFormatting(TextFormatting formatting) { + if (formatting.isColor()) { + frontColor = null; + pageInsertIntoCurrent(TextFormatting.RESET.toString()); + frontStyle.forEach(style->pageInsertIntoCurrent(style.toString())); + } else if (formatting.isFancyStyling()) { + pageInsertIntoCurrent(TextFormatting.RESET.toString()); + if (frontColor != null) { + pageInsertIntoCurrent(frontColor.toString()); + } + frontStyle.remove(formatting); + frontStyle.forEach(style->pageInsertIntoCurrent(style.toString())); + } + } + + public TextFormatting getFrontColorFormatting() { + return frontColor; + } + + public List getFrontStyleFormatting() { + return frontStyle; + } + + public void pageSetCurrent(String string) { if (!content.equals(string)) { - content = string; + content = cleanUpFormatting(string); + findFrontFormatting(); if(stringUpdate != null) { stringUpdate.accept(content); } @@ -98,8 +284,8 @@ private void pageSetCurrent(String string) { } } - private void pageInsertIntoCurrent(String string) { - content += string; + public void pageInsertIntoCurrent(String string) { + content = cleanUpFormatting(content + string); if(stringUpdate != null) { stringUpdate.accept(content); } @@ -107,9 +293,9 @@ private void pageInsertIntoCurrent(String string) { } @Override - protected boolean hookDrawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + public boolean hookDrawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { String contentString = content; - if (focus) { + if (focus && isActive()) { if (this.fontRenderer.getBidiFlag()) { contentString += "_"; } else if (this.updateCount / 6 % 2 == 0) { @@ -118,7 +304,12 @@ protected boolean hookDrawInBackground(int mouseX, int mouseY, float partialTick contentString += TextFormatting.GRAY + "_"; } } - this.fontRenderer.drawSplitString(contentString, getPosition().x, getPosition().y + SPACE, getSize().width - yBarWidth, 0); + int x = getPosition().x - scrollXOffset; + int y = getPosition().y + SPACE - scrollYOffset; + for (String textLine : this.fontRenderer.listFormattedStringToWidth(contentString, getSize().width - yBarWidth)) { + fontRenderer.drawString(textLine, x, y, 0xff000000, false); + y += fontRenderer.FONT_HEIGHT; + } return true; } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java index 5de5d4214aa..10dfee6a877 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java @@ -47,13 +47,20 @@ public GuideConfigEditor(int x, int y, int width, int height) { addButton[1].setVisible(false); } }); -// addButton[0] = new CircleButtonWidget(100, -5, 5, 1, 3) -// .setColors(new Color(255, 255, 255, 0).getRGB(), -// new Color(255, 255, 255).getRGB(), -// new Color(146, 253, 118).getRGB()) -// .setIcon(GuiTextures.TERMINAL_ADD) -// .setHoverText("add stream") -// .setClickListener(this::getJson); + this.addWidget(new CircleButtonWidget(100, -5, 5, 1, 3) + .setColors(new Color(255, 255, 255, 0).getRGB(), + new Color(255, 255, 255).getRGB(), + new Color(243, 208, 116).getRGB()) + .setIcon(GuiTextures.TERMINAL_ADD) + .setHoverText("Import Guide") + .setClickListener(this::loadJson)); + this.addWidget(new CircleButtonWidget(120, -5, 5, 1, 3) + .setColors(new Color(255, 255, 255, 0).getRGB(), + new Color(255, 255, 255).getRGB(), + new Color(146, 253, 118).getRGB()) + .setIcon(GuiTextures.TERMINAL_ADD) + .setHoverText("Export Config") + .setClickListener(this::getJson)); addButton[0] = new CircleButtonWidget(115, 15, 8, 1, 8) .setColors(new Color(255, 255, 255, 0).getRGB(), new Color(255, 255, 255).getRGB(), @@ -68,6 +75,8 @@ public GuideConfigEditor(int x, int y, int width, int height) { .setIcon(GuiTextures.TERMINAL_ADD) .setHoverText("add fixed") .setClickListener(this::addFixed); + addButton[0].setVisible(false); + addButton[1].setVisible(false); this.addWidget(addButton[0]); this.addWidget(addButton[1]); } @@ -92,11 +101,21 @@ private DraggableScrollableWidgetGroup createPageConfig() { .setValidator(s->true)); group.addWidget(new ImageWidget(5, 48,116, 1, new ColorRectTexture(-1))); group.addWidget(new LabelWidget(5, 55, "title", -1).setShadow(true)); - group.addWidget(new TextEditorWidget(5, 65, 116, 40, "Template", s->{ + group.addWidget(new TextEditorWidget(5, 65, 116, 70, "Template", s->{ if (pageEditor != null) { pageEditor.setTitle(s); } - }).setBackground(new ColorRectTexture(0xA3FFFFFF))); + }, true).setBackground(new ColorRectTexture(0xA3FFFFFF))); +// group.addWidget(new ImageWidget(5, 148,116, 1, new ColorRectTexture(-1))); +// group.addWidget(new LabelWidget(5, 155, "translate key", -1).setShadow(true)); +// group.addWidget(new TextFieldWidget(5, 165, 116, 20, new ColorRectTexture(0x9f000000), null, null) +// .setTextResponder(s->{ +// if (pageEditor != null) { +// pageEditor.setTranslateKey(s); +// } +// }, true) +// .setMaxStringLength(Integer.MAX_VALUE) +// .setValidator(s->true)); return group; } @@ -131,6 +150,12 @@ public void loadConfigurator(IGuideWidget widget) { } } + private void loadJson(ClickData data) { + if(pageEditor != null) { + System.out.println(pageEditor.getJsonString()); + } + } + private void getJson(ClickData data) { if(pageEditor != null) { System.out.println(pageEditor.getJsonString()); diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java index bdf2b1dfb59..15df7a65329 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java @@ -26,6 +26,7 @@ public class GuidePageEditorWidget extends GuidePageWidget { private final CustomPositionSizeWidget customPositionSizeWidget; private GuideConfigEditor configEditor; private String section = "default"; +// private String translateKey = ""; public GuidePageEditorWidget(int xPosition, int yPosition, int width, int height, int margin) { super(xPosition, yPosition, width, height, margin); @@ -63,6 +64,10 @@ public void setSection(String section) { this.section = section; } +// public void setTranslateKey(String translateKey) { +// this.translateKey = translateKey; +// } + private void onPosSizeChanged(Position pos, Size size) { Widget widget = customPositionSizeWidget.getControlled(); if (widget instanceof IGuideWidget && ((IGuideWidget) widget).isFixed()) { diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java index 1d6cfa26d20..4adc3648aa6 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java @@ -17,6 +17,7 @@ import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.function.Consumer; public abstract class GuideWidget extends Widget implements IGuideWidget { diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java index bbdb75acb2c..99c387e7a83 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java @@ -1,10 +1,7 @@ package gregtech.api.terminal.gui.widgets.guide; -import com.google.gson.JsonElement; import com.google.gson.JsonObject; import gregtech.api.gui.Widget; -import gregtech.api.gui.widgets.WidgetGroup; -import gregtech.api.terminal.gui.IDraggable; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; import gregtech.api.util.Position; import gregtech.api.util.Size; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java index ccdee1f6ace..2a45c6d6530 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java @@ -14,6 +14,7 @@ import gregtech.api.util.Position; import gregtech.api.util.Size; import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.resources.I18n; import net.minecraft.item.Item; import net.minecraft.util.ResourceLocation; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java index da993835380..d7dca38ab5d 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java @@ -23,18 +23,18 @@ public class TextTreeWidget extends Widget { private static final int ITEM_HEIGHT = 11; protected int scrollOffset; - protected List>> list; - protected TreeNode> selected; + protected List> list; + protected TreeNode selected; protected IGuiTexture background; protected IGuiTexture nodeTexture; protected IGuiTexture leafTexture; - protected Consumer>> onSelected; + protected Consumer> onSelected; protected Function iconSupplier; protected Function nameSupplier; public TextTreeWidget(int xPosition, int yPosition, int width, int height, - TreeNode> root, - Consumer>> onSelected, + TreeNode root, + Consumer> onSelected, Function iconSupplier, Function nameSupplier) { super(new Position(xPosition, yPosition), new Size(width, height)); @@ -88,7 +88,7 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender for (int i = minToRender; i < maxToRender; i++) { GlStateManager.color(1,1,1,1); - TreeNode> node = list.get(i); + TreeNode node = list.get(i); int x = position.x + 10 * node.dimension; int y = position.y - scrollOffset + i * ITEM_HEIGHT; String name = node.key; @@ -99,9 +99,9 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender drawSolidRect(position.x, y, size.width, ITEM_HEIGHT, 0xffff0000); } if (node.content != null) { - String nameS = nameSupplier.apply(node.content.getFirst()); + String nameS = nameSupplier.apply(node.content); name = nameS == null ? name : nameS; - IGuiTexture icon = iconSupplier.apply(node.content.getFirst()); + IGuiTexture icon = iconSupplier.apply(node.content); if (icon != null) { icon.draw(x - 9, y + 1, 8, 8); } @@ -126,14 +126,14 @@ public boolean mouseClicked(int mouseX, int mouseY, int button) { if (this.isMouseOverElement(mouseX, mouseY)) { int index = ((mouseY - getPosition().y) + scrollOffset) / ITEM_HEIGHT; if (index < list.size()) { - TreeNode> node = list.get(index); + TreeNode node = list.get(index); if (node.isLeaf()) { if (node != this.selected) { this.selected = node; onSelected.accept(node); } } else if (node.children.size() > 0 && list.contains(node.children.get(0))){ - for (TreeNode> child : node.children) { + for (TreeNode child : node.children) { list.remove(child); } } else { diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/TextListConfigurator.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/TextListConfigurator.java index 9ec086e11f3..23a12ac1ead 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/TextListConfigurator.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/TextListConfigurator.java @@ -1,11 +1,9 @@ package gregtech.api.terminal.gui.widgets.guide.configurator; -import com.google.gson.Gson; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; +import com.google.gson.*; import gregtech.api.gui.resources.ColorRectTexture; import gregtech.api.terminal.gui.widgets.TextEditorWidget; +import net.minecraft.client.resources.I18n; import java.util.List; @@ -20,7 +18,7 @@ public TextListConfigurator(int x, int y, int height, JsonObject config, String List init = new Gson().fromJson(element, List.class); StringBuilder s = new StringBuilder(); for (int i = 0; i < init.size(); i++) { - s.append(init.get(i)); + s.append(I18n.format(init.get(i).toString())); if(i != init.size() - 1) { s.append('\n'); } @@ -30,7 +28,7 @@ public TextListConfigurator(int x, int y, int height, JsonObject config, String } private void init(int height, String init) { - this.addWidget(new TextEditorWidget(0, 15, 116, height, init, this::updateTextList).setBackground(new ColorRectTexture(0xA3FFFFFF))); + this.addWidget(new TextEditorWidget(0, 15, 116, height, init, this::updateTextList, true).setBackground(new ColorRectTexture(0xA3FFFFFF))); } private void updateTextList(String saved) { diff --git a/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_0_guidepage.json b/src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_0_guidepage.json similarity index 100% rename from src/main/resources/assets/gregtech/terminal/guide/tutorials/api_0_guidepage.json rename to src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_0_guidepage.json diff --git a/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_1_widget.json b/src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_1_widget.json similarity index 100% rename from src/main/resources/assets/gregtech/terminal/guide/tutorials/api_1_widget.json rename to src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_1_widget.json diff --git a/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_2_textbox.json b/src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_2_textbox.json similarity index 100% rename from src/main/resources/assets/gregtech/terminal/guide/tutorials/api_2_textbox.json rename to src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_2_textbox.json diff --git a/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_3_image.json b/src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_3_image.json similarity index 100% rename from src/main/resources/assets/gregtech/terminal/guide/tutorials/api_3_image.json rename to src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_3_image.json diff --git a/src/main/resources/assets/gregtech/textures/gui/widget/formatting.png b/src/main/resources/assets/gregtech/textures/gui/widget/formatting.png new file mode 100644 index 0000000000000000000000000000000000000000..b6841a6f00f64a2b79ac2d2b747cdda210e90cfc GIT binary patch literal 1890 zcmcIle{9rL9Pf;5lK>8I7(uiY|3F!uShgb!{}A4_?{3}h+OF+( zH$*VNAE1dw7bgB78qt7Dwy6PPLKFf6bb?4CQw-S*8t@-sC>j#S;_LmA7{L8wlh^lN z`+1-5=li4I?rdzRn>l^{bb=seM(U*|JOex`%1iORabV(OJUw96ud@ka){r|&b}gN? zfFPzF)1oa-i@ZuyjFbneMhtl}DHEd!qI!A8gi1Sd$QVj!dWgDq_y|R6YKU6vlYwl8 zQL9$J(L&7|8=}g_b|t7%%a@VW84(ktkORp~DyiFICPZa-#x+Q` z$c<#!un_6<_-TdZy<{NhVf`TJ<*P_9U;_*YFf2y{Rs?>L3zGSZ!qzM`E;dOk^S1CV zM727ODKbnto%W}B3bhal=YMTqRlxCJqjjuh}?p-TAMh8Fl1WNsY{woCp=S(nFNurWmPI{;_t4 z=uJ&$jyBzjFzG##pM%*(+(|LE$#oC@O(&>R;VWsZkY__ zy27~4C6^H9-?_@ZyR8uw;JCZF%VJx_n_^=|I;OU8+pRfq;9G(ySs9UPqV+ouu3`1# zU`BOm!}_24$G&OvOuHeJtlRG!`(oa^%@dVfAN4=wOMNxa`O=J6tDD~2^u(H4`Nr7e zYv%Gqg~Im$uH?SiOSmH!r29{k}UR_4IAsF>>tW`L@G^cXard*T?2;yWTeV2RiWcvU$UGfz78n&Pyj7iCbIx zmL477J~Yw+9_*jJzvYx#K@25l4V@l5Ua{U=_VN#7sw1Czdefmx?c--JADv&-T|Kw% zrd;_6*mE&hcJ0EO-gvO}fkw(mXh-KEtFzn@-p?yB#dXC~h7+aZ;IeWqvh+HR?r qTXd%K!=AC{hbIRk4Sx;WKb9S$KP`LY{K0MRUocYJAPub8u=Q_&5QaJc literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/widget/palette.png b/src/main/resources/assets/gregtech/textures/gui/widget/palette.png new file mode 100644 index 0000000000000000000000000000000000000000..7accd700da76292a2da375d4e8ab73a4e66132f4 GIT binary patch literal 1921 zcmcIlTWs4@7CnDx4`?!6Ne7N$2P6`83REa7p!3$ zuXa3wAZ4G+;V!c)bbuGtq)U+02yms78bl*VOws0QI<7T%;Hp^>QwXB{`aT9HmLhOORfIa^ob$lPvG%(87g5Yq}KWJAzLX zY{8Wui<_p#6GSSNa;4lZRgV!A$8iKn6EuxO1a4#$Q%K{Av8Tuo1cs=~nklOaYB35C zwcqq(P-)(Uq*kI;j6#@Tz=*V<5tNIxTq*)Xq4lB3WC?AUO#{$MLGN9Ojc`T-L8#eTCvu)jA^{R031J2lMwLuyan)3fxOxviO4}uGG(MmM!Bq9I zswRqwYA>>&fdE={P*x;0W$d-|6yP8zn81(GBu(L@4=0&0#qbQrd)R8y$CG3p8iG|I z38t_yuqw&X%toN05Z|I0rl5$RCFsYXD3>ftycCsKw~wQ7Ho`=3hGyKj&j$qDO+`GS zo2D2x3Ua#O`JgKHTfwu==ZjWSMaWT#4==Hi2*jU1_(`wVd!l&0X3oOAytAgcU!d#*`XKBvH=s9DSREB;Q7KVA)~pH;|0;GbU!9q zDFzZ&crD*0dK=T3r%lBHBwZ)@d6=O_&6J>nh8T?Wf0Pz+FX@Ibu)gq(rTu>sUI?ie z7nB%)Et9}3R|u=QtJ6E~AI~q|D4!fH*Ewxp+C^crFKx!Sf-AnzpM-jvZ3%?;8 zAGta~wa(Sw-*g3i^Tp%)s=8f`(~AB8ADnNB4^+C|aA6PEZha{5QRlB_7R?OZTsbj0 zb>Zf&v5D8;UzypDleSly&mEp-;!|r2gnx8XG!)WpV9tw$AhS zuH}liXE)!N8-44{^zI|Jvpb}|`;K;_&z)Tnwd<3^+v+ztsupaOTGrm!P5!iMw~tr; z`33jAQ_Ef~+_010xIN^1j~hHqRsC@GtgnzFjj$)GgvsykYjhvh|Z}X=)9gY3zOB9|UQG A_W%F@ literal 0 HcmV?d00001 From 7a63134112d75e74a746328f9cf21f36f3c7da28 Mon Sep 17 00:00:00 2001 From: Yefancy Date: Wed, 4 Aug 2021 23:28:57 +0800 Subject: [PATCH 15/58] auto missing title --- .../java/gregtech/api/terminal/app/guide/ItemGuideApp.java | 1 + .../gregtech/api/terminal/app/guide/MultiBlockGuideApp.java | 1 + .../api/terminal/app/guide/SimpleMachineGuideApp.java | 4 ++++ 3 files changed, 6 insertions(+) diff --git a/src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java index 56d01160792..901524ab46a 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java @@ -53,6 +53,7 @@ protected JsonObject getPage(MetaItem.MetaValueItem item) { MAP.put(item, config); } if (MAP.get(item) == null) { + DEFAULT.addProperty("title", "Missing: §4" + item.unlocalizedName + ".json"); return DEFAULT; } return MAP.get(item); diff --git a/src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java index 3324866003d..599fcbc8848 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java @@ -57,6 +57,7 @@ protected JsonObject getPage(MetaTileEntity mte) { MAP.put(mte, config); } if (MAP.get(mte) == null) { + DEFAULT.addProperty("title", "Missing: §4" + mte.metaTileEntityId.getPath() + ".json"); return DEFAULT; } return MAP.get(mte); diff --git a/src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java index 1447f5cce7f..c72f24f7542 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java @@ -56,6 +56,10 @@ protected JsonObject getPage(MetaTileEntity mte) { } MAP.put(mte, config); } + if (MAP.get(mte) == null) { + DEFAULT.addProperty("title", "Missing: §4" + mte.metaTileEntityId.getPath() + ".json"); + return DEFAULT; + } return MAP.get(mte); } From acfdb97339c9a17580bf154b3cb60c6a5d30eca9 Mon Sep 17 00:00:00 2001 From: Yefancy Date: Sat, 7 Aug 2021 21:19:43 +0800 Subject: [PATCH 16/58] dd --- src/main/java/gregtech/api/gui/Widget.java | 7 +- .../api/gui/widgets/AbstractWidgetGroup.java | 38 ++- .../api/gui/widgets/PhantomFluidWidget.java | 33 ++- .../api/gui/widgets/PhantomSlotWidget.java | 2 + .../gregtech/api/gui/widgets/SlotWidget.java | 18 +- .../gregtech/api/gui/widgets/TabGroup.java | 3 + .../gregtech/api/gui/widgets/TankWidget.java | 12 +- .../api/gui/widgets/TextFieldWidget.java | 14 +- .../gregtech/api/gui/widgets/WidgetGroup.java | 11 + .../api/terminal/app/AbstractApplication.java | 89 +----- .../api/terminal/app/GuideEditorApp.java | 7 +- .../api/terminal/app/guide/GuideApp.java | 19 +- .../gui/widgets/AnimaWidgetGroup.java | 101 +++++++ .../gui/widgets/CircleButtonWidget.java | 9 + .../api/terminal/gui/widgets/ColorWidget.java | 21 +- .../gui/widgets/CustomPositionSizeWidget.java | 8 +- .../DraggableScrollableWidgetGroup.java | 40 ++- .../gui/widgets/RectButtonWidget.java | 3 + .../gui/widgets/TextEditorWidget.java | 13 +- .../terminal/gui/widgets/TreeListWidget.java | 198 +++++++++++++ .../gui/widgets/guide/CardWidget.java | 108 +++++++ .../gui/widgets/guide/GuideConfigEditor.java | 65 +++-- .../widgets/guide/GuidePageEditorWidget.java | 66 +++-- .../gui/widgets/guide/GuidePageWidget.java | 15 +- .../gui/widgets/guide/GuideWidget.java | 72 ++--- .../gui/widgets/guide/GuideWidgetGroup.java | 195 +++++++++++++ .../gui/widgets/guide/IGuideWidget.java | 33 ++- .../gui/widgets/guide/ImageWidget.java | 21 +- .../gui/widgets/guide/SlotListWidget.java | 126 ++++++++ .../gui/widgets/guide/TankListWidget.java | 119 ++++++++ .../gui/widgets/guide/TextBoxWidget.java | 12 +- .../gui/widgets/guide/TextTreeWidget.java | 150 ---------- .../configurator/BooleanConfigurator.java | 24 +- .../guide/configurator/ColorConfigurator.java | 23 +- .../configurator/ConfiguratorWidget.java | 35 ++- .../configurator/FluidStackConfigurator.java | 97 +++++++ .../configurator/ItemStackConfigurator.java | 101 +++++++ .../configurator/NumberConfigurator.java | 24 +- .../configurator/SelectorConfigurator.java | 32 +-- .../configurator/StringConfigurator.java | 22 +- .../configurator/TextListConfigurator.java | 48 ++-- .../gui/widgets/os/TerminalDialogWidget.java | 270 ++++++++++++++++++ .../gui/widgets/os/TerminalMenuWidget.java | 8 +- .../gui/widgets/os/TerminalOSWidget.java | 64 ++--- .../gregtech/api/terminal/util/FileTree.java | 65 +++++ .../gregtech/api/terminal/util/IContent.java | 4 - .../gregtech/api/terminal/util/TreeNode.java | 21 +- src/main/java/gregtech/api/util/SlotUtil.java | 3 +- .../textures/gui/terminal/cancel_disable.png | Bin 0 -> 3159 bytes .../textures/gui/terminal/cancel_hover.png | Bin 0 -> 3070 bytes .../textures/gui/terminal/cancel_normal.png | Bin 0 -> 3082 bytes .../textures/gui/terminal/ok_disable.png | Bin 0 -> 3322 bytes .../textures/gui/terminal/ok_hover.png | Bin 0 -> 3261 bytes .../textures/gui/terminal/ok_normal.png | Bin 0 -> 3278 bytes .../textures/gui/terminal/terminal_dialog.png | Bin 0 -> 5193 bytes 55 files changed, 1905 insertions(+), 564 deletions(-) create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/AnimaWidgetGroup.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/TreeListWidget.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/CardWidget.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidgetGroup.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/SlotListWidget.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/TankListWidget.java delete mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/FluidStackConfigurator.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ItemStackConfigurator.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalDialogWidget.java create mode 100644 src/main/java/gregtech/api/terminal/util/FileTree.java delete mode 100644 src/main/java/gregtech/api/terminal/util/IContent.java create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/cancel_disable.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/cancel_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/cancel_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/ok_disable.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/ok_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/ok_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/terminal_dialog.png diff --git a/src/main/java/gregtech/api/gui/Widget.java b/src/main/java/gregtech/api/gui/Widget.java index aecde19dcbf..8a741ea3ecd 100644 --- a/src/main/java/gregtech/api/gui/Widget.java +++ b/src/main/java/gregtech/api/gui/Widget.java @@ -414,6 +414,7 @@ public static void setColor(int color) { // ARGB @SideOnly(Side.CLIENT) public static void renderCircle(float x, float y, float r, int color, int segments) { + if (color == 0) return; Tessellator tessellator = Tessellator.getInstance(); BufferBuilder bufferbuilder = tessellator.getBuffer(); GlStateManager.enableBlend(); @@ -431,7 +432,7 @@ public static void renderCircle(float x, float y, float r, int color, int segmen @SideOnly(Side.CLIENT) public static void renderSector(float x, float y, float r, int color, int segments, int from, int to) { - if (from > to || from < 0) return; + if (from > to || from < 0 || color == 0) return; if(to > segments) to = segments; Tessellator tessellator = Tessellator.getInstance(); BufferBuilder bufferbuilder = tessellator.getBuffer(); @@ -464,6 +465,10 @@ protected boolean isCtrlDown() { return Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) || Keyboard.isKeyDown(Keyboard.KEY_RCONTROL); } + protected boolean isRemote() { + return gui.holder.isRemote(); + } + protected static boolean isClientSide() { return FMLCommonHandler.instance().getSide().isClient(); } diff --git a/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java b/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java index 1c7042b01c7..17cd3be18f2 100644 --- a/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java +++ b/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java @@ -21,10 +21,12 @@ public class AbstractWidgetGroup extends Widget implements IGhostIngredientTarget, IIngredientSlot { - public final List widgets = new ArrayList<>(); - private final WidgetGroupUIAccess groupUIAccess = new WidgetGroupUIAccess(); - private final boolean isDynamicSized; - private boolean initialized = false; + public transient final List widgets = new ArrayList<>(); + private transient final WidgetGroupUIAccess groupUIAccess = new WidgetGroupUIAccess(); + private transient final boolean isDynamicSized; + private transient boolean initialized = false; + protected transient List waitToRemoved; + public AbstractWidgetGroup(Position position) { super(position, Size.ZERO); @@ -94,6 +96,9 @@ protected Size computeDynamicSize() { } public void setVisible(boolean visible) { + if (this.isVisible() == visible) { + return; + } super.setVisible(visible); widgets.stream().flatMap(it -> it.getNativeWidgets().stream()).forEach(it -> it.setEnabled(visible)); } @@ -119,6 +124,13 @@ protected void addWidget(Widget widget) { } } + protected void waitToRemoved(Widget widget) { + if (waitToRemoved == null) { + waitToRemoved = new ArrayList<>(); + } + waitToRemoved.add(widget); + } + protected void removeWidget(Widget widget) { if (!widgets.contains(widget)) { throw new IllegalArgumentException("Not added"); @@ -210,6 +222,10 @@ public void detectAndSendChanges() { widget.detectAndSendChanges(); } } + if (waitToRemoved != null) { + waitToRemoved.forEach(this::removeWidget); + waitToRemoved = null; + } } @Override @@ -219,6 +235,10 @@ public void updateScreen() { widget.updateScreen(); } } + if (waitToRemoved != null) { + waitToRemoved.forEach(this::removeWidget); + waitToRemoved = null; + } } @Override @@ -244,7 +264,7 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender public boolean mouseWheelMove(int mouseX, int mouseY, int wheelDelta) { for (int i = widgets.size() - 1; i >= 0; i--) { Widget widget = widgets.get(i); - if(widget.isVisible() && widget.mouseWheelMove(mouseX, mouseY, wheelDelta)) { + if(widget.isVisible() && widget.isActive() && widget.mouseWheelMove(mouseX, mouseY, wheelDelta)) { return true; } } @@ -255,7 +275,7 @@ public boolean mouseWheelMove(int mouseX, int mouseY, int wheelDelta) { public boolean mouseClicked(int mouseX, int mouseY, int button) { for (int i = widgets.size() - 1; i >= 0; i--) { Widget widget = widgets.get(i); - if(widget.isVisible() && widget.mouseClicked(mouseX, mouseY, button)) { + if(widget.isVisible() && widget.isActive() && widget.mouseClicked(mouseX, mouseY, button)) { return true; } } @@ -266,7 +286,7 @@ public boolean mouseClicked(int mouseX, int mouseY, int button) { public boolean mouseDragged(int mouseX, int mouseY, int button, long timeDragged) { for (int i = widgets.size() - 1; i >= 0; i--) { Widget widget = widgets.get(i); - if(widget.isVisible() && widget.mouseDragged(mouseX, mouseY, button, timeDragged)) { + if(widget.isVisible() && widget.isActive() && widget.mouseDragged(mouseX, mouseY, button, timeDragged)) { return true; } } @@ -277,7 +297,7 @@ public boolean mouseDragged(int mouseX, int mouseY, int button, long timeDragged public boolean mouseReleased(int mouseX, int mouseY, int button) { for (int i = widgets.size() - 1; i >= 0; i--) { Widget widget = widgets.get(i); - if(widget.isVisible() && widget.mouseReleased(mouseX, mouseY, button)) { + if(widget.isVisible() && widget.isActive() && widget.mouseReleased(mouseX, mouseY, button)) { return true; } } @@ -288,7 +308,7 @@ public boolean mouseReleased(int mouseX, int mouseY, int button) { public boolean keyTyped(char charTyped, int keyCode) { for (int i = widgets.size() - 1; i >= 0; i--) { Widget widget = widgets.get(i); - if(widget.isVisible() && widget.keyTyped(charTyped, keyCode)) { + if(widget.isVisible() && widget.isActive() && widget.keyTyped(charTyped, keyCode)) { return true; } } diff --git a/src/main/java/gregtech/api/gui/widgets/PhantomFluidWidget.java b/src/main/java/gregtech/api/gui/widgets/PhantomFluidWidget.java index fe67542c1e5..7ff169bdf46 100644 --- a/src/main/java/gregtech/api/gui/widgets/PhantomFluidWidget.java +++ b/src/main/java/gregtech/api/gui/widgets/PhantomFluidWidget.java @@ -6,6 +6,7 @@ import gregtech.api.gui.Widget; import gregtech.api.gui.ingredient.IGhostIngredientTarget; import gregtech.api.gui.ingredient.IIngredientSlot; +import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.resources.RenderUtil; import gregtech.api.gui.resources.TextureArea; import gregtech.api.util.Position; @@ -30,10 +31,11 @@ public class PhantomFluidWidget extends Widget implements IIngredientSlot, IGhostIngredientTarget { - protected TextureArea backgroundTexture = GuiTextures.FLUID_SLOT; + protected IGuiTexture backgroundTexture = GuiTextures.FLUID_SLOT; private Supplier fluidStackSupplier; private Consumer fluidStackUpdater; + private boolean isClient; protected FluidStack lastFluidStack; public PhantomFluidWidget(int xPosition, int yPosition, int width, int height, Supplier fluidStackSupplier, Consumer fluidStackUpdater) { @@ -52,6 +54,18 @@ private FluidStack drainFrom(Object ingredient) { return null; } + public PhantomFluidWidget setFluidStackSupplier(Supplier fluidStackSupplier, boolean isClient) { + this.fluidStackSupplier = fluidStackSupplier; + this.isClient = isClient; + return this; + } + + public PhantomFluidWidget setFluidStackUpdater(Consumer fluidStackUpdater, boolean isClient) { + this.fluidStackUpdater = fluidStackUpdater; + this.isClient = isClient; + return this; + } + @Override public List> getPhantomTargets(Object ingredient) { if (!(ingredient instanceof FluidStack) && drainFrom(ingredient) == null) { @@ -77,6 +91,10 @@ public void accept(Object ingredient) { NBTTagCompound tagCompound = ingredientStack.writeToNBT(new NBTTagCompound()); writeClientAction(2, buffer -> buffer.writeCompoundTag(tagCompound)); } + + if (isClient && fluidStackUpdater != null) { + fluidStackUpdater.accept(ingredientStack); + } } }); } @@ -89,11 +107,19 @@ public Object getIngredientOverMouse(int mouseX, int mouseY) { return null; } - public PhantomFluidWidget setBackgroundTexture(TextureArea backgroundTexture) { + public PhantomFluidWidget setBackgroundTexture(IGuiTexture backgroundTexture) { this.backgroundTexture = backgroundTexture; return this; } + @Override + public void updateScreen() { + super.updateScreen(); + if (isClient && fluidStackSupplier != null) { + this.lastFluidStack = fluidStackSupplier.get(); + } + } + @Override public void detectAndSendChanges() { FluidStack currentStack = fluidStackSupplier.get(); @@ -155,6 +181,9 @@ public boolean mouseClicked(int mouseX, int mouseY, int button) { if (isMouseOverElement(mouseX, mouseY)) { writeClientAction(1, buffer -> { }); + if (isClient && fluidStackUpdater != null) { + fluidStackUpdater.accept(null); + } return true; } return false; diff --git a/src/main/java/gregtech/api/gui/widgets/PhantomSlotWidget.java b/src/main/java/gregtech/api/gui/widgets/PhantomSlotWidget.java index 4d03d80b438..98c2f70be4e 100644 --- a/src/main/java/gregtech/api/gui/widgets/PhantomSlotWidget.java +++ b/src/main/java/gregtech/api/gui/widgets/PhantomSlotWidget.java @@ -51,6 +51,8 @@ public void accept(Object ingredient) { if (ingredient instanceof ItemStack) { int mouseButton = Mouse.getEventButton(); boolean shiftDown = Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) || Keyboard.isKeyDown(Keyboard.KEY_RSHIFT); + ClickType clickType = shiftDown ? ClickType.QUICK_MOVE : ClickType.PICKUP; + SlotUtil.slotClickPhantom(slotReference, mouseButton, clickType, (ItemStack)ingredient); writeClientAction(1, buffer -> { buffer.writeItemStack((ItemStack) ingredient); buffer.writeVarInt(mouseButton); diff --git a/src/main/java/gregtech/api/gui/widgets/SlotWidget.java b/src/main/java/gregtech/api/gui/widgets/SlotWidget.java index 0a21746c724..67b68eb0318 100644 --- a/src/main/java/gregtech/api/gui/widgets/SlotWidget.java +++ b/src/main/java/gregtech/api/gui/widgets/SlotWidget.java @@ -4,10 +4,8 @@ import javax.annotation.Nonnull; -import gregtech.api.gui.INativeWidget; -import gregtech.api.gui.IRenderContext; -import gregtech.api.gui.IScissored; -import gregtech.api.gui.Widget; +import gregtech.api.gui.*; +import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.resources.TextureArea; import gregtech.api.util.Position; import gregtech.api.util.Size; @@ -31,7 +29,7 @@ public class SlotWidget extends Widget implements INativeWidget { protected boolean canPutItems; protected SlotLocationInfo locationInfo = new SlotLocationInfo(false, false); - protected TextureArea[] backgroundTexture; + protected IGuiTexture[] backgroundTexture; protected Runnable changeListener; protected Rectangle scissor; @@ -50,6 +48,12 @@ public SlotWidget(IItemHandler itemHandler, int slotIndex, int xPosition, int yP this.slotReference = createSlot(itemHandler, slotIndex); } + @Override + public void setSizes(ISizeProvider sizes) { + super.setSizes(sizes); + onPositionUpdate(); + } + protected Slot createSlot(IInventory inventory, int index) { return new WidgetSlot(inventory, index, 0, 0); } @@ -64,7 +68,7 @@ public void drawInBackground(int mouseX, int mouseY, IRenderContext context) { if (isEnabled() && backgroundTexture != null) { Position pos = getPosition(); Size size = getSize(); - for (TextureArea backgroundTexture : this.backgroundTexture) { + for (IGuiTexture backgroundTexture : this.backgroundTexture) { backgroundTexture.draw(pos.x, pos.y, size.width, size.height); } } @@ -110,7 +114,7 @@ public SlotWidget(IInventory inventory, int slotIndex, int xPosition, int yPosit * Sets array of background textures used by slot * they are drawn on top of each other */ - public SlotWidget setBackgroundTexture(TextureArea... backgroundTexture) { + public SlotWidget setBackgroundTexture(IGuiTexture... backgroundTexture) { this.backgroundTexture = backgroundTexture; return this; } diff --git a/src/main/java/gregtech/api/gui/widgets/TabGroup.java b/src/main/java/gregtech/api/gui/widgets/TabGroup.java index 7c92191048a..ec42c11bde2 100644 --- a/src/main/java/gregtech/api/gui/widgets/TabGroup.java +++ b/src/main/java/gregtech/api/gui/widgets/TabGroup.java @@ -51,6 +51,7 @@ public TabGroup addTab(ITabInfo tabInfo, AbstractWidgetGroup tabWidget) { int tabIndex = tabInfos.size() - 1; this.tabWidgets.put(tabIndex, tabWidget); tabWidget.setVisible(tabIndex == selectedTabIndex); + tabWidget.setActive(tabIndex == selectedTabIndex); addWidget(tabWidget); return this; } @@ -119,7 +120,9 @@ public boolean mouseClicked(int mouseX, int mouseY, int button) { private void setSelectedTab(int tabIndex) { int old = selectedTabIndex; this.tabWidgets.get(selectedTabIndex).setVisible(false); + this.tabWidgets.get(selectedTabIndex).setActive(false); this.tabWidgets.get(tabIndex).setVisible(true); + this.tabWidgets.get(tabIndex).setActive(true); this.selectedTabIndex = tabIndex; if (this.onTabChanged != null) { onTabChanged.accept(old, tabIndex); diff --git a/src/main/java/gregtech/api/gui/widgets/TankWidget.java b/src/main/java/gregtech/api/gui/widgets/TankWidget.java index 7575ef936ca..178d013222a 100644 --- a/src/main/java/gregtech/api/gui/widgets/TankWidget.java +++ b/src/main/java/gregtech/api/gui/widgets/TankWidget.java @@ -4,8 +4,8 @@ import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; import gregtech.api.gui.ingredient.IIngredientSlot; +import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.resources.RenderUtil; -import gregtech.api.gui.resources.TextureArea; import gregtech.api.util.FluidTooltipUtil; import gregtech.api.util.Position; import gregtech.api.util.Size; @@ -44,8 +44,8 @@ public class TankWidget extends Widget implements IIngredientSlot { private boolean allowClickFilling; private boolean allowClickEmptying; - private TextureArea[] backgroundTexture; - private TextureArea overlayTexture; + private IGuiTexture[] backgroundTexture; + private IGuiTexture overlayTexture; private FluidStack lastFluidInTank; private int lastTankCapacity; @@ -65,12 +65,12 @@ public TankWidget setAlwaysShowFull(boolean alwaysShowFull) { return this; } - public TankWidget setBackgroundTexture(TextureArea... backgroundTexture) { + public TankWidget setBackgroundTexture(IGuiTexture... backgroundTexture) { this.backgroundTexture = backgroundTexture; return this; } - public TankWidget setOverlayTexture(TextureArea overlayTexture) { + public TankWidget setOverlayTexture(IGuiTexture overlayTexture) { this.overlayTexture = overlayTexture; return this; } @@ -109,7 +109,7 @@ public void drawInBackground(int mouseX, int mouseY, IRenderContext context) { Position pos = getPosition(); Size size = getSize(); if (backgroundTexture != null) { - for (TextureArea textureArea : backgroundTexture) { + for (IGuiTexture textureArea : backgroundTexture) { textureArea.draw(pos.x, pos.y, size.width, size.height); } } diff --git a/src/main/java/gregtech/api/gui/widgets/TextFieldWidget.java b/src/main/java/gregtech/api/gui/widgets/TextFieldWidget.java index 68aff5b092c..2f89b089fb3 100644 --- a/src/main/java/gregtech/api/gui/widgets/TextFieldWidget.java +++ b/src/main/java/gregtech/api/gui/widgets/TextFieldWidget.java @@ -9,6 +9,7 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.gui.GuiTextField; +import net.minecraft.client.renderer.GlStateManager; import net.minecraft.network.PacketBuffer; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; @@ -84,7 +85,10 @@ public void setCurrentString(String currentString) { } public String getCurrentString() { - return this.textField.getText(); + if (isRemote()) { + return this.textField.getText(); + } + return this.currentString; } @Override @@ -122,6 +126,8 @@ public void drawInBackground(int mouseX, int mouseY, IRenderContext context) { background.draw(position.x, position.y, size.width, size.height); } this.textField.drawTextBox(); + GlStateManager.enableBlend(); + GlStateManager.color(1,1,1,1); } @Override @@ -145,7 +151,7 @@ public void updateScreen() { @Override public void detectAndSendChanges() { super.detectAndSendChanges(); - if (!textSupplier.get().equals(currentString)) { + if (textSupplier != null && !textSupplier.get().equals(currentString)) { this.currentString = textSupplier.get(); writeUpdateInfo(1, buffer -> buffer.writeString(currentString)); } @@ -178,7 +184,9 @@ public void handleClientAction(int id, PacketBuffer buffer) { clientText = clientText.substring(0, Math.min(clientText.length(), maxStringLength)); if (textValidator.test(clientText)) { this.currentString = clientText; - this.textResponder.accept(clientText); + if (textResponder != null) { + this.textResponder.accept(clientText); + } } } } diff --git a/src/main/java/gregtech/api/gui/widgets/WidgetGroup.java b/src/main/java/gregtech/api/gui/widgets/WidgetGroup.java index 9cd81ffd057..5bfef5d0d26 100644 --- a/src/main/java/gregtech/api/gui/widgets/WidgetGroup.java +++ b/src/main/java/gregtech/api/gui/widgets/WidgetGroup.java @@ -4,6 +4,8 @@ import gregtech.api.util.Position; import gregtech.api.util.Size; +import java.util.ArrayList; + public class WidgetGroup extends AbstractWidgetGroup { public WidgetGroup() { @@ -18,6 +20,10 @@ public WidgetGroup(Position position, Size size) { super(position, size); } + public WidgetGroup(int x, int y, int width, int height) { + super(new Position(x, y), new Size(width, height)); + } + @Override public void addWidget(Widget widget) { super.addWidget(widget); @@ -28,6 +34,11 @@ public void removeWidget(Widget widget) { super.removeWidget(widget); } + @Override + public void waitToRemoved(Widget widget) { + super.waitToRemoved(widget); + } + @Override public void clearAllWidgets() { super.clearAllWidgets(); diff --git a/src/main/java/gregtech/api/terminal/app/AbstractApplication.java b/src/main/java/gregtech/api/terminal/app/AbstractApplication.java index d2431be8a34..3a93dc51108 100644 --- a/src/main/java/gregtech/api/terminal/app/AbstractApplication.java +++ b/src/main/java/gregtech/api/terminal/app/AbstractApplication.java @@ -1,23 +1,16 @@ package gregtech.api.terminal.app; -import gregtech.api.gui.IRenderContext; import gregtech.api.gui.resources.IGuiTexture; -import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.terminal.gui.widgets.AnimaWidgetGroup; +import gregtech.api.terminal.gui.widgets.os.TerminalOSWidget; import gregtech.api.util.Position; import gregtech.api.util.Size; -import gregtech.api.util.interpolate.Eases; -import gregtech.api.util.interpolate.Interpolator; -import javafx.geometry.Pos; -import net.minecraft.client.renderer.GlStateManager; import net.minecraft.nbt.NBTTagCompound; -import java.util.function.Consumer; - -public abstract class AbstractApplication extends WidgetGroup { - protected Interpolator interpolator; +public abstract class AbstractApplication extends AnimaWidgetGroup { protected final String name; protected final IGuiTexture icon; - private float scale; + protected TerminalOSWidget os; public AbstractApplication (String name, IGuiTexture icon) { super(Position.ORIGIN, new Size(333, 232)); @@ -25,6 +18,11 @@ public AbstractApplication (String name, IGuiTexture icon) { this.icon = icon; } + public AbstractApplication setOs(TerminalOSWidget os) { + this.os = os; + return this; + } + public String getName() { return name; } @@ -35,34 +33,6 @@ public IGuiTexture getIcon() { public abstract AbstractApplication createApp(boolean isClient, NBTTagCompound nbt); - public void maximizeApp(Consumer callback) { - this.scale = 0; - setVisible(true); - interpolator = new Interpolator(0, 1, 10, Eases.EaseLinear, - value-> scale = value.floatValue(), - value-> { - interpolator = null; - if (callback != null) { - callback.accept(this); - } - }); - interpolator.start(); - } - - public void minimizeApp(Consumer callback) { - this.scale = 1; - interpolator = new Interpolator(1, 0, 10, Eases.EaseLinear, - value-> scale = value.floatValue(), - value-> { - setVisible(false); - interpolator = null; - if (callback != null) { - callback.accept(this); - } - }); - interpolator.start(); - } - public void closeApp(boolean isClient, NBTTagCompound nbt) { } @@ -70,44 +40,7 @@ public boolean isBackgroundApp() { return false; } - @Override - public void updateScreen() { - if (interpolator != null) { - interpolator.update(); - } - super.updateScreen(); - } - - @Override - public void drawInForeground(int mouseX, int mouseY) { - if (scale == 0) { - return; - } if (scale != 1) { - GlStateManager.pushMatrix(); - GlStateManager.translate((this.gui.getScreenWidth() - this.gui.getScreenWidth() * scale) / 2, - (this.gui.getScreenHeight() - this.gui.getScreenHeight() * scale) / 2, 0); - GlStateManager.scale(scale, scale, 1); - super.drawInForeground(0, 0); - GlStateManager.popMatrix(); - } else { - super.drawInForeground(mouseX, mouseY); - } - } - - @Override - public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { - if (scale == 0) { - return; - }if (scale != 1) { - GlStateManager.pushMatrix(); - GlStateManager.translate((this.gui.getScreenWidth() - this.gui.getScreenWidth() * scale) / 2, - (this.gui.getScreenHeight() - this.gui.getScreenHeight() * scale) / 2, 0); - GlStateManager.scale(scale, scale, 1); - super.drawInBackground(0, 0, partialTicks, context); - GlStateManager.popMatrix(); - } else { - super.drawInBackground(mouseX, mouseY, partialTicks, context); - } - + public TerminalOSWidget getOs() { + return os; } } diff --git a/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java b/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java index a5bbbc889d0..3dd11f4b5cc 100644 --- a/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java +++ b/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java @@ -17,17 +17,16 @@ public GuideEditorApp() { @Override public AbstractApplication createApp(boolean isClient, NBTTagCompound nbt) { + GuideEditorApp app = new GuideEditorApp(); if (isClient) { - GuideEditorApp app = new GuideEditorApp(); - GuideConfigEditor configEditor = new GuideConfigEditor(0, 0, 133, 232); + GuideConfigEditor configEditor = new GuideConfigEditor(0, 0, 133, 232, app); GuidePageEditorWidget pageEditor = new GuidePageEditorWidget(133, 0, 200, 232, 5); configEditor.setGuidePageEditorWidget(pageEditor); pageEditor.setGuideConfigEditor(configEditor); app.addWidget(pageEditor); app.addWidget(configEditor); - return app; } - return null; + return app; } @Override diff --git a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java index 63bde426b50..6c394c2c530 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java @@ -5,26 +5,20 @@ import com.google.gson.JsonObject; import gregtech.api.GTValues; import gregtech.api.gui.GuiTextures; -import gregtech.api.gui.Widget; -import gregtech.api.gui.resources.ColorRectTexture; import gregtech.api.gui.resources.IGuiTexture; -import gregtech.api.gui.widgets.WidgetGroup; import gregtech.api.terminal.app.AbstractApplication; +import gregtech.api.terminal.gui.widgets.TreeListWidget; import gregtech.api.terminal.gui.widgets.guide.*; import gregtech.api.terminal.util.TreeNode; import net.minecraft.client.Minecraft; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.PacketBuffer; import net.minecraft.util.ResourceLocation; -import net.minecraft.util.Tuple; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; import java.util.function.Consumer; public abstract class GuideApp extends AbstractApplication { @@ -39,19 +33,22 @@ public AbstractApplication createApp(boolean isClient, NBTTagCompound nbt) { GuideApp app = this.getClass().newInstance(); if (isClient && getTree() != null) { app.addWidget( - new TextTreeWidget<>(0, 0, 133, 232, getTree(), leaf -> { + new TreeListWidget<>(0, 0, 133, 232, getTree(), leaf -> { if (app.pageWidget != null) { app.removeWidget(app.pageWidget); } app.pageWidget = new GuidePageWidget(133, 0, 200, 232, 5); - if (leaf.isLeaf() && leaf.content != null) { - JsonObject page = getPage(leaf.content); + if (leaf.isLeaf() && leaf.getContent() != null) { + JsonObject page = getPage(leaf.getContent()); if (page != null) { app.pageWidget.loadJsonConfig(page); } } app.addWidget(app.pageWidget); - }, this::itemIcon, this::itemName).setNodeTexture(GuiTextures.BORDERED_BACKGROUND).setLeafTexture(GuiTextures.SLOT_DARKENED) + }).setContentIconSupplier(this::itemIcon) + .setContentNameSupplier(this::itemName) + .setNodeTexture(GuiTextures.BORDERED_BACKGROUND) + .setLeafTexture(GuiTextures.SLOT_DARKENED) ); } return app; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/AnimaWidgetGroup.java b/src/main/java/gregtech/api/terminal/gui/widgets/AnimaWidgetGroup.java new file mode 100644 index 00000000000..cc040f489a2 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/AnimaWidgetGroup.java @@ -0,0 +1,101 @@ +package gregtech.api.terminal.gui.widgets; + +import gregtech.api.gui.INativeWidget; +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.util.Position; +import gregtech.api.util.Size; +import gregtech.api.util.interpolate.Eases; +import gregtech.api.util.interpolate.Interpolator; +import net.minecraft.client.renderer.GlStateManager; + +import java.util.function.Consumer; + +public abstract class AnimaWidgetGroup extends WidgetGroup { + protected Interpolator interpolator; + protected float scale; + + public AnimaWidgetGroup(Position position, Size size) { + super(position, size); + } + + public AnimaWidgetGroup(int x, int y, int width, int height) { + super(new Position(x, y), new Size(width, height)); + } + + @Override + public void updateScreen() { + if (interpolator != null) { + interpolator.update(); + } + super.updateScreen(); + } + + public void maximizeWidget(Consumer callback) { + this.scale = 0; + setVisible(true); + interpolator = new Interpolator(0, 1, 10, Eases.EaseLinear, + value-> scale = value.floatValue(), + value-> { + interpolator = null; + if (callback != null) { + callback.accept(this); + } + }); + interpolator.start(); + } + + public void minimizeWidget(Consumer callback) { + this.scale = 1; + interpolator = new Interpolator(1, 0, 10, Eases.EaseLinear, + value-> scale = value.floatValue(), + value-> { + setVisible(false); + interpolator = null; + if (callback != null) { + callback.accept(this); + } + }); + interpolator.start(); + } + + protected void hookDrawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + super.drawInBackground(mouseX, mouseY, partialTicks, context); + } + + protected void hookDrawInForeground(int mouseX, int mouseY) { + super.drawInForeground(mouseX, mouseY); + } + + @Override + public final void drawInForeground(int mouseX, int mouseY) { + if (scale == 0) { + return; + } if (scale != 1) { + GlStateManager.pushMatrix(); + GlStateManager.translate((this.gui.getScreenWidth() - this.gui.getScreenWidth() * scale) / 2, + (this.gui.getScreenHeight() - this.gui.getScreenHeight() * scale) / 2, 0); + GlStateManager.scale(scale, scale, 1); + hookDrawInForeground(0, 0); + GlStateManager.popMatrix(); + } else { + hookDrawInForeground(mouseX, mouseY); + } + } + + @Override + public final void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + if (scale == 0) { + return; + }if (scale != 1) { + GlStateManager.pushMatrix(); + GlStateManager.translate((this.gui.getScreenWidth() - this.gui.getScreenWidth() * scale) / 2, + (this.gui.getScreenHeight() - this.gui.getScreenHeight() * scale) / 2, 0); + GlStateManager.scale(scale, scale, 1); + hookDrawInBackground(0, 0, partialTicks, context); + GlStateManager.popMatrix(); + } else { + hookDrawInBackground(mouseX, mouseY, partialTicks, context); + } + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java index 4b84b6707ab..fecc42d1dfe 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java @@ -23,6 +23,7 @@ public class CircleButtonWidget extends Widget { protected boolean isHover; protected String hoverText; protected IGuiTexture icon; + protected IGuiTexture hover; protected final int iconSize; protected Consumer onPressCallback; protected final int[] colors = { @@ -78,6 +79,11 @@ public CircleButtonWidget setClickListener(Consumer onPressed) { return this; } + public CircleButtonWidget setHoverIcon(IGuiTexture hover) { + this.hover = hover; + return this; + } + @Override public void updateScreen() { if (isHover) { @@ -104,6 +110,9 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender renderSector(x, y, r, colors[1], segments, 0, (int) (segments * ((hoverTick + partialTicks) / 8))); } renderCircle(x, y, r - border, colors[2], segments); + if (isHover && hover != null) { + hover.draw(x - iconSize / 2f, y - iconSize / 2f, iconSize, iconSize); + } if (icon != null) { icon.draw(x - iconSize / 2f, y - iconSize / 2f, iconSize, iconSize); } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/ColorWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/ColorWidget.java index 58b88ed577a..0dfc53e292f 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/ColorWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/ColorWidget.java @@ -40,8 +40,9 @@ public ColorWidget(int x, int y, int barWidth, int barHeight){ .setTextResponder((t) -> { setRed(t.isEmpty()? 0 : Integer.parseInt(t)); if (onColorChanged != null) { - onColorChanged.accept((alpha << 24) | (red << 16) | (green << 8) | (blue)); + onColorChanged.accept(getColor()); } + writeClientAction(2, buffer -> buffer.writeInt(getColor())); }, true) .setTextSupplier(() -> Integer.toString(red), true) .setValidator(this::checkValid); @@ -49,8 +50,9 @@ public ColorWidget(int x, int y, int barWidth, int barHeight){ .setTextResponder((t) -> { setGreen(t.isEmpty()? 0 : Integer.parseInt(t)); if (onColorChanged != null) { - onColorChanged.accept((alpha << 24) | (red << 16) | (green << 8) | (blue)); + onColorChanged.accept(getColor()); } + writeClientAction(2, buffer -> buffer.writeInt(getColor())); }, true) .setTextSupplier(() -> Integer.toString(green), true) .setValidator(this::checkValid); @@ -58,8 +60,9 @@ public ColorWidget(int x, int y, int barWidth, int barHeight){ .setTextResponder((t) -> { setBlue(t.isEmpty()? 0 : Integer.parseInt(t)); if (onColorChanged != null) { - onColorChanged.accept((alpha << 24) | (red << 16) | (green << 8) | (blue)); + onColorChanged.accept(getColor()); } + writeClientAction(2, buffer -> buffer.writeInt(getColor())); }, true) .setTextSupplier(() -> Integer.toString(blue), true) .setValidator(this::checkValid); @@ -67,8 +70,9 @@ public ColorWidget(int x, int y, int barWidth, int barHeight){ .setTextResponder((t) -> { setAlpha(t.isEmpty()? 0 : Integer.parseInt(t)); if (onColorChanged != null) { - onColorChanged.accept((alpha << 24) | (red << 16) | (green << 8) | (blue)); + onColorChanged.accept(getColor()); } + writeClientAction(2, buffer -> buffer.writeInt(getColor())); }, true) .setTextSupplier(() -> Integer.toString(alpha), true) .setValidator(this::checkValid); @@ -97,6 +101,10 @@ public ColorWidget setColorSupplier(Supplier colorSupplier, boolean isC return this; } + public int getColor() { + return (alpha << 24) | (red << 16) | (green << 8) | (blue); + } + @Override public void detectAndSendChanges() { super.detectAndSendChanges(); @@ -153,7 +161,7 @@ private void handleColor(int id, PacketBuffer buffer) { setBlue(b); setAlpha(a); if (onColorChanged != null) { - onColorChanged.accept((alpha << 24) | (red << 16) | (green << 8) | (blue)); + onColorChanged.accept(getColor()); } } } @@ -260,8 +268,9 @@ public boolean mouseDragged(int mouseX, int mouseY, int button, long timeDragged setAlpha(newX * 255 / barWidth); } if (onColorChanged != null) { - onColorChanged.accept((alpha << 24) | (red << 16) | (green << 8) | (blue)); + onColorChanged.accept(getColor()); } + writeClientAction(2, buffer -> buffer.writeInt(getColor())); dragged.setSelfPosition(new Position(newX - 4, dragged.getSelfPosition().y)); return true; } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/CustomPositionSizeWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/CustomPositionSizeWidget.java index 6bd708f2e5b..daf0a705b85 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/CustomPositionSizeWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/CustomPositionSizeWidget.java @@ -176,17 +176,17 @@ public boolean dragging(int mouseX, int mouseY, int deltaX, int deltaY) { if (!dragPos) { if (dragUp) { addY = deltaY; - height -= deltaY; + height = Math.max(1, height - deltaY); } if (dragDown) { - height += deltaY; + height = Math.max(1, height + deltaY); } if (dragLeft) { addX = deltaX; - width -= deltaX; + width = Math.max(1, width - deltaX); } if (dragRight) { - width += deltaX; + width = Math.max(1, width + deltaX); } controlled.addSelfPosition(addX, addY); controlled.setSize(new Size(width, height)); diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java b/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java index a00cfa35efe..f5dfe6121ed 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java @@ -8,8 +8,13 @@ import gregtech.api.util.Position; import gregtech.api.util.RenderUtil; import gregtech.api.util.Size; +import net.minecraft.client.renderer.GlStateManager; import net.minecraft.util.math.MathHelper; +import static gregtech.api.gui.impl.ModularUIGui.bColorForOverlay; +import static gregtech.api.gui.impl.ModularUIGui.gColorForOverlay; +import static gregtech.api.gui.impl.ModularUIGui.rColorForOverlay; + public class DraggableScrollableWidgetGroup extends WidgetGroup { protected int scrollXOffset; protected int scrollYOffset; @@ -84,6 +89,7 @@ public void addWidget(Widget widget) { maxHeight = Math.max(maxHeight, widget.getSize().height + widget.getSelfPosition().y); maxWidth = Math.max(maxWidth, widget.getSize().width + widget.getSelfPosition().x); widget.addSelfPosition(- scrollXOffset, - scrollYOffset); + widget.applyScissor(getPosition().x, getPosition().y, getSize().width - yBarWidth, getSize().height - xBarHeight); super.addWidget(widget); } @@ -108,6 +114,18 @@ public void setSize(Size size) { computeMax(); } + @Override + protected void onPositionUpdate() { + super.onPositionUpdate(); + this.applyScissor(getPosition().x, getPosition().y, getSize().width - yBarWidth, getSize().height - xBarHeight); + } + + @Override + protected void onSizeUpdate() { + super.onSizeUpdate(); + this.applyScissor(getPosition().x, getPosition().y, getSize().width - yBarWidth, getSize().height - xBarHeight); + } + protected void computeMax() { int mh = 0; int mw = 0; @@ -211,32 +229,34 @@ protected boolean hookDrawInBackground(int mouseX, int mouseY, float partialTick @Override public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { - Position position = getPosition(); - Size size = getSize(); + int x = getPosition().x; + int y = getPosition().y; + int width = getSize().width; + int height = getSize().height; if (background != null) { - background.draw(position.x, position.y, size.width, size.height); + background.draw(x, y, width, height); } - RenderUtil.useScissor(position.x, position.y, size.width - yBarWidth, size.height - xBarHeight, ()->{ + RenderUtil.useScissor(x, y, width - yBarWidth, height - xBarHeight, ()->{ if(!hookDrawInBackground(mouseX, mouseY, partialTicks, context)) { super.drawInBackground(mouseX, mouseY, partialTicks, context); } }); if (xBarHeight > 0) { if (xBarB != null) { - xBarB.draw(position.x, position.y - xBarHeight, size.width, xBarHeight); + xBarB.draw(x, y - xBarHeight, width, xBarHeight); } if (xBarF != null) { - int barWidth = size.width / getMaxWidth(); - xBarF.draw(position.x + scrollXOffset, position.y - xBarHeight, barWidth, xBarHeight); + int barWidth = width / getMaxWidth(); + xBarF.draw(x + scrollXOffset, y - xBarHeight, barWidth, xBarHeight); } } if (yBarWidth > 0) { if (yBarB != null) { - yBarB.draw(position.x + size.width - yBarWidth, position.y, yBarWidth, size.height); + yBarB.draw(x + width - yBarWidth, y, yBarWidth, height); } if (yBarF != null) { - int barHeight = (int) (size.height * 1.0f / getMaxHeight() * size.height); - yBarF.draw(position.x + size.width - yBarWidth, position.y + scrollYOffset * size.height * 1.0f / getMaxHeight(), yBarWidth, barHeight); + int barHeight = (int) (height * 1.0f / getMaxHeight() * height); + yBarF.draw(x + width - yBarWidth, y + scrollYOffset * height * 1.0f / getMaxHeight(), yBarWidth, barHeight); } } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/RectButtonWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/RectButtonWidget.java index a4060c2986e..6dde56eb33e 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/RectButtonWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/RectButtonWidget.java @@ -118,6 +118,9 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender drawSolidRect(x, (int) ((1 - per) * height) + y, border, (int) (height * per), colors[1]); } drawSolidRect(x + border, y + border, width - 2 * border, height - 2 * border, colors[2]); + if (isHover && hover != null) { + hover.draw(x + border, y + border, width - 2 * border, height - 2 * border); + } if (isPressed) { if (pressedIcon != null) { pressedIcon.draw(x + border, y + border, width - 2 * border, height - 2 * border); diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/TextEditorWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/TextEditorWidget.java index 98622a29dbe..d306e16dd94 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/TextEditorWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/TextEditorWidget.java @@ -25,9 +25,9 @@ public class TextEditorWidget extends WidgetGroup { private static final TextureArea STYLE = TextureArea.fullImage("textures/gui/widget/formatting.png"); private final TextPanelWidget textPanelWidget; - public TextEditorWidget(int x, int y, int width, int height, String initText,Consumer stringUpdate, boolean allowToolBox) { + public TextEditorWidget(int x, int y, int width, int height,Consumer stringUpdate, boolean allowToolBox) { super(new Position(x, y), new Size(Math.max(width, allowToolBox ? 80 : width), Math.max(height, allowToolBox ? 32 : height))); - textPanelWidget = new TextPanelWidget(0, 32, Math.max(width, allowToolBox ? 80 : width), Math.max(height, allowToolBox ? 32 : height) - 32, initText, stringUpdate); + textPanelWidget = new TextPanelWidget(0, 32, Math.max(width, allowToolBox ? 80 : width), Math.max(height, allowToolBox ? 32 : height) - 32, stringUpdate); this.addWidget(textPanelWidget); if (allowToolBox) { initToolBox(); @@ -39,6 +39,11 @@ public TextEditorWidget setBackground(IGuiTexture background) { return this; } + public TextEditorWidget setContent(String content) { + textPanelWidget.pageSetCurrent(content); + return this; + } + @Override public void setActive(boolean active) { super.setActive(active); @@ -103,10 +108,10 @@ private static class TextPanelWidget extends DraggableScrollableWidgetGroup { private static final Pattern COLOR_CODE_PATTERN = Pattern.compile("(?i)§[0-9A-F]"); - public TextPanelWidget(int x, int y, int width, int height, String text, Consumer stringUpdate) { + public TextPanelWidget(int x, int y, int width, int height, Consumer stringUpdate) { super(x, y, width, height); this.stringUpdate = stringUpdate; - this.content = text == null ? "" : text; + this.content = ""; if (isClientSide()) { fontRenderer = Minecraft.getMinecraft().fontRenderer; textHeight = fontRenderer.getWordWrappedHeight(content, width - yBarWidth); diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/TreeListWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/TreeListWidget.java new file mode 100644 index 00000000000..5c1939456ed --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/TreeListWidget.java @@ -0,0 +1,198 @@ +package gregtech.api.terminal.gui.widgets; + +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.terminal.util.TreeNode; +import gregtech.api.util.Position; +import gregtech.api.util.RenderUtil; +import gregtech.api.util.Size; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.resources.I18n; +import net.minecraft.util.math.MathHelper; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Function; + +public class TreeListWidget extends Widget { + private static final int ITEM_HEIGHT = 11; + protected int scrollOffset; + protected List> list; + protected TreeNode selected; + protected IGuiTexture background; + protected IGuiTexture nodeTexture; + protected IGuiTexture leafTexture; + protected Consumer> onSelected; + protected Function keyIconSupplier; + protected Function keyNameSupplier; + protected Function contentIconSupplier; + protected Function contentNameSupplier; + protected boolean canSelectNode; + private int tick; + + public TreeListWidget(int xPosition, int yPosition, int width, int height, + TreeNode root, + Consumer> onSelected) { + super(new Position(xPosition, yPosition), new Size(width, height)); + list = new ArrayList<>(); + if (root.getChildren() != null) { + list.addAll(root.getChildren()); + } + this.onSelected = onSelected; + } + + public TreeListWidget canSelectNode(boolean canSelectNode) { + this.canSelectNode = canSelectNode; + return this; + } + + public TreeListWidget setBackground(IGuiTexture background) { + this.background = background; + return this; + } + + public TreeListWidget setNodeTexture(IGuiTexture nodeTexture) { + this.nodeTexture = nodeTexture; + return this; + } + + public TreeListWidget setLeafTexture(IGuiTexture leafTexture) { + this.leafTexture = leafTexture; + return this; + } + + public TreeListWidget setContentIconSupplier(Function iconSupplier) { + contentIconSupplier = iconSupplier; + return this; + } + + public TreeListWidget setKeyIconSupplier(Function iconSupplier) { + keyIconSupplier = iconSupplier; + return this; + } + + public TreeListWidget setContentNameSupplier(Function nameSupplier) { + contentNameSupplier = nameSupplier; + return this; + } + + public TreeListWidget setKeyNameSupplier(Function nameSupplier) { + keyNameSupplier = nameSupplier; + return this; + } + + @Override + public void updateScreen() { + tick++; + } + + @Override + public boolean mouseWheelMove(int mouseX, int mouseY, int wheelDelta) { + if (this.isMouseOverElement(mouseX, mouseY, true)) { + int moveDelta = -MathHelper.clamp(wheelDelta, -1, 1) * 5; + this.scrollOffset = MathHelper.clamp(scrollOffset + moveDelta, 0, Math.max(list.size() * ITEM_HEIGHT - getSize().height, 0)); + return true; + } + return false; + } + + @Override + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + int x = getPosition().x; + int y = getPosition().y; + int width = getSize().width; + int height = getSize().height; + if (background != null) { + background.draw(x, y, width, height); + } else { + drawGradientRect(x, y, width, height, 0x8f000000, 0x8f000000); + } + RenderUtil.useScissor(x, y, width, height, ()->{ + FontRenderer fr = Minecraft.getMinecraft().fontRenderer; + int minToRender = scrollOffset / ITEM_HEIGHT; + int maxToRender = Math.min(list.size(), height / ITEM_HEIGHT + 2 + minToRender); + for (int i = minToRender; i < maxToRender; i++) { + GlStateManager.color(1,1,1,1); + TreeNode node = list.get(i); + int sX = x + 10 * node.dimension; + int sY = y - scrollOffset + i * ITEM_HEIGHT; + String name = node.toString(); + if (node.isLeaf()) { + if (leafTexture != null) { + leafTexture.draw(x, sY, width, ITEM_HEIGHT); + } else { + drawSolidRect(x, sY, width, ITEM_HEIGHT, 0xffff0000); + } + if (node.getContent() != null) { + String nameS = contentNameSupplier == null ? null : contentNameSupplier.apply(node.getContent()); + name = nameS == null ? name : nameS; + IGuiTexture icon = contentIconSupplier == null ? null : contentIconSupplier.apply(node.getContent()); + if (icon != null) { + icon.draw(sX - 9, sY + 1, 8, 8); + } + } + } else { + if (nodeTexture != null) { + nodeTexture.draw(x, sY, width, ITEM_HEIGHT); + } else { + drawSolidRect(x, sY, width, ITEM_HEIGHT, 0xffffff00); + } + String nameS = keyNameSupplier == null ? null : keyNameSupplier.apply(node.getKey()); + name = nameS == null ? name : nameS; + IGuiTexture icon = keyIconSupplier == null ? null : keyIconSupplier.apply(node.getKey()); + if (icon != null) { + icon.draw(sX - 9, sY + 1, 8, 8); + } + } + if (node == selected) { + drawSolidRect(x, sY, width, ITEM_HEIGHT, 0x7f000000); + } + int textW = Math.max(width - 10 * node.dimension, 10); + List list = fr.listFormattedStringToWidth(I18n.format(name), textW); + fr.drawString(list.get(Math.abs((tick / 20) % list.size())), sX, sY + 2, 0xff000000); + } + }); + GlStateManager.enableBlend(); + GlStateManager.color(1,1,1,1); + } + + @Override + public boolean mouseClicked(int mouseX, int mouseY, int button) { + if (this.isMouseOverElement(mouseX, mouseY)) { + int index = ((mouseY - getPosition().y) + scrollOffset) / ITEM_HEIGHT; + if (index < list.size()) { + TreeNode node = list.get(index); + if (node.isLeaf()) { + if (node != this.selected) { + this.selected = node; + if (onSelected != null){ + onSelected.accept(node); + } + } + } else { + if (canSelectNode && this.selected != node) { + this.selected = node; + if (onSelected != null){ + onSelected.accept(node); + } + } else if (node.getChildren().size() > 0 && list.contains(node.getChildren().get(0))){ + for (TreeNode child : node.getChildren()) { + list.remove(child); + } + } else { + for (int i = 0; i < node.getChildren().size(); i++) { + list.add(index + 1 + i, node.getChildren().get(i)); + } + } + } + playButtonClickSound(); + } + return true; + } + return false; + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/CardWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/CardWidget.java new file mode 100644 index 00000000000..07a108e97cc --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/CardWidget.java @@ -0,0 +1,108 @@ +package gregtech.api.terminal.gui.widgets.guide; + +import com.google.gson.JsonObject; +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.Widget; +import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; +import gregtech.api.terminal.gui.widgets.guide.configurator.BooleanConfigurator; +import gregtech.api.terminal.gui.widgets.guide.configurator.NumberConfigurator; +import gregtech.api.util.Position; +import gregtech.api.util.Size; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import org.lwjgl.opengl.GL11; + +import java.util.function.Consumer; + +public class CardWidget extends GuideWidget{ + public final static String NAME = "card"; + + //config + public int width; + public int height; + public boolean isShadow; + + @Override + public String getRegistryName() { + return NAME; + } + + @Override + public JsonObject getTemplate(boolean isFixed) { + JsonObject template = super.getTemplate(isFixed); + template.addProperty("fill", -3745585); + template.addProperty("width", 120); + template.addProperty("height", 60); + template.addProperty("isShadow", true); + return template; + } + + @Override + public void loadConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, boolean isFixed, Consumer needUpdate) { + super.loadConfigurator(group, config, isFixed, needUpdate); + if (!isFixed) { + group.addWidget(new NumberConfigurator(group, config, "width").setOnUpdated(needUpdate)); + group.addWidget(new NumberConfigurator(group, config, "height").setOnUpdated(needUpdate)); + } + group.addWidget(new BooleanConfigurator(group, config, "isShadow", true).setOnUpdated(needUpdate)); + } + + @Override + protected Widget initStream() { + int pageWidth = getSize().width; + int x = getSelfPosition().x; + int y = getSelfPosition().y; + if (page != null) { + x = page.getMargin(); + pageWidth = page.getPageWidth() - 2 * x; + } + this.setSelfPosition(new Position(x + (pageWidth - width) / 2, y)); + return initFixed(); + } + + @Override + protected Widget initFixed() { + this.setSize(new Size(width, height)); + return this; + } + + @Override + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + if (isShadow) { + int x = getPosition().x; + int y = getPosition().y; + int width = getSize().width; + int height = getSize().height; + drawGradientRect(x + 5, y + height, width - 5, 5, 0x4f000000, 0, false); + drawGradientRect(x + width, y + 5, 5, height - 5, 0x4f000000, 0, true); + + float startAlpha = (float) (0x4f) / 255.0F; + GlStateManager.disableTexture2D(); + GlStateManager.enableBlend(); + GlStateManager.disableAlpha(); + GlStateManager.tryBlendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO); + GlStateManager.shadeModel(GL11.GL_SMOOTH); + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder buffer = tessellator.getBuffer(); + buffer.begin(GL11.GL_TRIANGLES, DefaultVertexFormats.POSITION_COLOR); + x += width; + y += height; + width = 5; + height = 5; + buffer.pos(x, y, 0).color(0, 0, 0, startAlpha).endVertex(); + buffer.pos(x, y + height, 0).color(0, 0, 0, 0).endVertex(); + buffer.pos(x + width, y + height, 0).color(0, 0, 0, 0).endVertex(); + + buffer.pos(x, y, 0).color(0, 0, 0, startAlpha).endVertex(); + buffer.pos(x + width, y + height, 0).color(0, 0, 0, 0).endVertex(); + buffer.pos(x + width, y, 0).color(0, 0, 0, 0).endVertex(); + tessellator.draw(); + GlStateManager.shadeModel(GL11.GL_FLAT); + GlStateManager.enableAlpha(); + GlStateManager.enableTexture2D(); + } + super.drawInBackground(mouseX, mouseY, partialTicks, context); + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java index 10dfee6a877..191d3b8a7f0 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java @@ -1,22 +1,28 @@ package gregtech.api.terminal.gui.widgets.guide; import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.stream.JsonReader; import gregtech.api.gui.GuiTextures; import gregtech.api.gui.Widget; import gregtech.api.gui.resources.ColorRectTexture; import gregtech.api.gui.resources.TextTexture; import gregtech.api.gui.widgets.ImageWidget; -import gregtech.api.gui.widgets.LabelWidget; -import gregtech.api.gui.widgets.TabGroup; -import gregtech.api.gui.widgets.TextFieldWidget; +import gregtech.api.gui.widgets.*; import gregtech.api.gui.widgets.tab.IGuiTextureTabInfo; +import gregtech.api.terminal.app.GuideEditorApp; import gregtech.api.terminal.gui.CustomTabListRenderer; import gregtech.api.terminal.gui.widgets.CircleButtonWidget; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; import gregtech.api.terminal.gui.widgets.TextEditorWidget; +import gregtech.api.terminal.gui.widgets.os.TerminalDialogWidget; +import gregtech.api.util.Position; import gregtech.api.util.Size; import java.awt.*; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; import java.util.Map; public class GuideConfigEditor extends TabGroup { @@ -26,8 +32,9 @@ public class GuideConfigEditor extends TabGroup { private final DraggableScrollableWidgetGroup widgetSelector; private final DraggableScrollableWidgetGroup widgetConfigurator; private final CircleButtonWidget[] addButton; + private final GuideEditorApp app; - public GuideConfigEditor(int x, int y, int width, int height) { + public GuideConfigEditor(int x, int y, int width, int height, GuideEditorApp app) { super(x, y + 10, new CustomTabListRenderer( new ColorRectTexture(new Color(175, 0, 0, 131)), new ColorRectTexture(new Color(246, 120, 120, 190)), 30, 10)); @@ -60,7 +67,7 @@ public GuideConfigEditor(int x, int y, int width, int height) { new Color(146, 253, 118).getRGB()) .setIcon(GuiTextures.TERMINAL_ADD) .setHoverText("Export Config") - .setClickListener(this::getJson)); + .setClickListener(this::saveJson)); addButton[0] = new CircleButtonWidget(115, 15, 8, 1, 8) .setColors(new Color(255, 255, 255, 0).getRGB(), new Color(255, 255, 255).getRGB(), @@ -77,6 +84,7 @@ public GuideConfigEditor(int x, int y, int width, int height) { .setClickListener(this::addFixed); addButton[0].setVisible(false); addButton[1].setVisible(false); + this.app = app; this.addWidget(addButton[0]); this.addWidget(addButton[1]); } @@ -97,25 +105,16 @@ private DraggableScrollableWidgetGroup createPageConfig() { pageEditor.setSection(s); } }, true) + .setTextSupplier(pageEditor::getSection, true) .setMaxStringLength(Integer.MAX_VALUE) .setValidator(s->true)); group.addWidget(new ImageWidget(5, 48,116, 1, new ColorRectTexture(-1))); group.addWidget(new LabelWidget(5, 55, "title", -1).setShadow(true)); - group.addWidget(new TextEditorWidget(5, 65, 116, 70, "Template", s->{ + group.addWidget(new TextEditorWidget(5, 65, 116, 70, s->{ if (pageEditor != null) { pageEditor.setTitle(s); } - }, true).setBackground(new ColorRectTexture(0xA3FFFFFF))); -// group.addWidget(new ImageWidget(5, 148,116, 1, new ColorRectTexture(-1))); -// group.addWidget(new LabelWidget(5, 155, "translate key", -1).setShadow(true)); -// group.addWidget(new TextFieldWidget(5, 165, 116, 20, new ColorRectTexture(0x9f000000), null, null) -// .setTextResponder(s->{ -// if (pageEditor != null) { -// pageEditor.setTranslateKey(s); -// } -// }, true) -// .setMaxStringLength(Integer.MAX_VALUE) -// .setValidator(s->true)); + }, true).setContent(pageEditor.getTitle()).setBackground(new ColorRectTexture(0xA3FFFFFF))); return group; } @@ -128,11 +127,12 @@ private DraggableScrollableWidgetGroup createWidgetSelector() { for (Map.Entry entry : GuidePageWidget.REGISTER_WIDGETS.entrySet()) { IGuideWidget widgetTemplate = entry.getValue(); JsonObject template = widgetTemplate.getTemplate(false); - Widget guideWidget = widgetTemplate.createStreamWidget(5, y + 10, getSize().width - 14, template); + Widget guideWidget = widgetTemplate.updateOrCreateStreamWidget(5, y + 10, getSize().width - 14, template); group.addWidget(new LabelWidget(getSize().width / 2 - 1, y - 3, entry.getKey(), -1).setXCentered(true).setShadow(true)); y += guideWidget.getSize().height + 25; group.addWidget(guideWidget); } + group.addWidget(new WidgetGroup(new Position(5, group.getWidgetBottomHeight() + 5), Size.ZERO)); return group; } @@ -147,18 +147,41 @@ public void loadConfigurator(IGuideWidget widget) { widgetConfigurator.clearAllWidgets(); if (widget != null) { widget.loadConfigurator(widgetConfigurator, widget.getConfig(), widget.isFixed(), widget::updateValue); + widgetConfigurator.addWidget(new WidgetGroup(new Position(5, widgetConfigurator.getWidgetBottomHeight() + 5), Size.ZERO)); } } private void loadJson(ClickData data) { if(pageEditor != null) { - System.out.println(pageEditor.getJsonString()); + File file = new File("terminal\\guide_editor"); + TerminalDialogWidget.showFileDialog(app.getOs(), "Load Json", file, true, result->{ + if (result != null && result.isFile()) { + try { + FileReader reader = new FileReader(result); + pageEditor.loadJsonConfig(new JsonParser().parse(new JsonReader(reader)).getAsJsonObject()); + reader.close(); + } catch (Exception e) { + TerminalDialogWidget.showInfoDialog(app.getOs(), "ERROR", "An error occurred while loading the file.").setClientSide().open(); + } + } + }).setClientSide().open(); } } - private void getJson(ClickData data) { + private void saveJson(ClickData data) { if(pageEditor != null) { - System.out.println(pageEditor.getJsonString()); + File file = new File("terminal\\guide_editor"); + TerminalDialogWidget.showFileDialog(app.getOs(), "Save Json", file, false, result->{ + if (result != null) { + try { + FileWriter writer = new FileWriter(result); + writer.write(pageEditor.getJsonString()); + writer.close(); + } catch (Exception e) { + TerminalDialogWidget.showInfoDialog(app.getOs(), "ERROR", "An error occurred while saving the file.").setClientSide().open(); + } + } + }).setClientSide().open(); } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java index 15df7a65329..9283f11a7f7 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java @@ -14,6 +14,8 @@ import gregtech.api.util.Size; import gregtech.api.util.interpolate.Eases; import gregtech.api.util.interpolate.Interpolator; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.renderer.GlStateManager; import java.awt.*; @@ -26,7 +28,6 @@ public class GuidePageEditorWidget extends GuidePageWidget { private final CustomPositionSizeWidget customPositionSizeWidget; private GuideConfigEditor configEditor; private String section = "default"; -// private String translateKey = ""; public GuidePageEditorWidget(int xPosition, int yPosition, int width, int height, int margin) { super(xPosition, yPosition, width, height, margin); @@ -64,9 +65,9 @@ public void setSection(String section) { this.section = section; } -// public void setTranslateKey(String translateKey) { -// this.translateKey = translateKey; -// } + public String getSection() { + return section; + } private void onPosSizeChanged(Position pos, Size size) { Widget widget = customPositionSizeWidget.getControlled(); @@ -153,7 +154,7 @@ public JsonObject addGuideWidget(IGuideWidget widget, boolean isFixed) { int width = widgetConfig.get("width").getAsInt(); int height = widgetConfig.get("height").getAsInt(); - guideWidget = widget.createFixedWidget( + guideWidget = widget.updateOrCreateFixedWidget( (pageWidth - width) / 2 + 5, this.scrollYOffset + (this.getSize().height - height) / 2, width, @@ -163,7 +164,7 @@ public JsonObject addGuideWidget(IGuideWidget widget, boolean isFixed) { this.addWidget(guideWidget); } else { int y = getStreamBottom(); - guideWidget = widget.createStreamWidget(margin, y + 5, pageWidth - 2 * margin, widgetConfig); + guideWidget = widget.updateOrCreateStreamWidget(margin, y + 5, pageWidth - 2 * margin, widgetConfig); stream.add(guideWidget); this.addWidget(guideWidget); } @@ -194,6 +195,13 @@ public void moveUp(Widget widget) { stream.add(index - 1, widget); }).start(); } + } else { + int index2 = fixed.indexOf(widget); + if (index2 >= 0 && index2 < fixed.size() - 1) { + Widget target = fixed.get(index2 + 1); + fixed.remove(widget); + fixed.add(index2 + 1, widget); + } } } @@ -220,6 +228,13 @@ public void moveDown(Widget widget) { stream.add(index + 1, widget); }).start(); } + } else { + int index2 = fixed.indexOf(widget); + if (index2 > 0) { + Widget target = fixed.get(index2 - 1); + fixed.remove(widget); + fixed.add(index2 - 1, widget); + } } } @@ -259,7 +274,8 @@ public boolean mouseClicked(int mouseX, int mouseY, int button) { return true; } boolean flag = false; - for (Widget widget : fixed) { + for (int i = fixed.size() - 1; i >= 0; i--) { + Widget widget = fixed.get(i); if (widget.isMouseOverElement(mouseX, mouseY)) { if (widget instanceof IGuideWidget && widget != selected) { configEditor.loadConfigurator((IGuideWidget) widget); @@ -290,8 +306,10 @@ public boolean mouseClicked(int mouseX, int mouseY, int button) { @Override protected boolean hookDrawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { - Position position = getPosition(); - Size size = getSize(); + int x = getPosition().x; + int y = getPosition().y; + int width = getSize().width; + int height = getSize().height; if(title.isVisible()) { title.drawInBackground(mouseX, mouseY, partialTicks, context); } @@ -310,7 +328,7 @@ protected boolean hookDrawInBackground(int mouseX, int mouseY, float partialTick Position pos = widget.getPosition(); Size s = widget.getSize(); if (stream.contains(widget)) { - drawSolidRect(position.x, pos.y, size.width - yBarWidth, s.height, 0x6f000000); + drawSolidRect(x, pos.y, width - yBarWidth, s.height, 0x6f000000); } else { drawSolidRect(pos.x, pos.y, s.width, s.height, 0x6f000000); @@ -326,7 +344,7 @@ protected boolean hookDrawInBackground(int mouseX, int mouseY, float partialTick Position pos = widget.getPosition(); Size s = widget.getSize(); if (stream.contains(widget)) { - drawSolidRect(position.x, pos.y, size.width - yBarWidth, s.height, 0x6f000000); + drawSolidRect(x, pos.y, width - yBarWidth, s.height, 0x6f000000); } else { drawSolidRect(pos.x, pos.y, s.width, s.height, 0x6f000000); } @@ -335,13 +353,13 @@ protected boolean hookDrawInBackground(int mouseX, int mouseY, float partialTick } if (selected != null) { -// Position pos = selected.getPosition(); -// Size s = selected.getSize(); -// if (stream.contains(selected)) { -// drawSolidRect(position.x, pos.y, size.width - yBarWidth, s.height, 0x6f0000ff); -// } else { -// drawSolidRect(pos.x, pos.y, s.width, s.height, 0x6f0000ff); -// } + FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer; + int index = fixed.indexOf(selected); + String layer = "L: " + (index >= 0 ? index : stream.indexOf(selected)); + fontRenderer.drawString(layer, + selected.getPosition().x + (selected.getSize().width - fontRenderer.getStringWidth(layer)) / 2, + selected.getPosition().y - 20, + 0xffff0000, true); } if(toolButtons.isVisible()) { customPositionSizeWidget.drawInBackground(mouseX, mouseY, partialTicks, context); @@ -359,4 +377,16 @@ public boolean mouseDragged(int mouseX, int mouseY, int button, long timeDragged } return false; } + + @Override + public void clearAllWidgets() { + super.clearAllWidgets(); + selected = null; + configEditor.loadConfigurator(null); + toolButtons.setSelfPosition(new Position(-scrollYOffset, -scrollYOffset)); + customPositionSizeWidget.setControlled(null); + toolButtons.setVisible(false); + addWidget(customPositionSizeWidget); + addWidget(toolButtons); + } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java index 61669ee62d3..fa3ef7fe26a 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java @@ -21,6 +21,9 @@ public class GuidePageWidget extends DraggableScrollableWidgetGroup { static { //register guide widgets REGISTER_WIDGETS.put(TextBoxWidget.NAME, new TextBoxWidget()); REGISTER_WIDGETS.put(ImageWidget.NAME, new ImageWidget()); + REGISTER_WIDGETS.put(CardWidget.NAME, new CardWidget()); + REGISTER_WIDGETS.put(SlotListWidget.NAME, new SlotListWidget()); + REGISTER_WIDGETS.put(TankListWidget.NAME, new TankListWidget()); } protected TextBoxWidget title; protected List stream = new ArrayList<>(); @@ -72,6 +75,10 @@ public void setTitle(String config) { } } + public String getTitle() { + return title == null ? "" : String.join("\n", title.content); + } + public String loadJsonConfig(String config) { try { loadJsonConfig(new JsonParser().parse(config).getAsJsonObject()); @@ -83,6 +90,10 @@ public String loadJsonConfig(String config) { } public void loadJsonConfig(JsonObject config) { + this.stream.clear(); + this.fixed.clear(); + this.title = null; + this.clearAllWidgets(); int pageWidth = getPageWidth(); int margin = getMargin(); // add title @@ -94,7 +105,7 @@ public void loadJsonConfig(JsonObject config) { int y = title.getSize().height + 10; for (JsonElement element : config.getAsJsonArray("stream")) { JsonObject widgetConfig = element.getAsJsonObject(); - Widget widget = REGISTER_WIDGETS.get(widgetConfig.get("type").getAsString()).createStreamWidget(margin, y, pageWidth - 2 * margin, widgetConfig); + Widget widget = REGISTER_WIDGETS.get(widgetConfig.get("type").getAsString()).updateOrCreateStreamWidget(margin, y, pageWidth - 2 * margin, widgetConfig); y += widget.getSize().height + 5; stream.add(widget); this.addWidget(widget); @@ -105,7 +116,7 @@ public void loadJsonConfig(JsonObject config) { fixed = new ArrayList<>(); for (JsonElement element : config.getAsJsonArray("fixed")) { JsonObject widgetConfig = element.getAsJsonObject(); - Widget widget = REGISTER_WIDGETS.get(widgetConfig.get("type").getAsString()).createFixedWidget( + Widget widget = REGISTER_WIDGETS.get(widgetConfig.get("type").getAsString()).updateOrCreateFixedWidget( widgetConfig.get("x").getAsInt(), widgetConfig.get("y").getAsInt(), widgetConfig.get("width").getAsInt(), diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java index 4adc3648aa6..9cf86a39b6d 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java @@ -1,7 +1,6 @@ package gregtech.api.terminal.gui.widgets.guide; import com.google.gson.Gson; -import com.google.gson.JsonElement; import com.google.gson.JsonObject; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; @@ -14,10 +13,8 @@ import gregtech.api.util.Size; import net.minecraft.item.ItemStack; -import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; -import java.util.Map; import java.util.function.Consumer; public abstract class GuideWidget extends Widget implements IGuideWidget { @@ -29,7 +26,6 @@ public abstract class GuideWidget extends Widget implements IGuideWidget { public String link; public List hover_text; - private static final Gson GSON = new Gson(); private transient boolean isFixed; protected transient GuidePageWidget page; protected transient JsonObject config; @@ -44,26 +40,6 @@ public GuideWidget(){ public abstract String getRegistryName(); - public void updateValue(String field) { - if (config != null && config.has(field)) { - try { - Field f = this.getClass().getField(field); - JsonElement value = config.get(field); - if (value.isJsonNull()) { // default - f.set(this, f.get(GuidePageWidget.REGISTER_WIDGETS.get(getRegistryName()))); - } else { - f.set(this, new Gson().fromJson(value, f.getType())); - } - if (isFixed) { - initFixed(); - } else { - initStream(); - } - } catch (Exception e) { - } - } - } - @Override public JsonObject getConfig() { return config; @@ -74,9 +50,10 @@ public boolean isFixed() { return isFixed; } - @Override - public void onFixedPositionSizeChanged(Position position, Size size) { - this.initFixed(); + protected abstract Widget initFixed(); + + protected Widget initStream(){ + return initFixed(); } @Override @@ -102,11 +79,6 @@ protected void recomputePosition() { } } - @Override - public void setSelfPosition(Position selfPosition) { - super.setSelfPosition(selfPosition); - } - @Override public JsonObject getTemplate(boolean isFixed) { JsonObject template = new JsonObject(); @@ -128,12 +100,12 @@ public JsonObject getTemplate(boolean isFixed) { @Override public void loadConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, boolean isFixed, Consumer needUpdate) { - group.addWidget(new ColorConfigurator(5, group.getWidgetBottomHeight() + 5, config, "fill", 0).setOnUpdated(needUpdate)); - group.addWidget(new ColorConfigurator(5, group.getWidgetBottomHeight() + 5, config, "stroke", 0).setOnUpdated(needUpdate)); - group.addWidget(new NumberConfigurator(5, group.getWidgetBottomHeight() + 5, config, "stroke_width", 1).setOnUpdated(needUpdate)); - group.addWidget(new StringConfigurator(5, group.getWidgetBottomHeight() + 5, config, "ref", "").setOnUpdated(needUpdate)); - group.addWidget(new StringConfigurator(5, group.getWidgetBottomHeight() + 5, config, "link", "").setOnUpdated(needUpdate)); - group.addWidget(new TextListConfigurator(5, group.getWidgetBottomHeight() + 5, 40, config, "hover_text", true).setOnUpdated(needUpdate)); + group.addWidget(new ColorConfigurator(group, config, "fill", 0).setOnUpdated(needUpdate)); + group.addWidget(new ColorConfigurator(group, config, "stroke", 0).setOnUpdated(needUpdate)); + group.addWidget(new NumberConfigurator(group, config, "stroke_width", 1).setOnUpdated(needUpdate)); + group.addWidget(new StringConfigurator(group, config, "ref", "").setOnUpdated(needUpdate)); + group.addWidget(new StringConfigurator(group, config, "link", "").setOnUpdated(needUpdate)); + group.addWidget(new TextListConfigurator(group, 40, config, "hover_text", "").setOnUpdated(needUpdate)); } @Override @@ -142,8 +114,11 @@ public String getRef() { } @Override - public Widget createStreamWidget(int x, int y, int pageWidth, JsonObject config) { - GuideWidget widget = GSON.fromJson(config, this.getClass()); + public Widget updateOrCreateStreamWidget(int x, int y, int pageWidth, JsonObject config) { + if (config == null) { + return initStream(); + } + GuideWidget widget = new Gson().fromJson(config, this.getClass()); widget.isFixed = false; widget.setSelfPosition(new Position(x, y)); widget.setSize(new Size(pageWidth, 0)); @@ -152,8 +127,11 @@ public Widget createStreamWidget(int x, int y, int pageWidth, JsonObject config) } @Override - public Widget createFixedWidget(int x, int y, int width, int height, JsonObject config) { - GuideWidget widget = GSON.fromJson(config, this.getClass()); + public Widget updateOrCreateFixedWidget(int x, int y, int width, int height, JsonObject config) { + if (config == null) { + return initFixed(); + } + GuideWidget widget = new Gson().fromJson(config, this.getClass()); widget.isFixed = true; widget.setSelfPosition(new Position(x, y)); widget.setSize(new Size(width, height)); @@ -161,14 +139,6 @@ public Widget createFixedWidget(int x, int y, int width, int height, JsonObject return widget.initFixed(); } - protected Widget initStream() { - return initFixed(); - } - - protected Widget initFixed() { - return this; - } - @Override public void setPage(GuidePageWidget page) { this.page = page; @@ -198,7 +168,7 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender drawBorder(position.x, position.y, size.width, size.height, stroke, stroke_width); } if (fill != 0) { - drawGradientRect(position.x, position.y, size.width, size.height, fill, fill); + drawSolidRect(position.x, position.y, size.width, size.height, fill); } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidgetGroup.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidgetGroup.java new file mode 100644 index 00000000000..3dc31404fb2 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidgetGroup.java @@ -0,0 +1,195 @@ +package gregtech.api.terminal.gui.widgets.guide; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.Widget; +import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; +import gregtech.api.terminal.gui.widgets.guide.configurator.ColorConfigurator; +import gregtech.api.terminal.gui.widgets.guide.configurator.NumberConfigurator; +import gregtech.api.terminal.gui.widgets.guide.configurator.StringConfigurator; +import gregtech.api.terminal.gui.widgets.guide.configurator.TextListConfigurator; +import gregtech.api.util.Position; +import gregtech.api.util.Size; +import net.minecraft.item.ItemStack; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +public abstract class GuideWidgetGroup extends WidgetGroup implements IGuideWidget { + //config + public String ref; + public int fill; + public int stroke; + public int stroke_width = 1; + public String link; + public List hover_text; + + private transient boolean isFixed; + protected transient GuidePageWidget page; + protected transient JsonObject config; + + public GuideWidgetGroup(int x, int y, int width, int height) { + super(x, y, width, height); + } + + public GuideWidgetGroup(){ + super(Position.ORIGIN, Size.ZERO); + } + + public abstract String getRegistryName(); + + @Override + public JsonObject getConfig() { + return config; + } + + @Override + public boolean isFixed() { + return isFixed; + } + + @Override + public void setStroke(int color) { + this.stroke = color; + } + + @Override + public void setSize(Size size) { + Size oldSize = this.getSize(); + super.setSize(size); + if (page != null) { + page.onSizeUpdate(this, oldSize); + } + } + + @Override + protected void recomputePosition() { + Position oldPosition = getPosition(); + super.recomputePosition(); + if (page != null) { + page.onPositionUpdate(this, oldPosition); + } + } + + @Override + public JsonObject getTemplate(boolean isFixed) { + JsonObject template = new JsonObject(); + template.addProperty("type", getRegistryName()); + if (isFixed) { + template.addProperty("x", 0); + template.addProperty("y", 0); + template.addProperty("width", 100); + template.addProperty("height", 100); + } + template.addProperty("ref", (String) null); + template.addProperty("stroke", (String) null); + template.addProperty("stroke_width", (String) null); + template.addProperty("fill", (String) null); + template.addProperty("link", (String) null); + template.add("hover_text", new Gson().toJsonTree(hover_text)); + return template; + } + + @Override + public void loadConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, boolean isFixed, Consumer needUpdate) { + group.addWidget(new ColorConfigurator(group, config, "fill", 0).setOnUpdated(needUpdate)); + group.addWidget(new ColorConfigurator(group, config, "stroke", 0).setOnUpdated(needUpdate)); + group.addWidget(new NumberConfigurator(group, config, "stroke_width", 1).setOnUpdated(needUpdate)); + group.addWidget(new StringConfigurator(group, config, "ref", "").setOnUpdated(needUpdate)); + group.addWidget(new StringConfigurator(group, config, "link", "").setOnUpdated(needUpdate)); + group.addWidget(new TextListConfigurator(group, 40, config, "hover_text", "").setOnUpdated(needUpdate)); + } + + @Override + public String getRef() { + return ref; + } + + protected Widget initStream() { + return initFixed(); + } + + protected abstract Widget initFixed(); + + @Override + public Widget updateOrCreateStreamWidget(int x, int y, int pageWidth, JsonObject config) { + if (config == null) { + return initStream(); + } + GuideWidgetGroup widget = new Gson().fromJson(config, this.getClass()); + widget.isFixed = false; + widget.setSelfPosition(new Position(x, y)); + widget.setSize(new Size(pageWidth, 0)); + widget.config = config; + return widget.initStream(); + } + + @Override + public Widget updateOrCreateFixedWidget(int x, int y, int width, int height, JsonObject config) { + if (config == null) { + return initFixed(); + } + GuideWidgetGroup widget = new Gson().fromJson(config, this.getClass()); + widget.isFixed = true; + widget.setSelfPosition(new Position(x, y)); + widget.setSize(new Size(width, height)); + widget.config = config; + return widget.initFixed(); + } + + @Override + public void setPage(GuidePageWidget page) { + this.page = page; + } + + @Override + public void addWidget(Widget widget) { + super.addWidget(widget); + if (widget instanceof IGuideWidget) { + ((IGuideWidget) widget).setPage(page); + } + } + + @Override + public void drawInForeground(int mouseX, int mouseY) { + if (link != null && isMouseOverElement(mouseX, mouseY)) { + Position position = getPosition(); + Size size = getSize(); + drawBorder(position.x, position.y, size.width, size.height, 0xff0000ff, stroke_width); + } + if ((hover_text != null || link != null) && isMouseOverElement(mouseX, mouseY)) { + List tooltip = hover_text == null ? new ArrayList<>() : new ArrayList<>(hover_text); + if (link != null) { + tooltip.add("§9Ctrl+Click§r §e(" + link + ")§r"); + } + drawHoveringText(ItemStack.EMPTY, tooltip, 100, mouseX, mouseY); + } + super.drawInForeground(mouseX, mouseY); + } + + @Override + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + Position position = getPosition(); + Size size = getSize(); + if(stroke != 0) { + drawBorder(position.x, position.y, size.width, size.height, stroke, stroke_width); + } + if (fill != 0) { + drawSolidRect(position.x, position.y, size.width, size.height, fill); + } + super.drawInBackground(mouseX, mouseY, partialTicks, context); + } + + @Override + public boolean mouseClicked(int mouseX, int mouseY, int button) { + if (link != null && isMouseOverElement(mouseX, mouseY) && isCtrlDown()) { + page.jumpToRef(link); + return true; + } + return super.mouseClicked(mouseX, mouseY, button); + } + +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java index 99c387e7a83..5b55547f941 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java @@ -1,23 +1,48 @@ package gregtech.api.terminal.gui.widgets.guide; +import com.google.gson.Gson; +import com.google.gson.JsonElement; import com.google.gson.JsonObject; import gregtech.api.gui.Widget; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; import gregtech.api.util.Position; import gregtech.api.util.Size; +import java.lang.reflect.Field; import java.util.function.Consumer; public interface IGuideWidget { + String getRegistryName(); JsonObject getConfig(); boolean isFixed(); - Widget createStreamWidget(int x, int y, int pageWidth, JsonObject config); - Widget createFixedWidget(int x, int y, int width, int height, JsonObject config); + Widget updateOrCreateStreamWidget(int x, int y, int pageWidth, JsonObject config); + Widget updateOrCreateFixedWidget(int x, int y, int width, int height, JsonObject config); void setPage(GuidePageWidget page); - void updateValue(String field); + default void updateValue(String field){ + JsonObject config = getConfig(); + if (config != null && config.has(field)) { + try { + Field f = this.getClass().getField(field); + JsonElement value = config.get(field); + if (value.isJsonNull()) { // default + f.set(this, f.get(GuidePageWidget.REGISTER_WIDGETS.get(getRegistryName()))); + } else { + f.set(this, new Gson().fromJson(value, f.getGenericType())); + } + if (isFixed()) { + updateOrCreateFixedWidget(0,0,0,0,null); + } else { + updateOrCreateStreamWidget(0,0,0,null); + } + } catch (Exception e) { + } + } + } String getRef(); JsonObject getTemplate(boolean isFixed); void loadConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, boolean isFixed, Consumer needUpdate); void setStroke(int color); - void onFixedPositionSizeChanged(Position position, Size size); + default void onFixedPositionSizeChanged(Position position, Size size) { + updateOrCreateFixedWidget(0,0,0,0,null); + } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java index 2a45c6d6530..83900ef19bc 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java @@ -39,8 +39,8 @@ public String getRegistryName() { @Override public JsonObject getTemplate(boolean isFixed) { JsonObject template = super.getTemplate(isFixed); - template.addProperty("form", "item"); - template.addProperty("source", "minecraft:ender_pearl"); + template.addProperty("form", "resource"); + template.addProperty("source", "gregtech:textures/gui/icon/gregtech_logo.png"); template.addProperty("width", 50); template.addProperty("height", 50); return template; @@ -49,11 +49,11 @@ public JsonObject getTemplate(boolean isFixed) { @Override public void loadConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, boolean isFixed, Consumer needUpdate) { super.loadConfigurator(group, config, isFixed, needUpdate); - group.addWidget(new SelectorConfigurator(5, group.getWidgetBottomHeight() + 5, config, "form", Arrays.asList("url", "item", "resource")).setOnUpdated(needUpdate)); - group.addWidget(new StringConfigurator(5, group.getWidgetBottomHeight() + 5, config, "source").setOnUpdated(needUpdate)); + group.addWidget(new SelectorConfigurator(group, config, "form", Arrays.asList("url", "item", "resource")).setOnUpdated(needUpdate)); + group.addWidget(new StringConfigurator(group, config, "source").setOnUpdated(needUpdate)); if (!isFixed) { - group.addWidget(new NumberConfigurator(5, group.getWidgetBottomHeight() + 5, config, "width").setOnUpdated(needUpdate)); - group.addWidget(new NumberConfigurator(5, group.getWidgetBottomHeight() + 5, config, "height").setOnUpdated(needUpdate)); + group.addWidget(new NumberConfigurator(group, config, "width").setOnUpdated(needUpdate)); + group.addWidget(new NumberConfigurator(group, config, "height").setOnUpdated(needUpdate)); } } @@ -64,11 +64,6 @@ public void updateScreen() { } } - @Override - public void onFixedPositionSizeChanged(Position position, Size size) { - super.onFixedPositionSizeChanged(position, size); - } - @Override protected Widget initStream() { int pageWidth = getSize().width; @@ -78,12 +73,14 @@ protected Widget initStream() { x = page.getMargin(); pageWidth = page.getPageWidth() - 2 * x; } - this.setSelfPosition(new Position(x + (pageWidth - width) / 2, y)); + this.setSelfPosition(new Position(x + (pageWidth - Math.max(0, width)) / 2, y)); return initFixed(); } @Override protected Widget initFixed() { + width = Math.max(0, width); + height = Math.max(0, height); this.setSize(new Size(width, height)); switch (form) { case "url": diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/SlotListWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/SlotListWidget.java new file mode 100644 index 00000000000..502d8b7f29c --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/SlotListWidget.java @@ -0,0 +1,126 @@ +package gregtech.api.terminal.gui.widgets.guide; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.ColorRectTexture; +import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.widgets.SlotWidget; +import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; +import gregtech.api.terminal.gui.widgets.guide.configurator.ItemStackConfigurator; +import gregtech.api.util.Size; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.items.ItemStackHandler; + +import java.awt.*; +import java.util.Collections; +import java.util.List; +import java.util.function.Consumer; + +public class SlotListWidget extends GuideWidgetGroup { + public final static String NAME = "slots"; + + // config + public List item_list; + + protected transient Rectangle scissor; + + @Override + public Widget initFixed() { + this.clearAllWidgets(); + ItemStackHandler itemStackHandler = new ItemStackHandler(item_list.size()); + IGuiTexture background = new ColorRectTexture(0x4f000000); + int size = item_list.size(); + int maxXSize = getSize().width / 18; + int xPos; + if (maxXSize < 1) { + maxXSize = 1; + xPos = 0; + } else { + xPos = (getSize().width - (Math.min(size, maxXSize)) * 18) / 2; + } + int maxYSize = size / maxXSize + ((size % maxXSize) == 0 ? 0 : 1); + for (int y = 0; y <= size / maxXSize; y++) { + for (int x = 0; x < maxXSize; x++) { + int i = x + y * maxXSize; + if (i < size) { + itemStackHandler.setStackInSlot(i, item_list.get(i).getInstance()); + SlotWidget widget = new SlotWidget(itemStackHandler, i, xPos + x * 18, y * 18, false, false); + widget.setBackgroundTexture(background); + if (scissor != null) { + widget.applyScissor(scissor.x, scissor.y, scissor.width, scissor.height); + } + this.addWidget(widget); + } + } + } + setSize(new Size(getSize().width / 18 > 0 ? getSize().width : 18, maxYSize * 18)); + return this; + } + + @Override + public String getRegistryName() { + return NAME; + } + + @Override + public JsonObject getTemplate(boolean isFixed) { + JsonObject template = super.getTemplate(isFixed); + template.add("item_list", new Gson().toJsonTree(Collections.singletonList(new ItemStackInfo("gregtech:meta_item_2", 32581, 1)))); + return template; + } + + @Override + public void loadConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, boolean isFixed, Consumer needUpdate) { + super.loadConfigurator(group, config, isFixed, needUpdate); + group.addWidget(new ItemStackConfigurator(group, config, "item_list").setOnUpdated(needUpdate)); + } + + @Override + public void applyScissor(int parentX, int parentY, int parentWidth, int parentHeight) { + super.applyScissor(parentX, parentY, parentWidth, parentHeight); + scissor = new Rectangle(parentX, parentY, parentWidth, parentHeight); + } + + public static class ItemStackInfo { + // config + public String id; + public int damage; + public int count = 1; + + private transient ItemStack itemStack; + + public ItemStackInfo() { + + } + + public void update(ItemStack itemStack) { + ResourceLocation resourceLocation = itemStack.getItem().getRegistryName(); + id = resourceLocation == null ? "minecraft:air" : resourceLocation.toString(); + damage = itemStack.getItemDamage(); + count = itemStack.getCount(); + } + + public ItemStackInfo(String id, int damage, int count) { + this.id = id; + this.damage = damage; + this.count = count; + } + + public ItemStack getInstance() { + if (itemStack == null && id != null) { + Item item = Item.getByNameOrId(id); + if (item == null) { + itemStack = ItemStack.EMPTY; + return itemStack; + } + itemStack = item.getDefaultInstance(); + itemStack.setCount(count); + itemStack.setItemDamage(damage); + } + return itemStack == null ? ItemStack.EMPTY : itemStack; + } + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TankListWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TankListWidget.java new file mode 100644 index 00000000000..adac67ca2df --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TankListWidget.java @@ -0,0 +1,119 @@ +package gregtech.api.terminal.gui.widgets.guide; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.ColorRectTexture; +import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.widgets.TankWidget; +import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; +import gregtech.api.terminal.gui.widgets.guide.configurator.ItemStackConfigurator; +import gregtech.api.util.Size; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidRegistry; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.FluidTank; +import net.minecraftforge.items.ItemStackHandler; + +import java.awt.*; +import java.util.Collections; +import java.util.List; +import java.util.function.Consumer; + +public class TankListWidget extends GuideWidgetGroup { + public final static String NAME = "tanks"; + + // config + public List fluid_list; + + protected transient Rectangle scissor; + + @Override + public Widget initFixed() { + this.clearAllWidgets(); + IGuiTexture background = new ColorRectTexture(0x4f000000); + int size = fluid_list.size(); + int maxXSize = getSize().width / 18; + int xPos; + if (maxXSize < 1) { + maxXSize = 1; + xPos = 0; + } else { + xPos = (getSize().width - (Math.min(size, maxXSize)) * 18) / 2; + } + int maxYSize = size / maxXSize + ((size % maxXSize) == 0 ? 0 : 1); + for (int y = 0; y <= size / maxXSize; y++) { + for (int x = 0; x < maxXSize; x++) { + int i = x + y * maxXSize; + if (i < size) { + FluidStack fluidStack = fluid_list.get(i).getInstance(); + TankWidget widget = new TankWidget(new FluidTank(fluidStack, fluid_list.get(i).amount), xPos + x * 18, y * 18, 18, 18); + widget.setBackgroundTexture(background); + this.addWidget(widget); + } + } + } + setSize(new Size(getSize().width / 18 > 0 ? getSize().width : 18, maxYSize * 18)); + return this; + } + + @Override + public String getRegistryName() { + return NAME; + } + + @Override + public JsonObject getTemplate(boolean isFixed) { + JsonObject template = super.getTemplate(isFixed); + template.add("fluid_list", new Gson().toJsonTree(Collections.singletonList(new FluidStackInfo("distilled_water", 1)))); + return template; + } + + @Override + public void loadConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, boolean isFixed, Consumer needUpdate) { + super.loadConfigurator(group, config, isFixed, needUpdate); +// group.addWidget(new ItemStackConfigurator(group, config, "fluid_list").setOnUpdated(needUpdate)); + } + + @Override + public void applyScissor(int parentX, int parentY, int parentWidth, int parentHeight) { + super.applyScissor(parentX, parentY, parentWidth, parentHeight); + scissor = new Rectangle(parentX, parentY, parentWidth, parentHeight); + } + + public static class FluidStackInfo { + // config + public String id; + public int amount = 1; + + private transient FluidStack fluidStack; + + public FluidStackInfo() { + + } + + public void update(FluidStack itemStack) { + id = FluidRegistry.getFluidName(itemStack.getFluid()); + amount = itemStack.amount; + } + + public FluidStackInfo(String id, int amount) { + this.id = id; + this.amount = amount; + } + + public FluidStack getInstance() { + if (fluidStack == null && id != null) { + Fluid fluid = FluidRegistry.getFluid(id); + if (fluid != null) { + fluidStack = new FluidStack(fluid, amount); + } + id = null; + } + return fluidStack; + } + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java index 02eb98e8e9e..1d4fbcb06c7 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java @@ -70,12 +70,12 @@ public JsonObject getTemplate(boolean isFixed) { @Override public void loadConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, boolean isFixed, Consumer needUpdate) { super.loadConfigurator(group, config, isFixed, needUpdate); - group.addWidget(new NumberConfigurator(5, group.getWidgetBottomHeight() + 5, config, "space", 1).setOnUpdated(needUpdate)); - group.addWidget(new NumberConfigurator(5, group.getWidgetBottomHeight() + 5, config, "fontSize", 9).setOnUpdated(needUpdate)); - group.addWidget(new ColorConfigurator(5, group.getWidgetBottomHeight() + 5, config, "fontColor", 0xff000000).setOnUpdated(needUpdate)); - group.addWidget(new BooleanConfigurator(5, group.getWidgetBottomHeight() + 5, config, "isShadow", false).setOnUpdated(needUpdate)); - group.addWidget(new BooleanConfigurator(5, group.getWidgetBottomHeight() + 5, config, "isCenter", false).setOnUpdated(needUpdate)); - group.addWidget(new TextListConfigurator(5, group.getWidgetBottomHeight() + 5, 200, config, "content", false).setOnUpdated(needUpdate)); + group.addWidget(new NumberConfigurator(group, config, "space", 1).setOnUpdated(needUpdate)); + group.addWidget(new NumberConfigurator(group, config, "fontSize", 9).setOnUpdated(needUpdate)); + group.addWidget(new ColorConfigurator(group, config, "fontColor", 0xff000000).setOnUpdated(needUpdate)); + group.addWidget(new BooleanConfigurator(group, config, "isShadow", false).setOnUpdated(needUpdate)); + group.addWidget(new BooleanConfigurator(group, config, "isCenter", false).setOnUpdated(needUpdate)); + group.addWidget(new TextListConfigurator(group, 200, config, "content").setOnUpdated(needUpdate)); } @Override diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java deleted file mode 100644 index d7dca38ab5d..00000000000 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java +++ /dev/null @@ -1,150 +0,0 @@ -package gregtech.api.terminal.gui.widgets.guide; - -import com.google.gson.JsonObject; -import gregtech.api.gui.IRenderContext; -import gregtech.api.gui.Widget; -import gregtech.api.gui.resources.IGuiTexture; -import gregtech.api.terminal.util.TreeNode; -import gregtech.api.util.Position; -import gregtech.api.util.RenderUtil; -import gregtech.api.util.Size; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.FontRenderer; -import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.client.resources.I18n; -import net.minecraft.util.Tuple; -import net.minecraft.util.math.MathHelper; - -import java.util.ArrayList; -import java.util.List; -import java.util.function.Consumer; -import java.util.function.Function; - -public class TextTreeWidget extends Widget { - private static final int ITEM_HEIGHT = 11; - protected int scrollOffset; - protected List> list; - protected TreeNode selected; - protected IGuiTexture background; - protected IGuiTexture nodeTexture; - protected IGuiTexture leafTexture; - protected Consumer> onSelected; - protected Function iconSupplier; - protected Function nameSupplier; - - public TextTreeWidget(int xPosition, int yPosition, int width, int height, - TreeNode root, - Consumer> onSelected, - Function iconSupplier, - Function nameSupplier) { - super(new Position(xPosition, yPosition), new Size(width, height)); - list = new ArrayList<>(); - if (root.children != null) { - list.addAll(root.children); - } - this.onSelected = onSelected; - this.iconSupplier = iconSupplier; - this.nameSupplier = nameSupplier; - } - - public TextTreeWidget setBackground(IGuiTexture background) { - this.background = background; - return this; - } - - public TextTreeWidget setNodeTexture(IGuiTexture nodeTexture) { - this.nodeTexture = nodeTexture; - return this; - } - - public TextTreeWidget setLeafTexture(IGuiTexture leafTexture) { - this.leafTexture = leafTexture; - return this; - } - - @Override - public boolean mouseWheelMove(int mouseX, int mouseY, int wheelDelta) { - if (this.isMouseOverElement(mouseX, mouseY, true)) { - int moveDelta = -MathHelper.clamp(wheelDelta, -1, 1) * 5; - this.scrollOffset = MathHelper.clamp(scrollOffset + moveDelta, 0, Math.max(list.size() * ITEM_HEIGHT - getSize().height, 0)); - return true; - } - return false; - } - - @Override - public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { - Position position = getPosition(); - Size size = getSize(); - if (background != null) { - background.draw(position.x, position.y, size.width, size.height); - } else { - drawGradientRect(position.x, position.y, size.width, size.height, 0x8f000000, 0x8f000000); - } - RenderUtil.useScissor(position.x, position.y, size.width, size.height, ()->{ - FontRenderer fr = Minecraft.getMinecraft().fontRenderer; - int minToRender = scrollOffset / ITEM_HEIGHT; - int maxToRender = Math.min(list.size(), size.height / ITEM_HEIGHT + 2 + minToRender); - - for (int i = minToRender; i < maxToRender; i++) { - GlStateManager.color(1,1,1,1); - TreeNode node = list.get(i); - int x = position.x + 10 * node.dimension; - int y = position.y - scrollOffset + i * ITEM_HEIGHT; - String name = node.key; - if (node.isLeaf()) { - if (leafTexture != null) { - leafTexture.draw(position.x, y, size.width, ITEM_HEIGHT); - } else { - drawSolidRect(position.x, y, size.width, ITEM_HEIGHT, 0xffff0000); - } - if (node.content != null) { - String nameS = nameSupplier.apply(node.content); - name = nameS == null ? name : nameS; - IGuiTexture icon = iconSupplier.apply(node.content); - if (icon != null) { - icon.draw(x - 9, y + 1, 8, 8); - } - } - } else { - if (nodeTexture != null) { - nodeTexture.draw(position.x, y, size.width, ITEM_HEIGHT); - } else { - drawSolidRect(position.x, y, size.width, ITEM_HEIGHT, 0xffffff00); - } - } - if (node == selected) { - drawSolidRect(position.x, y, size.width, ITEM_HEIGHT, 0x7f000000); - } - fr.drawString(I18n.format(name), x, y + 2, 0xff000000); - } - }); - } - - @Override - public boolean mouseClicked(int mouseX, int mouseY, int button) { - if (this.isMouseOverElement(mouseX, mouseY)) { - int index = ((mouseY - getPosition().y) + scrollOffset) / ITEM_HEIGHT; - if (index < list.size()) { - TreeNode node = list.get(index); - if (node.isLeaf()) { - if (node != this.selected) { - this.selected = node; - onSelected.accept(node); - } - } else if (node.children.size() > 0 && list.contains(node.children.get(0))){ - for (TreeNode child : node.children) { - list.remove(child); - } - } else { - for (int i = 0; i < node.children.size(); i++) { - list.add(index + 1 + i, node.children.get(i)); - } - } - playButtonClickSound(); - } - return true; - } - return false; - } -} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/BooleanConfigurator.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/BooleanConfigurator.java index 2b4c4ae2ca8..8c3b3c567ea 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/BooleanConfigurator.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/BooleanConfigurator.java @@ -3,27 +3,24 @@ import com.google.gson.JsonObject; import gregtech.api.gui.GuiTextures; import gregtech.api.gui.resources.ColorRectTexture; +import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; import gregtech.api.terminal.gui.widgets.RectButtonWidget; import java.awt.*; -public class BooleanConfigurator extends ConfiguratorWidget{ - private boolean defaultValue; +public class BooleanConfigurator extends ConfiguratorWidget{ - public BooleanConfigurator(int x, int y, JsonObject config, String name) { - super(x, y, config, name, false); - init(); + public BooleanConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, String name) { + super(group, config, name); } - public BooleanConfigurator(int x, int y, JsonObject config, String name, boolean defaultValue) { - super(x, y, config, name, true); - this.defaultValue = defaultValue; - init(); + public BooleanConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, String name, boolean defaultValue) { + super(group, config, name, defaultValue); } - private void init(){ + protected void init(){ this.addWidget(new RectButtonWidget(0, 15, 10, 10, 2) - .setToggleButton(new ColorRectTexture(new Color(198, 198, 198).getRGB()), (c, p)-> update(p)) + .setToggleButton(new ColorRectTexture(new Color(198, 198, 198).getRGB()), (c, p)->updateValue(p)) .setValueSupplier(true, ()->{ if(config.get(name).isJsonNull()) { return defaultValue; @@ -35,9 +32,4 @@ private void init(){ new Color(255, 255, 255, 0).getRGB()) .setIcon(new ColorRectTexture(new Color(0, 0, 0, 74).getRGB()))); } - - private void update(boolean bool) { - config.addProperty(name, bool); - update(); - } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ColorConfigurator.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ColorConfigurator.java index f52019325ec..605593b0166 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ColorConfigurator.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ColorConfigurator.java @@ -2,33 +2,26 @@ import com.google.gson.JsonObject; import gregtech.api.terminal.gui.widgets.ColorWidget; +import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; -public class ColorConfigurator extends ConfiguratorWidget{ - private int defaultValue; +public class ColorConfigurator extends ConfiguratorWidget{ - public ColorConfigurator(int x, int y, JsonObject config, String name, int defaultValue) { - super(x, y, config, name, true); - this.defaultValue = defaultValue; - init(); + public ColorConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, String name, int defaultValue) { + super(group, config, name, defaultValue); } - public ColorConfigurator(int x, int y, JsonObject config, String name) { - super(x, y, config, name, false); - init(); + public ColorConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, String name) { + super(group, config, name); } - private void init(){ + protected void init(){ this.addWidget(new ColorWidget(0, 15, 85, 10).setColorSupplier(()->{ if(config.get(name).isJsonNull()) { return defaultValue; } return config.get(name).getAsInt(); - },true).setOnColorChanged(this::update)); + },true).setOnColorChanged(this::updateValue)); } - private void update(int color) { - config.addProperty(name, color); - update(); - } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ConfiguratorWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ConfiguratorWidget.java index 42b25898006..15c7fb5c561 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ConfiguratorWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ConfiguratorWidget.java @@ -1,9 +1,11 @@ package gregtech.api.terminal.gui.widgets.guide.configurator; +import com.google.gson.Gson; import com.google.gson.JsonObject; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.widgets.LabelWidget; import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; import gregtech.api.util.Position; import net.minecraft.client.Minecraft; import net.minecraft.item.ItemStack; @@ -11,20 +13,30 @@ import java.util.Collections; import java.util.function.Consumer; -public class ConfiguratorWidget extends WidgetGroup { +public class ConfiguratorWidget extends WidgetGroup { + protected T defaultValue; protected String name; protected boolean canDefault; protected boolean isDefault; protected JsonObject config; - + protected DraggableScrollableWidgetGroup group; private int nameWidth; private Consumer onUpdated; - public ConfiguratorWidget(int x, int y, JsonObject config, String name, boolean canDefault) { - super(new Position(x, y)); + public ConfiguratorWidget(DraggableScrollableWidgetGroup group, JsonObject config, String name) { + this(group, config, name, null); + } + + public ConfiguratorWidget(DraggableScrollableWidgetGroup group, JsonObject config, String name, T defaultValue) { + super(new Position(5, group.getWidgetBottomHeight() + 5)); + this.group = group; + this.defaultValue = defaultValue; this.name = name; - this.canDefault = canDefault; + this.canDefault = defaultValue != null; this.config = config; + if (config.get(name) == null) { + config.addProperty(name, (String)null); + } if (canDefault && config.get(name).isJsonNull()) { isDefault = true; } @@ -32,9 +44,20 @@ public ConfiguratorWidget(int x, int y, JsonObject config, String name, boolean if (isClientSide()) { nameWidth = Minecraft.getMinecraft().fontRenderer.getStringWidth(name); } + init(); + } + + protected void init() { + + } + + protected void updateValue(T value) { + if (canDefault && isDefault) return; + config.add(name, new Gson().toJsonTree(value)); + update(); } - public ConfiguratorWidget setOnUpdated(Consumer onUpdated) { + public ConfiguratorWidget setOnUpdated(Consumer onUpdated) { this.onUpdated = onUpdated; return this; } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/FluidStackConfigurator.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/FluidStackConfigurator.java new file mode 100644 index 00000000000..515003db110 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/FluidStackConfigurator.java @@ -0,0 +1,97 @@ +package gregtech.api.terminal.gui.widgets.guide.configurator; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import gregtech.api.gui.GuiTextures; +import gregtech.api.gui.resources.ColorRectTexture; +import gregtech.api.gui.resources.TextTexture; +import gregtech.api.gui.widgets.*; +import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; +import gregtech.api.terminal.gui.widgets.RectButtonWidget; +import gregtech.api.terminal.gui.widgets.guide.TankListWidget; + +import java.awt.*; +import java.util.ArrayList; +import java.util.List; + +public class FluidStackConfigurator extends ConfiguratorWidget>{ + DraggableScrollableWidgetGroup container; + List tanks; + + public FluidStackConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, String name) { + super(group, config, name); + } + + protected void init() { + container = new DraggableScrollableWidgetGroup(0, 27,116, 100); + this.addWidget(container); + this.addWidget(new RectButtonWidget(0, 15, 116, 10, 1) + .setIcon(new TextTexture("Add Slot", -1)) + .setClickListener(cd->{ + addSlot(container, new TankListWidget.FluidStackInfo(null, 0)); + updateValue(); + }) + .setColors(new Color(0, 0, 0, 74).getRGB(), + new Color(128, 255, 128).getRGB(), + new Color(255, 255, 255, 0).getRGB())); + tanks = new ArrayList<>(); + if (!config.get(name).isJsonNull()) { + Gson gson = new Gson(); + for (JsonElement o : config.get(name).getAsJsonArray()) { + addSlot(container, gson.fromJson(o, TankListWidget.FluidStackInfo.class)); + } + } + } + + private void addSlot(DraggableScrollableWidgetGroup container, TankListWidget.FluidStackInfo fluidStackInfo) { + WidgetGroup group = new WidgetGroup(0, tanks.size() * 20, 116, 20); + tanks.add(fluidStackInfo); + group.addWidget(new PhantomFluidWidget(1, 1, 18, 18, null, null) + .setBackgroundTexture(new ColorRectTexture(0x9f000000)) + .setFluidStackSupplier(fluidStackInfo::getInstance, true) + .setFluidStackUpdater(fluidStack->{ + fluidStackInfo.update(fluidStack); + updateValue(); + }, true)); + group.addWidget(new RectButtonWidget(20, 0, 20, 20) + .setColors(new Color(0, 0, 0, 74).getRGB(), + new Color(128, 255, 128).getRGB(), + new Color(255, 255, 255, 0).getRGB()) + .setClickListener(data -> { + fluidStackInfo.amount = Math.max(0, fluidStackInfo.amount - (data.isShiftClick ? 10 : 1)); + updateValue(); + }) + .setIcon(new TextTexture("-1", -1))); + group.addWidget(new RectButtonWidget(76, 0, 20, 20) + .setColors(new Color(0, 0, 0, 74).getRGB(), + new Color(128, 255, 128).getRGB(), + new Color(255, 255, 255, 0).getRGB()) + .setClickListener(data -> { + fluidStackInfo.amount = Math.max(0, fluidStackInfo.amount + (data.isShiftClick ? 10 : 1)); + updateValue(); + }) + .setIcon(new TextTexture("+1", -1))); + group.addWidget(new ImageWidget(40, 0, 36, 20, new ColorRectTexture(0x9f000000))); + group.addWidget(new SimpleTextWidget(58, 10, "", 0xFFFFFF, () -> Integer.toString(fluidStackInfo.amount), true)); + group.addWidget(new RectButtonWidget(96, 0, 20, 20) + .setColors(new Color(0, 0, 0, 74).getRGB(), + new Color(128, 255, 128).getRGB(), + new Color(255, 255, 255, 0).getRGB()) + .setClickListener(data -> { + container.waitToRemoved(group); + tanks.remove(fluidStackInfo); + int index = container.widgets.indexOf(group); + for (int i = container.widgets.size() - 1; i > index; i--) { + container.widgets.get(i).addSelfPosition(0, -20); + } + updateValue(); + }) + .setIcon(GuiTextures.TERMINAL_DELETE)); + container.addWidget(group); + } + + private void updateValue() { + updateValue(tanks); + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ItemStackConfigurator.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ItemStackConfigurator.java new file mode 100644 index 00000000000..1ddc765534e --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ItemStackConfigurator.java @@ -0,0 +1,101 @@ +package gregtech.api.terminal.gui.widgets.guide.configurator; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import gregtech.api.gui.GuiTextures; +import gregtech.api.gui.resources.ColorRectTexture; +import gregtech.api.gui.resources.TextTexture; +import gregtech.api.gui.widgets.ImageWidget; +import gregtech.api.gui.widgets.PhantomSlotWidget; +import gregtech.api.gui.widgets.SimpleTextWidget; +import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; +import gregtech.api.terminal.gui.widgets.RectButtonWidget; +import gregtech.api.terminal.gui.widgets.guide.SlotListWidget; +import net.minecraftforge.items.IItemHandlerModifiable; +import net.minecraftforge.items.ItemStackHandler; + +import java.awt.*; +import java.util.ArrayList; +import java.util.List; + +public class ItemStackConfigurator extends ConfiguratorWidget>{ + DraggableScrollableWidgetGroup container; + List slots; + + public ItemStackConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, String name) { + super(group, config, name); + } + + protected void init() { + container = new DraggableScrollableWidgetGroup(0, 27,116, 100); + this.addWidget(container); + this.addWidget(new RectButtonWidget(0, 15, 116, 10, 1) + .setIcon(new TextTexture("Add Slot", -1)) + .setClickListener(cd->{ + addSlot(container, new SlotListWidget.ItemStackInfo("minecraft:air", 0, 0)); + updateValue(); + }) + .setColors(new Color(0, 0, 0, 74).getRGB(), + new Color(128, 255, 128).getRGB(), + new Color(255, 255, 255, 0).getRGB())); + slots = new ArrayList<>(); + if (!config.get(name).isJsonNull()) { + Gson gson = new Gson(); + for (JsonElement o : config.get(name).getAsJsonArray()) { + addSlot(container, gson.fromJson(o, SlotListWidget.ItemStackInfo.class)); + } + } + } + + private void addSlot(DraggableScrollableWidgetGroup container, SlotListWidget.ItemStackInfo itemStackInfo) { + WidgetGroup group = new WidgetGroup(0,slots.size() * 20, 116, 20); + slots.add(itemStackInfo); + IItemHandlerModifiable handler = new ItemStackHandler(); + handler.setStackInSlot(0, itemStackInfo.getInstance()); + group.addWidget(new PhantomSlotWidget(handler, 0, 1, 1).setBackgroundTexture(new ColorRectTexture(0x9f000000)).setChangeListener(()->{ + itemStackInfo.update(handler.getStackInSlot(0)); + updateValue(); + })); + group.addWidget(new RectButtonWidget(20, 0, 20, 20) + .setColors(new Color(0, 0, 0, 74).getRGB(), + new Color(128, 255, 128).getRGB(), + new Color(255, 255, 255, 0).getRGB()) + .setClickListener(data -> { + itemStackInfo.count = Math.max(0, itemStackInfo.count - (data.isShiftClick ? 10 : 1)); + updateValue(); + }) + .setIcon(new TextTexture("-1", -1))); + group.addWidget(new RectButtonWidget(76, 0, 20, 20) + .setColors(new Color(0, 0, 0, 74).getRGB(), + new Color(128, 255, 128).getRGB(), + new Color(255, 255, 255, 0).getRGB()) + .setClickListener(data -> { + itemStackInfo.count = Math.max(0, itemStackInfo.count + (data.isShiftClick ? 10 : 1)); + updateValue(); + }) + .setIcon(new TextTexture("+1", -1))); + group.addWidget(new ImageWidget(40, 0, 36, 20, new ColorRectTexture(0x9f000000))); + group.addWidget(new SimpleTextWidget(58, 10, "", 0xFFFFFF, () -> Integer.toString(itemStackInfo.count), true)); + group.addWidget(new RectButtonWidget(96, 0, 20, 20) + .setColors(new Color(0, 0, 0, 74).getRGB(), + new Color(128, 255, 128).getRGB(), + new Color(255, 255, 255, 0).getRGB()) + .setClickListener(data -> { + container.waitToRemoved(group); + slots.remove(itemStackInfo); + int index = container.widgets.indexOf(group); + for (int i = container.widgets.size() - 1; i > index; i--) { + container.widgets.get(i).addSelfPosition(0, -20); + } + updateValue(); + }) + .setIcon(GuiTextures.TERMINAL_DELETE)); + container.addWidget(group); + } + + private void updateValue() { + updateValue(slots); + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/NumberConfigurator.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/NumberConfigurator.java index 58c4c8fb059..0779e0e661a 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/NumberConfigurator.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/NumberConfigurator.java @@ -7,25 +7,22 @@ import gregtech.api.gui.resources.TextTexture; import gregtech.api.gui.widgets.ImageWidget; import gregtech.api.gui.widgets.SimpleTextWidget; +import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; import gregtech.api.terminal.gui.widgets.RectButtonWidget; import java.awt.*; -public class NumberConfigurator extends ConfiguratorWidget{ - private int defaultValue; +public class NumberConfigurator extends ConfiguratorWidget{ - public NumberConfigurator(int x, int y, JsonObject config, String name) { - super(x, y, config, name, false); - init(0); + public NumberConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, String name) { + super(group, config, name); } - public NumberConfigurator(int x, int y, JsonObject config, String name, int defaultValue) { - super(x, y, config, name, true); - init(defaultValue); + public NumberConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, String name, int defaultValue) { + super(group, config, name, defaultValue); } - private void init(int defaultValue){ - this.defaultValue = defaultValue; + protected void init(){ int y = 15; this.addWidget(new RectButtonWidget(0, y, 20, 20) .setColors(new Color(0, 0, 0, 74).getRGB(), @@ -63,11 +60,12 @@ private void init(int defaultValue){ private void adjustTransferRate(int added) { JsonElement element = config.get(name); - int num = defaultValue; + int num = 0; if (!element.isJsonNull()) { num = element.getAsInt(); + } else { + num = defaultValue; } - config.addProperty(name, num + added); - update(); + updateValue(num + added); } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/SelectorConfigurator.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/SelectorConfigurator.java index eaeec766e7f..054f159ee57 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/SelectorConfigurator.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/SelectorConfigurator.java @@ -1,34 +1,24 @@ package gregtech.api.terminal.gui.widgets.guide.configurator; -import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import gregtech.api.gui.GuiTextures; -import gregtech.api.gui.resources.TextTexture; -import gregtech.api.gui.widgets.ImageWidget; -import gregtech.api.gui.widgets.SimpleTextWidget; -import gregtech.api.terminal.gui.widgets.RectButtonWidget; +import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; import gregtech.api.terminal.gui.widgets.SelectorWidget; import java.awt.*; import java.util.List; -public class SelectorConfigurator extends ConfiguratorWidget{ - private final List candidates; - private String defaultValue; - public SelectorConfigurator(int x, int y, JsonObject config, String name, List candidates, String defaultValue) { - super(x, y, config, name, true); - this.defaultValue = defaultValue; - this.candidates = candidates; - init(); +public class SelectorConfigurator extends ConfiguratorWidget{ + public SelectorConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, String name, List candidates, String defaultValue) { + super(group, config, name, defaultValue); + init(candidates); } - public SelectorConfigurator(int x, int y, JsonObject config, String name, List candidates) { - super(x, y, config, name, false); - this.candidates = candidates; - init(); + public SelectorConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, String name, List candidates) { + super(group, config, name); + init(candidates); } - private void init(){ + protected void init(List candidates){ this.addWidget(new SelectorWidget(0, 15, 80, 20, candidates, -1, ()->{ if(config.get(name).isJsonNull()) { return defaultValue; @@ -42,8 +32,4 @@ private void init(){ .setOnChanged(this::updateValue)); } - private void updateValue(String selected) { - config.addProperty(name, selected); - update(); - } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/StringConfigurator.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/StringConfigurator.java index 3ffba684148..fa5cc9616c2 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/StringConfigurator.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/StringConfigurator.java @@ -5,28 +5,23 @@ import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.resources.TextTexture; import gregtech.api.gui.widgets.TextFieldWidget; +import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; import gregtech.api.terminal.gui.widgets.RectButtonWidget; import java.awt.*; -public class StringConfigurator extends ConfiguratorWidget{ - private String defaultValue = ""; +public class StringConfigurator extends ConfiguratorWidget{ private TextFieldWidget textFieldWidget; - public StringConfigurator(int x, int y, JsonObject config, String name) { - super(x, y, config, name, false); - init(); - textFieldWidget.setCurrentString(config.get(name).isJsonNull() ? defaultValue : config.get(name).getAsString()); + public StringConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, String name) { + super(group, config, name); } - public StringConfigurator(int x, int y, JsonObject config, String name, String defaultValue) { - super(x, y, config, name, true); - this.defaultValue = defaultValue; - init(); - textFieldWidget.setCurrentString(config.get(name).isJsonNull() ? defaultValue : config.get(name).getAsString()); + public StringConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, String name, String defaultValue) { + super(group, config, name, defaultValue); } - private void init() { + protected void init() { this.addWidget(new RectButtonWidget(76, 15, 40, 20) .setColors(new Color(0, 0, 0, 74).getRGB(), new Color(128, 255, 128).getRGB(), @@ -40,8 +35,7 @@ private void init() { } private void updateString() { - config.addProperty(name, textFieldWidget.getCurrentString()); - update(); + updateValue(textFieldWidget.getCurrentString()); } @Override diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/TextListConfigurator.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/TextListConfigurator.java index 23a12ac1ead..1fae4a6711d 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/TextListConfigurator.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/TextListConfigurator.java @@ -2,39 +2,45 @@ import com.google.gson.*; import gregtech.api.gui.resources.ColorRectTexture; +import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; import gregtech.api.terminal.gui.widgets.TextEditorWidget; import net.minecraft.client.resources.I18n; +import java.util.Arrays; +import java.util.Collections; import java.util.List; -public class TextListConfigurator extends ConfiguratorWidget{ +public class TextListConfigurator extends ConfiguratorWidget>{ + private TextEditorWidget editor; - public TextListConfigurator(int x, int y, int height, JsonObject config, String name, boolean canDefault) { - super(x, y, config, name, canDefault); + public TextListConfigurator(DraggableScrollableWidgetGroup group, int height, JsonObject config, String name) { + super(group, config, name); + init(height); + } + + public TextListConfigurator(DraggableScrollableWidgetGroup group, int height, JsonObject config, String name, String defaultValue) { + super(group, config, name, Collections.singletonList(defaultValue)); + init(height); + } + + protected void init(int height) { JsonElement element = config.get(name); - if (element.isJsonNull()) { - init(height, ""); - } else { + String initValue = ""; + if (!element.isJsonNull()) { List init = new Gson().fromJson(element, List.class); - StringBuilder s = new StringBuilder(); - for (int i = 0; i < init.size(); i++) { - s.append(I18n.format(init.get(i).toString())); - if(i != init.size() - 1) { - s.append('\n'); - } - } - init(height, s.toString()); + initValue = String.join("\n", init); + } + editor = new TextEditorWidget(0, 15, 116, height, this::updateTextList, true).setContent(initValue).setBackground(new ColorRectTexture(0xA3FFFFFF)); + this.addWidget(editor); } - private void init(int height, String init) { - this.addWidget(new TextEditorWidget(0, 15, 116, height, init, this::updateTextList, true).setBackground(new ColorRectTexture(0xA3FFFFFF))); + private void updateTextList(String saved) { + updateValue(Collections.singletonList(saved)); } - private void updateTextList(String saved) { - JsonArray array = new JsonArray(); - array.add(saved); - config.add(name, array); - update(); + @Override + protected void onDefault() { + editor.setContent(defaultValue.get(0)); } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalDialogWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalDialogWidget.java new file mode 100644 index 00000000000..115420349cd --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalDialogWidget.java @@ -0,0 +1,270 @@ +package gregtech.api.terminal.gui.widgets.os; + +import gregtech.api.gui.GuiTextures; +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.ColorRectTexture; +import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.resources.TextureArea; +import gregtech.api.gui.widgets.*; +import gregtech.api.terminal.gui.widgets.AnimaWidgetGroup; +import gregtech.api.terminal.gui.widgets.CircleButtonWidget; +import gregtech.api.terminal.gui.widgets.ColorWidget; +import gregtech.api.terminal.gui.widgets.TreeListWidget; +import gregtech.api.terminal.util.FileTree; +import gregtech.api.util.Size; +import gregtech.api.util.interpolate.Interpolator; +import net.minecraft.inventory.IInventory; +import net.minecraft.network.PacketBuffer; + +import java.io.File; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; +import java.util.function.Predicate; + +public class TerminalDialogWidget extends AnimaWidgetGroup { + private static final IGuiTexture DIALOG_BACKGROUND = TextureArea.fullImage("textures/gui/terminal/terminal_dialog.png"); + private static final IGuiTexture OK_NORMAL = TextureArea.fullImage("textures/gui/terminal/ok_normal.png"); + private static final IGuiTexture OK_HOVER = TextureArea.fullImage("textures/gui/terminal/ok_hover.png"); + private static final IGuiTexture OK_DISABLE = TextureArea.fullImage("textures/gui/terminal/ok_disable.png"); + private static final IGuiTexture CANCEL_NORMAL = TextureArea.fullImage("textures/gui/terminal/cancel_normal.png"); + private static final IGuiTexture CANCEL_HOVER = TextureArea.fullImage("textures/gui/terminal/cancel_hover.png"); + private static final IGuiTexture CANCEL_DISABLE = TextureArea.fullImage("textures/gui/terminal/cancel_disable.png"); + private static final int HEIGHT = 128; + private static final int WIDTH = 184; + + protected Interpolator interpolator; + private final TerminalOSWidget os; + private IGuiTexture background; + private boolean isClient; + + private TerminalDialogWidget(TerminalOSWidget os, int x, int y, int width, int height) { + super(x, y, width, height); + this.os = os; + } + + public boolean isClient() { + return isClient; + } + + public void open(){ + os.openDialog(this); + } + + public TerminalDialogWidget setClientSide() { + this.isClient = true; + return this; + } + + public TerminalDialogWidget setBackground(IGuiTexture background) { + this.background = background; + return this; + } + + public TerminalDialogWidget addOkButton() { + addWidget(new CircleButtonWidget(WIDTH / 2, HEIGHT - 22, 12, 0, 24) + .setClickListener(cd -> os.closeDialog(this)) + .setColors(0, 0, 0) + .setIcon(OK_NORMAL) + .setHoverIcon(OK_HOVER)); + return this; + } + + public TerminalDialogWidget addConfirmButton(Consumer result) { + addWidget(new CircleButtonWidget(WIDTH / 2 - 30, HEIGHT - 22, 12, 0, 24) + .setClickListener(cd -> { + os.closeDialog(this); + if (result != null) + result.accept(true); + }) + .setColors(0, 0, 0) + .setIcon(OK_NORMAL) + .setHoverIcon(OK_HOVER)); + addWidget(new CircleButtonWidget(WIDTH / 2 + 30, HEIGHT - 22, 12, 0, 24) + .setClickListener(cd -> { + os.closeDialog(this); + if (result != null) + result.accept(false); + }) + .setColors(0, 0, 0) + .setIcon(CANCEL_NORMAL) + .setHoverIcon(CANCEL_HOVER)); + return this; + } + + public TerminalDialogWidget addTitle(String title) { + this.addWidget(new LabelWidget(WIDTH / 2, 11, title, -1).setXCentered(true)); + return this; + } + + public TerminalDialogWidget addInfo(String info) { + this.addWidget(new LabelWidget(WIDTH / 2, HEIGHT / 2 - 10, info, -1).setXCentered(true)); + return this; + } + + public TerminalDialogWidget addPlayerInventory() { + IInventory inventoryPlayer = os.getModularUI().entityPlayer.inventory; + int x = 20; + int y = 20; + for (int row = 0; row < 3; row++) { + for (int col = 0; col < 9; col++) { + this.addWidget(new SlotWidget(inventoryPlayer, col + (row + 1) * 9, x + col * 18, y + row * 18, true, true) + .setBackgroundTexture(GuiTextures.SLOT) + .setLocationInfo(true, false)); + } + } + y+=58; + for (int slot = 0; slot < 9; slot++) { + this.addWidget(new SlotWidget(inventoryPlayer, slot, x + slot * 18, y, true, true) + .setBackgroundTexture(GuiTextures.SLOT) + .setLocationInfo(true, true)); + } + return this; + } + + public static TerminalDialogWidget createEmptyTemplate(TerminalOSWidget os) { + Size size = os.getSize(); + return new TerminalDialogWidget(os, (size.width - WIDTH) / 2, (size.height - HEIGHT) / 2, WIDTH, HEIGHT).setBackground(DIALOG_BACKGROUND); + } + + public static TerminalDialogWidget showInfoDialog(TerminalOSWidget os, String title, String info) { + return createEmptyTemplate(os).addTitle(title).addInfo(info).addOkButton(); + } + + public static TerminalDialogWidget showConfirmDialog(TerminalOSWidget os, String info, Consumer result) { + TerminalDialogWidget dialog = createEmptyTemplate(os).addConfirmButton(result); + dialog.addWidget(new LabelWidget(WIDTH / 2, HEIGHT / 2 - 10, info, -1).setXCentered(true)); + return dialog; + } + + public static TerminalDialogWidget showTextFieldDialog(TerminalOSWidget os, String title, Predicate validator, Consumer result) { + TextFieldWidget textFieldWidget = new TextFieldWidget(WIDTH / 2 - 50, HEIGHT / 2 - 15, 100, 20, new ColorRectTexture(0x2fffffff), null, null).setValidator(validator); + TerminalDialogWidget dialog = createEmptyTemplate(os).addTitle(title).addConfirmButton(b -> { + if (b) { + if (result != null) + result.accept(textFieldWidget.getCurrentString()); + } else { + if (result != null) + result.accept(null); + } + }); + dialog.addWidget(textFieldWidget); + return dialog; + } + + public static TerminalDialogWidget showColorDialog(TerminalOSWidget os, String title, Consumer result) { + TerminalDialogWidget dialog = createEmptyTemplate(os).addTitle(title); + ColorWidget colorWidget = new ColorWidget(WIDTH / 2 - 60, HEIGHT / 2 - 35, 80, 10); + dialog.addWidget(colorWidget); + dialog.addConfirmButton(b -> { + if (b) { + if (result != null) + result.accept(colorWidget.getColor()); + } else { + if (result != null) + result.accept(null); + } + }); + return dialog; + } + + public static TerminalDialogWidget showFileDialog(TerminalOSWidget os, String title, File dir, boolean isSelector, Consumer result) { + Size size = os.getSize(); + TerminalDialogWidget dialog = new TerminalDialogWidget(os, 0, 0, size.width, size.height) + .setBackground(new ColorRectTexture(0x4f000000)); + if (!dir.isDirectory()) { + if (!dir.mkdirs()) { + return dialog.addInfo("error file path: " + dir.getPath()).addOkButton(); + } + } + AtomicReference selected = new AtomicReference<>(); + dialog.addWidget(new TreeListWidget<>(0, 0, 130, size.height, new FileTree(dir), node -> { + selected.set(node.getKey()); + System.out.println(node.toString()); + }).setNodeTexture(GuiTextures.BORDERED_BACKGROUND) + .canSelectNode(true) + .setLeafTexture(GuiTextures.SLOT_DARKENED)); + int x = 130 + (size.width - 133 - WIDTH) / 2; + int y = (size.height - HEIGHT) / 2; + dialog.addWidget(new ImageWidget(x, y, WIDTH, HEIGHT, DIALOG_BACKGROUND)); + dialog.addWidget(new CircleButtonWidget(x + WIDTH / 2 - 30, y + HEIGHT - 22, 12, 0, 24) + .setClickListener(cd -> { + os.closeDialog(dialog); + if (result != null) + result.accept(selected.get()); + }) + .setColors(0, 0, 0) + .setIcon(OK_NORMAL) + .setHoverIcon(OK_HOVER)); + dialog.addWidget(new CircleButtonWidget(x + WIDTH / 2 + 30, y + HEIGHT - 22, 12, 0, 24) + .setClickListener(cd -> { + os.closeDialog(dialog); + if (result != null) + result.accept(null); + }) + .setColors(0, 0, 0) + .setIcon(CANCEL_NORMAL) + .setHoverIcon(CANCEL_HOVER)); + if (isSelector) { + dialog.addWidget(new SimpleTextWidget(x + WIDTH / 2, y + HEIGHT / 2 - 5, "", -1, () -> { + if (selected.get() != null) { + return selected.get().toString(); + } + return "no file selected"; + }, true)); + } else { + dialog.addWidget(new TextFieldWidget(x + WIDTH / 2, y + HEIGHT / 2 - 5, 76, 20, new ColorRectTexture(0x4f000000), null, null) + .setTextResponder(res->{ + File file = selected.get(); + if (file == null) return; + if (file.isDirectory()) { + selected.set(new File(file, res)); + } else { + selected.set(new File(file.getParent(), res)); + } + },true) + .setTextSupplier(()->{ + File file = selected.get(); + if (file != null && !file.isDirectory()) { + return selected.get().getName(); + } + return ""; + }, true) + .setMaxStringLength(Integer.MAX_VALUE) + .setValidator(s->true)); + } + + dialog.addWidget(new LabelWidget(x + WIDTH / 2, y + 11, title, -1).setXCentered(true)); + os.menu.hideMenu(); + return dialog; + } + + @Override + public void hookDrawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + if (background != null) { + background.draw(getPosition().x, getPosition().y, getSize().width, getSize().height); + } + super.hookDrawInBackground(mouseX, mouseY, partialTicks, context); + } + + @Override + public boolean mouseClicked(int mouseX, int mouseY, int button) { + for (int i = widgets.size() - 1; i >= 0; i--) { + Widget widget = widgets.get(i); + if (widget.isVisible()) { + if (widget instanceof SlotWidget) { + return false; + } else if(widget.mouseClicked(mouseX, mouseY, button)){ + return true; + } + } + } + return true; + } + + @Override + protected void writeClientAction(int id, Consumer packetBufferWriter) { + if (isClient) return; + super.writeClientAction(id, packetBufferWriter); + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalMenuWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalMenuWidget.java index 935ce7f4948..0524137b242 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalMenuWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalMenuWidget.java @@ -12,6 +12,7 @@ import net.minecraft.client.renderer.GlStateManager; import java.awt.*; +import java.io.File; public class TerminalMenuWidget extends WidgetGroup { private Interpolator interpolator; @@ -64,11 +65,14 @@ public void minimize(ClickData clickData) { } public void maximize(ClickData clickData) { - + TerminalDialogWidget.showColorDialog(os, "test", System.out::println).addPlayerInventory().open(); } public void setting(ClickData clickData) { - +// TerminalDialogWidget.showInfoDialog(os, "test"); +// TerminalDialogWidget.showConfirmDialog(os, "test", null); +// TerminalDialogWidget.showTextFieldDialog(os, "test", s->true, System.out::println); +// TerminalDialogWidget.showFileDialog(os, "test", new File("./"), System.out::println).setClientSide().open(); } public void hideMenu() { diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalOSWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalOSWidget.java index 00589d4ca61..6668a0b09b9 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalOSWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalOSWidget.java @@ -2,36 +2,25 @@ import gregtech.api.gui.GuiTextures; import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.ModularUI; import gregtech.api.gui.Widget; import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.widgets.AbstractWidgetGroup; -import gregtech.api.gui.widgets.WidgetGroup; import gregtech.api.terminal.app.AbstractApplication; -import gregtech.api.terminal.gui.widgets.CircleButtonWidget; import gregtech.api.util.Position; import gregtech.api.util.RenderUtil; import gregtech.api.util.Size; -import gregtech.api.util.interpolate.Eases; -import gregtech.api.util.interpolate.Interpolator; -import javafx.application.Application; -import javafx.geometry.Pos; -import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import java.util.ArrayList; -import java.util.Collections; import java.util.List; -import static gregtech.api.gui.impl.ModularUIGui.*; - public class TerminalOSWidget extends AbstractWidgetGroup { private IGuiTexture background; public final List openedApps; public AbstractApplication focusApp; public final TerminalMenuWidget menu; public final TerminalDesktopWidget desktop; - public List waitToRemoved; private NBTTagCompound tabletNBT; public TerminalOSWidget(int xPosition, int yPosition, int width, int height, NBTTagCompound tabletNBT) { @@ -41,10 +30,13 @@ public TerminalOSWidget(int xPosition, int yPosition, int width, int height, NBT this.menu = new TerminalMenuWidget(Position.ORIGIN, new Size(31, 232), this).setBackground(GuiTextures.TERMINAL_MENU); this.addWidget(desktop); this.addWidget(menu); - this.waitToRemoved = new ArrayList<>(); this.tabletNBT = tabletNBT; } + public ModularUI getModularUI(){ + return this.gui; + } + public TerminalOSWidget setBackground(IGuiTexture background) { this.background = background; return this; @@ -69,7 +61,7 @@ public void openApplication(AbstractApplication application, boolean isClient) { if (!tabletNBT.hasKey(name)) { tabletNBT.setTag(name, new NBTTagCompound()); } - AbstractApplication app = application.createApp(isClient, tabletNBT.getCompoundTag(application.getName())); + AbstractApplication app = application.createApp(isClient, tabletNBT.getCompoundTag(application.getName())).setOs(this); if (app != null) { openedApps.add(app); desktop.addWidget(app); @@ -81,7 +73,7 @@ public void openApplication(AbstractApplication application, boolean isClient) { public void maximizeApplication(AbstractApplication application, boolean isClient) { application.setActive(true); if (isClient) { - application.maximizeApp(app->desktop.hideDesktop()); + application.maximizeWidget(app->desktop.hideDesktop()); if (!menu.isHide) { menu.hideMenu(); } @@ -95,7 +87,7 @@ public void minimizeApplication(AbstractApplication application, boolean isClien application.setActive(false); } if (isClient) { - application.minimizeApp(null); + application.minimizeWidget(null); } if(focusApp == application) { focusApp = null; @@ -112,9 +104,9 @@ public void closeApplication(AbstractApplication application, boolean isClient) } application.closeApp(isClient, tabletNBT.getCompoundTag(name)); if (isClient) { - application.minimizeApp(waitToRemoved::add); + application.minimizeWidget(desktop::waitToRemoved); } else { - waitToRemoved.add(application); + desktop.waitToRemoved(application); } openedApps.remove(application); if(focusApp == application) { @@ -134,6 +126,25 @@ public void homeTrigger(boolean isClient) { } } + protected TerminalDialogWidget openDialog(TerminalDialogWidget widget) { + if (isRemote()) { + widget.maximizeWidget(null); + } else if(widget.isClient()) { + return widget; + } + desktop.addWidget(widget); + return widget; + } + + protected TerminalDialogWidget closeDialog(TerminalDialogWidget widget) { + if (isRemote()) { + widget.minimizeWidget(desktop::waitToRemoved); + } else if(widget.isClient()) { + desktop.waitToRemoved(widget); + } + return widget; + } + @Override public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { Position position = getPosition(); @@ -148,21 +159,4 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender }); } - @Override - public void updateScreen() { - if (waitToRemoved.size() > 0) { - waitToRemoved.forEach(desktop::removeWidget); - } - waitToRemoved.clear(); - super.updateScreen(); - } - - @Override - public void detectAndSendChanges() { - if (waitToRemoved.size() > 0) { - waitToRemoved.forEach(desktop::removeWidget); - } - waitToRemoved.clear(); - super.detectAndSendChanges(); - } } diff --git a/src/main/java/gregtech/api/terminal/util/FileTree.java b/src/main/java/gregtech/api/terminal/util/FileTree.java new file mode 100644 index 00000000000..05be2dbacb6 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/util/FileTree.java @@ -0,0 +1,65 @@ +package gregtech.api.terminal.util; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class FileTree extends TreeNode { + + public FileTree(File dir){ + this(0, dir); + } + + private FileTree(int dimension, File key) { + super(dimension, key); + } + + @Override + public boolean isLeaf() { + return getKey().isFile(); + } + + @Override + public TreeNode getOrCreateChild(File childKey) { + return super.getOrCreateChild(childKey); + } + + @Override + public void addContent(File key, File content) { + super.addContent(key, content); + } + + @Override + public File getKey() { + return super.getKey(); + } + + @Override + public File getContent() { + return isLeaf() ? getKey() : null; + } + + @Override + public List> getChildren() { + if (children == null && !isLeaf()) { + children = new ArrayList<>(); + Arrays.stream(key.listFiles()).sorted((a, b)->{ + if (a.isFile() && b.isFile()) { + return a.compareTo(b); + } else if (a.isDirectory() && b.isDirectory()) { + return a.compareTo(b); + } else if(a.isDirectory()) { + return -1; + } + return 1; + }).forEach(file -> children.add(new FileTree(dimension + 1, file))); + } + return super.getChildren(); + } + + @Override + public String toString() { + return getKey().getName(); + } +} diff --git a/src/main/java/gregtech/api/terminal/util/IContent.java b/src/main/java/gregtech/api/terminal/util/IContent.java deleted file mode 100644 index 5e0652455e7..00000000000 --- a/src/main/java/gregtech/api/terminal/util/IContent.java +++ /dev/null @@ -1,4 +0,0 @@ -package gregtech.api.terminal.util; - -public class IContent { -} diff --git a/src/main/java/gregtech/api/terminal/util/TreeNode.java b/src/main/java/gregtech/api/terminal/util/TreeNode.java index e8d5c1aa7fb..93c1f2c3616 100644 --- a/src/main/java/gregtech/api/terminal/util/TreeNode.java +++ b/src/main/java/gregtech/api/terminal/util/TreeNode.java @@ -10,10 +10,11 @@ * @param leaf */ public class TreeNode { - public int dimension; - public List> children; - public final T key; - public K content; + public final int dimension; + protected final T key; + protected K content; + protected List> children; + public TreeNode(int dimension, T key) { this.dimension = dimension; @@ -44,6 +45,18 @@ public void addContent (T key, K content) { getOrCreateChild(key).content = content; } + public T getKey() { + return key; + } + + public K getContent() { + return content; + } + + public List> getChildren() { + return children; + } + @Override public String toString() { return key.toString(); diff --git a/src/main/java/gregtech/api/util/SlotUtil.java b/src/main/java/gregtech/api/util/SlotUtil.java index f9895706ddc..fd103880920 100644 --- a/src/main/java/gregtech/api/util/SlotUtil.java +++ b/src/main/java/gregtech/api/util/SlotUtil.java @@ -27,9 +27,8 @@ public static ItemStack slotClickPhantom(Slot slot, int mouseButton, ClickType c } else if (slot.isItemValid(stackHeld)) { if (areItemsEqual(stackSlot, stackHeld)) { adjustPhantomSlot(slot, mouseButton, clickTypeIn); - } else { - fillPhantomSlot(slot, stackHeld, mouseButton); } + fillPhantomSlot(slot, stackHeld, mouseButton); } } else if (mouseButton == 5) { if (!slot.getHasStack()) { diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/cancel_disable.png b/src/main/resources/assets/gregtech/textures/gui/terminal/cancel_disable.png new file mode 100644 index 0000000000000000000000000000000000000000..e0ec424c75e01da23e0f7f7daa335c952ac54d4d GIT binary patch literal 3159 zcmV-d45;&oP)78q>K_FC<2fLfQVuH;Az`)Cm-v- zaQo}%r{Bba$7;8hTSBfOqH+KR02@FGfK31xFaZP!umJd)G2&>y>!IE={l8Pdj=Gix zONi|N0vg=sYTa|&wr}np`Zzh?_rIuUwn~GcrHVwYAgU#RUDjv6(R2FZZx!(M>P;n! z4eQ$kL>$(g?bn7r`N!0Co%{W-f@O01k`lc~R-7;xuV;0^$Yd+y;~ zSI>=nZNQGYmbC#PANE+EZ@qH*WbXS{DmN@FHLM0xh$=}`CO~1Lj88Me*WjdP9&=dt zPqoNX?vdSa(l)?t9<5dTtm1Ua#7;sMNF$_{@C|^mHEm z%77>9@BfA(Y8p-_f3|n<<7pzoiMp27kdQkSQ5Zm)0Y9hbF8XuI1pxt{*-2{u{nti@ zj{Qq~*#D=c^~TnPrGKKq*B`jtdE}k}kJq(qu!P+Cd1~s%`-Uzi|6}>;!205ny#XPc z2}s=o*xg_SfRL^AmBIA%OZx{uj{j>}z1mb#`WGJaC#^l5r{?}i%pG{MW=okRk(Sm`@CR7`L_89+K)?KU@%<#Wd^XcWePaX2!%YS}VRDJczu3LqKGEDZx5 zk-WXSy8QO46-!78A|a>%5)4d-q-tre*-{MvDbG8hh&DdAqRF@eu%&Ey9RTm4-ZNJL zV4-2QN|1q!-{h26DzHSpZb5%$-DpN3NdzoPnwGaM9{J08J^Iedf;q;BfWkWu_1f45X0@ z2xb;UJY5tDFKOGedex@&B|*#5jR&5rNpEV7W*`+wLy@h0k>1oCUDNhtttq80S-RA$ zd*FSk>iFL*=XSUilgs3@MwRt4~_{^UfLd*vI`SM0Zz~ZFmUIBn&Wvr2)z#PAV zpHB0F%BZz!^TtKKo;x?m^ovdJRiW!*Kgb)H((jcG^rqR zzmnv@Y-CDz_{=VYbGdImIF^P%Y3)m=Wy7k*w!L*qDX`X@I|x~8R!X6n^c)us{vM$Ar)n2}03hjkU3zxi2M~dY$hdwp&Lg8S zNTDF5ASK24n;n-%4;~tj;gFQ!kQ_aDXkh%!j!UGZASsCfAwA!Yq@8Ks_cJb6u)RLu zP5E9I0E7**7Qp0Fpa0K{4+4O%^<^bQ6960@8R~OcU!zQ@&)hSVBzt%yJ^auA`EmN% za7|SJb>Gu{=LZ2m5;b~ScjdV9orTeK>eJ<+aLb$3n-~B4^hoSj?bdeH+9v(ub5JENkvD#{`6@egE{1o(~QIzDse`qvKY(QFHY3nm~^in4I?9$&d}5emsH+{|?$0~fSeU+bQlJPH6E zb=w*VD0+WvNGS%7=5T}<0r9}7$4yFXrjpLt;DVq(;>Uv!zLDU&=4)5G1s<^|1J zEjti&SdZVZQ!jr1dRO|j%8ikLkdLK&|LEV1_s=R)?zq)Gc;$4L&$@SY@uH^y;PJlm z*Ka!MpE;~!1cVE$@KuG8xzLAgt%pBPCx5!T|HIhdE~t=8tiaPQ^SOt6&kWqLy1QN6 z-)q?32Eg5M`Gc1M;Q8pfqN-r{aZAW`0`NI=6ct+YZcxaASsIL#*5}Sm#*X~;&CB-R zELc3sPwu#`It5>b)a z0WW)3o?D&?%CtTV2D^^tzPRt6e6;s$F95t;xuIx<6>MYh$d1dMzq-o;zr1<$ZvFOM zf>4*z-Wv~JIok&SWkmE`&6b*wP>qJ5r~oY_f<+*aF&q2LNNezftM%ZN_PQSHJvWfk zdAzQr*%IPmkNN!0p3Zl_X#RU@zjf5LG+IJD#K4V&=f1P+>bZQU>M@eyndsW$h*Cw0 z$Y21TW+&l0iG4$#+%D9AtZrL0C}b;uaMJgVKGJ)3@XO}D=LY7FmNlAdix=z=M5`GX z_nALSxK97${TJe2^uPA%EsKIm)e53U0zy9XN3B;*ci!u~U%3VR?20CfjnggYQP^l8MSb)Nq xIlCRroN!skh7yU`GdC|eU!v-F1NeU-{|m$vd^GfAGo}Cl002ovPDHLkV1lLP5Xb-k literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/cancel_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/cancel_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..b4187a19abdab8caa3363dd76700a13b11cc28c7 GIT binary patch literal 3070 zcmVau{rjC~5=ekTd9->#ESx~elRVHXg({eM`}m{R_SQNo)z-Gy zhY!HE&J+rkzD5)juN|${PVY>eDZvD_fVGlvLQ;%Gv?wK=lW`1k0{n=};{oQ*nVrKk1H}yd{dFo?zzS+TGp%NkpfVAP*U@CF;%9sBT z`)7UAg+!2u=%wXr>n#$WAfkl;3IH$wH)|rZzZf&0aG9TP?>+s(O(!~&|5CtThwA)G z3X5-)L=6CvnmMf597$>Y#@SS=?{}{siyun%V_WDl?-ZZE#3SX!lBiM;Ehk{A0q;MP zOg^--^SS;H9I(5#;aWxFRt8>6YW>i%!%rU>Z*xO%rVL1l9Yd$|_-`G{*DeZ3wN8L) z95#=KTALpDKmhkF{m+60!NQ#cOpj`JQ^n!t&fK?f)m7y|Wz{L7rGjX-00jVm!AZm1 z<1lw8wR`BH6UW6@c}(RN~8*cRY9If&p7Aul#623fJWQ(KASAWhg)eVZMOn?FeXk_xw&#-apF%&0C=Ug z@is;D#i;9EUmk8gcHV$(Rabtr*z)|=VY4IDy7y542v@JEDz@w&+9c`;NHGu}2bJG) zj)?$213rh%(TMBZU2(Yi_WZbZ$9EKy zd7JAG-mjVW=is_)8}BMo)(%OeF90rQOAJH>C{ZBQ=Hs=E+W=r`+tW=Bo5!cw-Uo>$ zx|{%btft{w0%nBT_I?ilUao1lDJa!F03r-Hxxv6-oLd4iHlucgOs@6?r22MuZNnV^ z5Nd7uIRnnIplnopPV`8vo?wPY|f2DPT2|(*Aecg zRu^1!-D?8>qz>AEynSsJ)>`}d2c+_tVL5%fvo5x^W|%p$RDalzCt z06^SzcN5VSElV!KtL*g(F73710p~wMG4oT!P>Gw>Besc{X(Los?09lw0?@7UMyiuezZYA+%M&I zyB3t&740pr0f@{F1XoM|w1im6%wYiduQ?YjRf5VGh+$;6GFWR^#Z$$?|Ne|uf}!IH zwuHpoJ8ms9tLps#kTiw{Ys&&lHr^KWDg~WNu}P)5q-=@hnO-8;$=xS1d<-NMiBLuH zjB)^A=CC4p`2;{By3}QE2Y{fm>IEp6KT{A93&HBIr<}o`?v7~31=%*4bea_j%)R}q zg~|E~|6pavU%Fv^&?6;uD#c{m1OUB1`1xS^Xm^@CHeswpF#*1SRP_Mhvgshg{4s!g zLMyxg3esA?0RR?>rP6uY%2>%nD@<_3rp|(M$jV_bSgap z*S~E?B)0EhlDwXLU!zk8Tty-T04c3c0w{R8^fKQF;D@~aA^>J6mFQm=oCzY##^}x+ z4+-J*QljNxqIdhQ2mltAMJDaA?Xh8dGEpVVB7nJn+x?Mf^ZtYg21X}2vAKdU>&D%g zx@CdV?|!GiiiiA8YAZ8n_zHEkuYVm=lB`09c|(x zfPYUWh5)FkK40-8(K9fN)0p_6VgQhq%7}1XSzyVAjFjYZjF7yukL-JAg&`2_NdMgq5s|oBC%(lPb7c;LbC72yCMu? zvTZV{4CLI6>x*P)p^cO?{&GPE9F4lpivXaAs+sxKk+skLagBbSh-v_!W1zRwWz$W7 zZ^Ri98GwCf`kmzOo{btJkk6aZxve`gQWEeJdA*cqK9K0!zH=y}lQzM&$?ZCxrgzS` zkOFxVX95DQ;iG%rd9y1!OjX*L{SyFB#iD;CU}{IznoGa(Mn^iX^bQ-4`==bK&5t992r zVwgJ@w>IsZ5J3PKOs94WqT2SVtLA_Hl|%7}<7_m5piGru^j1s+xGvncdvq3Vya;C^ zX<3v$`if%)B4!deOM}w`PI|+gZ+1DI)oaTMSlAPfJ(kZj2C%N<*_ z%?F~|*~~ym);1rK$Wr-H8{Y^3k;lfkWn}=;07b*DdslV1

c`K&h>cG54*0>A;wJ z&IB1l`0l90~`Ba^9&(1>4EQeg@ z8==;wtpISWw&6xWblF?+;jd3RyLWq-byTk{El}2zDWf+nY1_L806LeiT~(y4%@&De z1SGN#_xu;z1Sn*3*w26`&F0X6lipArZfOUA?%KwiETUWboYbf5+Mjv*ya02ML8Ttm z%ug(CZTcAiY+q3By=wZb>wH3fQ4y6A$eX=8I{8ol6a&(Lqb~E&xYoZYJN(RVG&=?W zj@LGB6+|og)2VCgj!X`BPCx*7zGC&vnI7Lm0GzX~v#~1N@;U&lE19QmnZLNoCsmyy z3JIcF1o8oZ0mlsUDVMn`>N^X{@=TUxZyj2nX z4+Cv6?f!4Y;pXGxZEl}BPsX&1oo9O{l;2*exw_gTGlvaxM^d{dqv_PZA5NT1c)T|1=6)m)u<&2q^DH4|x(R^e|z=pDU$bbi#d_2p{ucnPTuq@o% zdO_vp52DJyC$z#p%NHmVg8a-dnoa!ALjyzCy?!Kh?%w|ofd9(&4+uwZKT|7bX8-^I M07*qoM6N<$g0tPt>Hq)$ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/cancel_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/cancel_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..568c435b013efea20b9134c943729741968cb97a GIT binary patch literal 3082 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/ok_disable.png b/src/main/resources/assets/gregtech/textures/gui/terminal/ok_disable.png new file mode 100644 index 0000000000000000000000000000000000000000..a876388f3ca4321085643e1202a342d5cfe36a30 GIT binary patch literal 3322 zcmVSPY<^1uw zERs}i)vfB+@7;4gXSwGt#LW2r+>GlL5MTS-2w9P8A{haZ4S)c+&?=+-@nrAT6{FW9 zpT3L-Th||mlNp*1qBwy}04{^a0dfHV%od130BisXtS@ump6PkM^TPisVB5ySv&nG2 z0>EMBZYcMh$_{r&?~7mU1%Q^v zch}2k)9pgq^B`m;KpKPq3=Nco5kLZf1XzM~mX-T~%8nfB-MXR|0OC*VsgaS!hnZD( zV$-dA{%XLsr;dGfX_J{zKKTde#h0z5NMh-Iv&O>uIF`xA$*boo!t6N+{HJ+xN(I8(O*^#?EXOzr24jzG&@??ADHr)fJ6l8RDOd4_h9eV6<4B*9}{-d{0GT!+5yg# zDPrWoAccT!o3Jedra@#HM7CwXwoOPOidk6%&3lzOOVVyOtJ@#0e_)f<_sXgC<73Et(okas8d_@wDkv7V z#qp+)HKnDlY4NP#n%53r>^?PI)o(~sO@d^QBpHe=Bcg6*?rD4Gc-pL)F$X}`gbNCw?O+-}8;Q}PPB&``OPrlU#0MP0*q&a6oh#S|uV%UxI zYL%Pb4*Kg&eHuoI1V#jh~V$4e$HcAsMO!8CE+0zubF7fDT-`dtt1#z9wo1fnqP<;Kv7t-`jd% zxH~cAWxas47qGrG=w)9zFnsJf4hj(kI0XPQTo)x04#1_|3K;MM=Bc%II2yKWFk>VgWDlK9U#YO9EDKjD zr3pZVCFP;B>5r3{U>wY-3|rRJIy>wu=85YLGZ8t$sfre!Qy>v3n zWffxX06*g`nzSlq3rNsskC@boU@n0CW>W`#A-qKv z0_C?OsT_NnnKgrB6*3gF16vA-Lcq$^vSzRp5>>XcV->POGnkoqY@9v1YUx!SV8zP! zkQd|t@U8-~&H@w#0G%7l0PL0x1_3N3=)z!-&bZoRX4F-MLJOO@QENp~3My6TB_iYC#36Npd;NuCzR`{`bzWYv<)j~-B=Tg8qAt9 zuJ-nHr9LX4O-Kg-1}pzks%rc-u3_(;^gW2hgS6)EQ}n zI*_*%D3lFT5}oSFrCvWdcJ^CKV)KeD~gk?R^8umVuFU4gl(_BTh?w%!ZJx zl!7FpT_=-g&-CU}jwwXRGf75Rv|3_NM@DWJ>X?74SHGRQ)6;ii{1-sFa3warX{}wfVQVkJO&QV zC!Xtgr})u?yP06L=df8lZA0t&{nL70Sbi}W?%rkA&2A=X)l4cq1b~f#;*W;B@$(K`e#+n^odhl&z9TIunsU$y^T0;lf(D!khvj z1Qq|_2YOyy{viOgeD_yTqq6N0W_>xaY00lX#lX+MJZgLT z-LDhLS=!IM-t+t&-2gyD6kqrD46-A0NtjcJL@a-KS)8q`m^lYlBdq*O+D)D5ed%i# zOESOz&H^&*yI2J$63^Xs@U!%Pq3gHSjfdw7Bea6S{d#<4fA7}2N;g%`v<^{o$3In) z6^)WK@;f5sdpb9oy8P-Br~3bb{m@ zKo3I)r}cR9Lhs8f$3D}zb-%A6D>9RWoC{C|>)>S1=8mIZRPSGX1>CsiC$?38;{phI z1A(Fp_5ezObsC^teu{GiKoKH}aDLM<0v()5zVoB^Q-9i~K2OJW0hYI>hjutdRZATS zvlb-6$Zyjb%pO>$So=fX;JKkIzgXveSsm8}_CffOaK4? literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/ok_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/ok_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..bb85e273318897a7a2ef859555f633438939b40e GIT binary patch literal 3261 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/ok_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/ok_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..bb73df64b8f23facfdb250bf3567b314cc4e29b6 GIT binary patch literal 3278 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 M07*qoM6N<$f(*(#D*ylh literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_dialog.png b/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_dialog.png new file mode 100644 index 0000000000000000000000000000000000000000..d18efc6cbc13ee9bbc0bcfa3f1372fcfea7f9476 GIT binary patch literal 5193 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 Date: Sun, 8 Aug 2021 01:18:41 +0800 Subject: [PATCH 17/58] fix bad slotwidget in gtce --- src/main/java/gregtech/api/gui/Widget.java | 3 -- .../gregtech/api/gui/impl/ModularUIGui.java | 13 ------ .../api/gui/resources/ItemStackTexture.java | 7 ++-- .../api/gui/widgets/AbstractWidgetGroup.java | 6 --- .../api/gui/widgets/ScrollableListWidget.java | 1 - .../gregtech/api/gui/widgets/SlotWidget.java | 42 ++++++++----------- .../gregtech/api/gui/widgets/TankWidget.java | 2 + .../DraggableScrollableWidgetGroup.java | 13 ------ .../gui/widgets/guide/GuideConfigEditor.java | 21 ++++++++-- .../gui/widgets/guide/SlotListWidget.java | 12 ------ .../gui/widgets/guide/TankListWidget.java | 24 ++++++----- .../configurator/FluidStackConfigurator.java | 6 ++- .../gui/widgets/os/TerminalDialogWidget.java | 4 +- 13 files changed, 61 insertions(+), 93 deletions(-) diff --git a/src/main/java/gregtech/api/gui/Widget.java b/src/main/java/gregtech/api/gui/Widget.java index 8a741ea3ecd..2cf12e6bd22 100644 --- a/src/main/java/gregtech/api/gui/Widget.java +++ b/src/main/java/gregtech/api/gui/Widget.java @@ -136,9 +136,6 @@ protected void recomputePosition() { onPositionUpdate(); } - public void applyScissor(final int parentX, final int parentY, final int parentWidth, final int parentHeight) { - } - protected void onPositionUpdate() { } diff --git a/src/main/java/gregtech/api/gui/impl/ModularUIGui.java b/src/main/java/gregtech/api/gui/impl/ModularUIGui.java index c45fd42b154..dc912c69686 100644 --- a/src/main/java/gregtech/api/gui/impl/ModularUIGui.java +++ b/src/main/java/gregtech/api/gui/impl/ModularUIGui.java @@ -94,23 +94,10 @@ public void drawScreen(int mouseX, int mouseY, float partialTicks) { for (int i = 0; i < this.inventorySlots.inventorySlots.size(); ++i) { Slot slot = this.inventorySlots.inventorySlots.get(i); - Rectangle scissor = null; - if (slot instanceof IScissored) { - scissor = ((IScissored) slot).getScissor(); - if (scissor != null) { - RenderUtil.pushScissorFrame(scissor.x, scissor.y, scissor.width, scissor.height); - } - } - if (slot.isEnabled()) { - this.drawSlotContents(slot); - } if (isPointInRegion(slot.xPos, slot.yPos, 16, 16, mouseX, mouseY) && slot.isEnabled()) { renderSlotOverlay(slot); setHoveredSlot(slot); } - if (scissor != null) { - RenderUtil.popScissorFrame(); - } } RenderHelper.disableStandardItemLighting(); diff --git a/src/main/java/gregtech/api/gui/resources/ItemStackTexture.java b/src/main/java/gregtech/api/gui/resources/ItemStackTexture.java index bed8d58cccf..b339ff268ca 100644 --- a/src/main/java/gregtech/api/gui/resources/ItemStackTexture.java +++ b/src/main/java/gregtech/api/gui/resources/ItemStackTexture.java @@ -2,6 +2,7 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.client.renderer.RenderHelper; import net.minecraft.client.renderer.RenderItem; import net.minecraft.item.Item; @@ -20,12 +21,12 @@ public ItemStackTexture(Item item) { @Override public void draw(double x, double y, int width, int height) { - RenderHelper.enableStandardItemLighting(); + RenderHelper.enableGUIStandardItemLighting(); GlStateManager.pushMatrix(); GlStateManager.scale(width / 16f, height / 16f, 0.0001); GlStateManager.translate(x * 16 / width, y * 16 / height, 0); - RenderItem renderItem = Minecraft.getMinecraft().getRenderItem(); - renderItem.renderItemAndEffectIntoGUI(itemStack, 0, 0); + RenderItem itemRender = Minecraft.getMinecraft().getRenderItem(); + itemRender.renderItemAndEffectIntoGUI(itemStack, 0, 0); GlStateManager.enableAlpha(); GlStateManager.popMatrix(); RenderHelper.disableStandardItemLighting(); diff --git a/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java b/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java index 17cd3be18f2..86be3fec316 100644 --- a/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java +++ b/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java @@ -60,12 +60,6 @@ protected void onPositionUpdate() { recomputeSize(); } - public void applyScissor(final int parentX, final int parentY, final int parentWidth, final int parentHeight) { - for (Widget widget : getContainedWidgets(true)) { - widget.applyScissor(parentX, parentY, parentWidth, parentHeight); - } - } - protected boolean recomputeSize() { if (isDynamicSized) { Size currentSize = getSize(); diff --git a/src/main/java/gregtech/api/gui/widgets/ScrollableListWidget.java b/src/main/java/gregtech/api/gui/widgets/ScrollableListWidget.java index fa72a4ca6af..8129e3bd40e 100644 --- a/src/main/java/gregtech/api/gui/widgets/ScrollableListWidget.java +++ b/src/main/java/gregtech/api/gui/widgets/ScrollableListWidget.java @@ -66,7 +66,6 @@ private void updateElementPositions() { currentPosY += widget.getSize().getHeight(); totalListHeight += widget.getSize().getHeight(); final Size size = getSize(); - widget.applyScissor(position.x, position.y, size.width - scrollPaneWidth, size.height); } this.totalListHeight = totalListHeight; this.slotHeight = widgets.isEmpty() ? 0 : totalListHeight / widgets.size(); diff --git a/src/main/java/gregtech/api/gui/widgets/SlotWidget.java b/src/main/java/gregtech/api/gui/widgets/SlotWidget.java index 67b68eb0318..61b392c42ce 100644 --- a/src/main/java/gregtech/api/gui/widgets/SlotWidget.java +++ b/src/main/java/gregtech/api/gui/widgets/SlotWidget.java @@ -6,9 +6,15 @@ import gregtech.api.gui.*; import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.resources.ItemStackTexture; import gregtech.api.gui.resources.TextureArea; import gregtech.api.util.Position; import gregtech.api.util.Size; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.client.renderer.RenderItem; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.ClickType; import net.minecraft.inventory.IInventory; @@ -32,8 +38,6 @@ public class SlotWidget extends Widget implements INativeWidget { protected IGuiTexture[] backgroundTexture; protected Runnable changeListener; - protected Rectangle scissor; - public SlotWidget(IInventory inventory, int slotIndex, int xPosition, int yPosition, boolean canTakeItems, boolean canPutItems) { super(new Position(xPosition, yPosition), new Size(18, 18)); this.canTakeItems = canTakeItems; @@ -71,6 +75,15 @@ public void drawInBackground(int mouseX, int mouseY, IRenderContext context) { for (IGuiTexture backgroundTexture : this.backgroundTexture) { backgroundTexture.draw(pos.x, pos.y, size.width, size.height); } + + RenderHelper.enableGUIStandardItemLighting(); + GlStateManager.pushMatrix(); + RenderItem itemRender = Minecraft.getMinecraft().getRenderItem(); + itemRender.renderItemAndEffectIntoGUI(slotReference.getStack(), pos.x + 1, pos.y + 1); + itemRender.renderItemOverlayIntoGUI(Minecraft.getMinecraft().fontRenderer, slotReference.getStack(), pos.x + 1, pos.y + 1, null); + GlStateManager.enableAlpha(); + GlStateManager.popMatrix(); + RenderHelper.disableStandardItemLighting(); } } @@ -93,11 +106,6 @@ public void setEnabled(boolean enabled) { isEnabled = enabled; } - @Override - public void applyScissor(final int parentX, final int parentY, final int parentWidth, final int parentHeight) { - this.scissor = new Rectangle(parentX, parentY, parentWidth, parentHeight); - } - @Override public void detectAndSendChanges() { } @@ -138,13 +146,7 @@ public boolean canTakeStack(EntityPlayer player) { } public boolean isEnabled() { - if (!this.isEnabled) { - return false; - } - if (this.scissor == null) { - return true; - } - return scissor.intersects(toRectangleBox()); + return this.isEnabled; } @Override @@ -166,7 +168,7 @@ public final Slot getHandle() { return slotReference; } - protected class WidgetSlot extends Slot implements IScissored { + protected class WidgetSlot extends Slot { public WidgetSlot(IInventory inventory, int index, int xPosition, int yPosition) { super(inventory, index, xPosition, yPosition); } @@ -204,13 +206,9 @@ public boolean isEnabled() { return SlotWidget.this.isEnabled(); } - @Override - public Rectangle getScissor() { - return SlotWidget.this.scissor; - } } - protected class WidgetSlotItemHandler extends SlotItemHandler implements IScissored { + protected class WidgetSlotItemHandler extends SlotItemHandler { public WidgetSlotItemHandler(IItemHandler itemHandler, int index, int xPosition, int yPosition) { super(itemHandler, index, xPosition, yPosition); @@ -249,9 +247,5 @@ public boolean isEnabled() { return SlotWidget.this.isEnabled(); } - @Override - public Rectangle getScissor() { - return SlotWidget.this.scissor; - } } } diff --git a/src/main/java/gregtech/api/gui/widgets/TankWidget.java b/src/main/java/gregtech/api/gui/widgets/TankWidget.java index 178d013222a..a34e799e9fe 100644 --- a/src/main/java/gregtech/api/gui/widgets/TankWidget.java +++ b/src/main/java/gregtech/api/gui/widgets/TankWidget.java @@ -53,6 +53,8 @@ public class TankWidget extends Widget implements IIngredientSlot { public TankWidget(IFluidTank fluidTank, int x, int y, int width, int height) { super(new Position(x, y), new Size(width, height)); this.fluidTank = fluidTank; + this.lastFluidInTank = fluidTank != null ? fluidTank.getFluid() != null ? fluidTank.getFluid().copy() : null : null; + this.lastTankCapacity = fluidTank != null ? fluidTank.getCapacity() : 0; } public TankWidget setHideTooltip(boolean hideTooltip) { diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java b/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java index f5dfe6121ed..d5818e6eede 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java @@ -89,7 +89,6 @@ public void addWidget(Widget widget) { maxHeight = Math.max(maxHeight, widget.getSize().height + widget.getSelfPosition().y); maxWidth = Math.max(maxWidth, widget.getSize().width + widget.getSelfPosition().x); widget.addSelfPosition(- scrollXOffset, - scrollYOffset); - widget.applyScissor(getPosition().x, getPosition().y, getSize().width - yBarWidth, getSize().height - xBarHeight); super.addWidget(widget); } @@ -114,18 +113,6 @@ public void setSize(Size size) { computeMax(); } - @Override - protected void onPositionUpdate() { - super.onPositionUpdate(); - this.applyScissor(getPosition().x, getPosition().y, getSize().width - yBarWidth, getSize().height - xBarHeight); - } - - @Override - protected void onSizeUpdate() { - super.onSizeUpdate(); - this.applyScissor(getPosition().x, getPosition().y, getSize().width - yBarWidth, getSize().height - xBarHeight); - } - protected void computeMax() { int mh = 0; int mw = 0; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java index 191d3b8a7f0..a837b61a0e8 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java @@ -29,6 +29,7 @@ public class GuideConfigEditor extends TabGroup { public String json; private IGuideWidget selected; private GuidePageEditorWidget pageEditor; + private TextEditorWidget titleEditor; private final DraggableScrollableWidgetGroup widgetSelector; private final DraggableScrollableWidgetGroup widgetConfigurator; private final CircleButtonWidget[] addButton; @@ -93,6 +94,10 @@ public void setGuidePageEditorWidget(GuidePageEditorWidget pageEditor) { this.pageEditor = pageEditor; } + public GuidePageEditorWidget getPageEditor() { + return pageEditor; + } + private DraggableScrollableWidgetGroup createPageConfig() { DraggableScrollableWidgetGroup group = new DraggableScrollableWidgetGroup(0, 0, getSize().width, getSize().height - 10) .setBackground(new ColorRectTexture(new Color(246, 120, 120, 190))) @@ -105,19 +110,24 @@ private DraggableScrollableWidgetGroup createPageConfig() { pageEditor.setSection(s); } }, true) - .setTextSupplier(pageEditor::getSection, true) + .setTextSupplier(()-> getPageEditor().getSection(), true) .setMaxStringLength(Integer.MAX_VALUE) .setValidator(s->true)); group.addWidget(new ImageWidget(5, 48,116, 1, new ColorRectTexture(-1))); group.addWidget(new LabelWidget(5, 55, "title", -1).setShadow(true)); - group.addWidget(new TextEditorWidget(5, 65, 116, 70, s->{ + titleEditor = new TextEditorWidget(5, 65, 116, 70, s->{ if (pageEditor != null) { pageEditor.setTitle(s); } - }, true).setContent(pageEditor.getTitle()).setBackground(new ColorRectTexture(0xA3FFFFFF))); + }, true).setContent("Template").setBackground(new ColorRectTexture(0xA3FFFFFF)); + group.addWidget(titleEditor); return group; } + public void updateTitle(String title) { + titleEditor.setContent(title); + } + private DraggableScrollableWidgetGroup createWidgetSelector() { DraggableScrollableWidgetGroup group = new DraggableScrollableWidgetGroup(0, 0, getSize().width, getSize().height - 10) .setBackground(new ColorRectTexture(new Color(246, 120, 120, 190))) @@ -158,8 +168,11 @@ private void loadJson(ClickData data) { if (result != null && result.isFile()) { try { FileReader reader = new FileReader(result); - pageEditor.loadJsonConfig(new JsonParser().parse(new JsonReader(reader)).getAsJsonObject()); + JsonObject config = new JsonParser().parse(new JsonReader(reader)).getAsJsonObject(); + pageEditor.loadJsonConfig(config); reader.close(); + getPageEditor().setSection(config.get("section").getAsString()); + updateTitle(config.get("title").getAsString()); } catch (Exception e) { TerminalDialogWidget.showInfoDialog(app.getOs(), "ERROR", "An error occurred while loading the file.").setClientSide().open(); } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/SlotListWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/SlotListWidget.java index 502d8b7f29c..84b927691da 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/SlotListWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/SlotListWidget.java @@ -14,7 +14,6 @@ import net.minecraft.util.ResourceLocation; import net.minecraftforge.items.ItemStackHandler; -import java.awt.*; import java.util.Collections; import java.util.List; import java.util.function.Consumer; @@ -25,8 +24,6 @@ public class SlotListWidget extends GuideWidgetGroup { // config public List item_list; - protected transient Rectangle scissor; - @Override public Widget initFixed() { this.clearAllWidgets(); @@ -49,9 +46,6 @@ public Widget initFixed() { itemStackHandler.setStackInSlot(i, item_list.get(i).getInstance()); SlotWidget widget = new SlotWidget(itemStackHandler, i, xPos + x * 18, y * 18, false, false); widget.setBackgroundTexture(background); - if (scissor != null) { - widget.applyScissor(scissor.x, scissor.y, scissor.width, scissor.height); - } this.addWidget(widget); } } @@ -78,12 +72,6 @@ public void loadConfigurator(DraggableScrollableWidgetGroup group, JsonObject co group.addWidget(new ItemStackConfigurator(group, config, "item_list").setOnUpdated(needUpdate)); } - @Override - public void applyScissor(int parentX, int parentY, int parentWidth, int parentHeight) { - super.applyScissor(parentX, parentY, parentWidth, parentHeight); - scissor = new Rectangle(parentX, parentY, parentWidth, parentHeight); - } - public static class ItemStackInfo { // config public String id; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TankListWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TankListWidget.java index adac67ca2df..c42c7cc4f2c 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TankListWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TankListWidget.java @@ -7,6 +7,7 @@ import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.widgets.TankWidget; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; +import gregtech.api.terminal.gui.widgets.guide.configurator.FluidStackConfigurator; import gregtech.api.terminal.gui.widgets.guide.configurator.ItemStackConfigurator; import gregtech.api.util.Size; import net.minecraft.item.Item; @@ -51,7 +52,7 @@ public Widget initFixed() { if (i < size) { FluidStack fluidStack = fluid_list.get(i).getInstance(); TankWidget widget = new TankWidget(new FluidTank(fluidStack, fluid_list.get(i).amount), xPos + x * 18, y * 18, 18, 18); - widget.setBackgroundTexture(background); + widget.setBackgroundTexture(background).setAlwaysShowFull(true); this.addWidget(widget); } } @@ -75,13 +76,7 @@ public JsonObject getTemplate(boolean isFixed) { @Override public void loadConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, boolean isFixed, Consumer needUpdate) { super.loadConfigurator(group, config, isFixed, needUpdate); -// group.addWidget(new ItemStackConfigurator(group, config, "fluid_list").setOnUpdated(needUpdate)); - } - - @Override - public void applyScissor(int parentX, int parentY, int parentWidth, int parentHeight) { - super.applyScissor(parentX, parentY, parentWidth, parentHeight); - scissor = new Rectangle(parentX, parentY, parentWidth, parentHeight); + group.addWidget(new FluidStackConfigurator(group, config, "fluid_list").setOnUpdated(needUpdate)); } public static class FluidStackInfo { @@ -96,8 +91,14 @@ public FluidStackInfo() { } public void update(FluidStack itemStack) { - id = FluidRegistry.getFluidName(itemStack.getFluid()); - amount = itemStack.amount; + if (itemStack != null) { + id = FluidRegistry.getFluidName(itemStack.getFluid()); + amount = itemStack.amount; + } else { + id = null; + fluidStack = null; + amount = 0; + } } public FluidStackInfo(String id, int amount) { @@ -110,8 +111,9 @@ public FluidStack getInstance() { Fluid fluid = FluidRegistry.getFluid(id); if (fluid != null) { fluidStack = new FluidStack(fluid, amount); + } else { + id = null; } - id = null; } return fluidStack; } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/FluidStackConfigurator.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/FluidStackConfigurator.java index 515003db110..e62171cd33f 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/FluidStackConfigurator.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/FluidStackConfigurator.java @@ -59,18 +59,20 @@ private void addSlot(DraggableScrollableWidgetGroup container, TankListWidget.Fl new Color(128, 255, 128).getRGB(), new Color(255, 255, 255, 0).getRGB()) .setClickListener(data -> { - fluidStackInfo.amount = Math.max(0, fluidStackInfo.amount - (data.isShiftClick ? 10 : 1)); + fluidStackInfo.amount = Math.max(0, fluidStackInfo.amount - (data.isShiftClick ? data.isCtrlClick ? 1000 : 10 : data.isCtrlClick? 100: 1)); updateValue(); }) + .setHoverText("Shift -10|Ctrl -100|Shift+Ctrl -1000") .setIcon(new TextTexture("-1", -1))); group.addWidget(new RectButtonWidget(76, 0, 20, 20) .setColors(new Color(0, 0, 0, 74).getRGB(), new Color(128, 255, 128).getRGB(), new Color(255, 255, 255, 0).getRGB()) .setClickListener(data -> { - fluidStackInfo.amount = Math.max(0, fluidStackInfo.amount + (data.isShiftClick ? 10 : 1)); + fluidStackInfo.amount = Math.max(0, fluidStackInfo.amount + (data.isShiftClick ? data.isCtrlClick ? 1000 : 10 : data.isCtrlClick? 100: 1)); updateValue(); }) + .setHoverText("Shift +10|Ctrl +100|Shift+Ctrl +1000") .setIcon(new TextTexture("+1", -1))); group.addWidget(new ImageWidget(40, 0, 36, 20, new ColorRectTexture(0x9f000000))); group.addWidget(new SimpleTextWidget(58, 10, "", 0xFFFFFF, () -> Integer.toString(fluidStackInfo.amount), true)); diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalDialogWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalDialogWidget.java index 115420349cd..401d1fa51ff 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalDialogWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalDialogWidget.java @@ -17,6 +17,7 @@ import net.minecraft.inventory.IInventory; import net.minecraft.network.PacketBuffer; +import java.awt.*; import java.io.File; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; @@ -178,6 +179,7 @@ public static TerminalDialogWidget showFileDialog(TerminalOSWidget os, String ti } } AtomicReference selected = new AtomicReference<>(); + selected.set(dir); dialog.addWidget(new TreeListWidget<>(0, 0, 130, size.height, new FileTree(dir), node -> { selected.set(node.getKey()); System.out.println(node.toString()); @@ -213,7 +215,7 @@ public static TerminalDialogWidget showFileDialog(TerminalOSWidget os, String ti return "no file selected"; }, true)); } else { - dialog.addWidget(new TextFieldWidget(x + WIDTH / 2, y + HEIGHT / 2 - 5, 76, 20, new ColorRectTexture(0x4f000000), null, null) + dialog.addWidget(new TextFieldWidget(x + WIDTH / 2 - 38, y + HEIGHT / 2 - 10, 76, 20, new ColorRectTexture(0x4f000000), null, null) .setTextResponder(res->{ File file = selected.get(); if (file == null) return; From 990b7bb2a959c5b17357196eb46cd85f2dd856a7 Mon Sep 17 00:00:00 2001 From: Yefancy Date: Sun, 8 Aug 2021 13:50:28 +0800 Subject: [PATCH 18/58] adjust package structure --- .../api/terminal/app/AbstractApplication.java | 2 +- .../api/terminal/app/GuideEditorApp.java | 4 +-- .../api/terminal/app/guide/GuideApp.java | 2 +- .../guide/widget}/CardWidget.java | 6 ++-- .../guide/widget}/GuideConfigEditor.java | 33 ++++++++++++++----- .../guide/widget}/GuidePageEditorWidget.java | 2 +- .../guide/widget}/GuidePageWidget.java | 2 +- .../guide/widget}/GuideWidget.java | 10 +++--- .../guide/widget}/GuideWidgetGroup.java | 10 +++--- .../guide/widget}/IGuideWidget.java | 2 +- .../guide/widget}/ImageWidget.java | 9 +++-- .../guide/widget}/SlotListWidget.java | 4 +-- .../guide/widget}/TankListWidget.java | 9 ++--- .../guide/widget}/TextBoxWidget.java | 11 +++---- .../configurator/BooleanConfigurator.java | 3 +- .../configurator/ColorConfigurator.java | 2 +- .../configurator/ConfiguratorWidget.java | 2 +- .../configurator/FluidStackConfigurator.java | 4 +-- .../configurator/ItemStackConfigurator.java | 4 +-- .../configurator/NumberConfigurator.java | 3 +- .../configurator/SelectorConfigurator.java | 2 +- .../configurator/StringConfigurator.java | 3 +- .../configurator/TextListConfigurator.java | 4 +-- .../os/TerminalDesktopWidget.java | 2 +- .../widgets => }/os/TerminalDialogWidget.java | 9 ++--- .../widgets => }/os/TerminalMenuWidget.java | 3 +- .../widgets => }/os/TerminalOSWidget.java | 3 +- .../behaviors/GuideTerminalBehaviour.java | 2 +- 28 files changed, 76 insertions(+), 76 deletions(-) rename src/main/java/gregtech/api/terminal/{gui/widgets/guide => app/guide/widget}/CardWidget.java (95%) rename src/main/java/gregtech/api/terminal/{gui/widgets/guide => app/guide/widget}/GuideConfigEditor.java (89%) rename src/main/java/gregtech/api/terminal/{gui/widgets/guide => app/guide/widget}/GuidePageEditorWidget.java (99%) rename src/main/java/gregtech/api/terminal/{gui/widgets/guide => app/guide/widget}/GuidePageWidget.java (99%) rename src/main/java/gregtech/api/terminal/{gui/widgets/guide => app/guide/widget}/GuideWidget.java (94%) rename src/main/java/gregtech/api/terminal/{gui/widgets/guide => app/guide/widget}/GuideWidgetGroup.java (94%) rename src/main/java/gregtech/api/terminal/{gui/widgets/guide => app/guide/widget}/IGuideWidget.java (97%) rename src/main/java/gregtech/api/terminal/{gui/widgets/guide => app/guide/widget}/ImageWidget.java (91%) rename src/main/java/gregtech/api/terminal/{gui/widgets/guide => app/guide/widget}/SlotListWidget.java (96%) rename src/main/java/gregtech/api/terminal/{gui/widgets/guide => app/guide/widget}/TankListWidget.java (91%) rename src/main/java/gregtech/api/terminal/{gui/widgets/guide => app/guide/widget}/TextBoxWidget.java (92%) rename src/main/java/gregtech/api/terminal/{gui/widgets/guide => app/guide/widget}/configurator/BooleanConfigurator.java (93%) rename src/main/java/gregtech/api/terminal/{gui/widgets/guide => app/guide/widget}/configurator/ColorConfigurator.java (93%) rename src/main/java/gregtech/api/terminal/{gui/widgets/guide => app/guide/widget}/configurator/ConfiguratorWidget.java (98%) rename src/main/java/gregtech/api/terminal/{gui/widgets/guide => app/guide/widget}/configurator/FluidStackConfigurator.java (97%) rename src/main/java/gregtech/api/terminal/{gui/widgets/guide => app/guide/widget}/configurator/ItemStackConfigurator.java (97%) rename src/main/java/gregtech/api/terminal/{gui/widgets/guide => app/guide/widget}/configurator/NumberConfigurator.java (96%) rename src/main/java/gregtech/api/terminal/{gui/widgets/guide => app/guide/widget}/configurator/SelectorConfigurator.java (95%) rename src/main/java/gregtech/api/terminal/{gui/widgets/guide => app/guide/widget}/configurator/StringConfigurator.java (93%) rename src/main/java/gregtech/api/terminal/{gui/widgets/guide => app/guide/widget}/configurator/TextListConfigurator.java (91%) rename src/main/java/gregtech/api/terminal/{gui/widgets => }/os/TerminalDesktopWidget.java (97%) rename src/main/java/gregtech/api/terminal/{gui/widgets => }/os/TerminalDialogWidget.java (97%) rename src/main/java/gregtech/api/terminal/{gui/widgets => }/os/TerminalMenuWidget.java (98%) rename src/main/java/gregtech/api/terminal/{gui/widgets => }/os/TerminalOSWidget.java (98%) diff --git a/src/main/java/gregtech/api/terminal/app/AbstractApplication.java b/src/main/java/gregtech/api/terminal/app/AbstractApplication.java index 3a93dc51108..671538d2090 100644 --- a/src/main/java/gregtech/api/terminal/app/AbstractApplication.java +++ b/src/main/java/gregtech/api/terminal/app/AbstractApplication.java @@ -2,7 +2,7 @@ import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.terminal.gui.widgets.AnimaWidgetGroup; -import gregtech.api.terminal.gui.widgets.os.TerminalOSWidget; +import gregtech.api.terminal.os.TerminalOSWidget; import gregtech.api.util.Position; import gregtech.api.util.Size; import net.minecraft.nbt.NBTTagCompound; diff --git a/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java b/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java index 3dd11f4b5cc..dbe72974447 100644 --- a/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java +++ b/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java @@ -1,8 +1,8 @@ package gregtech.api.terminal.app; import gregtech.api.gui.resources.TextureArea; -import gregtech.api.terminal.gui.widgets.guide.GuideConfigEditor; -import gregtech.api.terminal.gui.widgets.guide.GuidePageEditorWidget; +import gregtech.api.terminal.app.guide.widget.GuideConfigEditor; +import gregtech.api.terminal.app.guide.widget.GuidePageEditorWidget; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.PacketBuffer; diff --git a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java index 6c394c2c530..a7d19ccb608 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java @@ -8,7 +8,7 @@ import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.terminal.app.AbstractApplication; import gregtech.api.terminal.gui.widgets.TreeListWidget; -import gregtech.api.terminal.gui.widgets.guide.*; +import gregtech.api.terminal.app.guide.widget.*; import gregtech.api.terminal.util.TreeNode; import net.minecraft.client.Minecraft; import net.minecraft.nbt.NBTTagCompound; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/CardWidget.java b/src/main/java/gregtech/api/terminal/app/guide/widget/CardWidget.java similarity index 95% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/CardWidget.java rename to src/main/java/gregtech/api/terminal/app/guide/widget/CardWidget.java index 07a108e97cc..77b8f0ae588 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/CardWidget.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/CardWidget.java @@ -1,11 +1,11 @@ -package gregtech.api.terminal.gui.widgets.guide; +package gregtech.api.terminal.app.guide.widget; import com.google.gson.JsonObject; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; -import gregtech.api.terminal.gui.widgets.guide.configurator.BooleanConfigurator; -import gregtech.api.terminal.gui.widgets.guide.configurator.NumberConfigurator; +import gregtech.api.terminal.app.guide.widget.configurator.BooleanConfigurator; +import gregtech.api.terminal.app.guide.widget.configurator.NumberConfigurator; import gregtech.api.util.Position; import gregtech.api.util.Size; import net.minecraft.client.renderer.BufferBuilder; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java b/src/main/java/gregtech/api/terminal/app/guide/widget/GuideConfigEditor.java similarity index 89% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java rename to src/main/java/gregtech/api/terminal/app/guide/widget/GuideConfigEditor.java index a837b61a0e8..f455d61ebba 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/GuideConfigEditor.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.gui.widgets.guide; +package gregtech.api.terminal.app.guide.widget; import com.google.gson.JsonObject; import com.google.gson.JsonParser; @@ -15,7 +15,7 @@ import gregtech.api.terminal.gui.widgets.CircleButtonWidget; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; import gregtech.api.terminal.gui.widgets.TextEditorWidget; -import gregtech.api.terminal.gui.widgets.os.TerminalDialogWidget; +import gregtech.api.terminal.os.TerminalDialogWidget; import gregtech.api.util.Position; import gregtech.api.util.Size; @@ -55,19 +55,26 @@ public GuideConfigEditor(int x, int y, int width, int height, GuideEditorApp app addButton[1].setVisible(false); } }); - this.addWidget(new CircleButtonWidget(100, -5, 5, 1, 3) + this.addWidget(new CircleButtonWidget(97, -5, 5, 1, 3) + .setColors(new Color(255, 255, 255, 0).getRGB(), + new Color(255, 255, 255).getRGB(), + new Color(144, 243, 116).getRGB()) + .setIcon(GuiTextures.TERMINAL_ADD) + .setHoverText("New Page") + .setClickListener(this::newPage)); + this.addWidget(new CircleButtonWidget(112, -5, 5, 1, 3) .setColors(new Color(255, 255, 255, 0).getRGB(), new Color(255, 255, 255).getRGB(), new Color(243, 208, 116).getRGB()) .setIcon(GuiTextures.TERMINAL_ADD) - .setHoverText("Import Guide") + .setHoverText("Import Page") .setClickListener(this::loadJson)); - this.addWidget(new CircleButtonWidget(120, -5, 5, 1, 3) + this.addWidget(new CircleButtonWidget(127, -5, 5, 1, 3) .setColors(new Color(255, 255, 255, 0).getRGB(), new Color(255, 255, 255).getRGB(), - new Color(146, 253, 118).getRGB()) + new Color(231, 95, 95).getRGB()) .setIcon(GuiTextures.TERMINAL_ADD) - .setHoverText("Export Config") + .setHoverText("Export Page") .setClickListener(this::saveJson)); addButton[0] = new CircleButtonWidget(115, 15, 8, 1, 8) .setColors(new Color(255, 255, 255, 0).getRGB(), @@ -161,8 +168,18 @@ public void loadConfigurator(IGuideWidget widget) { } } + private void newPage(ClickData data) { + TerminalDialogWidget.showConfirmDialog(app.getOs(), "New Page", "New page", res->{ + if (res) { + pageEditor.loadJsonConfig("{\"section\":\"default\",\"title\":\"Template\",\"stream\":[],\"fixed\":[]}"); + getPageEditor().setSection("default"); + updateTitle("Template"); + } + }).setClientSide().open(); + } + private void loadJson(ClickData data) { - if(pageEditor != null) { + if (pageEditor != null) { File file = new File("terminal\\guide_editor"); TerminalDialogWidget.showFileDialog(app.getOs(), "Load Json", file, true, result->{ if (result != null && result.isFile()) { diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java b/src/main/java/gregtech/api/terminal/app/guide/widget/GuidePageEditorWidget.java similarity index 99% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java rename to src/main/java/gregtech/api/terminal/app/guide/widget/GuidePageEditorWidget.java index 9283f11a7f7..95470e3a3fb 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/GuidePageEditorWidget.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.gui.widgets.guide; +package gregtech.api.terminal.app.guide.widget; import com.google.gson.Gson; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java b/src/main/java/gregtech/api/terminal/app/guide/widget/GuidePageWidget.java similarity index 99% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java rename to src/main/java/gregtech/api/terminal/app/guide/widget/GuidePageWidget.java index fa3ef7fe26a..fb3c7c29b4d 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/GuidePageWidget.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.gui.widgets.guide; +package gregtech.api.terminal.app.guide.widget; import com.google.gson.JsonElement; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java b/src/main/java/gregtech/api/terminal/app/guide/widget/GuideWidget.java similarity index 94% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java rename to src/main/java/gregtech/api/terminal/app/guide/widget/GuideWidget.java index 9cf86a39b6d..2ee618f80c6 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/GuideWidget.java @@ -1,14 +1,14 @@ -package gregtech.api.terminal.gui.widgets.guide; +package gregtech.api.terminal.app.guide.widget; import com.google.gson.Gson; import com.google.gson.JsonObject; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; -import gregtech.api.terminal.gui.widgets.guide.configurator.ColorConfigurator; -import gregtech.api.terminal.gui.widgets.guide.configurator.NumberConfigurator; -import gregtech.api.terminal.gui.widgets.guide.configurator.StringConfigurator; -import gregtech.api.terminal.gui.widgets.guide.configurator.TextListConfigurator; +import gregtech.api.terminal.app.guide.widget.configurator.ColorConfigurator; +import gregtech.api.terminal.app.guide.widget.configurator.NumberConfigurator; +import gregtech.api.terminal.app.guide.widget.configurator.StringConfigurator; +import gregtech.api.terminal.app.guide.widget.configurator.TextListConfigurator; import gregtech.api.util.Position; import gregtech.api.util.Size; import net.minecraft.item.ItemStack; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidgetGroup.java b/src/main/java/gregtech/api/terminal/app/guide/widget/GuideWidgetGroup.java similarity index 94% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidgetGroup.java rename to src/main/java/gregtech/api/terminal/app/guide/widget/GuideWidgetGroup.java index 3dc31404fb2..8ade843e2c5 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidgetGroup.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/GuideWidgetGroup.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.gui.widgets.guide; +package gregtech.api.terminal.app.guide.widget; import com.google.gson.Gson; import com.google.gson.JsonObject; @@ -6,10 +6,10 @@ import gregtech.api.gui.Widget; import gregtech.api.gui.widgets.WidgetGroup; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; -import gregtech.api.terminal.gui.widgets.guide.configurator.ColorConfigurator; -import gregtech.api.terminal.gui.widgets.guide.configurator.NumberConfigurator; -import gregtech.api.terminal.gui.widgets.guide.configurator.StringConfigurator; -import gregtech.api.terminal.gui.widgets.guide.configurator.TextListConfigurator; +import gregtech.api.terminal.app.guide.widget.configurator.ColorConfigurator; +import gregtech.api.terminal.app.guide.widget.configurator.NumberConfigurator; +import gregtech.api.terminal.app.guide.widget.configurator.StringConfigurator; +import gregtech.api.terminal.app.guide.widget.configurator.TextListConfigurator; import gregtech.api.util.Position; import gregtech.api.util.Size; import net.minecraft.item.ItemStack; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java b/src/main/java/gregtech/api/terminal/app/guide/widget/IGuideWidget.java similarity index 97% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java rename to src/main/java/gregtech/api/terminal/app/guide/widget/IGuideWidget.java index 5b55547f941..cd6f91be62b 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/IGuideWidget.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.gui.widgets.guide; +package gregtech.api.terminal.app.guide.widget; import com.google.gson.Gson; import com.google.gson.JsonElement; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java b/src/main/java/gregtech/api/terminal/app/guide/widget/ImageWidget.java similarity index 91% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java rename to src/main/java/gregtech/api/terminal/app/guide/widget/ImageWidget.java index 83900ef19bc..2001be50038 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/ImageWidget.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.gui.widgets.guide; +package gregtech.api.terminal.app.guide.widget; import com.google.gson.JsonObject; import gregtech.api.gui.IRenderContext; @@ -8,13 +8,12 @@ import gregtech.api.gui.resources.TextureArea; import gregtech.api.gui.resources.URLTexture; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; -import gregtech.api.terminal.gui.widgets.guide.configurator.NumberConfigurator; -import gregtech.api.terminal.gui.widgets.guide.configurator.SelectorConfigurator; -import gregtech.api.terminal.gui.widgets.guide.configurator.StringConfigurator; +import gregtech.api.terminal.app.guide.widget.configurator.NumberConfigurator; +import gregtech.api.terminal.app.guide.widget.configurator.SelectorConfigurator; +import gregtech.api.terminal.app.guide.widget.configurator.StringConfigurator; import gregtech.api.util.Position; import gregtech.api.util.Size; import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.client.resources.I18n; import net.minecraft.item.Item; import net.minecraft.util.ResourceLocation; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/SlotListWidget.java b/src/main/java/gregtech/api/terminal/app/guide/widget/SlotListWidget.java similarity index 96% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/SlotListWidget.java rename to src/main/java/gregtech/api/terminal/app/guide/widget/SlotListWidget.java index 84b927691da..e944d34f0cb 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/SlotListWidget.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/SlotListWidget.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.gui.widgets.guide; +package gregtech.api.terminal.app.guide.widget; import com.google.gson.Gson; import com.google.gson.JsonObject; @@ -7,7 +7,7 @@ import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.widgets.SlotWidget; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; -import gregtech.api.terminal.gui.widgets.guide.configurator.ItemStackConfigurator; +import gregtech.api.terminal.app.guide.widget.configurator.ItemStackConfigurator; import gregtech.api.util.Size; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TankListWidget.java b/src/main/java/gregtech/api/terminal/app/guide/widget/TankListWidget.java similarity index 91% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/TankListWidget.java rename to src/main/java/gregtech/api/terminal/app/guide/widget/TankListWidget.java index c42c7cc4f2c..587c3cd5f8f 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TankListWidget.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/TankListWidget.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.gui.widgets.guide; +package gregtech.api.terminal.app.guide.widget; import com.google.gson.Gson; import com.google.gson.JsonObject; @@ -7,17 +7,12 @@ import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.widgets.TankWidget; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; -import gregtech.api.terminal.gui.widgets.guide.configurator.FluidStackConfigurator; -import gregtech.api.terminal.gui.widgets.guide.configurator.ItemStackConfigurator; +import gregtech.api.terminal.app.guide.widget.configurator.FluidStackConfigurator; import gregtech.api.util.Size; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.util.ResourceLocation; import net.minecraftforge.fluids.Fluid; import net.minecraftforge.fluids.FluidRegistry; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.FluidTank; -import net.minecraftforge.items.ItemStackHandler; import java.awt.*; import java.util.Collections; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java b/src/main/java/gregtech/api/terminal/app/guide/widget/TextBoxWidget.java similarity index 92% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java rename to src/main/java/gregtech/api/terminal/app/guide/widget/TextBoxWidget.java index 1d4fbcb06c7..98c8259f10f 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/TextBoxWidget.java @@ -1,15 +1,14 @@ -package gregtech.api.terminal.gui.widgets.guide; +package gregtech.api.terminal.app.guide.widget; import com.google.gson.Gson; -import com.google.gson.JsonElement; import com.google.gson.JsonObject; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; -import gregtech.api.terminal.gui.widgets.guide.configurator.BooleanConfigurator; -import gregtech.api.terminal.gui.widgets.guide.configurator.ColorConfigurator; -import gregtech.api.terminal.gui.widgets.guide.configurator.NumberConfigurator; -import gregtech.api.terminal.gui.widgets.guide.configurator.TextListConfigurator; +import gregtech.api.terminal.app.guide.widget.configurator.BooleanConfigurator; +import gregtech.api.terminal.app.guide.widget.configurator.ColorConfigurator; +import gregtech.api.terminal.app.guide.widget.configurator.NumberConfigurator; +import gregtech.api.terminal.app.guide.widget.configurator.TextListConfigurator; import gregtech.api.util.Position; import gregtech.api.util.Size; import net.minecraft.client.Minecraft; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/BooleanConfigurator.java b/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/BooleanConfigurator.java similarity index 93% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/BooleanConfigurator.java rename to src/main/java/gregtech/api/terminal/app/guide/widget/configurator/BooleanConfigurator.java index 8c3b3c567ea..18605fa62e9 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/BooleanConfigurator.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/BooleanConfigurator.java @@ -1,7 +1,6 @@ -package gregtech.api.terminal.gui.widgets.guide.configurator; +package gregtech.api.terminal.app.guide.widget.configurator; import com.google.gson.JsonObject; -import gregtech.api.gui.GuiTextures; import gregtech.api.gui.resources.ColorRectTexture; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; import gregtech.api.terminal.gui.widgets.RectButtonWidget; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ColorConfigurator.java b/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/ColorConfigurator.java similarity index 93% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ColorConfigurator.java rename to src/main/java/gregtech/api/terminal/app/guide/widget/configurator/ColorConfigurator.java index 605593b0166..031c5206d55 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ColorConfigurator.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/ColorConfigurator.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.gui.widgets.guide.configurator; +package gregtech.api.terminal.app.guide.widget.configurator; import com.google.gson.JsonObject; import gregtech.api.terminal.gui.widgets.ColorWidget; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ConfiguratorWidget.java b/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/ConfiguratorWidget.java similarity index 98% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ConfiguratorWidget.java rename to src/main/java/gregtech/api/terminal/app/guide/widget/configurator/ConfiguratorWidget.java index 15c7fb5c561..522dd9abc32 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ConfiguratorWidget.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/ConfiguratorWidget.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.gui.widgets.guide.configurator; +package gregtech.api.terminal.app.guide.widget.configurator; import com.google.gson.Gson; import com.google.gson.JsonObject; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/FluidStackConfigurator.java b/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/FluidStackConfigurator.java similarity index 97% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/FluidStackConfigurator.java rename to src/main/java/gregtech/api/terminal/app/guide/widget/configurator/FluidStackConfigurator.java index e62171cd33f..7833d42569d 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/FluidStackConfigurator.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/FluidStackConfigurator.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.gui.widgets.guide.configurator; +package gregtech.api.terminal.app.guide.widget.configurator; import com.google.gson.Gson; import com.google.gson.JsonElement; @@ -9,7 +9,7 @@ import gregtech.api.gui.widgets.*; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; import gregtech.api.terminal.gui.widgets.RectButtonWidget; -import gregtech.api.terminal.gui.widgets.guide.TankListWidget; +import gregtech.api.terminal.app.guide.widget.TankListWidget; import java.awt.*; import java.util.ArrayList; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ItemStackConfigurator.java b/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/ItemStackConfigurator.java similarity index 97% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ItemStackConfigurator.java rename to src/main/java/gregtech/api/terminal/app/guide/widget/configurator/ItemStackConfigurator.java index 1ddc765534e..c9b81e4ffda 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ItemStackConfigurator.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/ItemStackConfigurator.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.gui.widgets.guide.configurator; +package gregtech.api.terminal.app.guide.widget.configurator; import com.google.gson.Gson; import com.google.gson.JsonElement; @@ -12,7 +12,7 @@ import gregtech.api.gui.widgets.WidgetGroup; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; import gregtech.api.terminal.gui.widgets.RectButtonWidget; -import gregtech.api.terminal.gui.widgets.guide.SlotListWidget; +import gregtech.api.terminal.app.guide.widget.SlotListWidget; import net.minecraftforge.items.IItemHandlerModifiable; import net.minecraftforge.items.ItemStackHandler; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/NumberConfigurator.java b/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/NumberConfigurator.java similarity index 96% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/NumberConfigurator.java rename to src/main/java/gregtech/api/terminal/app/guide/widget/configurator/NumberConfigurator.java index 0779e0e661a..54ce1be916b 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/NumberConfigurator.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/NumberConfigurator.java @@ -1,8 +1,7 @@ -package gregtech.api.terminal.gui.widgets.guide.configurator; +package gregtech.api.terminal.app.guide.widget.configurator; import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import gregtech.api.gui.GuiTextures; import gregtech.api.gui.resources.ColorRectTexture; import gregtech.api.gui.resources.TextTexture; import gregtech.api.gui.widgets.ImageWidget; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/SelectorConfigurator.java b/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/SelectorConfigurator.java similarity index 95% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/SelectorConfigurator.java rename to src/main/java/gregtech/api/terminal/app/guide/widget/configurator/SelectorConfigurator.java index 054f159ee57..a6e46f27eb9 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/SelectorConfigurator.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/SelectorConfigurator.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.gui.widgets.guide.configurator; +package gregtech.api.terminal.app.guide.widget.configurator; import com.google.gson.JsonObject; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/StringConfigurator.java b/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/StringConfigurator.java similarity index 93% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/StringConfigurator.java rename to src/main/java/gregtech/api/terminal/app/guide/widget/configurator/StringConfigurator.java index fa5cc9616c2..dbcb7d300f0 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/StringConfigurator.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/StringConfigurator.java @@ -1,8 +1,7 @@ -package gregtech.api.terminal.gui.widgets.guide.configurator; +package gregtech.api.terminal.app.guide.widget.configurator; import com.google.gson.JsonObject; import gregtech.api.gui.resources.ColorRectTexture; -import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.resources.TextTexture; import gregtech.api.gui.widgets.TextFieldWidget; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/TextListConfigurator.java b/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/TextListConfigurator.java similarity index 91% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/TextListConfigurator.java rename to src/main/java/gregtech/api/terminal/app/guide/widget/configurator/TextListConfigurator.java index 1fae4a6711d..c5f37b36f2e 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/TextListConfigurator.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/TextListConfigurator.java @@ -1,12 +1,10 @@ -package gregtech.api.terminal.gui.widgets.guide.configurator; +package gregtech.api.terminal.app.guide.widget.configurator; import com.google.gson.*; import gregtech.api.gui.resources.ColorRectTexture; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; import gregtech.api.terminal.gui.widgets.TextEditorWidget; -import net.minecraft.client.resources.I18n; -import java.util.Arrays; import java.util.Collections; import java.util.List; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalDesktopWidget.java b/src/main/java/gregtech/api/terminal/os/TerminalDesktopWidget.java similarity index 97% rename from src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalDesktopWidget.java rename to src/main/java/gregtech/api/terminal/os/TerminalDesktopWidget.java index ccff0af79b3..41118ea9127 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalDesktopWidget.java +++ b/src/main/java/gregtech/api/terminal/os/TerminalDesktopWidget.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.gui.widgets.os; +package gregtech.api.terminal.os; import gregtech.api.gui.widgets.WidgetGroup; import gregtech.api.terminal.app.AbstractApplication; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalDialogWidget.java b/src/main/java/gregtech/api/terminal/os/TerminalDialogWidget.java similarity index 97% rename from src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalDialogWidget.java rename to src/main/java/gregtech/api/terminal/os/TerminalDialogWidget.java index 401d1fa51ff..41b278c9638 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalDialogWidget.java +++ b/src/main/java/gregtech/api/terminal/os/TerminalDialogWidget.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.gui.widgets.os; +package gregtech.api.terminal.os; import gregtech.api.gui.GuiTextures; import gregtech.api.gui.IRenderContext; @@ -17,7 +17,6 @@ import net.minecraft.inventory.IInventory; import net.minecraft.network.PacketBuffer; -import java.awt.*; import java.io.File; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; @@ -132,10 +131,8 @@ public static TerminalDialogWidget showInfoDialog(TerminalOSWidget os, String ti return createEmptyTemplate(os).addTitle(title).addInfo(info).addOkButton(); } - public static TerminalDialogWidget showConfirmDialog(TerminalOSWidget os, String info, Consumer result) { - TerminalDialogWidget dialog = createEmptyTemplate(os).addConfirmButton(result); - dialog.addWidget(new LabelWidget(WIDTH / 2, HEIGHT / 2 - 10, info, -1).setXCentered(true)); - return dialog; + public static TerminalDialogWidget showConfirmDialog(TerminalOSWidget os, String title, String info, Consumer result) { + return createEmptyTemplate(os).addConfirmButton(result).addTitle(title).addInfo(info); } public static TerminalDialogWidget showTextFieldDialog(TerminalOSWidget os, String title, Predicate validator, Consumer result) { diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalMenuWidget.java b/src/main/java/gregtech/api/terminal/os/TerminalMenuWidget.java similarity index 98% rename from src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalMenuWidget.java rename to src/main/java/gregtech/api/terminal/os/TerminalMenuWidget.java index 0524137b242..8bf7bcbb199 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalMenuWidget.java +++ b/src/main/java/gregtech/api/terminal/os/TerminalMenuWidget.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.gui.widgets.os; +package gregtech.api.terminal.os; import gregtech.api.gui.GuiTextures; import gregtech.api.gui.IRenderContext; @@ -12,7 +12,6 @@ import net.minecraft.client.renderer.GlStateManager; import java.awt.*; -import java.io.File; public class TerminalMenuWidget extends WidgetGroup { private Interpolator interpolator; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalOSWidget.java b/src/main/java/gregtech/api/terminal/os/TerminalOSWidget.java similarity index 98% rename from src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalOSWidget.java rename to src/main/java/gregtech/api/terminal/os/TerminalOSWidget.java index 6668a0b09b9..b94cc7575ec 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalOSWidget.java +++ b/src/main/java/gregtech/api/terminal/os/TerminalOSWidget.java @@ -1,9 +1,8 @@ -package gregtech.api.terminal.gui.widgets.os; +package gregtech.api.terminal.os; import gregtech.api.gui.GuiTextures; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.ModularUI; -import gregtech.api.gui.Widget; import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.widgets.AbstractWidgetGroup; import gregtech.api.terminal.app.AbstractApplication; diff --git a/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java b/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java index a451c053d23..ebb61dd949f 100644 --- a/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java +++ b/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java @@ -8,7 +8,7 @@ import gregtech.api.items.metaitem.stats.IItemBehaviour; import gregtech.api.terminal.TerminalBuilder; import gregtech.api.terminal.gui.widgets.CircleButtonWidget; -import gregtech.api.terminal.gui.widgets.os.TerminalOSWidget; +import gregtech.api.terminal.os.TerminalOSWidget; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.util.ActionResult; From 15d7efbf819e5b7366f8d48ae3bf5b2af435e06f Mon Sep 17 00:00:00 2001 From: Yefancy Date: Sun, 8 Aug 2021 13:56:37 +0800 Subject: [PATCH 19/58] adjust package structure --- src/main/java/gregtech/api/terminal/TerminalBuilder.java | 1 + .../api/terminal/app/guide/widget/CardWidget.java | 4 ++-- .../api/terminal/app/guide/widget/GuideWidget.java | 8 ++++---- .../api/terminal/app/guide/widget/GuideWidgetGroup.java | 8 ++++---- .../api/terminal/app/guide/widget/ImageWidget.java | 6 +++--- .../api/terminal/app/guide/widget/SlotListWidget.java | 2 +- .../api/terminal/app/guide/widget/TankListWidget.java | 2 +- .../api/terminal/app/guide/widget/TextBoxWidget.java | 8 ++++---- .../terminal/app/{ => guideeditor}/GuideEditorApp.java | 9 +++++---- .../{guide => guideeditor}/widget/GuideConfigEditor.java | 6 ++++-- .../widget/GuidePageEditorWidget.java | 4 +++- .../widget/configurator/BooleanConfigurator.java | 2 +- .../widget/configurator/ColorConfigurator.java | 2 +- .../widget/configurator/ConfiguratorWidget.java | 2 +- .../widget/configurator/FluidStackConfigurator.java | 2 +- .../widget/configurator/ItemStackConfigurator.java | 2 +- .../widget/configurator/NumberConfigurator.java | 2 +- .../widget/configurator/SelectorConfigurator.java | 2 +- .../widget/configurator/StringConfigurator.java | 2 +- .../widget/configurator/TextListConfigurator.java | 2 +- 20 files changed, 41 insertions(+), 35 deletions(-) rename src/main/java/gregtech/api/terminal/app/{ => guideeditor}/GuideEditorApp.java (77%) rename src/main/java/gregtech/api/terminal/app/{guide => guideeditor}/widget/GuideConfigEditor.java (98%) rename src/main/java/gregtech/api/terminal/app/{guide => guideeditor}/widget/GuidePageEditorWidget.java (98%) rename src/main/java/gregtech/api/terminal/app/{guide => guideeditor}/widget/configurator/BooleanConfigurator.java (95%) rename src/main/java/gregtech/api/terminal/app/{guide => guideeditor}/widget/configurator/ColorConfigurator.java (92%) rename src/main/java/gregtech/api/terminal/app/{guide => guideeditor}/widget/configurator/ConfiguratorWidget.java (98%) rename src/main/java/gregtech/api/terminal/app/{guide => guideeditor}/widget/configurator/FluidStackConfigurator.java (98%) rename src/main/java/gregtech/api/terminal/app/{guide => guideeditor}/widget/configurator/ItemStackConfigurator.java (98%) rename src/main/java/gregtech/api/terminal/app/{guide => guideeditor}/widget/configurator/NumberConfigurator.java (97%) rename src/main/java/gregtech/api/terminal/app/{guide => guideeditor}/widget/configurator/SelectorConfigurator.java (95%) rename src/main/java/gregtech/api/terminal/app/{guide => guideeditor}/widget/configurator/StringConfigurator.java (96%) rename src/main/java/gregtech/api/terminal/app/{guide => guideeditor}/widget/configurator/TextListConfigurator.java (95%) diff --git a/src/main/java/gregtech/api/terminal/TerminalBuilder.java b/src/main/java/gregtech/api/terminal/TerminalBuilder.java index 38b4f0a0cb2..4b45d754825 100644 --- a/src/main/java/gregtech/api/terminal/TerminalBuilder.java +++ b/src/main/java/gregtech/api/terminal/TerminalBuilder.java @@ -5,6 +5,7 @@ import gregtech.api.terminal.app.guide.MultiBlockGuideApp; import gregtech.api.terminal.app.guide.SimpleMachineGuideApp; import gregtech.api.terminal.app.guide.TutorialGuideApp; +import gregtech.api.terminal.app.guideeditor.GuideEditorApp; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/CardWidget.java b/src/main/java/gregtech/api/terminal/app/guide/widget/CardWidget.java index 77b8f0ae588..a3e8f6a1f76 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/CardWidget.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/CardWidget.java @@ -4,8 +4,8 @@ import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; -import gregtech.api.terminal.app.guide.widget.configurator.BooleanConfigurator; -import gregtech.api.terminal.app.guide.widget.configurator.NumberConfigurator; +import gregtech.api.terminal.app.guideeditor.widget.configurator.BooleanConfigurator; +import gregtech.api.terminal.app.guideeditor.widget.configurator.NumberConfigurator; import gregtech.api.util.Position; import gregtech.api.util.Size; import net.minecraft.client.renderer.BufferBuilder; diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/GuideWidget.java b/src/main/java/gregtech/api/terminal/app/guide/widget/GuideWidget.java index 2ee618f80c6..fda63019391 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/GuideWidget.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/GuideWidget.java @@ -5,10 +5,10 @@ import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; -import gregtech.api.terminal.app.guide.widget.configurator.ColorConfigurator; -import gregtech.api.terminal.app.guide.widget.configurator.NumberConfigurator; -import gregtech.api.terminal.app.guide.widget.configurator.StringConfigurator; -import gregtech.api.terminal.app.guide.widget.configurator.TextListConfigurator; +import gregtech.api.terminal.app.guideeditor.widget.configurator.ColorConfigurator; +import gregtech.api.terminal.app.guideeditor.widget.configurator.NumberConfigurator; +import gregtech.api.terminal.app.guideeditor.widget.configurator.StringConfigurator; +import gregtech.api.terminal.app.guideeditor.widget.configurator.TextListConfigurator; import gregtech.api.util.Position; import gregtech.api.util.Size; import net.minecraft.item.ItemStack; diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/GuideWidgetGroup.java b/src/main/java/gregtech/api/terminal/app/guide/widget/GuideWidgetGroup.java index 8ade843e2c5..0ac2f9c3542 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/GuideWidgetGroup.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/GuideWidgetGroup.java @@ -6,10 +6,10 @@ import gregtech.api.gui.Widget; import gregtech.api.gui.widgets.WidgetGroup; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; -import gregtech.api.terminal.app.guide.widget.configurator.ColorConfigurator; -import gregtech.api.terminal.app.guide.widget.configurator.NumberConfigurator; -import gregtech.api.terminal.app.guide.widget.configurator.StringConfigurator; -import gregtech.api.terminal.app.guide.widget.configurator.TextListConfigurator; +import gregtech.api.terminal.app.guideeditor.widget.configurator.ColorConfigurator; +import gregtech.api.terminal.app.guideeditor.widget.configurator.NumberConfigurator; +import gregtech.api.terminal.app.guideeditor.widget.configurator.StringConfigurator; +import gregtech.api.terminal.app.guideeditor.widget.configurator.TextListConfigurator; import gregtech.api.util.Position; import gregtech.api.util.Size; import net.minecraft.item.ItemStack; diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/ImageWidget.java b/src/main/java/gregtech/api/terminal/app/guide/widget/ImageWidget.java index 2001be50038..8749aa572be 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/ImageWidget.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/ImageWidget.java @@ -8,9 +8,9 @@ import gregtech.api.gui.resources.TextureArea; import gregtech.api.gui.resources.URLTexture; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; -import gregtech.api.terminal.app.guide.widget.configurator.NumberConfigurator; -import gregtech.api.terminal.app.guide.widget.configurator.SelectorConfigurator; -import gregtech.api.terminal.app.guide.widget.configurator.StringConfigurator; +import gregtech.api.terminal.app.guideeditor.widget.configurator.NumberConfigurator; +import gregtech.api.terminal.app.guideeditor.widget.configurator.SelectorConfigurator; +import gregtech.api.terminal.app.guideeditor.widget.configurator.StringConfigurator; import gregtech.api.util.Position; import gregtech.api.util.Size; import net.minecraft.client.renderer.GlStateManager; diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/SlotListWidget.java b/src/main/java/gregtech/api/terminal/app/guide/widget/SlotListWidget.java index e944d34f0cb..8cc14e1fad4 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/SlotListWidget.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/SlotListWidget.java @@ -7,7 +7,7 @@ import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.widgets.SlotWidget; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; -import gregtech.api.terminal.app.guide.widget.configurator.ItemStackConfigurator; +import gregtech.api.terminal.app.guideeditor.widget.configurator.ItemStackConfigurator; import gregtech.api.util.Size; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/TankListWidget.java b/src/main/java/gregtech/api/terminal/app/guide/widget/TankListWidget.java index 587c3cd5f8f..8b67b853137 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/TankListWidget.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/TankListWidget.java @@ -7,7 +7,7 @@ import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.widgets.TankWidget; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; -import gregtech.api.terminal.app.guide.widget.configurator.FluidStackConfigurator; +import gregtech.api.terminal.app.guideeditor.widget.configurator.FluidStackConfigurator; import gregtech.api.util.Size; import net.minecraftforge.fluids.Fluid; import net.minecraftforge.fluids.FluidRegistry; diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/TextBoxWidget.java b/src/main/java/gregtech/api/terminal/app/guide/widget/TextBoxWidget.java index 98c8259f10f..2594280a3b5 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/TextBoxWidget.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/TextBoxWidget.java @@ -5,10 +5,10 @@ import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; -import gregtech.api.terminal.app.guide.widget.configurator.BooleanConfigurator; -import gregtech.api.terminal.app.guide.widget.configurator.ColorConfigurator; -import gregtech.api.terminal.app.guide.widget.configurator.NumberConfigurator; -import gregtech.api.terminal.app.guide.widget.configurator.TextListConfigurator; +import gregtech.api.terminal.app.guideeditor.widget.configurator.BooleanConfigurator; +import gregtech.api.terminal.app.guideeditor.widget.configurator.ColorConfigurator; +import gregtech.api.terminal.app.guideeditor.widget.configurator.NumberConfigurator; +import gregtech.api.terminal.app.guideeditor.widget.configurator.TextListConfigurator; import gregtech.api.util.Position; import gregtech.api.util.Size; import net.minecraft.client.Minecraft; diff --git a/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java b/src/main/java/gregtech/api/terminal/app/guideeditor/GuideEditorApp.java similarity index 77% rename from src/main/java/gregtech/api/terminal/app/GuideEditorApp.java rename to src/main/java/gregtech/api/terminal/app/guideeditor/GuideEditorApp.java index dbe72974447..7bd1c2c2a1c 100644 --- a/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java +++ b/src/main/java/gregtech/api/terminal/app/guideeditor/GuideEditorApp.java @@ -1,14 +1,15 @@ -package gregtech.api.terminal.app; +package gregtech.api.terminal.app.guideeditor; import gregtech.api.gui.resources.TextureArea; -import gregtech.api.terminal.app.guide.widget.GuideConfigEditor; -import gregtech.api.terminal.app.guide.widget.GuidePageEditorWidget; +import gregtech.api.terminal.app.AbstractApplication; +import gregtech.api.terminal.app.guideeditor.widget.GuideConfigEditor; +import gregtech.api.terminal.app.guideeditor.widget.GuidePageEditorWidget; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.PacketBuffer; import java.util.function.Consumer; -public class GuideEditorApp extends AbstractApplication{ +public class GuideEditorApp extends AbstractApplication { public static final TextureArea ICON = TextureArea.fullImage("textures/gui/terminal/guide_editor/icon.png"); public GuideEditorApp() { diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/GuideConfigEditor.java b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/GuideConfigEditor.java similarity index 98% rename from src/main/java/gregtech/api/terminal/app/guide/widget/GuideConfigEditor.java rename to src/main/java/gregtech/api/terminal/app/guideeditor/widget/GuideConfigEditor.java index f455d61ebba..8d6aa85fcfe 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/GuideConfigEditor.java +++ b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/GuideConfigEditor.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.guide.widget; +package gregtech.api.terminal.app.guideeditor.widget; import com.google.gson.JsonObject; import com.google.gson.JsonParser; @@ -10,7 +10,9 @@ import gregtech.api.gui.widgets.ImageWidget; import gregtech.api.gui.widgets.*; import gregtech.api.gui.widgets.tab.IGuiTextureTabInfo; -import gregtech.api.terminal.app.GuideEditorApp; +import gregtech.api.terminal.app.guide.widget.GuidePageWidget; +import gregtech.api.terminal.app.guide.widget.IGuideWidget; +import gregtech.api.terminal.app.guideeditor.GuideEditorApp; import gregtech.api.terminal.gui.CustomTabListRenderer; import gregtech.api.terminal.gui.widgets.CircleButtonWidget; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/GuidePageEditorWidget.java b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/GuidePageEditorWidget.java similarity index 98% rename from src/main/java/gregtech/api/terminal/app/guide/widget/GuidePageEditorWidget.java rename to src/main/java/gregtech/api/terminal/app/guideeditor/widget/GuidePageEditorWidget.java index 95470e3a3fb..6995f88cc6a 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/GuidePageEditorWidget.java +++ b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/GuidePageEditorWidget.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.guide.widget; +package gregtech.api.terminal.app.guideeditor.widget; import com.google.gson.Gson; @@ -8,6 +8,8 @@ import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.terminal.app.guide.widget.GuidePageWidget; +import gregtech.api.terminal.app.guide.widget.IGuideWidget; import gregtech.api.terminal.gui.widgets.CircleButtonWidget; import gregtech.api.terminal.gui.widgets.CustomPositionSizeWidget; import gregtech.api.util.Position; diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/BooleanConfigurator.java b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/BooleanConfigurator.java similarity index 95% rename from src/main/java/gregtech/api/terminal/app/guide/widget/configurator/BooleanConfigurator.java rename to src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/BooleanConfigurator.java index 18605fa62e9..cfb4ff12802 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/BooleanConfigurator.java +++ b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/BooleanConfigurator.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.guide.widget.configurator; +package gregtech.api.terminal.app.guideeditor.widget.configurator; import com.google.gson.JsonObject; import gregtech.api.gui.resources.ColorRectTexture; diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/ColorConfigurator.java b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/ColorConfigurator.java similarity index 92% rename from src/main/java/gregtech/api/terminal/app/guide/widget/configurator/ColorConfigurator.java rename to src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/ColorConfigurator.java index 031c5206d55..c561275cc46 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/ColorConfigurator.java +++ b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/ColorConfigurator.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.guide.widget.configurator; +package gregtech.api.terminal.app.guideeditor.widget.configurator; import com.google.gson.JsonObject; import gregtech.api.terminal.gui.widgets.ColorWidget; diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/ConfiguratorWidget.java b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/ConfiguratorWidget.java similarity index 98% rename from src/main/java/gregtech/api/terminal/app/guide/widget/configurator/ConfiguratorWidget.java rename to src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/ConfiguratorWidget.java index 522dd9abc32..26300ca40ba 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/ConfiguratorWidget.java +++ b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/ConfiguratorWidget.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.guide.widget.configurator; +package gregtech.api.terminal.app.guideeditor.widget.configurator; import com.google.gson.Gson; import com.google.gson.JsonObject; diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/FluidStackConfigurator.java b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/FluidStackConfigurator.java similarity index 98% rename from src/main/java/gregtech/api/terminal/app/guide/widget/configurator/FluidStackConfigurator.java rename to src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/FluidStackConfigurator.java index 7833d42569d..a79ed58485e 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/FluidStackConfigurator.java +++ b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/FluidStackConfigurator.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.guide.widget.configurator; +package gregtech.api.terminal.app.guideeditor.widget.configurator; import com.google.gson.Gson; import com.google.gson.JsonElement; diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/ItemStackConfigurator.java b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/ItemStackConfigurator.java similarity index 98% rename from src/main/java/gregtech/api/terminal/app/guide/widget/configurator/ItemStackConfigurator.java rename to src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/ItemStackConfigurator.java index c9b81e4ffda..c361b889772 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/ItemStackConfigurator.java +++ b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/ItemStackConfigurator.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.guide.widget.configurator; +package gregtech.api.terminal.app.guideeditor.widget.configurator; import com.google.gson.Gson; import com.google.gson.JsonElement; diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/NumberConfigurator.java b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/NumberConfigurator.java similarity index 97% rename from src/main/java/gregtech/api/terminal/app/guide/widget/configurator/NumberConfigurator.java rename to src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/NumberConfigurator.java index 54ce1be916b..ece9cc52422 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/NumberConfigurator.java +++ b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/NumberConfigurator.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.guide.widget.configurator; +package gregtech.api.terminal.app.guideeditor.widget.configurator; import com.google.gson.JsonElement; import com.google.gson.JsonObject; diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/SelectorConfigurator.java b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/SelectorConfigurator.java similarity index 95% rename from src/main/java/gregtech/api/terminal/app/guide/widget/configurator/SelectorConfigurator.java rename to src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/SelectorConfigurator.java index a6e46f27eb9..23511f0a03d 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/SelectorConfigurator.java +++ b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/SelectorConfigurator.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.guide.widget.configurator; +package gregtech.api.terminal.app.guideeditor.widget.configurator; import com.google.gson.JsonObject; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/StringConfigurator.java b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/StringConfigurator.java similarity index 96% rename from src/main/java/gregtech/api/terminal/app/guide/widget/configurator/StringConfigurator.java rename to src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/StringConfigurator.java index dbcb7d300f0..8329ec1365d 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/StringConfigurator.java +++ b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/StringConfigurator.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.guide.widget.configurator; +package gregtech.api.terminal.app.guideeditor.widget.configurator; import com.google.gson.JsonObject; import gregtech.api.gui.resources.ColorRectTexture; diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/TextListConfigurator.java b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/TextListConfigurator.java similarity index 95% rename from src/main/java/gregtech/api/terminal/app/guide/widget/configurator/TextListConfigurator.java rename to src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/TextListConfigurator.java index c5f37b36f2e..ccc30ac3152 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/TextListConfigurator.java +++ b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/TextListConfigurator.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.guide.widget.configurator; +package gregtech.api.terminal.app.guideeditor.widget.configurator; import com.google.gson.*; import gregtech.api.gui.resources.ColorRectTexture; From 899515f597cd29efe798ff5fb7bdf6cddf3fd71e Mon Sep 17 00:00:00 2001 From: KilaBash Date: Thu, 22 Jul 2021 23:14:09 +0800 Subject: [PATCH 20/58] add item Terminal --- .../java/gregtech/common/items/MetaItems.java | 1 + .../items/behaviors/GuideTerminalBehaviour.java | 12 ++++++++++++ .../resources/assets/gregtech/lang/en_us.lang | 3 +++ .../models/item/metaitems/guide_terminal.json | 6 ++++++ .../items/metaitems/tool.guide_terminal.png | Bin 0 -> 2868 bytes 5 files changed, 22 insertions(+) create mode 100644 src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java create mode 100644 src/main/resources/assets/gregtech/models/item/metaitems/guide_terminal.json create mode 100644 src/main/resources/assets/gregtech/textures/items/metaitems/tool.guide_terminal.png diff --git a/src/main/java/gregtech/common/items/MetaItems.java b/src/main/java/gregtech/common/items/MetaItems.java index 6f7457465f1..17f3a0f7aa0 100644 --- a/src/main/java/gregtech/common/items/MetaItems.java +++ b/src/main/java/gregtech/common/items/MetaItems.java @@ -414,6 +414,7 @@ private MetaItems() { public static MetaItem.MetaValueItem NANO_SABER; public static MetaItem.MetaValueItem ENERGY_FIELD_PROJECTOR; public static MetaItem.MetaValueItem SCANNER; + public static MetaItem.MetaValueItem GUIDE_TERMINAL; public static final MetaItem.MetaValueItem[] DYE_ONLY_ITEMS = new MetaItem.MetaValueItem[EnumDyeColor.values().length]; public static final MetaItem.MetaValueItem[] SPRAY_CAN_DYES = new MetaItem.MetaValueItem[EnumDyeColor.values().length]; diff --git a/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java b/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java new file mode 100644 index 00000000000..9c796d99263 --- /dev/null +++ b/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java @@ -0,0 +1,12 @@ +package gregtech.common.items.behaviors; + +import gregtech.api.items.metaitem.stats.IItemBehaviour; +import net.minecraft.item.ItemStack; + +import java.util.List; + +public class GuideTerminalBehaviour implements IItemBehaviour { + @Override + public void addInformation(ItemStack itemStack, List lines) { + } +} diff --git a/src/main/resources/assets/gregtech/lang/en_us.lang b/src/main/resources/assets/gregtech/lang/en_us.lang index 35afaa8513e..3178ad0ea71 100644 --- a/src/main/resources/assets/gregtech/lang/en_us.lang +++ b/src/main/resources/assets/gregtech/lang/en_us.lang @@ -1960,6 +1960,9 @@ behavior.scanner.analyzing_failed=Analyzing failed! behavior.scanner.analyzing_complete=Analyzing complete! behavior.scanner.not_enough_energy=Analyzing failed: Not Enough Energy! +metaitem.guide_terminal.name=Guide Terminal +metaitem.guide_terminal.tooltip=Hope it will help you + tile.casing.ulv=ULV Machine Casing tile.casing.lv=LV Machine Casing tile.casing.mv=MV Machine Casing diff --git a/src/main/resources/assets/gregtech/models/item/metaitems/guide_terminal.json b/src/main/resources/assets/gregtech/models/item/metaitems/guide_terminal.json new file mode 100644 index 00000000000..ddeac5c5ad4 --- /dev/null +++ b/src/main/resources/assets/gregtech/models/item/metaitems/guide_terminal.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "gregtech:items/metaitems/tool.guide_terminal" + } +} diff --git a/src/main/resources/assets/gregtech/textures/items/metaitems/tool.guide_terminal.png b/src/main/resources/assets/gregtech/textures/items/metaitems/tool.guide_terminal.png new file mode 100644 index 0000000000000000000000000000000000000000..3c9b810359d1e18bae247397f2dffa1ac0ca7360 GIT binary patch literal 2868 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 Sd!AAN0000 Date: Sun, 25 Jul 2021 02:33:02 +0800 Subject: [PATCH 21/58] amongus --- .../java/gregtech/api/gui/GuiTextures.java | 2 ++ .../api/gui/resources/RenderUtil.java | 25 +++++++++++++++ .../api/terminal/TerminalBuilder.java | 4 +++ .../terminal/gui/widgets/CircleButton.java | 26 +++++++++++++++ .../behaviors/GuideTerminalBehaviour.java | 30 +++++++++++++++++- .../gui/terminal/terminal_background.png | Bin 0 -> 25109 bytes 6 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 src/main/java/gregtech/api/terminal/TerminalBuilder.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/CircleButton.java create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/terminal_background.png diff --git a/src/main/java/gregtech/api/gui/GuiTextures.java b/src/main/java/gregtech/api/gui/GuiTextures.java index 5988888c12d..d073a19ffab 100644 --- a/src/main/java/gregtech/api/gui/GuiTextures.java +++ b/src/main/java/gregtech/api/gui/GuiTextures.java @@ -167,4 +167,6 @@ public class GuiTextures { public static final TextureArea INFO_ICON = TextureArea.fullImage("textures/gui/widget/information.png"); public static final TextureArea MULTIBLOCK_CATEGORY = TextureArea.fullImage("textures/gui/icon/coke_oven.png"); + //Terminal + public static final TextureArea TERMINAL_BACKGROUND = TextureArea.fullImage("textures/gui/terminal/terminal_background.png"); } diff --git a/src/main/java/gregtech/api/gui/resources/RenderUtil.java b/src/main/java/gregtech/api/gui/resources/RenderUtil.java index ebc04858cd4..bf0ac9dbaf2 100644 --- a/src/main/java/gregtech/api/gui/resources/RenderUtil.java +++ b/src/main/java/gregtech/api/gui/resources/RenderUtil.java @@ -13,6 +13,9 @@ import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; +import net.minecraft.client.renderer.GlStateManager.DestFactor; +import net.minecraft.client.renderer.GlStateManager.SourceFactor; +import org.lwjgl.opengl.GL11; @SideOnly(Side.CLIENT) public class RenderUtil { @@ -103,5 +106,27 @@ private static void drawFluidTexture(double xCoord, double yCoord, TextureAtlasS tessellator.draw(); } + public static void setColor(int color) { // ARGB + GlStateManager.color((color >> 16 & 255) / 255.0F, + (color >> 8 & 255) / 255.0F, + (color & 255) / 255.0F, + (color >> 24 & 255) / 255.0F); + } + + public static void renderCircle(float x, float y, float r, int color, int detail) { + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder bufferbuilder = tessellator.getBuffer(); + GlStateManager.enableBlend(); + GlStateManager.disableTexture2D(); + GlStateManager.tryBlendFuncSeparate(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ZERO); + setColor(color); + bufferbuilder.begin(GL11.GL_POLYGON, DefaultVertexFormats.POSITION); + for (int i = 0; i < detail; i++) { + bufferbuilder.pos(x + r * Math.cos(-2 * Math.PI * i / detail), y + r * Math.sin(-2 * Math.PI * i / detail), 0.0D).endVertex(); + } + tessellator.draw(); + GlStateManager.enableTexture2D(); + GlStateManager.disableBlend(); + } } diff --git a/src/main/java/gregtech/api/terminal/TerminalBuilder.java b/src/main/java/gregtech/api/terminal/TerminalBuilder.java new file mode 100644 index 00000000000..0a89229be3b --- /dev/null +++ b/src/main/java/gregtech/api/terminal/TerminalBuilder.java @@ -0,0 +1,4 @@ +package gregtech.api.terminal; + +public class TerminalBuilder { +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/CircleButton.java b/src/main/java/gregtech/api/terminal/gui/widgets/CircleButton.java new file mode 100644 index 00000000000..b8e34d99bf5 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/CircleButton.java @@ -0,0 +1,26 @@ +package gregtech.api.terminal.gui.widgets; + +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.RenderUtil; +import gregtech.api.util.Position; +import gregtech.api.util.Size; + +public class CircleButton extends Widget { + int x, y, r; + public CircleButton(int x, int y, int r) { + super(new Position(x - r, y - r), new Size(2 * r, 2 * r)); + this.r = r; + } + + @Override + public void drawInBackground(int mouseX, int mouseY, IRenderContext context) { + int r = this.getSize().getHeight() / 2; + int x = this.getPosition().x + r; + int y = this.getPosition().y + r; + + RenderUtil.renderCircle(x, y, r, 0xffff0000, 24); + RenderUtil.renderCircle(x, y, r - 2, 0xffffffff, 24); + + } +} diff --git a/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java b/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java index 9c796d99263..4b014eaec5a 100644 --- a/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java +++ b/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java @@ -1,12 +1,40 @@ package gregtech.common.items.behaviors; +import gregtech.api.gui.GuiTextures; +import gregtech.api.gui.ModularUI; +import gregtech.api.items.gui.ItemUIFactory; +import gregtech.api.items.gui.PlayerInventoryHolder; import gregtech.api.items.metaitem.stats.IItemBehaviour; +import gregtech.api.terminal.gui.widgets.CircleButton; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; +import net.minecraft.util.ActionResult; +import net.minecraft.util.EnumActionResult; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; import java.util.List; -public class GuideTerminalBehaviour implements IItemBehaviour { +public class GuideTerminalBehaviour implements IItemBehaviour, ItemUIFactory { + + @Override + public ActionResult onItemRightClick(World world, EntityPlayer player, EnumHand hand) { + ItemStack itemStack = player.getHeldItem(hand); + if (!world.isRemote) { + PlayerInventoryHolder holder = new PlayerInventoryHolder(player, hand); + holder.openUI(); + } + return ActionResult.newResult(EnumActionResult.SUCCESS, itemStack); + } + @Override public void addInformation(ItemStack itemStack, List lines) { } + + @Override + public ModularUI createUI(PlayerInventoryHolder holder, EntityPlayer entityPlayer) { + return ModularUI.builder(GuiTextures.TERMINAL_BACKGROUND, 380, 256) + .widget(new CircleButton(27, 40, 12)) + .build(holder, entityPlayer); + } } diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_background.png b/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_background.png new file mode 100644 index 0000000000000000000000000000000000000000..3bb4031f9c1324203ff6cc74b891bdd4a13e2a3f GIT binary patch literal 25109 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 Date: Sun, 25 Jul 2021 17:39:14 +0800 Subject: [PATCH 22/58] update gui system --- src/main/java/gregtech/api/gui/Widget.java | 24 +++- .../gregtech/api/gui/impl/ModularUIGui.java | 2 +- .../api/gui/resources/IGuiTexture.java | 5 + .../api/gui/resources/RenderUtil.java | 39 ++++++- .../api/gui/resources/TextureArea.java | 2 +- .../api/gui/resources/TextureItemStack.java | 27 +++++ .../api/gui/widgets/AbstractWidgetGroup.java | 4 +- .../terminal/gui/widgets/CircleButton.java | 107 +++++++++++++++++- .../terminal/gui/widgets/TerminalMenu.java | 48 ++++++++ .../behaviors/GuideTerminalBehaviour.java | 7 +- 10 files changed, 250 insertions(+), 15 deletions(-) create mode 100644 src/main/java/gregtech/api/gui/resources/IGuiTexture.java create mode 100644 src/main/java/gregtech/api/gui/resources/TextureItemStack.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/TerminalMenu.java diff --git a/src/main/java/gregtech/api/gui/Widget.java b/src/main/java/gregtech/api/gui/Widget.java index 0b4213fe7b9..b45a1fdaf28 100644 --- a/src/main/java/gregtech/api/gui/Widget.java +++ b/src/main/java/gregtech/api/gui/Widget.java @@ -152,12 +152,21 @@ public void drawInForeground(int mouseX, int mouseY) { } /** - * Called each draw tick to draw this widget in GUI + * Called each draw tick to draw this widget in GUI (@Deprecated) */ + @Deprecated @SideOnly(Side.CLIENT) public void drawInBackground(int mouseX, int mouseY, IRenderContext context) { } + /** + * Called each draw tick to draw this widget in GUI + */ + @SideOnly(Side.CLIENT) + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + drawInBackground(mouseX, mouseY, context); + } + /** * Called when mouse wheel is moved in GUI * For some -redacted- reason mouseX position is relative against GUI not game window as in other mouse events @@ -341,24 +350,35 @@ public static final class ClickData { public final int button; public final boolean isShiftClick; public final boolean isCtrlClick; + public final boolean isClient; public ClickData(int button, boolean isShiftClick, boolean isCtrlClick) { this.button = button; this.isShiftClick = isShiftClick; this.isCtrlClick = isCtrlClick; + this.isClient = false; + } + + public ClickData(int button, boolean isShiftClick, boolean isCtrlClick, boolean isClient) { + this.button = button; + this.isShiftClick = isShiftClick; + this.isCtrlClick = isCtrlClick; + this.isClient = isClient; } public void writeToBuf(PacketBuffer buf) { buf.writeVarInt(button); buf.writeBoolean(isShiftClick); buf.writeBoolean(isCtrlClick); + buf.writeBoolean(isClient); } public static ClickData readFromBuf(PacketBuffer buf) { int button = buf.readVarInt(); boolean shiftClick = buf.readBoolean(); boolean ctrlClick = buf.readBoolean(); - return new ClickData(button, shiftClick, ctrlClick); + boolean isClient = buf.readBoolean(); + return new ClickData(button, shiftClick, ctrlClick, isClient); } } diff --git a/src/main/java/gregtech/api/gui/impl/ModularUIGui.java b/src/main/java/gregtech/api/gui/impl/ModularUIGui.java index bc6c3508969..a081aaaa38f 100644 --- a/src/main/java/gregtech/api/gui/impl/ModularUIGui.java +++ b/src/main/java/gregtech/api/gui/impl/ModularUIGui.java @@ -216,7 +216,7 @@ protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, i modularUI.guiWidgets.values().forEach(widget -> { GlStateManager.pushMatrix(); GlStateManager.enableBlend(); - widget.drawInBackground(mouseX, mouseY, this); + widget.drawInBackground(mouseX, mouseY, partialTicks,this); GlStateManager.color(rColorForOverlay, gColorForOverlay, bColorForOverlay, 1.0F); GlStateManager.popMatrix(); }); diff --git a/src/main/java/gregtech/api/gui/resources/IGuiTexture.java b/src/main/java/gregtech/api/gui/resources/IGuiTexture.java new file mode 100644 index 00000000000..5bc5627a626 --- /dev/null +++ b/src/main/java/gregtech/api/gui/resources/IGuiTexture.java @@ -0,0 +1,5 @@ +package gregtech.api.gui.resources; + +public interface IGuiTexture { + void draw(double x, double y, int width, int height); +} diff --git a/src/main/java/gregtech/api/gui/resources/RenderUtil.java b/src/main/java/gregtech/api/gui/resources/RenderUtil.java index bf0ac9dbaf2..e0077eb716a 100644 --- a/src/main/java/gregtech/api/gui/resources/RenderUtil.java +++ b/src/main/java/gregtech/api/gui/resources/RenderUtil.java @@ -3,10 +3,12 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.RenderItem; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.texture.TextureMap; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.item.ItemStack; import net.minecraft.util.ResourceLocation; import net.minecraftforge.fluids.Fluid; import net.minecraftforge.fluids.FluidRegistry; @@ -106,6 +108,17 @@ private static void drawFluidTexture(double xCoord, double yCoord, TextureAtlasS tessellator.draw(); } + public static void renderItemOverLay(float x, float y, float z, float scale, ItemStack itemStack) { + net.minecraft.client.renderer.RenderHelper.enableStandardItemLighting(); + GlStateManager.pushMatrix(); + GlStateManager.scale(scale, scale, 0.0001f); + GlStateManager.translate(x * 16, y * 16, z * 16); + RenderItem renderItem = Minecraft.getMinecraft().getRenderItem(); + renderItem.renderItemAndEffectIntoGUI(itemStack, 0, 0 ); + GlStateManager.popMatrix(); + net.minecraft.client.renderer.RenderHelper.disableStandardItemLighting(); + } + public static void setColor(int color) { // ARGB GlStateManager.color((color >> 16 & 255) / 255.0F, (color >> 8 & 255) / 255.0F, @@ -113,7 +126,7 @@ public static void setColor(int color) { // ARGB (color >> 24 & 255) / 255.0F); } - public static void renderCircle(float x, float y, float r, int color, int detail) { + public static void renderCircle(float x, float y, float r, int color, int segments) { Tessellator tessellator = Tessellator.getInstance(); BufferBuilder bufferbuilder = tessellator.getBuffer(); GlStateManager.enableBlend(); @@ -121,8 +134,28 @@ public static void renderCircle(float x, float y, float r, int color, int detail GlStateManager.tryBlendFuncSeparate(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ZERO); setColor(color); bufferbuilder.begin(GL11.GL_POLYGON, DefaultVertexFormats.POSITION); - for (int i = 0; i < detail; i++) { - bufferbuilder.pos(x + r * Math.cos(-2 * Math.PI * i / detail), y + r * Math.sin(-2 * Math.PI * i / detail), 0.0D).endVertex(); + for (int i = 0; i < segments; i++) { + bufferbuilder.pos(x + r * Math.cos(-2 * Math.PI * i / segments), y + r * Math.sin(-2 * Math.PI * i / segments), 0.0D).endVertex(); + } + tessellator.draw(); + GlStateManager.enableTexture2D(); + GlStateManager.disableBlend(); + } + + public static void renderSector(float x, float y, float r, int color, int segments, int from, int to) { + if (from > to || from < 0) return; + if(to > segments) to = segments; + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder bufferbuilder = tessellator.getBuffer(); + GlStateManager.enableBlend(); + GlStateManager.disableTexture2D(); + GlStateManager.tryBlendFuncSeparate(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ZERO); + setColor(color); + bufferbuilder.begin(GL11.GL_TRIANGLES, DefaultVertexFormats.POSITION); + for (int i = from; i < to; i++) { + bufferbuilder.pos(x + r * Math.cos(-2 * Math.PI * i / segments), y + r * Math.sin(-2 * Math.PI * i / segments), 0.0D).endVertex(); + bufferbuilder.pos(x + r * Math.cos(-2 * Math.PI * (i + 1) / segments), y + r * Math.sin(-2 * Math.PI * (i + 1) / segments), 0.0D).endVertex(); + bufferbuilder.pos(x, y, 0.0D).endVertex(); } tessellator.draw(); GlStateManager.enableTexture2D(); diff --git a/src/main/java/gregtech/api/gui/resources/TextureArea.java b/src/main/java/gregtech/api/gui/resources/TextureArea.java index 4edfd4991b9..4fb6db081af 100644 --- a/src/main/java/gregtech/api/gui/resources/TextureArea.java +++ b/src/main/java/gregtech/api/gui/resources/TextureArea.java @@ -22,7 +22,7 @@ * This representation doesn't take image size in account, so all image variables are * 0.0 - 1.0 bounds */ -public class TextureArea { +public class TextureArea implements IGuiTexture { public final ResourceLocation imageLocation; diff --git a/src/main/java/gregtech/api/gui/resources/TextureItemStack.java b/src/main/java/gregtech/api/gui/resources/TextureItemStack.java new file mode 100644 index 00000000000..394be67cc4c --- /dev/null +++ b/src/main/java/gregtech/api/gui/resources/TextureItemStack.java @@ -0,0 +1,27 @@ +package gregtech.api.gui.resources; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.client.renderer.RenderItem; +import net.minecraft.item.ItemStack; + +public class TextureItemStack implements IGuiTexture{ + private ItemStack itemStack; + + public TextureItemStack(ItemStack itemStack) { + this.itemStack = itemStack; + } + + @Override + public void draw(double x, double y, int width, int height) { + RenderHelper.enableStandardItemLighting(); + GlStateManager.pushMatrix(); + GlStateManager.scale(width / 16f, height / 16f, 0.0001); + GlStateManager.translate(x * 16 / width, y * 16 / height, 0); + RenderItem renderItem = Minecraft.getMinecraft().getRenderItem(); + renderItem.renderItemAndEffectIntoGUI(itemStack, 0, 0); + GlStateManager.popMatrix(); + RenderHelper.disableStandardItemLighting(); + } +} diff --git a/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java b/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java index 9644b91401d..6552bfb23ab 100644 --- a/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java +++ b/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java @@ -236,10 +236,10 @@ public void drawInForeground(int mouseX, int mouseY) { } @Override - public void drawInBackground(int mouseX, int mouseY, IRenderContext context) { + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { for (Widget widget : widgets) { if (isWidgetVisible(widget)) { - widget.drawInBackground(mouseX, mouseY, context); + widget.drawInBackground(mouseX, mouseY, partialTicks, context); } } GlStateManager.color(rColorForOverlay, gColorForOverlay, bColorForOverlay, 1.0F); diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/CircleButton.java b/src/main/java/gregtech/api/terminal/gui/widgets/CircleButton.java index b8e34d99bf5..77bd34dcb9e 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/CircleButton.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/CircleButton.java @@ -2,25 +2,122 @@ import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.resources.RenderUtil; import gregtech.api.util.Position; import gregtech.api.util.Size; +import net.minecraft.client.resources.I18n; +import net.minecraft.item.ItemStack; +import net.minecraft.network.PacketBuffer; +import org.lwjgl.input.Mouse; + +import java.awt.*; +import java.util.Collections; +import java.util.function.Consumer; public class CircleButton extends Widget { - int x, y, r; + private int hoverTick; + private boolean isHover; + private String hoverText; + private IGuiTexture icon; + private Consumer onPressCallback; + private final int[] colors = { + new Color(146, 146, 146).getRGB(), + new Color(39, 232, 141).getRGB(), + new Color(255, 255, 255).getRGB(), + }; + public CircleButton(int x, int y, int r) { super(new Position(x - r, y - r), new Size(2 * r, 2 * r)); - this.r = r; + } + + public CircleButton setIcon(IGuiTexture icon) { + this.icon = icon; + return this; + } + + public CircleButton setHoverText(String hoverText) { + this.hoverText = hoverText; + return this; + } + + public CircleButton setColors(int stroke, int strokeAnima, int fill) { + colors[0] = stroke; + colors[1] = strokeAnima; + colors[2] = fill; + return this; + } + + public CircleButton setFillColors(int fill) { + colors[2] = fill; + return this; + } + + public CircleButton setClickListener(Consumer onPressed) { + this.onPressCallback = onPressed; + return this; } @Override - public void drawInBackground(int mouseX, int mouseY, IRenderContext context) { + public void updateScreen() { + if (isHover) { + if (hoverTick < 8) { + hoverTick += 1; + } + } else { + if (hoverTick > 0) { + hoverTick -= 1; + } + } + } + + @Override + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { int r = this.getSize().getHeight() / 2; int x = this.getPosition().x + r; int y = this.getPosition().y + r; + int segments = 24; + + RenderUtil.renderCircle(x, y, r, colors[0], segments); + isHover = this.isMouseOverElement(mouseX, mouseY); + if (isHover || hoverTick != 0) { + RenderUtil.renderSector(x, y, r, colors[1], segments, 0, (int) (segments * ((hoverTick + partialTicks) / 8))); + } + RenderUtil.renderCircle(x, y, r - 2, colors[2], segments); + if (icon != null) { + icon.draw(x - 8, y - 8, 16, 16); + } + } + + @Override + public void drawInForeground(int mouseX, int mouseY) { + if (this.isMouseOverElement(mouseX, mouseY)) { + this.drawHoveringText(ItemStack.EMPTY, Collections.singletonList(I18n.format(hoverText)), 300, mouseX, mouseY); + } + } - RenderUtil.renderCircle(x, y, r, 0xffff0000, 24); - RenderUtil.renderCircle(x, y, r - 2, 0xffffffff, 24); + @Override + public boolean mouseClicked(int mouseX, int mouseY, int button) { + if (isMouseOverElement(mouseX, mouseY)) { + ClickData clickData = new ClickData(Mouse.getEventButton(), isShiftDown(), isCtrlDown(), false); + writeClientAction(1, clickData::writeToBuf); + playButtonClickSound(); + if (onPressCallback != null) { + onPressCallback.accept(new ClickData(Mouse.getEventButton(), isShiftDown(), isCtrlDown(), true)); + } + return true; + } + return false; + } + @Override + public void handleClientAction(int id, PacketBuffer buffer) { + if (id == 1) { + ClickData clickData = ClickData.readFromBuf(buffer); + if (onPressCallback != null) { + onPressCallback.accept(clickData); + } + } } + } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/TerminalMenu.java b/src/main/java/gregtech/api/terminal/gui/widgets/TerminalMenu.java new file mode 100644 index 00000000000..0f0de4667a7 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/TerminalMenu.java @@ -0,0 +1,48 @@ +package gregtech.api.terminal.gui.widgets; + +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.widgets.AbstractWidgetGroup; +import gregtech.api.util.Position; +import gregtech.api.util.Size; + +import java.util.function.Supplier; + +public class TerminalMenu extends AbstractWidgetGroup { + private IGuiTexture background; + private Widget activeContent; + private CircleButton activeButton; + public TerminalMenu(int xPosition, int yPosition, int width, int height) { + super(new Position(xPosition, yPosition), new Size(width, height)); + } + + public TerminalMenu setBackGround(IGuiTexture background) { + this.background = background; + return this; + } + + public TerminalMenu addApp(IGuiTexture icon, String nameKey, Supplier content){ + CircleButton button = new CircleButton(27,40,12).setIcon(icon).setHoverText(nameKey); + button.setClickListener(clickData -> { + if (button != activeButton) { + removeWidget(activeContent); + if(content != null) { + activeContent = content.get(); + addWidget(activeContent); + } + activeButton.setFillColors(0xffffffff); + activeButton = button; + activeButton.setFillColors(0xFF929292); + } + }); + this.addWidget(button); + return this; + } + + @Override + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + background.draw(this.getPosition().x, this.getPosition().y, this.getSize().width, this.getSize().height); + super.drawInBackground(mouseX, mouseY, partialTicks, context); + } +} diff --git a/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java b/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java index 4b014eaec5a..bb3487c1f7a 100644 --- a/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java +++ b/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java @@ -2,11 +2,14 @@ import gregtech.api.gui.GuiTextures; import gregtech.api.gui.ModularUI; +import gregtech.api.gui.resources.TextureItemStack; import gregtech.api.items.gui.ItemUIFactory; import gregtech.api.items.gui.PlayerInventoryHolder; import gregtech.api.items.metaitem.stats.IItemBehaviour; import gregtech.api.terminal.gui.widgets.CircleButton; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Blocks; +import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.util.ActionResult; import net.minecraft.util.EnumActionResult; @@ -33,8 +36,10 @@ public void addInformation(ItemStack itemStack, List lines) { @Override public ModularUI createUI(PlayerInventoryHolder holder, EntityPlayer entityPlayer) { + CircleButton circleButton = new CircleButton(27, 40, 12) + .setIcon(new TextureItemStack(Item.getItemFromBlock(Blocks.CHEST).getDefaultInstance())); return ModularUI.builder(GuiTextures.TERMINAL_BACKGROUND, 380, 256) - .widget(new CircleButton(27, 40, 12)) + .widget(circleButton) .build(holder, entityPlayer); } } From c98ed551cfc975a4f8b04b9e6cec329231f6901d Mon Sep 17 00:00:00 2001 From: KilaBash Date: Thu, 29 Jul 2021 11:18:21 +0800 Subject: [PATCH 23/58] textbox image widgets --- src/main/java/gregtech/api/GregTechAPI.java | 6 + src/main/java/gregtech/api/gui/Widget.java | 38 +- .../gregtech/api/gui/impl/ModularUIGui.java | 2 + .../api/gui/resources/IGuiTexture.java | 1 + ...reItemStack.java => ItemStackTexture.java} | 9 +- .../api/gui/resources/RenderUtil.java | 55 ++ .../api/gui/resources/URLTexture.java | 77 ++ .../resources/onlinepic/DownloadThread.java | 260 +++++++ .../gui/resources/onlinepic/GifDecoder.java | 721 ++++++++++++++++++ .../onlinepic/ProcessedImageData.java | 137 ++++ .../gui/resources/onlinepic/TextureCache.java | 150 ++++ .../AnimatedPictureTexture.java | 66 ++ .../onlinepictexture/OrdinaryTexture.java | 23 + .../onlinepictexture/PictureTexture.java | 65 ++ .../onlinepictexture/VideoTexture.java | 19 + .../api/gui/widgets/AbstractWidgetGroup.java | 56 +- .../gregtech/api/gui/widgets/TabGroup.java | 1 - .../gregtech/api/gui/widgets/WidgetGroup.java | 10 + .../api/terminal/TerminalBuilder.java | 21 + .../api/terminal/app/AbstractApplication.java | 32 + .../api/terminal/app/guide/GuideApp.java | 114 +++ .../api/terminal/app/guide/ItemGuideApp.java | 34 + .../app/guide/MultiBlockGuideApp.java | 47 ++ .../app/guide/SimpleMachineGuideApp.java | 46 ++ .../terminal/app/guide/TutorialGuideApp.java | 46 ++ ...cleButton.java => CircleButtonWidget.java} | 14 +- .../terminal/gui/widgets/TerminalMenu.java | 48 -- .../gui/widgets/TerminalMenuWidget.java | 54 ++ .../gui/widgets/guide/GuidePageWidget.java | 83 ++ .../gui/widgets/guide/GuideWidget.java | 69 ++ .../gui/widgets/guide/IGuideWidget.java | 10 + .../gui/widgets/guide/ImageWidget.java | 61 ++ .../gui/widgets/guide/TextBoxWidget.java | 83 ++ .../gui/widgets/guide/TextTreeWidget.java | 150 ++++ .../gregtech/api/terminal/util/IContent.java | 4 + .../gregtech/api/terminal/util/TreeNode.java | 51 ++ .../java/gregtech/common/CommonProxy.java | 17 + .../behaviors/GuideTerminalBehaviour.java | 12 +- .../terminal/guide/items/default.json | 34 + .../terminal/guide/multiblocks/default.json | 24 + .../guide/simplemachines/default.json | 34 + .../guide/tutorials/api_0_guidepage.json | 36 + .../guide/tutorials/api_1_textbox.json | 265 +++++++ .../terminal/guide/tutorials/api_2_image.json | 80 ++ 44 files changed, 3072 insertions(+), 93 deletions(-) rename src/main/java/gregtech/api/gui/resources/{TextureItemStack.java => ItemStackTexture.java} (79%) create mode 100644 src/main/java/gregtech/api/gui/resources/URLTexture.java create mode 100644 src/main/java/gregtech/api/gui/resources/onlinepic/DownloadThread.java create mode 100644 src/main/java/gregtech/api/gui/resources/onlinepic/GifDecoder.java create mode 100644 src/main/java/gregtech/api/gui/resources/onlinepic/ProcessedImageData.java create mode 100644 src/main/java/gregtech/api/gui/resources/onlinepic/TextureCache.java create mode 100644 src/main/java/gregtech/api/gui/resources/onlinepictexture/AnimatedPictureTexture.java create mode 100644 src/main/java/gregtech/api/gui/resources/onlinepictexture/OrdinaryTexture.java create mode 100644 src/main/java/gregtech/api/gui/resources/onlinepictexture/PictureTexture.java create mode 100644 src/main/java/gregtech/api/gui/resources/onlinepictexture/VideoTexture.java create mode 100644 src/main/java/gregtech/api/terminal/app/AbstractApplication.java create mode 100644 src/main/java/gregtech/api/terminal/app/guide/GuideApp.java create mode 100644 src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java create mode 100644 src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java create mode 100644 src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java create mode 100644 src/main/java/gregtech/api/terminal/app/guide/TutorialGuideApp.java rename src/main/java/gregtech/api/terminal/gui/widgets/{CircleButton.java => CircleButtonWidget.java} (88%) delete mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/TerminalMenu.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/TerminalMenuWidget.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java create mode 100644 src/main/java/gregtech/api/terminal/util/IContent.java create mode 100644 src/main/java/gregtech/api/terminal/util/TreeNode.java create mode 100644 src/main/resources/assets/gregtech/terminal/guide/items/default.json create mode 100644 src/main/resources/assets/gregtech/terminal/guide/multiblocks/default.json create mode 100644 src/main/resources/assets/gregtech/terminal/guide/simplemachines/default.json create mode 100644 src/main/resources/assets/gregtech/terminal/guide/tutorials/api_0_guidepage.json create mode 100644 src/main/resources/assets/gregtech/terminal/guide/tutorials/api_1_textbox.json create mode 100644 src/main/resources/assets/gregtech/terminal/guide/tutorials/api_2_image.json diff --git a/src/main/java/gregtech/api/GregTechAPI.java b/src/main/java/gregtech/api/GregTechAPI.java index 0467fa1f05d..e376c035c18 100644 --- a/src/main/java/gregtech/api/GregTechAPI.java +++ b/src/main/java/gregtech/api/GregTechAPI.java @@ -2,6 +2,8 @@ import gregtech.api.block.machines.BlockMachine; import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.multiblock.MultiblockControllerBase; +import gregtech.api.terminal.app.guide.MultiBlockGuideApp; import gregtech.api.unification.OreDictUnifier; import gregtech.api.unification.material.Material; import gregtech.api.unification.material.Materials; @@ -11,6 +13,7 @@ import gregtech.api.util.GTControlledRegistry; import gregtech.api.util.IBlockOre; import gregtech.common.items.MetaItems; +import gregtech.common.metatileentities.electric.multiblockpart.MetaTileEntityMultiblockPart; import net.minecraft.util.ResourceLocation; import java.util.HashMap; @@ -32,6 +35,9 @@ public class GregTechAPI { public static T registerMetaTileEntity(int id, T sampleMetaTileEntity) { META_TILE_ENTITY_REGISTRY.register(id, sampleMetaTileEntity.metaTileEntityId, sampleMetaTileEntity); + if (sampleMetaTileEntity instanceof MultiblockControllerBase || sampleMetaTileEntity instanceof MetaTileEntityMultiblockPart) { + MultiBlockGuideApp.registerMultiBlock(sampleMetaTileEntity); + } return sampleMetaTileEntity; } diff --git a/src/main/java/gregtech/api/gui/Widget.java b/src/main/java/gregtech/api/gui/Widget.java index b45a1fdaf28..832cba2ef5d 100644 --- a/src/main/java/gregtech/api/gui/Widget.java +++ b/src/main/java/gregtech/api/gui/Widget.java @@ -37,13 +37,14 @@ */ public abstract class Widget { - protected ModularUI gui; - protected ISizeProvider sizes; - protected WidgetUIAccess uiAccess; - private Position parentPosition = Position.ORIGIN; - private Position selfPosition; - private Position position; - private Size size; + protected transient ModularUI gui; + protected transient ISizeProvider sizes; + protected transient WidgetUIAccess uiAccess; + private transient Position parentPosition = Position.ORIGIN; + private transient Position selfPosition; + private transient Position position; + private transient Size size; + private transient boolean isVisible; public Widget(Position selfPosition, Size size) { Preconditions.checkNotNull(selfPosition, "selfPosition"); @@ -51,6 +52,11 @@ public Widget(Position selfPosition, Size size) { this.selfPosition = selfPosition; this.size = size; this.position = this.parentPosition.add(selfPosition); + this.isVisible = true; + } + + public Widget(int x, int y, int width, int height) { + this(new Position(x, y), new Size(width, height)); } public void setGui(ModularUI gui) { @@ -91,6 +97,14 @@ public final Size getSize() { return size; } + public boolean isVisible() { + return isVisible; + } + + public void setVisible(boolean visible) { + isVisible = visible; + } + public Rectangle toRectangleBox() { Position pos = getPosition(); Size size = getSize(); @@ -112,7 +126,7 @@ protected void onSizeUpdate() { } public boolean isMouseOverElement(int mouseX, int mouseY, boolean correctPositionOnMouseWheelMoveEvent) { - mouseX = correctPositionOnMouseWheelMoveEvent ? mouseX + getPosition().x : mouseX; + mouseX = correctPositionOnMouseWheelMoveEvent ? mouseX + this.gui.getGuiLeft(): mouseX; return isMouseOverElement(mouseX, mouseY); } @@ -241,6 +255,14 @@ protected final void writeClientAction(int id, Consumer packetBuff } } + @SideOnly(Side.CLIENT) + protected void drawBorder(int x, int y, int width, int height, int stroke, int stroke_width) { + drawGradientRect(x - stroke_width, y - stroke_width, width + 2 * stroke_width, stroke_width, stroke, stroke); + drawGradientRect(x - stroke_width, y + height, width + 2 * stroke_width, stroke_width, stroke, stroke); + drawGradientRect(x - stroke_width, y - stroke_width, stroke_width, height + 2 * stroke_width, stroke, stroke); + drawGradientRect(x + width, y - stroke_width, stroke_width, height + 2 * stroke_width, stroke, stroke); + } + @SideOnly(Side.CLIENT) protected void drawHoveringText(ItemStack itemStack, List tooltip, int maxTextWidth, int mouseX, int mouseY) { Minecraft mc = Minecraft.getMinecraft(); diff --git a/src/main/java/gregtech/api/gui/impl/ModularUIGui.java b/src/main/java/gregtech/api/gui/impl/ModularUIGui.java index a081aaaa38f..575ef2aed9d 100644 --- a/src/main/java/gregtech/api/gui/impl/ModularUIGui.java +++ b/src/main/java/gregtech/api/gui/impl/ModularUIGui.java @@ -199,6 +199,7 @@ private void renderReturningItemStack() { @Override protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { modularUI.guiWidgets.values().forEach(widget -> { + if (!widget.isVisible()) return; GlStateManager.pushMatrix(); GlStateManager.color(1.0f, 1.0f, 1.0f); widget.drawInForeground(mouseX, mouseY); @@ -214,6 +215,7 @@ protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, i GlStateManager.popMatrix(); modularUI.backgroundPath.draw(guiLeft, guiTop, xSize, ySize); modularUI.guiWidgets.values().forEach(widget -> { + if (!widget.isVisible()) return; GlStateManager.pushMatrix(); GlStateManager.enableBlend(); widget.drawInBackground(mouseX, mouseY, partialTicks,this); diff --git a/src/main/java/gregtech/api/gui/resources/IGuiTexture.java b/src/main/java/gregtech/api/gui/resources/IGuiTexture.java index 5bc5627a626..ee40a3b2004 100644 --- a/src/main/java/gregtech/api/gui/resources/IGuiTexture.java +++ b/src/main/java/gregtech/api/gui/resources/IGuiTexture.java @@ -2,4 +2,5 @@ public interface IGuiTexture { void draw(double x, double y, int width, int height); + default void updateTick() { } } diff --git a/src/main/java/gregtech/api/gui/resources/TextureItemStack.java b/src/main/java/gregtech/api/gui/resources/ItemStackTexture.java similarity index 79% rename from src/main/java/gregtech/api/gui/resources/TextureItemStack.java rename to src/main/java/gregtech/api/gui/resources/ItemStackTexture.java index 394be67cc4c..1bcdc7a461d 100644 --- a/src/main/java/gregtech/api/gui/resources/TextureItemStack.java +++ b/src/main/java/gregtech/api/gui/resources/ItemStackTexture.java @@ -4,15 +4,20 @@ import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.RenderHelper; import net.minecraft.client.renderer.RenderItem; +import net.minecraft.item.Item; import net.minecraft.item.ItemStack; -public class TextureItemStack implements IGuiTexture{ +public class ItemStackTexture implements IGuiTexture{ private ItemStack itemStack; - public TextureItemStack(ItemStack itemStack) { + public ItemStackTexture(ItemStack itemStack) { this.itemStack = itemStack; } + public ItemStackTexture(Item item) { + this.itemStack = new ItemStack(item); + } + @Override public void draw(double x, double y, int width, int height) { RenderHelper.enableStandardItemLighting(); diff --git a/src/main/java/gregtech/api/gui/resources/RenderUtil.java b/src/main/java/gregtech/api/gui/resources/RenderUtil.java index e0077eb716a..b0dce74f99b 100644 --- a/src/main/java/gregtech/api/gui/resources/RenderUtil.java +++ b/src/main/java/gregtech/api/gui/resources/RenderUtil.java @@ -162,4 +162,59 @@ public static void renderSector(float x, float y, float r, int color, int segmen GlStateManager.disableBlend(); } + public static void renderRect(float x, float y, float width, float height, float z, int color) { + renderGradientRect(x, y, width, height, z, color, color, false); + } + + public static void renderGradientRect(float x, float y, float width, float height, float z, int startColor, int endColor, boolean horizontal) { + float startAlpha = (float) (startColor >> 24 & 255) / 255.0F; + float startRed = (float) (startColor >> 16 & 255) / 255.0F; + float startGreen = (float) (startColor >> 8 & 255) / 255.0F; + float startBlue = (float) (startColor & 255) / 255.0F; + float endAlpha = (float) (endColor >> 24 & 255) / 255.0F; + float endRed = (float) (endColor >> 16 & 255) / 255.0F; + float endGreen = (float) (endColor >> 8 & 255) / 255.0F; + float endBlue = (float) (endColor & 255) / 255.0F; + GlStateManager.disableTexture2D(); + GlStateManager.enableBlend(); + GlStateManager.disableAlpha(); + GlStateManager.tryBlendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO); + GlStateManager.shadeModel(GL11.GL_SMOOTH); + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder buffer = tessellator.getBuffer(); + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR); + if (horizontal) { + buffer.pos(x + width, y, z).color(endRed, endGreen, endBlue, endAlpha).endVertex(); + buffer.pos(x, y, z).color(startRed, startGreen, startBlue, startAlpha).endVertex(); + buffer.pos(x, y + height, z).color(startRed, startGreen, startBlue, startAlpha).endVertex(); + buffer.pos(x + width, y + height, z).color(endRed, endGreen, endBlue, endAlpha).endVertex(); + tessellator.draw(); + } else { + buffer.pos(x + width, y, z).color(startRed, startGreen, startBlue, startAlpha).endVertex(); + buffer.pos(x, y, z).color(startRed, startGreen, startBlue, startAlpha).endVertex(); + buffer.pos(x, y + height, z).color(endRed, endGreen, endBlue, endAlpha).endVertex(); + buffer.pos(x + width, y + height, z).color(endRed, endGreen, endBlue, endAlpha).endVertex(); + tessellator.draw(); + } + GlStateManager.shadeModel(GL11.GL_FLAT); + GlStateManager.disableBlend(); + GlStateManager.enableAlpha(); + GlStateManager.enableTexture2D(); + } + + public static void renderTextureArea(TextureArea textureArea, float x, float y, float width, float height, float z) { + double imageU = textureArea.offsetX; + double imageV = textureArea.offsetY; + double imageWidth = textureArea.imageWidth; + double imageHeight = textureArea.imageHeight; + Minecraft.getMinecraft().renderEngine.bindTexture(textureArea.imageLocation); + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder bufferbuilder = tessellator.getBuffer(); + bufferbuilder.begin(7, DefaultVertexFormats.POSITION_TEX); + bufferbuilder.pos(x, y + height, z).tex(imageU, imageV + imageHeight).endVertex(); + bufferbuilder.pos(x + width, y + height, z).tex(imageU + imageWidth, imageV + imageHeight).endVertex(); + bufferbuilder.pos(x + width, y, z).tex(imageU + imageWidth, imageV).endVertex(); + bufferbuilder.pos(x, y, z).tex(imageU, imageV).endVertex(); + tessellator.draw(); + } } diff --git a/src/main/java/gregtech/api/gui/resources/URLTexture.java b/src/main/java/gregtech/api/gui/resources/URLTexture.java new file mode 100644 index 00000000000..7f2fd4679d1 --- /dev/null +++ b/src/main/java/gregtech/api/gui/resources/URLTexture.java @@ -0,0 +1,77 @@ +package gregtech.api.gui.resources; + +import gregtech.api.gui.resources.onlinepic.DownloadThread; +import gregtech.api.gui.resources.onlinepictexture.PictureTexture; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +public class URLTexture implements IGuiTexture{ + private final String url; + @SideOnly(Side.CLIENT) + private DownloadThread downloader; + @SideOnly(Side.CLIENT) + private PictureTexture texture; + @SideOnly(Side.CLIENT) + private boolean failed; + @SideOnly(Side.CLIENT) + private String error; + + + public URLTexture(String url) { + this.url = url; + } + + @SideOnly(Side.CLIENT) + @Override + public void updateTick() { + if(this.texture != null) { + texture.tick(); // gif\video update + } + } + + @Override + public void draw(double x, double y, int width, int height) { + if (url != null &&!this.url.equals("")) { + if (texture != null && texture.hasTexture()) { + texture.render((float)x, (float)y, width, height, 0, 1, 1, false, false); + } else { + this.loadTexture(); + if (failed) { + + } else { + + } + } + } + } + + @SideOnly(Side.CLIENT) + public void loadTexture() { + if (texture == null && !failed) { + if (downloader == null && DownloadThread.activeDownloads < DownloadThread.MAXIMUM_ACTIVE_DOWNLOADS) { + PictureTexture loadedTexture = DownloadThread.loadedImages.get(url); + + if (loadedTexture == null) { + synchronized (DownloadThread.LOCK) { + if (!DownloadThread.loadingImages.contains(url)) { + downloader = new DownloadThread(url); + return; + } + } + } else { + texture = loadedTexture; + } + } + if (downloader != null && downloader.hasFinished()) { + if (downloader.hasFailed()) { + failed = true; + error = downloader.getError(); + DownloadThread.LOGGER.error("Could not load image of " + url + " : " + error); + } else { + texture = DownloadThread.loadImage(downloader); + } + downloader = null; + } + } + } +} diff --git a/src/main/java/gregtech/api/gui/resources/onlinepic/DownloadThread.java b/src/main/java/gregtech/api/gui/resources/onlinepic/DownloadThread.java new file mode 100644 index 00000000000..fb344586ed2 --- /dev/null +++ b/src/main/java/gregtech/api/gui/resources/onlinepic/DownloadThread.java @@ -0,0 +1,260 @@ +package gregtech.api.gui.resources.onlinepic; + +import gregtech.GregTechMod; +import gregtech.api.gui.resources.onlinepictexture.AnimatedPictureTexture; +import gregtech.api.gui.resources.onlinepictexture.OrdinaryTexture; +import gregtech.api.gui.resources.onlinepictexture.PictureTexture; +import gregtech.api.gui.resources.onlinepictexture.VideoTexture; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import org.apache.commons.compress.utils.IOUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import javax.imageio.ImageIO; +import javax.imageio.ImageReadParam; +import javax.imageio.ImageReader; +import javax.imageio.stream.ImageInputStream; +import java.awt.image.BufferedImage; +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLConnection; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.*; + +@SideOnly(Side.CLIENT) +public class DownloadThread extends Thread { + public static final Logger LOGGER = LogManager.getLogger(GregTechMod.class); + + public static final TextureCache TEXTURE_CACHE = new TextureCache(); + public static final DateFormat FORMAT = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z"); + public static final Object LOCK = new Object(); + public static final int MAXIMUM_ACTIVE_DOWNLOADS = 5; + + public static int activeDownloads = 0; + + public static HashMap loadedImages = new HashMap<>(); + public static Set loadingImages = new HashSet<>(); + + private final String url; + + private ProcessedImageData processedImage; + private String error; + private boolean complete; + private boolean isVideo; + + public DownloadThread(String url) { + this.url = url; + synchronized (DownloadThread.LOCK) { + DownloadThread.loadingImages.add(url); + DownloadThread.activeDownloads++; + } + setName("OPF Download \"" + url + "\""); + setDaemon(true); + start(); + } + + public boolean hasFinished() { + return complete; + } + + public boolean hasFailed() { + return hasFinished() && error != null; + } + + public boolean isVideo() { + return isVideo; + } + + public String getError() { + return error; + } + + @Override + public void run() { + Exception exception = null; + try { + byte[] data = load(url); + String type = readType(data); + ByteArrayInputStream in = null; + try { + in = new ByteArrayInputStream(data); + if (type.equalsIgnoreCase("gif")) { + GifDecoder gif = new GifDecoder(); + int status = gif.read(in); + if (status == GifDecoder.STATUS_OK) { + processedImage = new ProcessedImageData(gif); + } else { + LOGGER.error("Failed to read gif: {}", status); + } + } else { + try { + BufferedImage image = ImageIO.read(in); + if (image != null) { + processedImage = new ProcessedImageData(image); + } + } catch (IOException e1) { + exception = e1; + LOGGER.error("Failed to parse BufferedImage from stream", e1); + } + } + } finally { + IOUtils.closeQuietly(in); + } + } catch (FoundVideoException e) { + isVideo = true; + } catch (Exception e) { + exception = e; + LOGGER.error("An exception occurred while loading OPFrame image", e); + } + if (!isVideo && processedImage == null) { + if (exception == null) + error = "download.exception.gif"; + else if (exception.getMessage() == null) + error = "download.exception.invalid"; + else if (exception.getMessage().startsWith("Server returned HTTP response code: 403")) + error = "download.exception.forbidden"; + else if (exception.getMessage().startsWith("Server returned HTTP response code: 404")) + error = "download.exception.notfound"; + else + error = "download.exception.invalid"; + TEXTURE_CACHE.deleteEntry(url); + } + complete = true; + + synchronized (DownloadThread.LOCK) { + DownloadThread.loadingImages.remove(url); + DownloadThread.activeDownloads--; + } + } + + public static byte[] load(String url) throws IOException, FoundVideoException { + TextureCache.CacheEntry entry = TEXTURE_CACHE.getEntry(url); + long requestTime = System.currentTimeMillis(); + URLConnection connection = new URL(url).openConnection(); + connection.addRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:25.0) Gecko/20100101 Firefox/25.0"); + int responseCode = -1; + if (connection instanceof HttpURLConnection) { + HttpURLConnection httpConnection = (HttpURLConnection) connection; + if (entry != null) { + if (entry.getEtag() != null) { + httpConnection.setRequestProperty("If-None-Match", entry.getEtag()); + } else if (entry.getTime() != -1) { + httpConnection.setRequestProperty("If-Modified-Since", FORMAT.format(new Date(entry.getTime()))); + } + } + responseCode = httpConnection.getResponseCode(); + } + InputStream in = null; + try { + in = connection.getInputStream(); + if (!connection.getContentType().startsWith("image")) + throw new FoundVideoException(); + String etag = connection.getHeaderField("ETag"); + long lastModifiedTimestamp; + long expireTimestamp = -1; + String maxAge = connection.getHeaderField("max-age"); + if (maxAge != null && !maxAge.isEmpty()) { + try { + expireTimestamp = requestTime + Long.parseLong(maxAge) * 1000; + } catch (NumberFormatException ignored) {} + } + String expires = connection.getHeaderField("Expires"); + if (expires != null && !expires.isEmpty()) { + try { + expireTimestamp = FORMAT.parse(expires).getTime(); + } catch (ParseException ignored) {} + } + String lastModified = connection.getHeaderField("Last-Modified"); + if (lastModified != null && !lastModified.isEmpty()) { + try { + lastModifiedTimestamp = FORMAT.parse(lastModified).getTime(); + } catch (ParseException e) { + lastModifiedTimestamp = requestTime; + } + } else { + lastModifiedTimestamp = requestTime; + } + if (entry != null) { + if (etag != null && !etag.isEmpty()) { + entry.setEtag(etag); + } + entry.setTime(lastModifiedTimestamp); + if (responseCode == HttpURLConnection.HTTP_NOT_MODIFIED) { + File file = entry.getFile(); + if (file.exists()) { + try (FileInputStream fileStream = new FileInputStream(file)) { + return IOUtils.toByteArray(fileStream); + } + + } + } + } + byte[] data = IOUtils.toByteArray(in); + TEXTURE_CACHE.save(url, etag, lastModifiedTimestamp, expireTimestamp, data); + return data; + } finally { + IOUtils.closeQuietly(in); + } + } + + private static String readType(byte[] input) throws IOException { + InputStream in = null; + try { + in = new ByteArrayInputStream(input); + return readType(in); + } finally { + IOUtils.closeQuietly(in); + } + } + + private static String readType(InputStream input) throws IOException { + ImageInputStream stream = ImageIO.createImageInputStream(input); + Iterator iter = ImageIO.getImageReaders(stream); + if (!iter.hasNext()) { + return ""; + } + ImageReader reader = iter.next(); + + if (reader.getFormatName().equalsIgnoreCase("gif")) + return "gif"; + + ImageReadParam param = reader.getDefaultReadParam(); + reader.setInput(stream, true, true); + try { + reader.read(0, param); + } catch (IOException e) { + LOGGER.error("Failed to parse input format", e); + } finally { + reader.dispose(); + IOUtils.closeQuietly(stream); + } + input.reset(); + return reader.getFormatName(); + } + + public static PictureTexture loadImage(DownloadThread thread) { + PictureTexture texture = null; + + if (!thread.hasFailed()) { + if (thread.isVideo()) + texture = new VideoTexture(thread.url); + else if (thread.processedImage.isAnimated()) + texture = new AnimatedPictureTexture(thread.processedImage); + else + texture = new OrdinaryTexture(thread.processedImage); + } + if (texture != null) + synchronized (LOCK) { + loadedImages.put(thread.url, texture); + } + return texture; + } + + public static class FoundVideoException extends Exception { + + } +} diff --git a/src/main/java/gregtech/api/gui/resources/onlinepic/GifDecoder.java b/src/main/java/gregtech/api/gui/resources/onlinepic/GifDecoder.java new file mode 100644 index 00000000000..425953dab42 --- /dev/null +++ b/src/main/java/gregtech/api/gui/resources/onlinepic/GifDecoder.java @@ -0,0 +1,721 @@ +package gregtech.api.gui.resources.onlinepic; + +import java.awt.*; +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferInt; +import java.io.BufferedInputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.ArrayList; + +/** Class GifDecoder - Decodes a GIF file into one or more frames. + * + * Example: + * + *

+ * {
+ *     @code
+ *     GifDecoder d = new GifDecoder();
+ *     d.read("sample.gif");
+ *     int n = d.getFrameCount();
+ *     for (int i = 0; i < n; i++) {
+ *         BufferedImage frame = d.getFrame(i); // frame i
+ *         int t = d.getDelay(i); // display duration of frame in milliseconds
+ *         // do something with frame
+ *     }
+ * }
+ * 
+ * + * No copyright asserted on the source code of this class. May be used for + * any purpose, however, refer to the Unisys LZW patent for any additional + * restrictions. Please forward any corrections to questions at fmsware.com. + * + * @author Kevin Weiner, FM Software; LZW decoder adapted from John Cristy's ImageMagick. + * @version 1.03 November 2003 */ + +public class GifDecoder { + + /** File read status: No errors. */ + public static final int STATUS_OK = 0; + + /** File read status: Error decoding file (may be partially decoded) */ + public static final int STATUS_FORMAT_ERROR = 1; + + /** File read status: Unable to open source. */ + public static final int STATUS_OPEN_ERROR = 2; + + protected BufferedInputStream in; + protected int status; + + protected int width; // full image width + protected int height; // full image height + protected boolean gctFlag; // global color table used + protected int gctSize; // size of global color table + protected int loopCount = 1; // iterations; 0 = repeat forever + + protected int[] gct; // global color table + protected int[] lct; // local color table + protected int[] act; // active color table + + protected int bgIndex; // background color index + protected int bgColor; // background color + protected int lastBgColor; // previous bg color + protected int pixelAspect; // pixel aspect ratio + + protected boolean lctFlag; // local color table flag + protected boolean interlace; // interlace flag + protected int lctSize; // local color table size + + protected int ix, iy, iw, ih; // current image rectangle + protected Rectangle lastRect; // last image rect + protected BufferedImage image; // current frame + protected BufferedImage lastImage; // previous frame + + protected byte[] block = new byte[256]; // current data block + protected int blockSize = 0; // block size + + // last graphic control extension info + protected int dispose = 0; + // 0=no action; 1=leave in place; 2=restore to bg; 3=restore to prev + protected int lastDispose = 0; + protected boolean transparency = false; // use transparent color + protected int delay = 0; // delay in milliseconds + protected int transIndex; // transparent color index + + protected static final int MaxStackSize = 4096; + // max decoder pixel stack size + + // LZW decoder working arrays + protected short[] prefix; + protected byte[] suffix; + protected byte[] pixelStack; + protected byte[] pixels; + + protected ArrayList frames; // frames read from current file + protected int frameCount; + + static class GifFrame { + public GifFrame(BufferedImage im, int del) { + image = im; + delay = del; + } + + public BufferedImage image; + public int delay; + } + + /** Gets display duration for specified frame. + * + * @param n + * int index of frame + * @return delay in milliseconds */ + public int getDelay(int n) { + // + delay = -1; + if ((n >= 0) && (n < frameCount)) { + delay = ((GifFrame) frames.get(n)).delay; + } + return delay; + } + + /** Gets the number of frames read from file. + * + * @return frame count */ + public int getFrameCount() { + return frameCount; + } + + /** Gets the first (or only) image read. + * + * @return BufferedImage containing first frame, or null if none. */ + public BufferedImage getImage() { + return getFrame(0); + } + + /** Gets the "Netscape" iteration count, if any. + * A count of 0 means repeat indefinitiely. + * + * @return iteration count if one was specified, else 1. */ + public int getLoopCount() { + return loopCount; + } + + /** Creates new frame image from current data (and previous + * frames as specified by their disposition codes). */ + protected void setPixels() { + // expose destination image's pixels as int array + int[] dest = ((DataBufferInt) image.getRaster().getDataBuffer()).getData(); + + // fill in starting image contents based on last image's dispose code + if (lastDispose > 0) { + if (lastDispose == 3) { + // use image before last + int n = frameCount - 2; + if (n > 0) { + lastImage = getFrame(n - 1); + } else { + lastImage = null; + } + } + + if (lastImage != null) { + int[] prev = ((DataBufferInt) lastImage.getRaster().getDataBuffer()).getData(); + System.arraycopy(prev, 0, dest, 0, width * height); + // copy pixels + + if (lastDispose == 2) { + // fill last image rect area with background color + Graphics2D g = image.createGraphics(); + Color c = null; + if (transparency) { + c = new Color(0, 0, 0, 0); // assume background is transparent + } else { + c = new Color(lastBgColor); // use given background color + } + g.setColor(c); + g.setComposite(AlphaComposite.Src); // replace area + g.fill(lastRect); + g.dispose(); + } + } + } + + // copy each source line to the appropriate place in the destination + int pass = 1; + int inc = 8; + int iline = 0; + for (int i = 0; i < ih; i++) { + int line = i; + if (interlace) { + if (iline >= ih) { + pass++; + switch (pass) { + case 2: + iline = 4; + break; + case 3: + iline = 2; + inc = 4; + break; + case 4: + iline = 1; + inc = 2; + } + } + line = iline; + iline += inc; + } + line += iy; + if (line < height) { + int k = line * width; + int dx = k + ix; // start of line in dest + int dlim = dx + iw; // end of dest line + if ((k + width) < dlim) { + dlim = k + width; // past dest edge + } + int sx = i * iw; // start of line in source + while (dx < dlim) { + // map color and insert in destination + int index = (pixels[sx++]) & 0xff; + int c = act[index]; + if (c != 0) { + dest[dx] = c; + } + dx++; + } + } + } + } + + /** Gets the image contents of frame n. + * + * @return BufferedImage representation of frame, or null if n is invalid. */ + public BufferedImage getFrame(int n) { + BufferedImage im = null; + if ((n >= 0) && (n < frameCount)) { + im = ((GifFrame) frames.get(n)).image; + } + return im; + } + + /** Gets image size. + * + * @return GIF image dimensions */ + public Dimension getFrameSize() { + return new Dimension(width, height); + } + + /** Reads GIF image from stream + * + * @param is + * BufferedInputStream containing GIF file. + * @return read status code (0 = no errors) */ + public int read(BufferedInputStream is) { + init(); + if (is != null) { + in = is; + readHeader(); + if (!err()) { + readContents(); + if (frameCount < 0) { + status = STATUS_FORMAT_ERROR; + } + } + } else { + status = STATUS_OPEN_ERROR; + } + try { + is.close(); + } catch (IOException e) { + } + return status; + } + + /** Reads GIF image from stream + * + * @param is + * InputStream containing GIF file. + * @return read status code (0 = no errors) */ + public int read(InputStream is) { + init(); + if (is != null) { + if (!(is instanceof BufferedInputStream)) + is = new BufferedInputStream(is); + in = (BufferedInputStream) is; + readHeader(); + if (!err()) { + readContents(); + if (frameCount < 0) { + status = STATUS_FORMAT_ERROR; + } + } + } else { + status = STATUS_OPEN_ERROR; + } + try { + is.close(); + } catch (IOException e) { + } + return status; + } + + /** Reads GIF file from specified file/URL source + * (URL assumed if name contains ":/" or "file:") + * + * @param name + * String containing source + * @return read status code (0 = no errors) */ + public int read(String name) { + status = STATUS_OK; + try { + name = name.trim().toLowerCase(); + if ((name.indexOf("file:") >= 0) || (name.indexOf(":/") > 0)) { + URL url = new URL(name); + in = new BufferedInputStream(url.openStream()); + } else { + in = new BufferedInputStream(new FileInputStream(name)); + } + status = read(in); + } catch (IOException e) { + status = STATUS_OPEN_ERROR; + } + + return status; + } + + /** Decodes LZW image data into pixel array. + * Adapted from John Cristy's ImageMagick. */ + protected void decodeImageData() { + int NullCode = -1; + int npix = iw * ih; + int available, clear, code_mask, code_size, end_of_information, in_code, old_code, bits, code, count, i, datum, + data_size, first, top, bi, pi; + + if ((pixels == null) || (pixels.length < npix)) { + pixels = new byte[npix]; // allocate new pixel array + } + if (prefix == null) + prefix = new short[MaxStackSize]; + if (suffix == null) + suffix = new byte[MaxStackSize]; + if (pixelStack == null) + pixelStack = new byte[MaxStackSize + 1]; + + // Initialize GIF data stream decoder. + + data_size = read(); + clear = 1 << data_size; + end_of_information = clear + 1; + available = clear + 2; + old_code = NullCode; + code_size = data_size + 1; + code_mask = (1 << code_size) - 1; + for (code = 0; code < clear; code++) { + prefix[code] = 0; + suffix[code] = (byte) code; + } + + // Decode GIF pixel stream. + + datum = bits = count = first = top = pi = bi = 0; + + for (i = 0; i < npix;) { + if (top == 0) { + if (bits < code_size) { + // Load bytes until there are enough bits for a code. + if (count == 0) { + // Read a new data block. + count = readBlock(); + if (count <= 0) + break; + bi = 0; + } + datum += ((block[bi]) & 0xff) << bits; + bits += 8; + bi++; + count--; + continue; + } + + // Get the next code. + + code = datum & code_mask; + datum >>= code_size; + bits -= code_size; + + // Interpret the code + + if ((code > available) || (code == end_of_information)) + break; + if (code == clear) { + // Reset decoder. + code_size = data_size + 1; + code_mask = (1 << code_size) - 1; + available = clear + 2; + old_code = NullCode; + continue; + } + if (old_code == NullCode) { + pixelStack[top++] = suffix[code]; + old_code = code; + first = code; + continue; + } + in_code = code; + if (code == available) { + pixelStack[top++] = (byte) first; + code = old_code; + } + while (code > clear) { + pixelStack[top++] = suffix[code]; + code = prefix[code]; + } + first = (suffix[code]) & 0xff; + + // Add a new string to the string table, + + if (available >= MaxStackSize) { + pixelStack[top++] = (byte) first; + continue; + } + pixelStack[top++] = (byte) first; + prefix[available] = (short) old_code; + suffix[available] = (byte) first; + available++; + if (((available & code_mask) == 0) && (available < MaxStackSize)) { + code_size++; + code_mask += available; + } + old_code = in_code; + } + + // Pop a pixel off the pixel stack. + + top--; + pixels[pi++] = pixelStack[top]; + i++; + } + + for (i = pi; i < npix; i++) { + pixels[i] = 0; // clear missing pixels + } + + } + + /** Returns true if an error was encountered during reading/decoding */ + protected boolean err() { + return status != STATUS_OK; + } + + /** Initializes or re-initializes reader */ + protected void init() { + status = STATUS_OK; + frameCount = 0; + frames = new ArrayList(); + gct = null; + lct = null; + } + + /** Reads a single byte from the input stream. */ + protected int read() { + int curByte = 0; + try { + curByte = in.read(); + } catch (IOException e) { + status = STATUS_FORMAT_ERROR; + } + return curByte; + } + + /** Reads next variable length block from input. + * + * @return number of bytes stored in "buffer" */ + protected int readBlock() { + blockSize = read(); + int n = 0; + if (blockSize > 0) { + try { + int count = 0; + while (n < blockSize) { + count = in.read(block, n, blockSize - n); + if (count == -1) + break; + n += count; + } + } catch (IOException e) { + } + + if (n < blockSize) { + status = STATUS_FORMAT_ERROR; + } + } + return n; + } + + /** Reads color table as 256 RGB integer values + * + * @param ncolors + * int number of colors to read + * @return int array containing 256 colors (packed ARGB with full alpha) */ + protected int[] readColorTable(int ncolors) { + int nbytes = 3 * ncolors; + int[] tab = null; + byte[] c = new byte[nbytes]; + int n = 0; + try { + n = in.read(c); + } catch (IOException e) { + } + if (n < nbytes) { + status = STATUS_FORMAT_ERROR; + } else { + tab = new int[256]; // max size to avoid bounds checks + int i = 0; + int j = 0; + while (i < ncolors) { + int r = (c[j++]) & 0xff; + int g = (c[j++]) & 0xff; + int b = (c[j++]) & 0xff; + tab[i++] = 0xff000000 | (r << 16) | (g << 8) | b; + } + } + return tab; + } + + /** Main file parser. Reads GIF content blocks. */ + protected void readContents() { + // read GIF file content blocks + boolean done = false; + while (!(done || err())) { + int code = read(); + switch (code) { + + case 0x2C: // image separator + readImage(); + break; + + case 0x21: // extension + code = read(); + switch (code) { + case 0xf9: // graphics control extension + readGraphicControlExt(); + break; + + case 0xff: // application extension + readBlock(); + String app = ""; + for (int i = 0; i < 11; i++) { + app += (char) block[i]; + } + if (app.equals("NETSCAPE2.0")) { + readNetscapeExt(); + } else + skip(); // don't care + break; + + default: // uninteresting extension + skip(); + } + break; + + case 0x3b: // terminator + done = true; + break; + + case 0x00: // bad byte, but keep going and see what happens + break; + + default: + status = STATUS_FORMAT_ERROR; + } + } + } + + /** Reads Graphics Control Extension values */ + protected void readGraphicControlExt() { + read(); // block size + int packed = read(); // packed fields + dispose = (packed & 0x1c) >> 2; // disposal method + if (dispose == 0) { + dispose = 1; // elect to keep old image if discretionary + } + transparency = (packed & 1) != 0; + delay = readShort() * 10; // delay in milliseconds + transIndex = read(); // transparent color index + read(); // block terminator + } + + /** Reads GIF file header information. */ + protected void readHeader() { + String id = ""; + for (int i = 0; i < 6; i++) { + id += (char) read(); + } + if (!id.startsWith("GIF")) { + status = STATUS_FORMAT_ERROR; + return; + } + + readLSD(); + if (gctFlag && !err()) { + gct = readColorTable(gctSize); + bgColor = gct[bgIndex]; + } + } + + /** Reads next frame image */ + protected void readImage() { + ix = readShort(); // (sub)image position & size + iy = readShort(); + iw = readShort(); + ih = readShort(); + + int packed = read(); + lctFlag = (packed & 0x80) != 0; // 1 - local color table flag + interlace = (packed & 0x40) != 0; // 2 - interlace flag + // 3 - sort flag + // 4-5 - reserved + lctSize = 2 << (packed & 7); // 6-8 - local color table size + + if (lctFlag) { + lct = readColorTable(lctSize); // read table + act = lct; // make local table active + } else { + act = gct; // make global table active + if (bgIndex == transIndex) + bgColor = 0; + } + int save = 0; + if (transparency) { + save = act[transIndex]; + act[transIndex] = 0; // set transparent color if specified + } + + if (act == null) { + status = STATUS_FORMAT_ERROR; // no color table defined + } + + if (err()) + return; + + decodeImageData(); // decode pixel data + skip(); + + if (err()) + return; + + frameCount++; + + // create new image to receive frame data + image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB_PRE); + + setPixels(); // transfer pixel data to image + + frames.add(new GifFrame(image, delay)); // add image to frame list + + if (transparency) { + act[transIndex] = save; + } + resetFrame(); + + } + + /** Reads Logical Screen Descriptor */ + protected void readLSD() { + + // logical screen size + width = readShort(); + height = readShort(); + + // packed fields + int packed = read(); + gctFlag = (packed & 0x80) != 0; // 1 : global color table flag + // 2-4 : color resolution + // 5 : gct sort flag + gctSize = 2 << (packed & 7); // 6-8 : gct size + + bgIndex = read(); // background color index + pixelAspect = read(); // pixel aspect ratio + } + + /** Reads Netscape extenstion to obtain iteration count */ + protected void readNetscapeExt() { + do { + readBlock(); + if (block[0] == 1) { + // loop count sub-block + int b1 = (block[1]) & 0xff; + int b2 = (block[2]) & 0xff; + loopCount = (b2 << 8) | b1; + } + } while ((blockSize > 0) && !err()); + } + + /** Reads next 16-bit value, LSB first */ + protected int readShort() { + // read 16-bit value, LSB first + return read() | (read() << 8); + } + + /** Resets frame state for reading next image. */ + protected void resetFrame() { + lastDispose = dispose; + lastRect = new Rectangle(ix, iy, iw, ih); + lastImage = image; + lastBgColor = bgColor; + int dispose = 0; + boolean transparency = false; + int delay = 0; + lct = null; + } + + /** Skips variable length blocks up to and including + * next zero length block. */ + protected void skip() { + do { + readBlock(); + } while ((blockSize > 0) && !err()); + } +} diff --git a/src/main/java/gregtech/api/gui/resources/onlinepic/ProcessedImageData.java b/src/main/java/gregtech/api/gui/resources/onlinepic/ProcessedImageData.java new file mode 100644 index 00000000000..794c2f28afe --- /dev/null +++ b/src/main/java/gregtech/api/gui/resources/onlinepic/ProcessedImageData.java @@ -0,0 +1,137 @@ +package gregtech.api.gui.resources.onlinepic; + +import org.lwjgl.BufferUtils; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL12; + +import java.awt.*; +import java.awt.image.BufferedImage; +import java.nio.ByteBuffer; + + +public class ProcessedImageData { + private final int width; + private final int height; + private final Frame[] frames; + private final long[] delay; + private final long duration; + + public ProcessedImageData(BufferedImage image) { + width = image.getWidth(); + height = image.getHeight(); + frames = new Frame[] { loadFrom(image) }; + delay = new long[] { 0 }; + duration = 0; + } + + public ProcessedImageData(GifDecoder decoder) { + Dimension frameSize = decoder.getFrameSize(); + width = (int) frameSize.getWidth(); + height = (int) frameSize.getHeight(); + frames = new Frame[decoder.getFrameCount()]; + delay = new long[decoder.getFrameCount()]; + long time = 0; + for (int i = 0; i < decoder.getFrameCount(); i++) { + frames[i] = loadFrom(decoder.getFrame(i)); + delay[i] = time; + time += decoder.getDelay(i); + } + duration = time; + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public long[] getDelay() { + return delay; + } + + public long getDuration() { + return duration; + } + + public boolean isAnimated() { + return frames.length > 1; + } + + public int getFrameCount() { + return frames.length; + } + + public int uploadFrame(int index) { + if (index >= 0 && index < frames.length) { + Frame frame = frames[index]; + if (frame != null) { + frames[index] = null; + return uploadFrame(frame.buffer, frame.hasAlpha, width, height); + } + } + return -1; + } + + private static int uploadFrame(ByteBuffer buffer, boolean hasAlpha, int width, int height) { + int textureID = GL11.glGenTextures(); //Generate texture ID + GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureID); //Bind texture ID + + //Setup wrap mode + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE); + + //Setup texture scaling filtering + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); + + if (!hasAlpha) { + GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1); + } + + //Send texel data to OpenGL + GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, hasAlpha ? GL11.GL_RGBA8 : GL11.GL_RGB8, width, height, 0, hasAlpha ? GL11.GL_RGBA : GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, buffer); + + //Return the texture ID so we can bind it later again + return textureID; + } + + private static Frame loadFrom(BufferedImage image) { + int width = image.getWidth(); + int height = image.getHeight(); + int[] pixels = new int[width * height]; + image.getRGB(0, 0, width, height, pixels, 0, width); + boolean hasAlpha = false; + if (image.getColorModel().hasAlpha()) { + for (int pixel : pixels) { + if ((pixel >> 24 & 0xFF) < 0xFF) { + hasAlpha = true; + break; + } + } + } + int bytesPerPixel = hasAlpha ? 4 : 3; + ByteBuffer buffer = BufferUtils.createByteBuffer(width * height * bytesPerPixel); + for (int pixel : pixels) { + buffer.put((byte) ((pixel >> 16) & 0xFF)); // Red component + buffer.put((byte) ((pixel >> 8) & 0xFF)); // Green component + buffer.put((byte) (pixel & 0xFF)); // Blue component + if (hasAlpha) { + buffer.put((byte) ((pixel >> 24) & 0xFF)); // Alpha component. Only for RGBA + } + } + buffer.flip(); + return new Frame(buffer, hasAlpha); + } + + private static class Frame { + private final ByteBuffer buffer; + private final boolean hasAlpha; + + public Frame(ByteBuffer buffer, boolean alpha) { + this.buffer = buffer; + this.hasAlpha = alpha; + } + } +} diff --git a/src/main/java/gregtech/api/gui/resources/onlinepic/TextureCache.java b/src/main/java/gregtech/api/gui/resources/onlinepic/TextureCache.java new file mode 100644 index 00000000000..d48678e5153 --- /dev/null +++ b/src/main/java/gregtech/api/gui/resources/onlinepic/TextureCache.java @@ -0,0 +1,150 @@ +package gregtech.api.gui.resources.onlinepic; + +import net.minecraft.client.Minecraft; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.io.IOUtils; + +import java.io.*; +import java.util.HashMap; +import java.util.Map; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; + +public class TextureCache { + private File cacheDirectory = new File(Minecraft.getMinecraft().gameDir, "opframe_cache"); + private File index = new File(cacheDirectory, "index"); + + private Map entries = new HashMap(); + + public TextureCache() { + if (!cacheDirectory.exists()) { + cacheDirectory.mkdirs(); + } + loadIndex(); + } + + public void save(String url, String etag, long time, long expireTime, byte[] data) { + CacheEntry entry = new CacheEntry(url, etag, time, expireTime); + boolean saved = false; + OutputStream out = null; + try { + out = new FileOutputStream(entry.getFile()); + out.write(data); + saved = true; + } catch (IOException e) { + DownloadThread.LOGGER.error("Failed to save cache entry {}", e, url); + } finally { + IOUtils.closeQuietly(out); + } + if (saved) { + entries.put(url, entry); + saveIndex(); + } + } + + public CacheEntry getEntry(String url) { + return entries.get(url); + } + + private void loadIndex() { + if (index.exists()) { + Map previousEntries = entries; + entries = new HashMap(); + DataInputStream in = null; + try { + in = new DataInputStream(new GZIPInputStream(new FileInputStream(index))); + int length = in.readInt(); + for (int i = 0; i < length; i++) { + String url = in.readUTF(); + String etag = in.readUTF(); + long time = in.readLong(); + long expireTime = in.readLong(); + CacheEntry entry = new CacheEntry(url, etag.length() > 0 ? etag : null, time, expireTime); + entries.put(entry.getUrl(), entry); + } + } catch (IOException e) { + DownloadThread.LOGGER.error("Failed to load cache index", e); + entries = previousEntries; + } finally { + IOUtils.closeQuietly(in); + } + } + } + + private void saveIndex() { + DataOutputStream out = null; + try { + out = new DataOutputStream(new GZIPOutputStream(new FileOutputStream(index))); + out.writeInt(entries.size()); + for (Map.Entry mapEntry : entries.entrySet()) { + CacheEntry entry = mapEntry.getValue(); + out.writeUTF(entry.getUrl()); + out.writeUTF(entry.getEtag() == null ? "" : entry.getEtag()); + out.writeLong(entry.getTime()); + out.writeLong(entry.getExpireTime()); + } + } catch (IOException e) { + DownloadThread.LOGGER.error("Failed to save cache index", e); + } finally { + IOUtils.closeQuietly(out); + } + } + + public void deleteEntry(String url) { + entries.remove(url); + File file = getFile(url); + if (file.exists()) { + file.delete(); + } + } + + private static File getFile(String url) { + return new File(DownloadThread.TEXTURE_CACHE.cacheDirectory, Base64.encodeBase64String(url.getBytes())); + } + + public static class CacheEntry { + private String url; + private String etag; + private long time; + private long expireTime; + + public CacheEntry(String url, String etag, long time, long expireTime) { + this.url = url; + this.etag = etag; + this.time = time; + this.expireTime = expireTime; + } + + public void setEtag(String etag) { + this.etag = etag; + } + + public void setTime(long time) { + this.time = time; + } + + public void setExpireTime(long expireTime) { + this.expireTime = expireTime; + } + + public String getUrl() { + return url; + } + + public String getEtag() { + return etag; + } + + public long getTime() { + return time; + } + + public long getExpireTime() { + return expireTime; + } + + public File getFile() { + return TextureCache.getFile(url); + } + } +} diff --git a/src/main/java/gregtech/api/gui/resources/onlinepictexture/AnimatedPictureTexture.java b/src/main/java/gregtech/api/gui/resources/onlinepictexture/AnimatedPictureTexture.java new file mode 100644 index 00000000000..bee61ca36b3 --- /dev/null +++ b/src/main/java/gregtech/api/gui/resources/onlinepictexture/AnimatedPictureTexture.java @@ -0,0 +1,66 @@ +package gregtech.api.gui.resources.onlinepictexture; + + +import gregtech.api.gui.resources.onlinepic.ProcessedImageData; +import net.minecraft.client.renderer.GlStateManager; + +import java.util.Arrays; + +public class AnimatedPictureTexture extends PictureTexture { + private final int[] textureIDs; + private final long[] delay; + private final long duration; + + private int completedFrames; + private ProcessedImageData imageData; + + public AnimatedPictureTexture(ProcessedImageData image) { + super(image.getWidth(), image.getHeight()); + imageData = image; + textureIDs = new int[image.getFrameCount()]; + delay = image.getDelay(); + duration = image.getDuration(); + Arrays.fill(textureIDs, -1); + } + + @Override + public void tick() { + if (imageData != null) { + long startTime = System.currentTimeMillis(); + int index = 0; + while (completedFrames < textureIDs.length && index < textureIDs.length && System.currentTimeMillis() - startTime < 10) { + while (textureIDs[index] != -1 && index < textureIDs.length - 1) + index++; + if (textureIDs[index] == -1) + textureIDs[index] = uploadFrame(index); + } + } + } + + @Override + public int getTextureID() { + long time = duration > 0 ? System.currentTimeMillis() % duration : 0; + int index = 0; + for (int i = 0; i < delay.length; i++) { + if (delay[i] >= time) { + index = i; + break; + } + } + return textureIDs[index]; + } + + private int uploadFrame(int index) { + int id = imageData.uploadFrame(index); + textureIDs[index] = id; + if (++completedFrames >= imageData.getFrameCount()) { + imageData = null; + } + return id; + } + + @Override + public void release() { + for (int textureID : textureIDs) GlStateManager.deleteTexture(textureID); + } +} diff --git a/src/main/java/gregtech/api/gui/resources/onlinepictexture/OrdinaryTexture.java b/src/main/java/gregtech/api/gui/resources/onlinepictexture/OrdinaryTexture.java new file mode 100644 index 00000000000..2eea82b9ea8 --- /dev/null +++ b/src/main/java/gregtech/api/gui/resources/onlinepictexture/OrdinaryTexture.java @@ -0,0 +1,23 @@ +package gregtech.api.gui.resources.onlinepictexture; + +import gregtech.api.gui.resources.onlinepic.ProcessedImageData; + +public class OrdinaryTexture extends PictureTexture { + + private final int textureID; + + public OrdinaryTexture(ProcessedImageData image) { + super(image.getWidth(), image.getHeight()); + textureID = image.uploadFrame(0); + } + + @Override + public void tick() { + } + + @Override + public int getTextureID() { + return textureID; + } +} + diff --git a/src/main/java/gregtech/api/gui/resources/onlinepictexture/PictureTexture.java b/src/main/java/gregtech/api/gui/resources/onlinepictexture/PictureTexture.java new file mode 100644 index 00000000000..268734fb623 --- /dev/null +++ b/src/main/java/gregtech/api/gui/resources/onlinepictexture/PictureTexture.java @@ -0,0 +1,65 @@ +package gregtech.api.gui.resources.onlinepictexture; + +import gregtech.api.gui.resources.IGuiTexture; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.OpenGlHelper; +import org.lwjgl.opengl.GL11; + +public abstract class PictureTexture implements IGuiTexture { + public int width; + public int height; + + public PictureTexture(int width, int height) { + this.width = width; + this.height = height; + + } + + public void beforeRender() { + + } + + @Override + public void draw(double x, double y, int width, int height) { + render((float)x, (float)y, 1, 1, 0, width, height, false, false); + } + + public void render(float x, float y, float ux, float uv, float rotation, float sizeX, float sizeY, boolean flippedX, boolean flippedY) { + this.beforeRender(); + GlStateManager.color(1,1,1,1); + GlStateManager.enableBlend(); + OpenGlHelper.glBlendFunc(770, 771, 1, 0); + GlStateManager.bindTexture(this.getTextureID()); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); + GlStateManager.pushMatrix(); + GL11.glRotated(rotation, 0, 0, 1); + GlStateManager.enableRescaleNormal(); + GL11.glScaled(sizeX, sizeY, 1); + GL11.glBegin(GL11.GL_POLYGON); + GL11.glTexCoord3f(flippedY ? 1 : 0, flippedX ? 1 : 0, 0); + GL11.glVertex3f(x, y, 0.01f); + GL11.glTexCoord3f(flippedY ? 1 : 0, flippedX ? 0 : 1, 0); + GL11.glVertex3f(x, y + uv, 0.01f); + GL11.glTexCoord3f(flippedY ? 0 : 1, flippedX ? 0 : 1, 0); + GL11.glVertex3f(x + ux, y + uv, 0.01f); + GL11.glTexCoord3f(flippedY ? 0 : 1, flippedX ? 1 : 0, 0); + GL11.glVertex3f(x + ux, y, 0.01f); + GL11.glEnd(); + GlStateManager.popMatrix(); + GlStateManager.disableRescaleNormal(); + GlStateManager.disableBlend(); + } + + public abstract void tick(); + + public abstract int getTextureID(); + + public boolean hasTexture() { + return getTextureID() != -1; + } + + public void release() { + GlStateManager.deleteTexture(getTextureID()); + } +} diff --git a/src/main/java/gregtech/api/gui/resources/onlinepictexture/VideoTexture.java b/src/main/java/gregtech/api/gui/resources/onlinepictexture/VideoTexture.java new file mode 100644 index 00000000000..af5ea14b8fe --- /dev/null +++ b/src/main/java/gregtech/api/gui/resources/onlinepictexture/VideoTexture.java @@ -0,0 +1,19 @@ +package gregtech.api.gui.resources.onlinepictexture; + +public class VideoTexture extends PictureTexture { + //TODO implementations of it in the future + + public VideoTexture(String url) { + super(100, 100); + } + + @Override + public void tick() { + + } + + @Override + public int getTextureID() { + return 0; + } +} diff --git a/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java b/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java index 6552bfb23ab..286c38be809 100644 --- a/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java +++ b/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java @@ -23,7 +23,6 @@ public class AbstractWidgetGroup extends Widget implements IGhostIngredientTarge protected final List widgets = new ArrayList<>(); private final WidgetGroupUIAccess groupUIAccess = new WidgetGroupUIAccess(); - private boolean isVisible = true; private final boolean isDynamicSized; private boolean initialized = false; @@ -95,14 +94,10 @@ protected Size computeDynamicSize() { } public void setVisible(boolean visible) { - this.isVisible = visible; + super.setVisible(visible); widgets.stream().flatMap(it -> it.getNativeWidgets().stream()).forEach(it -> it.setEnabled(visible)); } - public boolean isVisible() { - return isVisible; - } - protected void addWidget(Widget widget) { if (widget == this) { throw new IllegalArgumentException("Cannot add self"); @@ -153,12 +148,8 @@ protected void clearAllWidgets() { } } - public boolean isWidgetVisible(Widget widget) { - return this.isVisible; - } - public boolean isWidgetClickable(Widget widget) { - return isWidgetVisible(widget); + return isVisible(); } @Override @@ -185,7 +176,7 @@ public List getNativeWidgets() { @Override public List> getPhantomTargets(Object ingredient) { - if (!isVisible) { + if (!isVisible()) { return Collections.emptyList(); } ArrayList> targets = new ArrayList<>(); @@ -199,7 +190,7 @@ public List> getPhantomTargets(Object ingredient) { @Override public Object getIngredientOverMouse(int mouseX, int mouseY) { - if (!isVisible) { + if (!isVisible()) { return Collections.emptyList(); } for (Widget widget : widgets) { @@ -229,7 +220,7 @@ public void updateScreen() { @Override public void drawInForeground(int mouseX, int mouseY) { for (Widget widget : widgets) { - if (isWidgetVisible(widget)) { + if (widget.isVisible()) { widget.drawInForeground(mouseX, mouseY); } } @@ -238,7 +229,7 @@ public void drawInForeground(int mouseX, int mouseY) { @Override public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { for (Widget widget : widgets) { - if (isWidgetVisible(widget)) { + if (widget.isVisible()) { widget.drawInBackground(mouseX, mouseY, partialTicks, context); } } @@ -247,27 +238,52 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender @Override public boolean mouseWheelMove(int mouseX, int mouseY, int wheelDelta) { - return widgets.stream().filter(this::isWidgetClickable).anyMatch(it -> it.mouseWheelMove(mouseX, mouseY, wheelDelta)); + for (Widget widget : widgets) { + if(widget.mouseWheelMove(mouseX, mouseY, wheelDelta)) { + return true; + } + } + return false; } @Override public boolean mouseClicked(int mouseX, int mouseY, int button) { - return widgets.stream().filter(this::isWidgetClickable).anyMatch(it -> it.mouseClicked(mouseX, mouseY, button)); + for (Widget widget : widgets) { + if(widget.mouseClicked(mouseX, mouseY, button)) { + return true; + } + } + return false; } @Override public boolean mouseDragged(int mouseX, int mouseY, int button, long timeDragged) { - return widgets.stream().filter(this::isWidgetClickable).anyMatch(it -> it.mouseDragged(mouseX, mouseY, button, timeDragged)); + for (Widget widget : widgets) { + if(widget.mouseDragged(mouseX, mouseY, button, timeDragged)) { + return true; + } + } + return false; } @Override public boolean mouseReleased(int mouseX, int mouseY, int button) { - return widgets.stream().filter(this::isWidgetClickable).anyMatch(it -> it.mouseReleased(mouseX, mouseY, button)); + for (Widget widget : widgets) { + if(widget.mouseReleased(mouseX, mouseY, button)) { + return true; + } + } + return false; } @Override public boolean keyTyped(char charTyped, int keyCode) { - return widgets.stream().filter(this::isWidgetClickable).anyMatch(it -> it.keyTyped(charTyped, keyCode)); + for (Widget widget : widgets) { + if(widget.keyTyped(charTyped, keyCode)) { + return true; + } + } + return false; } @Override diff --git a/src/main/java/gregtech/api/gui/widgets/TabGroup.java b/src/main/java/gregtech/api/gui/widgets/TabGroup.java index bbe6cfedf71..d9741df338e 100644 --- a/src/main/java/gregtech/api/gui/widgets/TabGroup.java +++ b/src/main/java/gregtech/api/gui/widgets/TabGroup.java @@ -141,7 +141,6 @@ private static boolean isMouseOverTab(int mouseX, int mouseY, int[] tabSizes) { return mouseX >= minX && mouseY >= minY && mouseX < maxX && mouseY < maxY; } - @Override public boolean isWidgetVisible(Widget widget) { return tabWidgets.containsKey(selectedTabIndex) && tabWidgets.get(selectedTabIndex) == widget; } diff --git a/src/main/java/gregtech/api/gui/widgets/WidgetGroup.java b/src/main/java/gregtech/api/gui/widgets/WidgetGroup.java index 0bea41fee67..9cd81ffd057 100644 --- a/src/main/java/gregtech/api/gui/widgets/WidgetGroup.java +++ b/src/main/java/gregtech/api/gui/widgets/WidgetGroup.java @@ -22,4 +22,14 @@ public WidgetGroup(Position position, Size size) { public void addWidget(Widget widget) { super.addWidget(widget); } + + @Override + public void removeWidget(Widget widget) { + super.removeWidget(widget); + } + + @Override + public void clearAllWidgets() { + super.clearAllWidgets(); + } } diff --git a/src/main/java/gregtech/api/terminal/TerminalBuilder.java b/src/main/java/gregtech/api/terminal/TerminalBuilder.java index 0a89229be3b..fb667768b4c 100644 --- a/src/main/java/gregtech/api/terminal/TerminalBuilder.java +++ b/src/main/java/gregtech/api/terminal/TerminalBuilder.java @@ -1,4 +1,25 @@ package gregtech.api.terminal; +import gregtech.api.terminal.app.*; +import gregtech.api.terminal.app.guide.ItemGuideApp; +import gregtech.api.terminal.app.guide.MultiBlockGuideApp; +import gregtech.api.terminal.app.guide.SimpleMachineGuideApp; +import gregtech.api.terminal.app.guide.TutorialGuideApp; + +import java.util.ArrayList; +import java.util.List; + public class TerminalBuilder { + private static final List appRegister = new ArrayList<>(); + + public static void init() { + appRegister.add(new SimpleMachineGuideApp()); + appRegister.add(new MultiBlockGuideApp()); + appRegister.add(new ItemGuideApp()); + appRegister.add(new TutorialGuideApp()); + } + + public static List getApplications() { + return appRegister; + } } diff --git a/src/main/java/gregtech/api/terminal/app/AbstractApplication.java b/src/main/java/gregtech/api/terminal/app/AbstractApplication.java new file mode 100644 index 00000000000..b1d2fd1ffaf --- /dev/null +++ b/src/main/java/gregtech/api/terminal/app/AbstractApplication.java @@ -0,0 +1,32 @@ +package gregtech.api.terminal.app; + +import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.widgets.WidgetGroup; + +public abstract class AbstractApplication { + protected final String name; + protected final IGuiTexture icon; + + public AbstractApplication (String name, IGuiTexture icon) { + this.name = name; + this.icon = icon; + } + + public String getName() { + return name; + } + + public IGuiTexture getIcon() { + return icon; + } + + public void loadApp(WidgetGroup group, boolean isClient) { + + } + + public void unloadApp(boolean isClient) { + + } + +} diff --git a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java new file mode 100644 index 00000000000..4156d7a2abb --- /dev/null +++ b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java @@ -0,0 +1,114 @@ +package gregtech.api.terminal.app.guide; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import gregtech.api.GTValues; +import gregtech.api.gui.GuiTextures; +import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.terminal.app.AbstractApplication; +import gregtech.api.terminal.gui.widgets.guide.*; +import gregtech.api.terminal.util.TreeNode; +import net.minecraft.client.Minecraft; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.Tuple; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public abstract class GuideApp extends AbstractApplication { + private static final Map REGISTER_WIDGETS = new HashMap<>(); + static { //register guide widgets + REGISTER_WIDGETS.put("textbox", new TextBoxWidget()); + REGISTER_WIDGETS.put("image", new ImageWidget()); + } + private GuidePageWidget pageWidget; + public GuideApp(String name, IGuiTexture icon) { + super(name, icon); + } + + @Override + public void loadApp(WidgetGroup group, boolean isClient) { + pageWidget = null; + if (isClient && getTree() != null) { + group.addWidget( + new TextTreeWidget<>(0, 0, 100, 232, getTree(), leaf -> { + if (pageWidget != null) { + group.removeWidget(pageWidget); + } + pageWidget = loadLeaf(leaf); + group.addWidget(pageWidget); + }, this::itemIcon, this::itemName).setNodeTexture(GuiTextures.BORDERED_BACKGROUND).setLeafTexture(GuiTextures.SLOT_DARKENED) + ); + } + } + + protected IGuiTexture itemIcon(T item) { + return null; + } + + protected String itemName(T item) { + return null; + } + + + protected abstract TreeNode> getTree(); + + public static JsonObject getConfig(String fileName) { + try { + InputStream inputStream = Minecraft.getMinecraft().getResourceManager().getResource(new ResourceLocation(GTValues.MODID, fileName)).getInputStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); + JsonElement je = new Gson().fromJson(reader, JsonElement.class); + reader.close(); + inputStream.close(); + return je.getAsJsonObject(); + } catch (IOException e) { + return null; + } + } + + private GuidePageWidget loadLeaf(TreeNode> leaf) { + GuidePageWidget page = new GuidePageWidget(100, 0, 200, 232); + if (leaf.isLeaf() && leaf.content != null) { + JsonObject config = leaf.content.getSecond(); + // add title + Widget title = new TextBoxWidget(5, 2, 190, + Collections.singletonList(config.get("title").getAsString()), + 0, 15, 0xffffffff, 0x6fff0000, 0xff000000, + true, true); + page.addWidget(title); + + // add stream widgets + if (config.has("stream")) { + int y = title.getSize().height + 10; + for (JsonElement element : config.getAsJsonArray("stream")) { + JsonObject widgetConfig = element.getAsJsonObject(); + Widget widget = REGISTER_WIDGETS.get(widgetConfig.get("type").getAsString()).createStreamWidget(5, y, 190, widgetConfig); + y += widget.getSize().height + 5; + page.addWidget(widget); + } + } + // add fixed widgets + if (config.has("fixed")) { + for (JsonElement element : config.getAsJsonArray("fixed")) { + JsonObject widgetConfig = element.getAsJsonObject(); + Widget widget = REGISTER_WIDGETS.get(widgetConfig.get("type").getAsString()).createFixedWidget( + widgetConfig.get("x").getAsInt(), + widgetConfig.get("y").getAsInt(), + widgetConfig.get("width").getAsInt(), + widgetConfig.get("height").getAsInt(), + widgetConfig); + page.addWidget(widget); + } + } + } + return page; + } +} diff --git a/src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java new file mode 100644 index 00000000000..a79e4d4acc6 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java @@ -0,0 +1,34 @@ +package gregtech.api.terminal.app.guide; + +import com.google.gson.JsonObject; +import gregtech.api.gui.resources.ItemStackTexture; +import gregtech.api.items.metaitem.MetaItem; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.terminal.util.TreeNode; +import gregtech.common.items.MetaItems; +import net.minecraft.util.Tuple; +import net.minecraftforge.fml.common.FMLCommonHandler; + +public class ItemGuideApp extends GuideApp> { + private static TreeNode, JsonObject>> ROOT; + private static JsonObject DEFAULT; + static { + if (FMLCommonHandler.instance().getSide().isClient()) { + ROOT = new TreeNode<>(0,"root"); + DEFAULT = getConfig("terminal/guide/items/default.json"); + } + } + + public ItemGuideApp() { + super("Items Machines", new ItemStackTexture(MetaItems.SCANNER.getStackForm())); + } + + @Override + protected TreeNode, JsonObject>> getTree() { + return ROOT; + } + + public static void registerItem(MetaTileEntity mte) { + + } +} diff --git a/src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java new file mode 100644 index 00000000000..311e0dbec03 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java @@ -0,0 +1,47 @@ +package gregtech.api.terminal.app.guide; + +import com.google.gson.JsonObject; +import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.resources.ItemStackTexture; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.terminal.util.TreeNode; +import gregtech.common.metatileentities.MetaTileEntities; +import net.minecraft.util.Tuple; +import net.minecraftforge.fml.common.FMLCommonHandler; + +public class MultiBlockGuideApp extends GuideApp { + private static TreeNode> ROOT; + private static JsonObject DEFAULT; + static { + if (FMLCommonHandler.instance().getSide().isClient()) { + ROOT = new TreeNode<>(0, "root"); + DEFAULT = getConfig("terminal/guide/multiblocks/default.json"); + } + } + + public MultiBlockGuideApp() { + super("Multi-Block Machines", new ItemStackTexture(MetaTileEntities.ELECTRIC_BLAST_FURNACE.getStackForm())); + } + + @Override + protected TreeNode> getTree() { + return ROOT; + } + + @Override + protected IGuiTexture itemIcon(MetaTileEntity item) { + return new ItemStackTexture(item.getStackForm()); + } + + public static void registerMultiBlock(MetaTileEntity mte) { + if (FMLCommonHandler.instance().getSide().isClient()) { + JsonObject config = getConfig("terminal/guide/multiblocks/" + mte.metaTileEntityId.getPath() + ".json"); + if (config == null) { + ROOT.getOrCreateChild("default").addContent(mte.getMetaFullName(), new Tuple<>(mte, DEFAULT)); + } else { + ROOT.getOrCreateChild(config.get("section").getAsString()).addContent(mte.getMetaFullName(), new Tuple<>(mte, config)); + } + } + } + +} diff --git a/src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java new file mode 100644 index 00000000000..633e4943ad9 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java @@ -0,0 +1,46 @@ +package gregtech.api.terminal.app.guide; + +import com.google.gson.JsonObject; +import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.resources.ItemStackTexture; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.terminal.util.TreeNode; +import gregtech.common.metatileentities.MetaTileEntities; +import net.minecraft.util.Tuple; +import net.minecraftforge.fml.common.FMLCommonHandler; + +public class SimpleMachineGuideApp extends GuideApp { + private static TreeNode> ROOT; + private static JsonObject DEFAULT; + static { + if (FMLCommonHandler.instance().getSide().isClient()) { + ROOT = new TreeNode<>(0,"root"); + DEFAULT = getConfig("terminal/guide/simplemachines/default.json"); + } + } + + public SimpleMachineGuideApp() { + super("Simple Machines", new ItemStackTexture(MetaTileEntities.CHEMICAL_REACTOR[0].getStackForm())); + } + + @Override + protected TreeNode> getTree() { + return ROOT; + } + + @Override + protected IGuiTexture itemIcon(MetaTileEntity item) { + return new ItemStackTexture(item.getStackForm()); + } + + public static void registerSimpleMachine(MetaTileEntity mte) { + if (FMLCommonHandler.instance().getSide().isClient()) { + JsonObject config = getConfig("terminal/guide/simplemachines/" + mte.metaTileEntityId.getPath() + ".json"); + if (config == null) { + ROOT.getOrCreateChild("default").addContent(mte.getMetaFullName(), new Tuple<>(mte, DEFAULT)); + } else { + ROOT.getOrCreateChild(config.get("section").getAsString()).addContent(mte.getMetaFullName(), new Tuple<>(mte, config)); + } + } + } +} diff --git a/src/main/java/gregtech/api/terminal/app/guide/TutorialGuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/TutorialGuideApp.java new file mode 100644 index 00000000000..32aad915681 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/app/guide/TutorialGuideApp.java @@ -0,0 +1,46 @@ +package gregtech.api.terminal.app.guide; + +import com.google.gson.JsonObject; +import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.resources.ItemStackTexture; +import gregtech.api.terminal.util.TreeNode; +import net.minecraft.init.Items; +import net.minecraft.util.Tuple; +import net.minecraftforge.fml.common.FMLCommonHandler; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URL; + +public class TutorialGuideApp extends GuideApp { + private static TreeNode> ROOT; + static { + if (FMLCommonHandler.instance().getSide().isClient()) { + ROOT = new TreeNode<>(0,"root"); + try { + URL folder = ClassLoader.getSystemClassLoader().getResource("assets/gregtech/terminal/guide/tutorials"); + if (folder != null) { + new BufferedReader(new InputStreamReader(folder.openStream())).lines().forEach(file->{ + JsonObject config = getConfig("terminal/guide/tutorials/" + file); + if (config != null) { + ROOT.getOrCreateChild(config.get("section").getAsString()).addContent(config.get("title").getAsString(), new Tuple<>(null, config)); + } + }); + + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + public TutorialGuideApp() { + super("Tutorials", new ItemStackTexture(Items.PAPER)); + } + + @Override + protected TreeNode> getTree() { + return ROOT; + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/CircleButton.java b/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java similarity index 88% rename from src/main/java/gregtech/api/terminal/gui/widgets/CircleButton.java rename to src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java index 77bd34dcb9e..9eadc58360f 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/CircleButton.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java @@ -15,7 +15,7 @@ import java.util.Collections; import java.util.function.Consumer; -public class CircleButton extends Widget { +public class CircleButtonWidget extends Widget { private int hoverTick; private boolean isHover; private String hoverText; @@ -27,33 +27,33 @@ public class CircleButton extends Widget { new Color(255, 255, 255).getRGB(), }; - public CircleButton(int x, int y, int r) { + public CircleButtonWidget(int x, int y, int r) { super(new Position(x - r, y - r), new Size(2 * r, 2 * r)); } - public CircleButton setIcon(IGuiTexture icon) { + public CircleButtonWidget setIcon(IGuiTexture icon) { this.icon = icon; return this; } - public CircleButton setHoverText(String hoverText) { + public CircleButtonWidget setHoverText(String hoverText) { this.hoverText = hoverText; return this; } - public CircleButton setColors(int stroke, int strokeAnima, int fill) { + public CircleButtonWidget setColors(int stroke, int strokeAnima, int fill) { colors[0] = stroke; colors[1] = strokeAnima; colors[2] = fill; return this; } - public CircleButton setFillColors(int fill) { + public CircleButtonWidget setFillColors(int fill) { colors[2] = fill; return this; } - public CircleButton setClickListener(Consumer onPressed) { + public CircleButtonWidget setClickListener(Consumer onPressed) { this.onPressCallback = onPressed; return this; } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/TerminalMenu.java b/src/main/java/gregtech/api/terminal/gui/widgets/TerminalMenu.java deleted file mode 100644 index 0f0de4667a7..00000000000 --- a/src/main/java/gregtech/api/terminal/gui/widgets/TerminalMenu.java +++ /dev/null @@ -1,48 +0,0 @@ -package gregtech.api.terminal.gui.widgets; - -import gregtech.api.gui.IRenderContext; -import gregtech.api.gui.Widget; -import gregtech.api.gui.resources.IGuiTexture; -import gregtech.api.gui.widgets.AbstractWidgetGroup; -import gregtech.api.util.Position; -import gregtech.api.util.Size; - -import java.util.function.Supplier; - -public class TerminalMenu extends AbstractWidgetGroup { - private IGuiTexture background; - private Widget activeContent; - private CircleButton activeButton; - public TerminalMenu(int xPosition, int yPosition, int width, int height) { - super(new Position(xPosition, yPosition), new Size(width, height)); - } - - public TerminalMenu setBackGround(IGuiTexture background) { - this.background = background; - return this; - } - - public TerminalMenu addApp(IGuiTexture icon, String nameKey, Supplier content){ - CircleButton button = new CircleButton(27,40,12).setIcon(icon).setHoverText(nameKey); - button.setClickListener(clickData -> { - if (button != activeButton) { - removeWidget(activeContent); - if(content != null) { - activeContent = content.get(); - addWidget(activeContent); - } - activeButton.setFillColors(0xffffffff); - activeButton = button; - activeButton.setFillColors(0xFF929292); - } - }); - this.addWidget(button); - return this; - } - - @Override - public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { - background.draw(this.getPosition().x, this.getPosition().y, this.getSize().width, this.getSize().height); - super.drawInBackground(mouseX, mouseY, partialTicks, context); - } -} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/TerminalMenuWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/TerminalMenuWidget.java new file mode 100644 index 00000000000..673d6b5b7c8 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/TerminalMenuWidget.java @@ -0,0 +1,54 @@ +package gregtech.api.terminal.gui.widgets; + +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.widgets.AbstractWidgetGroup; +import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.terminal.app.AbstractApplication; +import gregtech.api.util.Position; +import gregtech.api.util.Size; + +public class TerminalMenuWidget extends AbstractWidgetGroup { + private int appCount; + private IGuiTexture background; + private final WidgetGroup activeContent; + private CircleButtonWidget activeButton; + public TerminalMenuWidget(int xPosition, int yPosition, int width, int height) { + super(new Position(xPosition, yPosition), new Size(width, height)); + this.activeContent = new WidgetGroup(new Position(27,-19), new Size(300, 232)); + this.addWidget(activeContent); + } + + public TerminalMenuWidget setBackground(IGuiTexture background) { + this.background = background; + return this; + } + + public void addApp(AbstractApplication application){ + int x = this.getSize().width / 2; + int r = 12; + int y = appCount * (2 * r + 4) + r; + CircleButtonWidget button = new CircleButtonWidget(x,y,r).setIcon(application.getIcon()).setHoverText(application.getName()); + button.setClickListener(clickData -> { + if (button != activeButton) { + activeContent.clearAllWidgets(); + application.loadApp(activeContent, clickData.isClient); + if (activeButton != null) { + activeButton.setFillColors(0xffffffff); + } + activeButton = button; + activeButton.setFillColors(0xFFAAF1DB); + } + }); + this.addWidget(button); + appCount++; + } + + @Override + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + if( background != null) { + background.draw(this.getPosition().x, this.getPosition().y, this.getSize().width, this.getSize().height); + } + super.drawInBackground(mouseX, mouseY, partialTicks, context); + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java new file mode 100644 index 00000000000..44b298de62b --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java @@ -0,0 +1,83 @@ +package gregtech.api.terminal.gui.widgets.guide; + + +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.resources.URLTexture; +import gregtech.api.gui.widgets.AbstractWidgetGroup; +import gregtech.api.util.Position; +import gregtech.api.util.RenderUtil; +import gregtech.api.util.Size; +import javafx.geometry.Pos; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.util.math.MathHelper; + +import static gregtech.api.gui.impl.ModularUIGui.*; + +public class GuidePageWidget extends AbstractWidgetGroup { + private IGuiTexture background; + private int scrollYOffset; + private int maxHeight; + + public GuidePageWidget(int xPosition, int yPosition, int width, int height) { + super(new Position(xPosition, yPosition), new Size(width, height)); + } + + public GuidePageWidget setBackground(IGuiTexture background) { + this.background = background; + return this; + } + + protected void setScrollYOffset(int scrollYOffset) { + if (scrollYOffset == this.scrollYOffset) return; + this.scrollYOffset = scrollYOffset; + int minY = this.scrollYOffset + getPosition().y; + int maxY = minY + getSize().height; + for (Widget widget : widgets) { + if (widget.getPosition().y < maxY && widget.getPosition().y + widget.getSize().height > minY) { + widget.setVisible(true); + } + } + } + + @Override + public void addWidget(Widget widget) { + maxHeight = Math.max(maxHeight, widget.getSize().height + widget.getPosition().y); + super.addWidget(widget); + if (widget instanceof IGuideWidget) { + ((IGuideWidget) widget).setPage(this); + } + } + + @Override + public boolean mouseWheelMove(int mouseX, int mouseY, int wheelDelta) { + if (this.isMouseOverElement(mouseX, mouseY, true)) { + int moveDelta = -MathHelper.clamp(wheelDelta, -1, 1) * 5; + setScrollYOffset(MathHelper.clamp(scrollYOffset + moveDelta, 0, Math.max(maxHeight - getSize().height, 0))); + return true; + } + return false; + } + + @Override + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + Position position = getPosition(); + Size size = getSize(); + if (background != null) { + background.draw(position.x, position.y, size.width, size.height); + } else { + gregtech.api.gui.resources.RenderUtil.renderRect(position.x, position.y, size.width, size.height, 0, 0xffffffff); + } + GlStateManager.translate(0, -scrollYOffset, 0); + RenderUtil.useScissor(position.x, position.y, size.width, size.height, ()->{ + for (Widget widget : widgets) { + if (widget.isVisible()) { + widget.drawInBackground(mouseX, mouseY, partialTicks, context); + } + } + GlStateManager.color(rColorForOverlay, gColorForOverlay, bColorForOverlay, 1.0F); + }); + GlStateManager.translate(0, scrollYOffset, 0); + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java new file mode 100644 index 00000000000..395c3f36e6c --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java @@ -0,0 +1,69 @@ +package gregtech.api.terminal.gui.widgets.guide; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.sun.istack.internal.Nullable; +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.Widget; +import gregtech.api.util.Position; +import gregtech.api.util.Size; + +public abstract class GuideWidget extends Widget implements IGuideWidget { + //config + public String ref; + public int fill; + public int stroke; + public int stroke_width = 1; + + private static final Gson GSON = new Gson(); + protected transient GuidePageWidget page; + + public GuideWidget(int x, int y, int width, int height) { + super(x, y, width, height); + } + + public GuideWidget(){ + super(Position.ORIGIN, Size.ZERO); + } + + @Override + public Widget createStreamWidget(int x, int y, int pageWidth, JsonObject config) { + GuideWidget widget = GSON.fromJson(config, this.getClass()); + widget.setSelfPosition(new Position(x, y)); + widget.setSize(new Size(pageWidth, 0)); + return widget.initStream(x, y, pageWidth, config); + } + + @Override + public Widget createFixedWidget(int x, int y, int width, int height, JsonObject config) { + GuideWidget widget = GSON.fromJson(config, this.getClass()); + widget.setSelfPosition(new Position(x, y)); + widget.setSize(new Size(width, height)); + return widget.initFixed(x, y, width, height, config); + } + + protected Widget initStream(int x, int y, int pageWidth, @Nullable JsonObject config) { + return initFixed(x, y, pageWidth, 0, config); + } + + protected Widget initFixed(int x, int y, int width, int height, @Nullable JsonObject config) { + return this; + } + + @Override + public void setPage(GuidePageWidget page) { + this.page = page; + } + + @Override + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + Position position = getPosition(); + Size size = getSize(); + if(stroke != 0) { + drawBorder(position.x, position.y, size.width, size.height, stroke, stroke_width); + } + if (fill != 0) { + drawGradientRect(position.x, position.y, size.width, size.height, fill, fill); + } + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java new file mode 100644 index 00000000000..9bec77e3724 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java @@ -0,0 +1,10 @@ +package gregtech.api.terminal.gui.widgets.guide; + +import com.google.gson.JsonObject; +import gregtech.api.gui.Widget; + +public interface IGuideWidget { + Widget createStreamWidget(int x, int y, int pageWidth, JsonObject config); + Widget createFixedWidget(int x, int y, int width, int height, JsonObject config); + void setPage(GuidePageWidget page); +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java new file mode 100644 index 00000000000..f2f0da27cf9 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java @@ -0,0 +1,61 @@ +package gregtech.api.terminal.gui.widgets.guide; + +import com.google.gson.JsonObject; +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.resources.ItemStackTexture; +import gregtech.api.gui.resources.TextureArea; +import gregtech.api.gui.resources.URLTexture; +import gregtech.api.util.Position; +import gregtech.api.util.Size; +import net.minecraft.item.Item; + +public class ImageWidget extends GuideWidget{ + //config + public String form; + public String source; + public int width; + public int height; + + public IGuiTexture image; + + @Override + public void updateScreen() { + if (image != null) { + image.updateTick(); + } + } + + @Override + protected Widget initStream(int x, int y, int pageWidth, JsonObject config) { + this.setSelfPosition(new Position(x + (pageWidth - width) / 2, y)); + this.setSize(new Size(width, height)); + return super.initStream(x, y, pageWidth, config); + } + + @Override + protected Widget initFixed(int x, int y, int width, int height, JsonObject config) { + switch (form) { + case "url": + image = new URLTexture(source); + break; + case "item": + image = new ItemStackTexture(Item.getByNameOrId(source)); + break; + case "resource": + image = TextureArea.fullImage(source); + break; + } + return this; + } + + @Override + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + if (image != null) { + super.drawInBackground(mouseX, mouseY, partialTicks,context); + Position position = getPosition(); + image.draw(position.x, position.y, width, height); + } + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java new file mode 100644 index 00000000000..7f0d67d3e0a --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java @@ -0,0 +1,83 @@ +package gregtech.api.terminal.gui.widgets.guide; + +import com.google.gson.JsonObject; +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.RenderUtil; +import gregtech.api.util.Position; +import gregtech.api.util.Size; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.resources.I18n; + +import java.util.ArrayList; +import java.util.List; + +public class TextBoxWidget extends GuideWidget { + // config + public List content; + public int space = 1; + public int fontSize = 9; + public int fontColor = 0xff000000; + public boolean isShadow = false; + public boolean isCenter = false; + + private List textLines; + + public TextBoxWidget(int x, int y, int width, List content, int space, int fontSize, int fontColor, int fill, int stroke, boolean isCenter, boolean isShadow) { + super(x, y, width, 0); + this.content = content; + this.space = space; + this.fontSize = fontSize; + this.fontColor = fontColor; + this.fill = fill; + this.stroke = stroke; + this.isCenter = isCenter; + this.isShadow = isShadow; + this.initFixed(x, y, width, 0, null); + } + + public TextBoxWidget() {} + + @Override + protected Widget initFixed(int x, int y, int width, int height, JsonObject config) { + this.textLines = new ArrayList<>(); + FontRenderer font = Minecraft.getMinecraft().fontRenderer; + this.space = Math.max(space, 0); + this.fontSize = Math.max(fontSize, 1); + int wrapWidth = width * font.FONT_HEIGHT / fontSize; + if (content != null) { + for (String textLine : content) { + this.textLines.addAll(font.listFormattedStringToWidth(I18n.format(textLine), wrapWidth)); + } + } + this.setSize(new Size(this.getSize().width, this.textLines.size() * (fontSize + space))); + return this; + } + + @Override + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + super.drawInBackground(mouseX, mouseY, partialTicks, context); + if (!textLines.isEmpty()) { + Position position = getPosition(); + Size size = getSize(); + FontRenderer font = Minecraft.getMinecraft().fontRenderer; + float scale = fontSize * 1.0f / font.FONT_HEIGHT; + GlStateManager.pushMatrix(); + GlStateManager.scale(scale, scale, 1); + GlStateManager.translate(position.x / scale, position.y / scale, 0); + float x = 0; + float y = 0; + float ySpace = font.FONT_HEIGHT + space / scale; + for (String textLine : textLines) { + if (isCenter) { + x = (size.width / scale - font.getStringWidth(textLine)) / 2; + } + font.drawString(textLine, x, y, fontColor, isShadow); + y += ySpace; + } + GlStateManager.popMatrix(); + } + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java new file mode 100644 index 00000000000..d20a9a82ccb --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java @@ -0,0 +1,150 @@ +package gregtech.api.terminal.gui.widgets.guide; + +import com.google.gson.JsonObject; +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.terminal.util.TreeNode; +import gregtech.api.util.Position; +import gregtech.api.util.RenderUtil; +import gregtech.api.util.Size; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.resources.I18n; +import net.minecraft.util.Tuple; +import net.minecraft.util.math.MathHelper; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Function; + +public class TextTreeWidget extends Widget { + private static final int ITEM_HEIGHT = 11; + protected int scrollOffset; + protected List>> list; + protected TreeNode> selected; + protected IGuiTexture background; + protected IGuiTexture nodeTexture; + protected IGuiTexture leafTexture; + protected Consumer>> onSelected; + protected Function iconSupplier; + protected Function nameSupplier; + + public TextTreeWidget(int xPosition, int yPosition, int width, int height, + TreeNode> root, + Consumer>> onSelected, + Function iconSupplier, + Function nameSupplier) { + super(new Position(xPosition, yPosition), new Size(width, height)); + list = new ArrayList<>(); + if (root.children != null) { + list.addAll(root.children); + } + this.onSelected = onSelected; + this.iconSupplier = iconSupplier; + this.nameSupplier = nameSupplier; + } + + public TextTreeWidget setBackground(IGuiTexture background) { + this.background = background; + return this; + } + + public TextTreeWidget setNodeTexture(IGuiTexture nodeTexture) { + this.nodeTexture = nodeTexture; + return this; + } + + public TextTreeWidget setLeafTexture(IGuiTexture leafTexture) { + this.leafTexture = leafTexture; + return this; + } + + @Override + public boolean mouseWheelMove(int mouseX, int mouseY, int wheelDelta) { + if (this.isMouseOverElement(mouseX, mouseY, true)) { + int moveDelta = -MathHelper.clamp(wheelDelta, -1, 1) * 5; + this.scrollOffset = MathHelper.clamp(scrollOffset + moveDelta, 0, Math.max(list.size() * ITEM_HEIGHT - getSize().height, 0)); + return true; + } + return false; + } + + @Override + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + Position position = getPosition(); + Size size = getSize(); + if (background != null) { + background.draw(position.x, position.y, size.width, size.height); + } else { + gregtech.api.gui.resources.RenderUtil.renderRect(position.x, position.y, size.width, size.height, 0, 0x8f000000); + } + RenderUtil.useScissor(position.x, position.y, size.width, size.height, ()->{ + FontRenderer fr = Minecraft.getMinecraft().fontRenderer; + int minToRender = scrollOffset / ITEM_HEIGHT; + int maxToRender = Math.min(list.size(), size.height / ITEM_HEIGHT + 2 + minToRender); + + for (int i = minToRender; i < maxToRender; i++) { + GlStateManager.color(1,1,1,1); + TreeNode> node = list.get(i); + int x = position.x + 10 * node.dimension; + int y = position.y - scrollOffset + i * ITEM_HEIGHT; + String name = node.key; + if (node.isLeaf()) { + if (leafTexture != null) { + leafTexture.draw(position.x, y, size.width, ITEM_HEIGHT); + } else { + gregtech.api.gui.resources.RenderUtil.renderRect(position.x, y, size.width, ITEM_HEIGHT, 0, 0xffff0000); + } + if (node.content != null) { + String nameS = nameSupplier.apply(node.content.getFirst()); + name = nameS == null ? name : nameS; + IGuiTexture icon = iconSupplier.apply(node.content.getFirst()); + if (icon != null) { + icon.draw(x - 9, y + 1, 8, 8); + } + } + } else { + if (nodeTexture != null) { + nodeTexture.draw(position.x, y, size.width, ITEM_HEIGHT); + } else { + gregtech.api.gui.resources.RenderUtil.renderRect(position.x, y, size.width, ITEM_HEIGHT, 0, 0xffffff00); + } + } + if (node == selected) { + gregtech.api.gui.resources.RenderUtil.renderRect(position.x, y, size.width, ITEM_HEIGHT, 0, 0x7f000000); + } + fr.drawString(I18n.format(name), x, y + 2, 0xff000000); + } + }); + } + + @Override + public boolean mouseClicked(int mouseX, int mouseY, int button) { + if (this.isMouseOverElement(mouseX, mouseY)) { + int index = ((mouseY - getPosition().y) + scrollOffset) / ITEM_HEIGHT; + if (index < list.size()) { + TreeNode> node = list.get(index); + if (node.isLeaf()) { + if (node != this.selected) { + this.selected = node; + onSelected.accept(node); + } + } else if (list.contains(node.children.get(node.children.size() - 1))){ + for (TreeNode> child : node.children) { + list.remove(child); + } + } else { + for (TreeNode> child : node.children) { + list.add(index + 1, child); + } + } + playButtonClickSound(); + } + return true; + } + return false; + } +} diff --git a/src/main/java/gregtech/api/terminal/util/IContent.java b/src/main/java/gregtech/api/terminal/util/IContent.java new file mode 100644 index 00000000000..5e0652455e7 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/util/IContent.java @@ -0,0 +1,4 @@ +package gregtech.api.terminal.util; + +public class IContent { +} diff --git a/src/main/java/gregtech/api/terminal/util/TreeNode.java b/src/main/java/gregtech/api/terminal/util/TreeNode.java new file mode 100644 index 00000000000..e8d5c1aa7fb --- /dev/null +++ b/src/main/java/gregtech/api/terminal/util/TreeNode.java @@ -0,0 +1,51 @@ +package gregtech.api.terminal.util; + + +import java.util.ArrayList; +import java.util.List; + +/*** + * Tree + * @param key + * @param leaf + */ +public class TreeNode { + public int dimension; + public List> children; + public final T key; + public K content; + + public TreeNode(int dimension, T key) { + this.dimension = dimension; + this.key = key; + } + + public boolean isLeaf(){ + return children == null || children.isEmpty(); + } + + public TreeNode getOrCreateChild (T childKey) { + TreeNode result; + if (children != null) { + result = children.stream().filter(child->child.key.equals(childKey)).findFirst().orElseGet(()->{ + TreeNode newNode = new TreeNode<>(dimension + 1, childKey); + children.add(newNode); + return newNode; + }); + } else { + children = new ArrayList<>(); + result = new TreeNode<>(dimension + 1, childKey); + children.add(result); + } + return result; + } + + public void addContent (T key, K content) { + getOrCreateChild(key).content = content; + } + + @Override + public String toString() { + return key.toString(); + } +} diff --git a/src/main/java/gregtech/common/CommonProxy.java b/src/main/java/gregtech/common/CommonProxy.java index bbf7ae04ffc..08e32ac1fc2 100644 --- a/src/main/java/gregtech/common/CommonProxy.java +++ b/src/main/java/gregtech/common/CommonProxy.java @@ -1,5 +1,9 @@ package gregtech.common; +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import forestry.core.config.Constants; import gregtech.api.GTValues; import gregtech.api.block.machines.MachineItemBlock; import gregtech.api.enchants.EnchantmentEnderDamage; @@ -10,6 +14,9 @@ import gregtech.api.unification.material.Material; import gregtech.api.unification.material.properties.DustProperty; import gregtech.api.unification.material.properties.PropertyKey; +import gregtech.api.terminal.TerminalBuilder; +import gregtech.api.unification.material.type.DustMaterial; +import gregtech.api.unification.material.type.Material; import gregtech.api.unification.ore.OrePrefix; import gregtech.api.util.GTLog; import gregtech.common.blocks.*; @@ -31,12 +38,14 @@ import gregtech.loaders.recipe.*; import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; +import net.minecraft.client.Minecraft; import net.minecraft.enchantment.Enchantment; import net.minecraft.item.Item; import net.minecraft.item.ItemBlock; import net.minecraft.item.ItemMultiTexture; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.IRecipe; +import net.minecraft.util.ResourceLocation; import net.minecraftforge.common.config.Config.Type; import net.minecraftforge.common.config.ConfigManager; import net.minecraftforge.event.RegistryEvent; @@ -47,7 +56,14 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.registries.IForgeRegistry; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; +import java.util.Enumeration; import java.util.function.Function; +import java.util.stream.Collectors; import static gregtech.common.blocks.MetaBlocks.*; @@ -270,5 +286,6 @@ public void onLoad() { public void onPostLoad() { WoodMachineRecipes.postInit(); + TerminalBuilder.init(); } } diff --git a/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java b/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java index bb3487c1f7a..8cc400aa343 100644 --- a/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java +++ b/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java @@ -2,14 +2,12 @@ import gregtech.api.gui.GuiTextures; import gregtech.api.gui.ModularUI; -import gregtech.api.gui.resources.TextureItemStack; import gregtech.api.items.gui.ItemUIFactory; import gregtech.api.items.gui.PlayerInventoryHolder; import gregtech.api.items.metaitem.stats.IItemBehaviour; -import gregtech.api.terminal.gui.widgets.CircleButton; +import gregtech.api.terminal.TerminalBuilder; +import gregtech.api.terminal.gui.widgets.TerminalMenuWidget; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.Blocks; -import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.util.ActionResult; import net.minecraft.util.EnumActionResult; @@ -36,10 +34,10 @@ public void addInformation(ItemStack itemStack, List lines) { @Override public ModularUI createUI(PlayerInventoryHolder holder, EntityPlayer entityPlayer) { - CircleButton circleButton = new CircleButton(27, 40, 12) - .setIcon(new TextureItemStack(Item.getItemFromBlock(Blocks.CHEST).getDefaultInstance())); + TerminalMenuWidget menu = new TerminalMenuWidget(15, 30, 24, 24); + TerminalBuilder.getApplications().forEach(menu::addApp); return ModularUI.builder(GuiTextures.TERMINAL_BACKGROUND, 380, 256) - .widget(circleButton) + .widget(menu) .build(holder, entityPlayer); } } diff --git a/src/main/resources/assets/gregtech/terminal/guide/items/default.json b/src/main/resources/assets/gregtech/terminal/guide/items/default.json new file mode 100644 index 00000000000..460662d7376 --- /dev/null +++ b/src/main/resources/assets/gregtech/terminal/guide/items/default.json @@ -0,0 +1,34 @@ +{ + "section": "default", + "title": "Json Tutorial", + "stream": [ + { + "type": "textbox", + "isCenter": false, + "content": [ + "If you see this page, §4unfortunately§r, this item lacks a Guide Page.", + "Let's start the tutorial.Rest assured, this is not difficult, you can easily customize the Guide Page with JSON. We look forward to your contributions.", + "------------" + ] + }, + { + "type": "textbox", + "isCenter": true, + "fontSize": 5, + "content": [ + "§nMinecraft Formatting", + "§r§00 §11 §22 §33", + "§44 §55 §66 §77", + "§88 §99 §aa §bb", + "§cc §dd §ee §ff", + "§r§0k §kMinecraft", + "§rl §lMinecraft", + "§rm §mMinecraft", + "§rn §nMinecraft", + "§ro §oMinecraft", + "§rr §rMinecraft" + ] + } + ], + "fixed": [] +} diff --git a/src/main/resources/assets/gregtech/terminal/guide/multiblocks/default.json b/src/main/resources/assets/gregtech/terminal/guide/multiblocks/default.json new file mode 100644 index 00000000000..8e1f44a4c3c --- /dev/null +++ b/src/main/resources/assets/gregtech/terminal/guide/multiblocks/default.json @@ -0,0 +1,24 @@ +{ + "section": "default", + "title": "Missing Guide", + "stream": [ + { + "type": "textbox", + "isCenter": false, + "content": [ + "If you see this page, §4unfortunately§r, this item lacks a Guide Page.", + "You can learn it from the APP §lTutorial§r. Don't worry, it is not difficult, you can easily customize the Guide Page with JSON. We look forward to your contributions.", + "-------------------------------" + ] + }, + { + "type": "textbox", + "isCenter": false, + "content": [ + "§c§lNote§r: Configuration files should in §n\"assets/gregtech/terminal/guide/multiblocks\"§r", + "Please name the file with the registered name of a machine to help the system automatically match the machines." + ] + } + ], + "fixed": [] +} diff --git a/src/main/resources/assets/gregtech/terminal/guide/simplemachines/default.json b/src/main/resources/assets/gregtech/terminal/guide/simplemachines/default.json new file mode 100644 index 00000000000..460662d7376 --- /dev/null +++ b/src/main/resources/assets/gregtech/terminal/guide/simplemachines/default.json @@ -0,0 +1,34 @@ +{ + "section": "default", + "title": "Json Tutorial", + "stream": [ + { + "type": "textbox", + "isCenter": false, + "content": [ + "If you see this page, §4unfortunately§r, this item lacks a Guide Page.", + "Let's start the tutorial.Rest assured, this is not difficult, you can easily customize the Guide Page with JSON. We look forward to your contributions.", + "------------" + ] + }, + { + "type": "textbox", + "isCenter": true, + "fontSize": 5, + "content": [ + "§nMinecraft Formatting", + "§r§00 §11 §22 §33", + "§44 §55 §66 §77", + "§88 §99 §aa §bb", + "§cc §dd §ee §ff", + "§r§0k §kMinecraft", + "§rl §lMinecraft", + "§rm §mMinecraft", + "§rn §nMinecraft", + "§ro §oMinecraft", + "§rr §rMinecraft" + ] + } + ], + "fixed": [] +} diff --git a/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_0_guidepage.json b/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_0_guidepage.json new file mode 100644 index 00000000000..34873e69ca1 --- /dev/null +++ b/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_0_guidepage.json @@ -0,0 +1,36 @@ +{ + "section": "Guide Widget API", + "title": "Guide Page", + "stream": [ + { + "type": "textbox", + "content": [ + "In this section we'll learn how to write a guide page.", + "-------------------------------", + "Let's take a look at an example config file for a guide page.", + "§lJSON§r:", + "{", + " \"section\": \"section name here\",", + " \"title\": \"title here\",", + " \"stream\": [", + " {", + " \"type\": \"textbox\",", + " \"content\": [\"TextBox widget\"]", + " }", + " ],", + " \"fixed\": [", + " {", + " \"x\": 50,", + " \"y\": 100,", + " \"width\": 150,", + " \"height\": 40,", + " \"type\": 0,", + " \"content\": [\"TextBox widget\"]", + " }", + " ]", + "}" + ] + } + ], + "fixed": [] +} diff --git a/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_1_textbox.json b/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_1_textbox.json new file mode 100644 index 00000000000..8f20574c947 --- /dev/null +++ b/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_1_textbox.json @@ -0,0 +1,265 @@ +{ + "section": "Guide Widget API", + "title": "TextBox Widget", + "stream": [ + { + "type": "textbox", + "content": [ + "In this section we'll learn how to use the powerful §4§lTextBox§r, which is the most commonly used. So you should read the API documentation carefully.", + "-------------------------------", + "§lWidget Type§r: §ntextbox§r", + "-------------------------------", + "§lJSON§r:", + "{", + " \"type\": \"textbox\",", + " \"space\": 1,", + " \"fontSize\": 9,", + " \"fontColor\": 4278190080,", + " \"fill\": 0,", + " \"stroke\": 0,", + " \"isCenter\": false,", + " \"isShadow\": false,", + " \"content\": [\"content here!\"]", + "}" + ] + }, { + "type": "textbox", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §ncontent§r (§4required§r)", + "§ltype§r: Array", + "§lillustrate§r: Text contents, each item will be a newline.Text that is too long will auto wrap itself. (Supporting Minecraft Formatting Code)" + ] + }, + { + "type": "textbox", + "isCenter": true, + "stroke": 4294901760, + "content": [ + "§lDemo§r: [...]", + "§nMinecraft Formatting", + "§r§00 §11 §22 §33", + "§44 §55 §66 §77", + "§88 §99 §aa §bb", + "§cc §dd §ee §ff", + "§r§0k §kMinecraft", + "§rl §lMinecraft", + "§rm §mMinecraft", + "§rn §nMinecraft", + "§ro §oMinecraft", + "§rr §rMinecraft" + ] + }, + { + "type": "textbox", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §nspace§r (§6optional§r)", + "§ltype§r: Number", + "§ldefault§r: 1", + "§lillustrate§r: The spacing between lines of text." + ] + }, + { + "type": "textbox", + "isCenter": true, + "stroke": 4294901760, + "space": 5, + "content": [ + "§lDemo§r: 5", + "§nMinecraft Formatting", + "§r§00 §11 §22 §33", + "§44 §55 §66 §77", + "§88 §99 §aa §bb", + "§cc §dd §ee §ff", + "§r§0k §kMinecraft", + "§rl §lMinecraft", + "§rm §mMinecraft", + "§rn §nMinecraft", + "§ro §oMinecraft", + "§rr §rMinecraft" + ] + },{ + "type": "textbox", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §nfontSize§r (§6optional§r)", + "§ltype§r: Number", + "§ldefault§r: 9", + "§lillustrate§r: The font size. (Actually it's the height of the font)" + ] + }, + { + "type": "textbox", + "isCenter": true, + "stroke": 4294901760, + "fontSize": 5, + "content": [ + "§lDemo§r: 5", + "§nMinecraft Formatting", + "§r§00 §11 §22 §33", + "§44 §55 §66 §77", + "§88 §99 §aa §bb", + "§cc §dd §ee §ff", + "§r§0k §kMinecraft", + "§rl §lMinecraft", + "§rm §mMinecraft", + "§rn §nMinecraft", + "§ro §oMinecraft", + "§rr §rMinecraft" + ] + },{ + "type": "textbox", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §nfontColor§r (§6optional§r)", + "§ltype§r: Number", + "§ldefault§r: 4278190080", + "§lillustrate§r: The default color of the content. You can also set the colors with special symbols (provided by Minecraft).But maybe you need it sometimes." + ] + }, + { + "type": "textbox", + "isCenter": true, + "stroke": 4294901760, + "fontColor": 5, + "content": [ + "§lDemo§r: 4294901760 (0xFFFF0000)", + "§nMinecraft Formatting", + "§r§00 §11 §22 §33", + "§44 §55 §66 §77", + "§88 §99 §aa §bb", + "§cc §dd §ee §ff", + "§r§0k §kMinecraft", + "§rl §lMinecraft", + "§rm §mMinecraft", + "§rn §nMinecraft", + "§ro §oMinecraft", + "§rr §rMinecraft" + ] + },{ + "type": "textbox", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §nfill§r (§6optional§r)", + "§ltype§r: Number", + "§ldefault§r: 0", + "§lillustrate§r: The background color." + ] + }, + { + "type": "textbox", + "isCenter": true, + "stroke": 4294901760, + "fill": 4278190335, + "content": [ + "§lDemo§r: 4278190335 (0xFF0000FF)", + "§nMinecraft Formatting", + "§r§00 §11 §22 §33", + "§44 §55 §66 §77", + "§88 §99 §aa §bb", + "§cc §dd §ee §ff", + "§r§0k §kMinecraft", + "§rl §lMinecraft", + "§rm §mMinecraft", + "§rn §nMinecraft", + "§ro §oMinecraft", + "§rr §rMinecraft" + ] + },{ + "type": "textbox", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §nstroke§r (§6optional§r)", + "§ltype§r: Number", + "§ldefault§r: 0", + "§lillustrate§r: The border color." + ] + }, + { + "type": "textbox", + "isCenter": true, + "stroke": 4278190335, + "content": [ + "§lDemo§r: 4278190335 (0xFF0000FF)", + "§nMinecraft Formatting", + "§r§00 §11 §22 §33", + "§44 §55 §66 §77", + "§88 §99 §aa §bb", + "§cc §dd §ee §ff", + "§r§0k §kMinecraft", + "§rl §lMinecraft", + "§rm §mMinecraft", + "§rn §nMinecraft", + "§ro §oMinecraft", + "§rr §rMinecraft" + ] + },{ + "type": "textbox", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §nisCenter§r (§6optional§r)", + "§ltype§r: Boolean", + "§ldefault§r: false", + "§lillustrate§r: Text-align center." + ] + }, + { + "type": "textbox", + "isCenter": false, + "stroke": 4294901760, + "content": [ + "§lDemo§r: false", + "§nMinecraft Formatting", + "§r§00 §11 §22 §33", + "§44 §55 §66 §77", + "§88 §99 §aa §bb", + "§cc §dd §ee §ff", + "§r§0k §kMinecraft", + "§rl §lMinecraft", + "§rm §mMinecraft", + "§rn §nMinecraft", + "§ro §oMinecraft", + "§rr §rMinecraft" + ] + },{ + "type": "textbox", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §nisShadow§r (§6optional§r)", + "§ltype§r: Boolean", + "§ldefault§r: false", + "§lillustrate§r: Render shadow." + ] + }, + { + "type": "textbox", + "isCenter": true, + "stroke": 4294901760, + "isShadow": true, + "content": [ + "§lDemo§r: true", + "§nMinecraft Formatting", + "§r§00 §11 §22 §33", + "§44 §55 §66 §77", + "§88 §99 §aa §bb", + "§cc §dd §ee §ff", + "§r§0k §kMinecraft", + "§rl §lMinecraft", + "§rm §mMinecraft", + "§rn §nMinecraft", + "§ro §oMinecraft", + "§rr §rMinecraft" + ] + } + ], + "fixed": [] +} diff --git a/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_2_image.json b/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_2_image.json new file mode 100644 index 00000000000..fa1276130c4 --- /dev/null +++ b/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_2_image.json @@ -0,0 +1,80 @@ +{ + "section": "Guide Widget API", + "title": "Image Widget", + "stream": [ + { + "type": "textbox", + "content": [ + "In this section we'll learn how to add an §4§lImage§r. There are three different forms of image supported here: §4Url§r, §4Item§r, and §4ResourceLocation§r. Don't worry, it's easy", + "-------------------------------", + "§lWidget Type§r: §nimage§r", + "-------------------------------", + "§lJSON§r:", + "{", + " \"type\": \"image\",", + " \"form\": \"Item\",", + " \"source\": \"minecraft:ender_pearl\",", + " \"width\": 100,", + " \"height\": 100", + "}" + ] + }, { + "type": "textbox", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §nform§r (§4required§r)", + "§ltype§r: String", + "§lillustrate§r: It can only be set one of §Url§r, §4Item§r, or §4ResourceLocation§r.", + " \"url\" -- image url.", + " \"item\" -- The registered name of the Item in game.", + " \"resource\" -- The resource location." + ] + }, + { + "type": "textbox", + "isCenter": true, + "content": [ + "§lDemo§r: \"url\"" + ] + }, + { + "type": "image", + "form": "url", + "source": "https://i.pinimg.com/originals/38/9d/e7/389de7ca61163911e72d4adcaabe1433.gif", + "stroke": 4278190080, + "stroke_width": 2, + "width": 100, + "height": 100 + }, + { + "type": "textbox", + "isCenter": true, + "content": [ + "§lDemo§r: \"item\"" + ] + }, + { + "type": "image", + "form": "item", + "source": "minecraft:ender_pearl", + "width": 100, + "height": 100 + }, + { + "type": "textbox", + "isCenter": true, + "content": [ + "§lDemo§r: \"resource\"" + ] + }, + { + "type": "image", + "form": "resource", + "source": "textures/gui/icon/gregtech_logo.png", + "width": 100, + "height": 100 + } + ], + "fixed": [] +} From ab382bf07f62c639b987972e77102138c4b139e6 Mon Sep 17 00:00:00 2001 From: Yefancy Date: Thu, 29 Jul 2021 18:35:38 +0800 Subject: [PATCH 24/58] frame --- src/main/java/gregtech/api/gui/Widget.java | 4 + .../gui/widgets/guide/GuidePageWidget.java | 42 ++- .../gui/widgets/guide/GuideWidget.java | 35 ++ .../gui/widgets/guide/IGuideWidget.java | 1 + .../gui/widgets/guide/ImageWidget.java | 8 +- .../gui/widgets/guide/TextTreeWidget.java | 6 +- .../gregtech/api/util/interpolate/Eases.java | 24 ++ .../gregtech/api/util/interpolate/IEase.java | 5 + .../api/util/interpolate/Interpolator.java | 42 +++ .../guide/tutorials/api_0_guidepage.json | 118 ++++++- .../guide/tutorials/api_1_widget.json | 304 ++++++++++++++++++ .../terminal/guide/tutorials/api_2_image.json | 80 ----- ...{api_1_textbox.json => api_2_textbox.json} | 119 ++++--- .../terminal/guide/tutorials/api_3_image.json | 207 ++++++++++++ 14 files changed, 840 insertions(+), 155 deletions(-) create mode 100644 src/main/java/gregtech/api/util/interpolate/Eases.java create mode 100644 src/main/java/gregtech/api/util/interpolate/IEase.java create mode 100644 src/main/java/gregtech/api/util/interpolate/Interpolator.java create mode 100644 src/main/resources/assets/gregtech/terminal/guide/tutorials/api_1_widget.json delete mode 100644 src/main/resources/assets/gregtech/terminal/guide/tutorials/api_2_image.json rename src/main/resources/assets/gregtech/terminal/guide/tutorials/{api_1_textbox.json => api_2_textbox.json} (78%) create mode 100644 src/main/resources/assets/gregtech/terminal/guide/tutorials/api_3_image.json diff --git a/src/main/java/gregtech/api/gui/Widget.java b/src/main/java/gregtech/api/gui/Widget.java index 832cba2ef5d..3538d352115 100644 --- a/src/main/java/gregtech/api/gui/Widget.java +++ b/src/main/java/gregtech/api/gui/Widget.java @@ -83,6 +83,10 @@ protected void setSelfPosition(Position selfPosition) { recomputePosition(); } + public Position getSelfPosition() { + return selfPosition; + } + protected void setSize(Size size) { Preconditions.checkNotNull(size, "size"); this.size = size; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java index 44b298de62b..efcc5110d43 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java @@ -9,6 +9,8 @@ import gregtech.api.util.Position; import gregtech.api.util.RenderUtil; import gregtech.api.util.Size; +import gregtech.api.util.interpolate.Eases; +import gregtech.api.util.interpolate.Interpolator; import javafx.geometry.Pos; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.util.math.MathHelper; @@ -19,6 +21,7 @@ public class GuidePageWidget extends AbstractWidgetGroup { private IGuiTexture background; private int scrollYOffset; private int maxHeight; + private Interpolator interpolator; public GuidePageWidget(int xPosition, int yPosition, int width, int height) { super(new Position(xPosition, yPosition), new Size(width, height)); @@ -35,8 +38,28 @@ protected void setScrollYOffset(int scrollYOffset) { int minY = this.scrollYOffset + getPosition().y; int maxY = minY + getSize().height; for (Widget widget : widgets) { - if (widget.getPosition().y < maxY && widget.getPosition().y + widget.getSize().height > minY) { - widget.setVisible(true); + widget.setVisible(widget.getPosition().y < maxY && widget.getPosition().y + widget.getSize().height > minY); + } + } + + public int getScrollYOffset() { + return scrollYOffset; + } + + @Override + public void updateScreen() { + if (interpolator != null) interpolator.update(); + super.updateScreen(); + } + + public void jumpToRef(String ref){ + if (interpolator != null && !interpolator.isFinish()) return; + for (Widget widget : widgets) { + if (widget instanceof IGuideWidget && ref.equals(((IGuideWidget) widget).getRef())) { + interpolator = new Interpolator(scrollYOffset, widget.getSelfPosition().y, 20, Eases.EaseQuadOut, (value)->{ + setScrollYOffset(value.intValue()); + }); + interpolator.start(); } } } @@ -71,13 +94,26 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender } GlStateManager.translate(0, -scrollYOffset, 0); RenderUtil.useScissor(position.x, position.y, size.width, size.height, ()->{ + int offsetY = mouseY + scrollYOffset; for (Widget widget : widgets) { if (widget.isVisible()) { - widget.drawInBackground(mouseX, mouseY, partialTicks, context); + widget.drawInBackground(mouseX, offsetY, partialTicks, context); } } GlStateManager.color(rColorForOverlay, gColorForOverlay, bColorForOverlay, 1.0F); }); GlStateManager.translate(0, scrollYOffset, 0); } + + @Override + public void drawInForeground(int mouseX, int mouseY) { + GlStateManager.translate(0, -scrollYOffset, 0); + super.drawInForeground(mouseX, mouseY + scrollYOffset); + GlStateManager.translate(0, scrollYOffset, 0); + } + + @Override + public boolean mouseClicked(int mouseX, int mouseY, int button) { + return super.mouseClicked(mouseX, mouseY + scrollYOffset, button); + } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java index 395c3f36e6c..d35062750d8 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java @@ -7,6 +7,10 @@ import gregtech.api.gui.Widget; import gregtech.api.util.Position; import gregtech.api.util.Size; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.item.ItemStack; + +import java.util.List; public abstract class GuideWidget extends Widget implements IGuideWidget { //config @@ -14,6 +18,8 @@ public abstract class GuideWidget extends Widget implements IGuideWidget { public int fill; public int stroke; public int stroke_width = 1; + public String link; + public List hover_text; private static final Gson GSON = new Gson(); protected transient GuidePageWidget page; @@ -26,6 +32,11 @@ public GuideWidget(){ super(Position.ORIGIN, Size.ZERO); } + @Override + public String getRef() { + return ref; + } + @Override public Widget createStreamWidget(int x, int y, int pageWidth, JsonObject config) { GuideWidget widget = GSON.fromJson(config, this.getClass()); @@ -55,6 +66,21 @@ public void setPage(GuidePageWidget page) { this.page = page; } + @Override + public void drawInForeground(int mouseX, int mouseY) { + if (link != null && isMouseOverElement(mouseX, mouseY)) { + Position position = getPosition(); + Size size = getSize(); + drawBorder(position.x, position.y, size.width, size.height, 0xff0000ff, stroke_width); + } + if (hover_text != null && isMouseOverElement(mouseX, mouseY)) { + int scrollYOffset = page.getScrollYOffset(); + GlStateManager.translate(0, scrollYOffset, 0); + drawHoveringText(ItemStack.EMPTY, hover_text, 100, mouseX, mouseY - scrollYOffset); + GlStateManager.translate(0, -scrollYOffset, 0); + } + } + @Override public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { Position position = getPosition(); @@ -66,4 +92,13 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender drawGradientRect(position.x, position.y, size.width, size.height, fill, fill); } } + + @Override + public boolean mouseClicked(int mouseX, int mouseY, int button) { + if (link != null && isMouseOverElement(mouseX, mouseY)) { + page.jumpToRef(link); + return true; + } + return false; + } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java index 9bec77e3724..4d2b3808367 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java @@ -7,4 +7,5 @@ public interface IGuideWidget { Widget createStreamWidget(int x, int y, int pageWidth, JsonObject config); Widget createFixedWidget(int x, int y, int width, int height, JsonObject config); void setPage(GuidePageWidget page); + String getRef(); } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java index f2f0da27cf9..b5a1d8127c0 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java @@ -1,6 +1,7 @@ package gregtech.api.terminal.gui.widgets.guide; import com.google.gson.JsonObject; +import gregtech.api.GTValues; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; import gregtech.api.gui.resources.IGuiTexture; @@ -9,7 +10,9 @@ import gregtech.api.gui.resources.URLTexture; import gregtech.api.util.Position; import gregtech.api.util.Size; +import net.minecraft.client.renderer.GlStateManager; import net.minecraft.item.Item; +import net.minecraft.util.ResourceLocation; public class ImageWidget extends GuideWidget{ //config @@ -38,13 +41,13 @@ protected Widget initStream(int x, int y, int pageWidth, JsonObject config) { protected Widget initFixed(int x, int y, int width, int height, JsonObject config) { switch (form) { case "url": - image = new URLTexture(source); + image = new URLTexture("https://i0.hdslb.com/bfs/article/bcd3d609c1899810113fdb90c8d0e1dd4aa8ed38.gif"); break; case "item": image = new ItemStackTexture(Item.getByNameOrId(source)); break; case "resource": - image = TextureArea.fullImage(source); + image = new TextureArea(new ResourceLocation(source), 0.0, 0.0, 1.0, 1.0); break; } return this; @@ -54,6 +57,7 @@ protected Widget initFixed(int x, int y, int width, int height, JsonObject confi public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { if (image != null) { super.drawInBackground(mouseX, mouseY, partialTicks,context); + GlStateManager.color(1,1,1,1); Position position = getPosition(); image.draw(position.x, position.y, width, height); } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java index d20a9a82ccb..ecd8db3fbad 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java @@ -132,13 +132,13 @@ public boolean mouseClicked(int mouseX, int mouseY, int button) { this.selected = node; onSelected.accept(node); } - } else if (list.contains(node.children.get(node.children.size() - 1))){ + } else if (node.children.size() > 0 && list.contains(node.children.get(0))){ for (TreeNode> child : node.children) { list.remove(child); } } else { - for (TreeNode> child : node.children) { - list.add(index + 1, child); + for (int i = 0; i < node.children.size(); i++) { + list.add(index + 1 + i, node.children.get(i)); } } playButtonClickSound(); diff --git a/src/main/java/gregtech/api/util/interpolate/Eases.java b/src/main/java/gregtech/api/util/interpolate/Eases.java new file mode 100644 index 00000000000..87f74763cb4 --- /dev/null +++ b/src/main/java/gregtech/api/util/interpolate/Eases.java @@ -0,0 +1,24 @@ +package gregtech.api.util.interpolate; + +public enum Eases implements IEase{ + EaseLinear(input-> input), + EaseQuadIn(input-> input * input), + EaseQuadInOut(input->{ + if((input /= 0.5f) < 1) { + return 0.5f * input * input; + } + return -0.5f * ((--input) * (input - 2) - 1); + }), + EaseQuadOut(input->-input * (input - 2)); + + + IEase ease; + + Eases(IEase ease){ + this.ease = ease; + } + @Override + public float getInterpolation(float t) { + return ease.getInterpolation(t); + } +} diff --git a/src/main/java/gregtech/api/util/interpolate/IEase.java b/src/main/java/gregtech/api/util/interpolate/IEase.java new file mode 100644 index 00000000000..cb4c02b0e4e --- /dev/null +++ b/src/main/java/gregtech/api/util/interpolate/IEase.java @@ -0,0 +1,5 @@ +package gregtech.api.util.interpolate; + +public interface IEase { + float getInterpolation(float t); +} diff --git a/src/main/java/gregtech/api/util/interpolate/Interpolator.java b/src/main/java/gregtech/api/util/interpolate/Interpolator.java new file mode 100644 index 00000000000..2eef08dea52 --- /dev/null +++ b/src/main/java/gregtech/api/util/interpolate/Interpolator.java @@ -0,0 +1,42 @@ +package gregtech.api.util.interpolate; + +import net.minecraft.util.ITickable; + +import java.util.function.Consumer; + +public class Interpolator implements ITickable { + float from; + float to; + int duration; + IEase ease; + Consumer callback; + + int tick = -1; + + public Interpolator(float from, float to, int duration, IEase ease, Consumer callback) { + this.from = from; + this.to = to; + this.duration = duration; + this.ease = ease; + this.callback = callback; + } + + public void reset() { + tick = -1; + } + + public void start() { + tick = 0; + } + + public boolean isFinish(){ + return tick == duration; + } + + @Override + public void update() { + if (tick < 0 || tick >= duration) return; + callback.accept(ease.getInterpolation(tick * 1.0f / duration) * (to - from) + from); + tick++; + } +} diff --git a/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_0_guidepage.json b/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_0_guidepage.json index 34873e69ca1..cc671653f25 100644 --- a/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_0_guidepage.json +++ b/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_0_guidepage.json @@ -5,7 +5,7 @@ { "type": "textbox", "content": [ - "In this section we'll learn how to write a guide page.", + "In this page we'll learn how to write a guide page.", "-------------------------------", "Let's take a look at an example config file for a guide page.", "§lJSON§r:", @@ -28,9 +28,121 @@ " \"content\": [\"TextBox widget\"]", " }", " ]", - "}" + "}", + "-------------------------------", + "§lContents§r" + ] + }, + { + "type": "textbox", + "link": "section", + "content": [ + " 1.§nsection§r" + ] + }, + { + "type": "textbox", + "link": "title", + "content": [ + " 2.§ntitle§r" + ] + }, + { + "type": "textbox", + "link": "stream", + "content": [ + " 3.§nstream§r" + ] + }, + { + "type": "textbox", + "link": "fixed", + "content": [ + " 4.§nfixed§r" + ] + }, + { + "type": "textbox", + "ref": "section", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §nsection§r (§4required§r)", + "§ltype§r: String", + "§lillustrate§r: Specifies which section of the application the page belongs to.", + "The application automatically merges pages of the same section name and builds a directory tree." + ] + }, + { + "type": "textbox", + "ref": "title", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §ntitle§r (§4required§r)", + "§ltype§r: String", + "§lillustrate§r: The page title." + ] + }, + { + "type": "textbox", + "ref": "stream", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §nstream§r (§4required§r)", + "§ltype§r: Array", + "§lillustrate§r: Widgets in streaming layout. You don't need to care the position and size of widgets in stream, all typography will be done automatically." + ] + }, + { + "type": "textbox", + "ref": "fixed", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §nfixed§r (§4required§r)", + "§ltype§r: Array", + "§lillustrate§r: Widgets in fixed layout. You need to specify the position and size of each widget." + ] + }, + { + "type": "textbox", + "isCenter": true, + "content": [ + "§lDemo§r: fixed and stream" + ] + }, + { + "type": "textbox", + "isCenter": true, + "hover_text": ["stream widget"], + "content": [ + "§nMinecraft Formatting", + "§r§00 §11 §22 §33", + "§44 §55 §66 §77", + "§88 §99 §aa §bb", + "§cc §dd §ee §ff", + "§r§0k §kMinecraft", + "§rl §lMinecraft", + "§rm §mMinecraft", + "§rn §nMinecraft", + "§ro §oMinecraft", + "§rr §rMinecraft" ] } ], - "fixed": [] + "fixed": [ + { + "type": "image", + "x": 30, + "y": 800, + "stroke": 4278190335, + "hover_text": ["fixed widget", "\"x\": 30","\"y\": 800","\"width\": 100","\"width\": 100"], + "form": "item", + "source": "minecraft:ender_pearl", + "width": 100, + "height": 100 + } + ] } diff --git a/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_1_widget.json b/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_1_widget.json new file mode 100644 index 00000000000..6ff3a760930 --- /dev/null +++ b/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_1_widget.json @@ -0,0 +1,304 @@ +{ + "section": "Guide Widget API", + "title": "Guide Widget", + "stream": [ + { + "type": "textbox", + "content": [ + "In this page we'll learn what is §4§lGuide Widget§r, and its public attributes.", + "Widgets are rendered in the Guide Page, which is the basis for your custom pages. §nTextbox§r, §nImage§r, etc", + "To use it, just add the related JSON code under the §l\"fixed\"§r or §l\"stream\"§r.", + "There are some attributes effects (styles) that are valid for all widgets", + "-------------------------------", + "§lJSON§r:", + "{", + " \"type\": \"type here\",", + " \"x\": 50,", + " \"y\": 100,", + " \"width\": 150,", + " \"height\": 40,", + " \"ref\": \"ref\",", + " \"stroke\": 0,", + " \"stroke_width\": 1,", + " \"fill\": 0,", + " \"link\": \"ref\"", + " \"hover_text\": [\"text here\"]", + "}", + "-------------------------------", + "§lContents§r" + ] + }, + { + "type": "textbox", + "link": "type", + "content": [ + " 1.§ntype§r" + ] + }, + { + "type": "textbox", + "link": "xywh", + "content": [ + " 2.§nx, y, width, height§r" + ] + }, + { + "type": "textbox", + "link": "ref", + "content": [ + " 3.§nref§r" + ] + }, + { + "type": "textbox", + "link": "fill", + "content": [ + " 4.§nfill§r" + ] + }, + { + "type": "textbox", + "link": "stroke", + "content": [ + " 5.§nstroke§r" + ] + }, + { + "type": "textbox", + "link": "stroke_width", + "content": [ + " 6.§nstroke_width§r" + ] + }, + { + "type": "textbox", + "link": "link", + "content": [ + " 7.§nlink§r" + ] + }, + { + "type": "textbox", + "link": "hover", + "content": [ + " 8.§nhover_text§r" + ] + }, + { + "type": "textbox", + "ref": "type", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §ntype§r (§4required§r)", + "§ltype§r: String", + "§lillustrate§r: This is the unique id of the widget. See the API documentation for each widget." + ] + }, + { + "type": "textbox", + "ref": "xywh", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §nx, y, width, height§r (§4optional§r)", + "§ltype§r: Integer", + "§lillustrate§r: The position and size of the widget. In a stream layout, you usually don't need to set it (the image widget needs to set width and height). Under fixed layout you must set these four attributes." + ] + }, + { + "type": "textbox", + "ref": "ref", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §nref§r (§4optional§r)", + "§ltype§r: String", + "§ldefault§r: null", + "§lillustrate§r: This is a tag of this widget. The ref should be unique on the same page." + ] + }, + { + "type": "textbox", + "ref": "fill", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §nfill§r (§6optional§r)", + "§ltype§r: Number", + "§ldefault§r: 0", + "§lillustrate§r: The background color." + ] + }, + { + "type": "textbox", + "isCenter": true, + "content": [ + "§lDemo§r: 4278190335 (0xFF0000FF)" + ] + }, + { + "type": "textbox", + "isCenter": true, + "fill": 4278190335, + "content": [ + "§nMinecraft Formatting", + "§r§00 §11 §22 §33", + "§44 §55 §66 §77", + "§88 §99 §aa §bb", + "§cc §dd §ee §ff", + "§r§0k §kMinecraft", + "§rl §lMinecraft", + "§rm §mMinecraft", + "§rn §nMinecraft", + "§ro §oMinecraft", + "§rr §rMinecraft" + ] + }, + { + "type": "textbox", + "ref": "stroke", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §nstroke§r (§6optional§r)", + "§ltype§r: Number", + "§ldefault§r: 0", + "§lillustrate§r: The border color." + ] + }, + { + "type": "textbox", + "isCenter": true, + "content": [ + "§lDemo§r: 4278190335 (0xFF0000FF)" + ] + }, + { + "type": "image", + "form": "item", + "source": "minecraft:ender_pearl", + "stroke": 4278190335, + "width": 50, + "height": 50 + }, + { + "type": "textbox", + "ref": "stroke_width", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §nstroke_width§r (§6optional§r)", + "§ltype§r: Number", + "§ldefault§r: 1", + "§lillustrate§r: The border width." + ] + }, + { + "type": "textbox", + "isCenter": true, + "content": [ + "§lDemo§r: 5" + ] + }, + { + "type": "image", + "form": "item", + "source": "minecraft:ender_pearl", + "stroke": 4278190335, + "stroke_width": 5, + "width": 50, + "height": 50 + }, + { + "type": "textbox", + "ref": "link", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §nlink§r (§6optional§r)", + "§ltype§r: String", + "§ldefault§r: null", + "§lillustrate§r: Click to jump to the specified location. Need to be used with ref, target is ref." + ] + }, + { + "type": "textbox", + "isCenter": true, + "content": [ + "§lDemo§r: \"P2\"" + ] + }, + { + "type": "textbox", + "isCenter": true, + "fill": 4286430975, + "hover_text": ["\"ref\": \"P1\""], + "ref": "P1", + "link": "P2", + "content": ["Click Me!"] + }, + { + "type": "textbox", + "content": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ] + }, + { + "type": "textbox", + "isCenter": true, + "content": [ + "§lDemo§r: \"P1\"" + ] + }, + { + "type": "textbox", + "isCenter": true, + "fill": 4286430975, + "hover_text": ["\"ref\": \"P2\""], + "ref": "P2", + "link": "P1", + "content": ["Click Me!"] + }, + { + "type": "textbox", + "ref": "hover", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §nhover_text§r (§6optional§r)", + "§ltype§r: Array", + "§ldefault§r: null", + "§lillustrate§r: Displays text when the mouse is over the widget." + ] + }, + { + "type": "textbox", + "isCenter": true, + "content": [ + "§lDemo§r: [\"THIS IS\",\"GT ICON\"]" + ] + }, + { + "type": "image", + "hover_text": ["THIS IS","GT ICON"], + "form": "resource", + "source": "gregtech:textures/gui/icon/gregtech_logo.png", + "width": 100, + "height": 100 + } + ], + "fixed": [] +} diff --git a/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_2_image.json b/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_2_image.json deleted file mode 100644 index fa1276130c4..00000000000 --- a/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_2_image.json +++ /dev/null @@ -1,80 +0,0 @@ -{ - "section": "Guide Widget API", - "title": "Image Widget", - "stream": [ - { - "type": "textbox", - "content": [ - "In this section we'll learn how to add an §4§lImage§r. There are three different forms of image supported here: §4Url§r, §4Item§r, and §4ResourceLocation§r. Don't worry, it's easy", - "-------------------------------", - "§lWidget Type§r: §nimage§r", - "-------------------------------", - "§lJSON§r:", - "{", - " \"type\": \"image\",", - " \"form\": \"Item\",", - " \"source\": \"minecraft:ender_pearl\",", - " \"width\": 100,", - " \"height\": 100", - "}" - ] - }, { - "type": "textbox", - "content": [ - "-------------------------------", - "", - "§lAttr§r: §nform§r (§4required§r)", - "§ltype§r: String", - "§lillustrate§r: It can only be set one of §Url§r, §4Item§r, or §4ResourceLocation§r.", - " \"url\" -- image url.", - " \"item\" -- The registered name of the Item in game.", - " \"resource\" -- The resource location." - ] - }, - { - "type": "textbox", - "isCenter": true, - "content": [ - "§lDemo§r: \"url\"" - ] - }, - { - "type": "image", - "form": "url", - "source": "https://i.pinimg.com/originals/38/9d/e7/389de7ca61163911e72d4adcaabe1433.gif", - "stroke": 4278190080, - "stroke_width": 2, - "width": 100, - "height": 100 - }, - { - "type": "textbox", - "isCenter": true, - "content": [ - "§lDemo§r: \"item\"" - ] - }, - { - "type": "image", - "form": "item", - "source": "minecraft:ender_pearl", - "width": 100, - "height": 100 - }, - { - "type": "textbox", - "isCenter": true, - "content": [ - "§lDemo§r: \"resource\"" - ] - }, - { - "type": "image", - "form": "resource", - "source": "textures/gui/icon/gregtech_logo.png", - "width": 100, - "height": 100 - } - ], - "fixed": [] -} diff --git a/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_1_textbox.json b/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_2_textbox.json similarity index 78% rename from src/main/resources/assets/gregtech/terminal/guide/tutorials/api_1_textbox.json rename to src/main/resources/assets/gregtech/terminal/guide/tutorials/api_2_textbox.json index 8f20574c947..416286361a7 100644 --- a/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_1_textbox.json +++ b/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_2_textbox.json @@ -1,11 +1,11 @@ { "section": "Guide Widget API", - "title": "TextBox Widget", + "title": "1. TextBox Widget", "stream": [ { "type": "textbox", "content": [ - "In this section we'll learn how to use the powerful §4§lTextBox§r, which is the most commonly used. So you should read the API documentation carefully.", + "In this page we'll learn how to use the powerful §4§lTextBox§r, which is the most commonly used. So you should read the API documentation carefully.", "-------------------------------", "§lWidget Type§r: §ntextbox§r", "-------------------------------", @@ -15,15 +15,59 @@ " \"space\": 1,", " \"fontSize\": 9,", " \"fontColor\": 4278190080,", - " \"fill\": 0,", - " \"stroke\": 0,", " \"isCenter\": false,", " \"isShadow\": false,", " \"content\": [\"content here!\"]", - "}" + "}", + "-------------------------------", + "§lContents§r" ] - }, { + }, + { "type": "textbox", + "link": "content", + "content": [ + " 1.§ncontent§r" + ] + }, + { + "type": "textbox", + "link": "space", + "content": [ + " 2.§nspace§r" + ] + }, + { + "type": "textbox", + "link": "fontSize", + "content": [ + " 3.§nfontSize§r" + ] + }, + { + "type": "textbox", + "link": "fontColor", + "content": [ + " 4.§nfontColor§r" + ] + }, + { + "type": "textbox", + "link": "isCenter", + "content": [ + " 5.§nisCenter§r" + ] + }, + { + "type": "textbox", + "link": "isShadow", + "content": [ + " 6.§nisShadow§r" + ] + }, + { + "type": "textbox", + "ref": "content", "content": [ "-------------------------------", "", @@ -53,6 +97,7 @@ }, { "type": "textbox", + "ref": "space", "content": [ "-------------------------------", "", @@ -83,6 +128,7 @@ ] },{ "type": "textbox", + "ref": "fontSize", "content": [ "-------------------------------", "", @@ -113,6 +159,7 @@ ] },{ "type": "textbox", + "ref": "fontColor", "content": [ "-------------------------------", "", @@ -141,67 +188,10 @@ "§ro §oMinecraft", "§rr §rMinecraft" ] - },{ - "type": "textbox", - "content": [ - "-------------------------------", - "", - "§lAttr§r: §nfill§r (§6optional§r)", - "§ltype§r: Number", - "§ldefault§r: 0", - "§lillustrate§r: The background color." - ] }, { "type": "textbox", - "isCenter": true, - "stroke": 4294901760, - "fill": 4278190335, - "content": [ - "§lDemo§r: 4278190335 (0xFF0000FF)", - "§nMinecraft Formatting", - "§r§00 §11 §22 §33", - "§44 §55 §66 §77", - "§88 §99 §aa §bb", - "§cc §dd §ee §ff", - "§r§0k §kMinecraft", - "§rl §lMinecraft", - "§rm §mMinecraft", - "§rn §nMinecraft", - "§ro §oMinecraft", - "§rr §rMinecraft" - ] - },{ - "type": "textbox", - "content": [ - "-------------------------------", - "", - "§lAttr§r: §nstroke§r (§6optional§r)", - "§ltype§r: Number", - "§ldefault§r: 0", - "§lillustrate§r: The border color." - ] - }, - { - "type": "textbox", - "isCenter": true, - "stroke": 4278190335, - "content": [ - "§lDemo§r: 4278190335 (0xFF0000FF)", - "§nMinecraft Formatting", - "§r§00 §11 §22 §33", - "§44 §55 §66 §77", - "§88 §99 §aa §bb", - "§cc §dd §ee §ff", - "§r§0k §kMinecraft", - "§rl §lMinecraft", - "§rm §mMinecraft", - "§rn §nMinecraft", - "§ro §oMinecraft", - "§rr §rMinecraft" - ] - },{ - "type": "textbox", + "ref": "isCenter", "content": [ "-------------------------------", "", @@ -231,6 +221,7 @@ ] },{ "type": "textbox", + "ref": "isShadow", "content": [ "-------------------------------", "", diff --git a/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_3_image.json b/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_3_image.json new file mode 100644 index 00000000000..0305b73fa87 --- /dev/null +++ b/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_3_image.json @@ -0,0 +1,207 @@ +{ + "section": "Guide Widget API", + "title": "2. Image Widget", + "stream": [ + { + "type": "textbox", + "content": [ + "In this page we'll learn how to add an §4§lImage§r. There are three different forms of image supported here: §4Url§r, §4Item§r, and §4ResourceLocation§r. Don't worry, it's easy", + "-------------------------------", + "§lWidget Type§r: §nimage§r", + "-------------------------------", + "§lJSON§r:", + "{", + " \"type\": \"image\",", + " \"form\": \"Item\",", + " \"source\": \"minecraft:ender_pearl\",", + " \"width\": 100,", + " \"height\": 100", + "}", + "-------------------------------", + "§lContents§r" + ] + }, + { + "type": "textbox", + "link": "form", + "content": [ + " 1.§nform§r" + ] + }, + { + "type": "textbox", + "link": "source", + "content": [ + " 2.§nsource§r" + ] + }, + { + "type": "textbox", + "link": "wh", + "content": [ + " 3.§nwidth, height§r" + ] + }, + { + "type": "textbox", + "ref": "form", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §nform§r (§4required§r)", + "§ltype§r: String", + "§lillustrate§r: It can only be set one of §4Url§r, §4Item§r, or §4ResourceLocation§r.", + " \"url\" -- image url.", + " \"item\" -- The registered name of the Item in game.", + " \"resource\" -- The resource location." + ] + }, + { + "type": "textbox", + "isCenter": true, + "content": [ + "§lDemo§r: \"url\"" + ] + }, + { + "type": "image", + "hover_text": ["https://z3.ax1x.com/2021/07/29/Wb4Djs.gif"], + "form": "url", + "source": "https://z3.ax1x.com/2021/07/29/Wb4Djs.gif", + "stroke": 4278190080, + "stroke_width": 2, + "width": 100, + "height": 100 + }, + { + "type": "textbox", + "isCenter": true, + "content": [ + "§lDemo§r: \"item\"" + ] + }, + { + "type": "image", + "hover_text": ["minecraft:ender_pearl"], + "form": "item", + "source": "minecraft:ender_pearl", + "width": 100, + "height": 100 + }, + { + "type": "textbox", + "isCenter": true, + "content": [ + "§lDemo§r: \"resource\"" + ] + }, + { + "type": "image", + "hover_text": ["gregtech:textures/gui/icon/coke_oven.png"], + "form": "resource", + "source": "gregtech:textures/gui/icon/coke_oven.png", + "width": 100, + "height": 100 + }, + { + "type": "textbox", + "ref": "source", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §nsource§r (§4required§r)", + "§ltype§r: String", + "§lillustrate§r: The source of the picture. The three images above correspond to the following sources:" + ] + }, + { + "type": "textbox", + "isCenter": true, + "content": [ + "§lDemo§r: \"https://z3.ax1x.com/2021/07/29/Wb4Djs.gif\"" + ] + }, + { + "type": "image", + "hover_text": ["https://z3.ax1x.com/2021/07/29/Wb4Djs.gif"], + "form": "url", + "source": "https://z3.ax1x.com/2021/07/29/Wb4Djs.gif", + "stroke": 4278190080, + "stroke_width": 2, + "width": 100, + "height": 100 + }, + { + "type": "textbox", + "isCenter": true, + "content": [ + "§lDemo§r: \"minecraft:ender_pearl\"" + ] + }, + { + "type": "image", + "hover_text": ["minecraft:ender_pearl"], + "form": "item", + "source": "minecraft:ender_pearl", + "width": 100, + "height": 100 + }, + { + "type": "textbox", + "isCenter": true, + "content": [ + "§lDemo§r: \"gregtech:textures/gui/icon/coke_oven.png\"" + ] + }, + { + "type": "image", + "hover_text": ["gregtech:textures/gui/icon/coke_oven.png"], + "form": "resource", + "source": "gregtech:textures/gui/icon/coke_oven.png", + "width": 100, + "height": 100 + }, + { + "type": "textbox", + "ref": "wh", + "content": [ + "-------------------------------", + "", + "§lAttr§r: §nwidth, height§r (§4required§r)", + "§ltype§r: Integer", + "§lillustrate§r: The Size of the picture." + ] + }, + { + "type": "textbox", + "isCenter": true, + "content": [ + "§lDemo§r: \"50, 50\"" + ] + }, + { + "type": "image", + "hover_text": ["minecraft:ender_pearl"], + "form": "item", + "source": "minecraft:ender_pearl", + "width": 50, + "height": 50 + }, + { + "type": "textbox", + "isCenter": true, + "content": [ + "§lDemo§r: \"100, 50\"" + ] + }, + { + "type": "image", + "hover_text": ["minecraft:ender_pearl"], + "form": "item", + "source": "minecraft:ender_pearl", + "width": 100, + "height": 50 + } + ], + "fixed": [] +} From e7af22baecc121f7f3bd000bc8e14cdf8f3e1295 Mon Sep 17 00:00:00 2001 From: Yefancy Date: Thu, 29 Jul 2021 23:51:46 +0800 Subject: [PATCH 25/58] os system --- .../java/gregtech/api/gui/GuiTextures.java | 3 + .../api/gui/widgets/AbstractWidgetGroup.java | 4 +- .../api/terminal/app/guide/GuideApp.java | 4 +- .../gui/widgets/TerminalMenuWidget.java | 54 ----------- .../gui/widgets/guide/GuidePageWidget.java | 6 +- .../gui/widgets/guide/TextTreeWidget.java | 2 +- .../gui/widgets/os/TerminalDesktopWidget.java | 13 +++ .../gui/widgets/os/TerminalMenuWidget.java | 91 ++++++++++++++++++ .../gui/widgets/os/TerminalOSWidget.java | 77 +++++++++++++++ .../api/util/interpolate/Interpolator.java | 35 ++++--- .../behaviors/GuideTerminalBehaviour.java | 12 ++- .../gui/terminal/terminal_background.png | Bin 25109 -> 398697 bytes .../textures/gui/terminal/terminal_frame.png | Bin 0 -> 24072 bytes .../textures/gui/terminal/terminal_menu.png | Bin 0 -> 2798 bytes 14 files changed, 223 insertions(+), 78 deletions(-) delete mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/TerminalMenuWidget.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalDesktopWidget.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalMenuWidget.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalOSWidget.java create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/terminal_frame.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/terminal_menu.png diff --git a/src/main/java/gregtech/api/gui/GuiTextures.java b/src/main/java/gregtech/api/gui/GuiTextures.java index d073a19ffab..70e4af8789e 100644 --- a/src/main/java/gregtech/api/gui/GuiTextures.java +++ b/src/main/java/gregtech/api/gui/GuiTextures.java @@ -168,5 +168,8 @@ public class GuiTextures { public static final TextureArea MULTIBLOCK_CATEGORY = TextureArea.fullImage("textures/gui/icon/coke_oven.png"); //Terminal + public static final TextureArea TERMINAL_FRAME = TextureArea.fullImage("textures/gui/terminal/terminal_frame.png"); public static final TextureArea TERMINAL_BACKGROUND = TextureArea.fullImage("textures/gui/terminal/terminal_background.png"); + public static final TextureArea TERMINAL_MENU = TextureArea.fullImage("textures/gui/terminal/terminal_menu.png"); + } diff --git a/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java b/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java index 286c38be809..42b63d80cab 100644 --- a/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java +++ b/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java @@ -248,8 +248,8 @@ public boolean mouseWheelMove(int mouseX, int mouseY, int wheelDelta) { @Override public boolean mouseClicked(int mouseX, int mouseY, int button) { - for (Widget widget : widgets) { - if(widget.mouseClicked(mouseX, mouseY, button)) { + for (int i = widgets.size() - 1; i >= 0; i--) { + if(widgets.get(i).mouseClicked(mouseX, mouseY, button)) { return true; } } diff --git a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java index 4156d7a2abb..3fffd971337 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java @@ -39,7 +39,7 @@ public void loadApp(WidgetGroup group, boolean isClient) { pageWidget = null; if (isClient && getTree() != null) { group.addWidget( - new TextTreeWidget<>(0, 0, 100, 232, getTree(), leaf -> { + new TextTreeWidget<>(0, 0, 133, 232, getTree(), leaf -> { if (pageWidget != null) { group.removeWidget(pageWidget); } @@ -75,7 +75,7 @@ public static JsonObject getConfig(String fileName) { } private GuidePageWidget loadLeaf(TreeNode> leaf) { - GuidePageWidget page = new GuidePageWidget(100, 0, 200, 232); + GuidePageWidget page = new GuidePageWidget(133, 0, 200, 232); if (leaf.isLeaf() && leaf.content != null) { JsonObject config = leaf.content.getSecond(); // add title diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/TerminalMenuWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/TerminalMenuWidget.java deleted file mode 100644 index 673d6b5b7c8..00000000000 --- a/src/main/java/gregtech/api/terminal/gui/widgets/TerminalMenuWidget.java +++ /dev/null @@ -1,54 +0,0 @@ -package gregtech.api.terminal.gui.widgets; - -import gregtech.api.gui.IRenderContext; -import gregtech.api.gui.resources.IGuiTexture; -import gregtech.api.gui.widgets.AbstractWidgetGroup; -import gregtech.api.gui.widgets.WidgetGroup; -import gregtech.api.terminal.app.AbstractApplication; -import gregtech.api.util.Position; -import gregtech.api.util.Size; - -public class TerminalMenuWidget extends AbstractWidgetGroup { - private int appCount; - private IGuiTexture background; - private final WidgetGroup activeContent; - private CircleButtonWidget activeButton; - public TerminalMenuWidget(int xPosition, int yPosition, int width, int height) { - super(new Position(xPosition, yPosition), new Size(width, height)); - this.activeContent = new WidgetGroup(new Position(27,-19), new Size(300, 232)); - this.addWidget(activeContent); - } - - public TerminalMenuWidget setBackground(IGuiTexture background) { - this.background = background; - return this; - } - - public void addApp(AbstractApplication application){ - int x = this.getSize().width / 2; - int r = 12; - int y = appCount * (2 * r + 4) + r; - CircleButtonWidget button = new CircleButtonWidget(x,y,r).setIcon(application.getIcon()).setHoverText(application.getName()); - button.setClickListener(clickData -> { - if (button != activeButton) { - activeContent.clearAllWidgets(); - application.loadApp(activeContent, clickData.isClient); - if (activeButton != null) { - activeButton.setFillColors(0xffffffff); - } - activeButton = button; - activeButton.setFillColors(0xFFAAF1DB); - } - }); - this.addWidget(button); - appCount++; - } - - @Override - public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { - if( background != null) { - background.draw(this.getPosition().x, this.getPosition().y, this.getSize().width, this.getSize().height); - } - super.drawInBackground(mouseX, mouseY, partialTicks, context); - } -} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java index efcc5110d43..1cfaea846e4 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java @@ -56,9 +56,9 @@ public void jumpToRef(String ref){ if (interpolator != null && !interpolator.isFinish()) return; for (Widget widget : widgets) { if (widget instanceof IGuideWidget && ref.equals(((IGuideWidget) widget).getRef())) { - interpolator = new Interpolator(scrollYOffset, widget.getSelfPosition().y, 20, Eases.EaseQuadOut, (value)->{ - setScrollYOffset(value.intValue()); - }); + interpolator = new Interpolator(scrollYOffset, widget.getSelfPosition().y, 20, Eases.EaseQuadOut, + value-> setScrollYOffset(value.intValue()), + value-> interpolator = null); interpolator.start(); } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java index ecd8db3fbad..e7e96cdb565 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java @@ -79,7 +79,7 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender if (background != null) { background.draw(position.x, position.y, size.width, size.height); } else { - gregtech.api.gui.resources.RenderUtil.renderRect(position.x, position.y, size.width, size.height, 0, 0x8f000000); + drawGradientRect(position.x, position.y, size.width, size.height, 0x8f000000, 0x8f000000); } RenderUtil.useScissor(position.x, position.y, size.width, size.height, ()->{ FontRenderer fr = Minecraft.getMinecraft().fontRenderer; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalDesktopWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalDesktopWidget.java new file mode 100644 index 00000000000..ccdf5f1ede2 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalDesktopWidget.java @@ -0,0 +1,13 @@ +package gregtech.api.terminal.gui.widgets.os; + +import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.util.Position; +import gregtech.api.util.Size; + +public class TerminalDesktopWidget extends WidgetGroup { + private final TerminalOSWidget os; + public TerminalDesktopWidget(Position position, Size size, TerminalOSWidget os) { + super(position, size); + this.os = os; + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalMenuWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalMenuWidget.java new file mode 100644 index 00000000000..83f5209e4fb --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalMenuWidget.java @@ -0,0 +1,91 @@ +package gregtech.api.terminal.gui.widgets.os; + +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.terminal.app.AbstractApplication; +import gregtech.api.terminal.gui.widgets.CircleButtonWidget; +import gregtech.api.util.Position; +import gregtech.api.util.Size; +import gregtech.api.util.interpolate.Eases; +import gregtech.api.util.interpolate.Interpolator; +import net.minecraft.client.renderer.GlStateManager; + +public class TerminalMenuWidget extends WidgetGroup { + private Interpolator interpolator; + private int appCount; + private IGuiTexture background; + private CircleButtonWidget activeButton; + private final TerminalOSWidget os; + public boolean isHide; + + + public TerminalMenuWidget(Position position, Size size, TerminalOSWidget os) { + super(position, size); + this.os = os; + } + + public TerminalMenuWidget setBackground(IGuiTexture background) { + this.background = background; + return this; + } + + public void addApp(AbstractApplication application){ + int x = this.getSize().width / 2; + int r = 12; + int y = appCount * (2 * r + 4) + r + 20; + CircleButtonWidget button = new CircleButtonWidget(x,y,r).setIcon(application.getIcon()).setHoverText(application.getName()); + button.setClickListener(clickData -> { + if (button != activeButton) { + os.openApplication(application, clickData.isClient); + if (activeButton != null) { + activeButton.setFillColors(0xffffffff); + } + activeButton = button; + activeButton.setFillColors(0xFFAAF1DB); + } + }); + this.addWidget(button); + appCount++; + } + + public void hideMenu() { + if (!isHide && interpolator == null) { + int y = getSelfPosition().y; + interpolator = new Interpolator(getSelfPosition().x, getSelfPosition().x - getSize().width, 10, Eases.EaseLinear, + value-> setSelfPosition(new Position(value.intValue(), y)), + value-> interpolator = null); + interpolator.start(); + isHide = true; + } + } + + public void showMenu() { + if (isHide && interpolator == null) { + int y = getSelfPosition().y; + interpolator = new Interpolator(getSelfPosition().x, getSelfPosition().x + getSize().width, 10, Eases.EaseLinear, + value-> setSelfPosition(new Position(value.intValue(), y)), + value-> interpolator = null); + interpolator.start(); + isHide = false; + } + } + + @Override + public void updateScreen() { + if(interpolator != null) interpolator.update(); + super.updateScreen(); + } + + @Override + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + GlStateManager.color(1,1,1,0.5f); + if( background != null) { + background.draw(this.getPosition().x, this.getPosition().y, this.getSize().width, this.getSize().height); + } else { + drawGradientRect(this.getPosition().x, this.getPosition().y, this.getSize().width, this.getSize().height, 0xff000000, 0xff000000); + } + GlStateManager.color(1,1,1,1); + super.drawInBackground(mouseX, mouseY, partialTicks, context); + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalOSWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalOSWidget.java new file mode 100644 index 00000000000..24e531a82f8 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalOSWidget.java @@ -0,0 +1,77 @@ +package gregtech.api.terminal.gui.widgets.os; + +import gregtech.api.gui.GuiTextures; +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.widgets.AbstractWidgetGroup; +import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.terminal.app.AbstractApplication; +import gregtech.api.terminal.gui.widgets.CircleButtonWidget; +import gregtech.api.util.Position; +import gregtech.api.util.Size; +import gregtech.api.util.interpolate.Eases; +import gregtech.api.util.interpolate.Interpolator; +import javafx.application.Application; +import javafx.geometry.Pos; +import net.minecraft.client.renderer.GlStateManager; + +import java.util.ArrayList; +import java.util.List; + +public class TerminalOSWidget extends AbstractWidgetGroup { + private IGuiTexture background; + private final List apps; + private final TerminalMenuWidget menu; + private final TerminalDesktopWidget desktop; + + public TerminalOSWidget(int xPosition, int yPosition, int width, int height) { + super(new Position(xPosition, yPosition), new Size(width, height)); + this.apps = new ArrayList<>(); + this.desktop = new TerminalDesktopWidget(new Position(0,0), new Size(333, 232), this); + this.menu = new TerminalMenuWidget(new Position(0,0), new Size(35, 232), this).setBackground(GuiTextures.TERMINAL_MENU); + this.addWidget(desktop); + this.addWidget(menu); + } + + public TerminalOSWidget setBackground(IGuiTexture background) { + this.background = background; + return this; + } + + public void installApplication(AbstractApplication application){ + apps.add(application); + menu.addApp(application); + } + + public void openApplication(AbstractApplication application, boolean isClient) { + desktop.clearAllWidgets(); + application.loadApp(desktop, isClient); + } + + public void backToHome() { + } + + @Override + public boolean mouseClicked(int mouseX, int mouseY, int button) { + if (super.mouseClicked(mouseX, mouseY, button)) { + return true; + } else { + if (menu.isHide) { + menu.showMenu(); + } else { + menu.hideMenu(); + } + } + return true; + } + + @Override + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + if( background != null) { + background.draw(this.getPosition().x, this.getPosition().y, this.getSize().width, this.getSize().height); + } else { + drawGradientRect(this.getPosition().x, this.getPosition().y, this.getSize().width, this.getSize().height, -1, -1); + } + super.drawInBackground(mouseX, mouseY, partialTicks, context); + } +} diff --git a/src/main/java/gregtech/api/util/interpolate/Interpolator.java b/src/main/java/gregtech/api/util/interpolate/Interpolator.java index 2eef08dea52..7e73e7a8e58 100644 --- a/src/main/java/gregtech/api/util/interpolate/Interpolator.java +++ b/src/main/java/gregtech/api/util/interpolate/Interpolator.java @@ -1,32 +1,42 @@ package gregtech.api.util.interpolate; +import crafttweaker.IAction; +import gregtech.api.util.function.BooleanConsumer; import net.minecraft.util.ITickable; +import scala.Function; +import scala.swing.Action; import java.util.function.Consumer; public class Interpolator implements ITickable { - float from; - float to; - int duration; - IEase ease; - Consumer callback; + private final float from; + private final float to; + private final int duration; + private final IEase ease; + private final Consumer interpolate; + private final Consumer callback; - int tick = -1; + private int tick = 0; - public Interpolator(float from, float to, int duration, IEase ease, Consumer callback) { + public Interpolator(float from, float to, int duration, IEase ease, Consumer interpolate) { + this(from, to, duration, ease, interpolate, null); + } + + public Interpolator(float from, float to, int duration, IEase ease, Consumer interpolate, Consumer callback) { this.from = from; this.to = to; this.duration = duration; this.ease = ease; + this.interpolate = interpolate; this.callback = callback; } public void reset() { - tick = -1; + tick = 0; } public void start() { - tick = 0; + tick = 1; } public boolean isFinish(){ @@ -35,8 +45,11 @@ public boolean isFinish(){ @Override public void update() { - if (tick < 0 || tick >= duration) return; - callback.accept(ease.getInterpolation(tick * 1.0f / duration) * (to - from) + from); + if (tick < 1 || tick > duration) return; + if (tick == duration) { + callback.accept(ease.getInterpolation(tick * 1.0f / duration) * (to - from) + from); + } + interpolate.accept(ease.getInterpolation(tick * 1.0f / duration) * (to - from) + from); tick++; } } diff --git a/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java b/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java index 8cc400aa343..82d0d45dc11 100644 --- a/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java +++ b/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java @@ -2,11 +2,12 @@ import gregtech.api.gui.GuiTextures; import gregtech.api.gui.ModularUI; +import gregtech.api.gui.widgets.ImageWidget; import gregtech.api.items.gui.ItemUIFactory; import gregtech.api.items.gui.PlayerInventoryHolder; import gregtech.api.items.metaitem.stats.IItemBehaviour; import gregtech.api.terminal.TerminalBuilder; -import gregtech.api.terminal.gui.widgets.TerminalMenuWidget; +import gregtech.api.terminal.gui.widgets.os.TerminalOSWidget; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.util.ActionResult; @@ -34,10 +35,11 @@ public void addInformation(ItemStack itemStack, List lines) { @Override public ModularUI createUI(PlayerInventoryHolder holder, EntityPlayer entityPlayer) { - TerminalMenuWidget menu = new TerminalMenuWidget(15, 30, 24, 24); - TerminalBuilder.getApplications().forEach(menu::addApp); - return ModularUI.builder(GuiTextures.TERMINAL_BACKGROUND, 380, 256) - .widget(menu) + TerminalOSWidget os = new TerminalOSWidget(12, 11, 333, 232).setBackground(GuiTextures.TERMINAL_BACKGROUND); + TerminalBuilder.getApplications().forEach(os::installApplication); + return ModularUI.builder(GuiTextures.TERMINAL_FRAME, 380, 256) + .widget(os) + .widget(new ImageWidget(0, 0, 380, 256, GuiTextures.TERMINAL_FRAME)) .build(holder, entityPlayer); } } diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_background.png b/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_background.png index 3bb4031f9c1324203ff6cc74b891bdd4a13e2a3f..e7a6cf37cdbec068c9478bf130b6cc07667a4e1c 100644 GIT binary patch literal 398697 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 tHo3?QDO7z`!Ew-J>Q|R{{ZX@#ajRX literal 25109 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_menu.png b/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_menu.png new file mode 100644 index 0000000000000000000000000000000000000000..3a2c78e329fbef69538d22bcf820558000b9b9ff GIT binary patch literal 2798 zcmeHJO^@3|81^EHXi+85N~l5{EEkDZF!qe?*cq#)Y@MYE!pmwKX_pgBX2yxNvB%i6 zn`AFYy&!HJxPU5g;(&yJdk>U9fVgphUjRbAaYT&sVYcn|gA~CdcLh`Peso@qekDndGk~CI9qhzt2FJo_4>D_eR1o8rk(jC z?eEFG_?>`?%p^<KAhzAtbsHkzg1&_u08s$Fz`^?RW2k5)OM;!wTgzDLEi^__7J+3=CKGew zn4%n72xDwP+p=w-5TKgnl1xEfU0gAActy*!kg3S^nvo2|fea0$ba8~NXlV0lX_GR{ znv%joCajM%2Qu2=ii2`I56-B?$2{Y?tP~bC*kUB4s7B%;)Xnle0hG0I+{8FhOO`bu zD!F;6j*G&cvj; zd<@PzMDozEp^X6afsOmfu5$*x*I+wPmObjA17NrWT)H%oJdr`DqiXg|d(nnOuB1|O`IUyzA7%J}`Q-jvSq*vtd(ZZiBkqbo+2*1B(|GV&| zC3HmcAy>WCGU}sPbr)JB#JWFM^R;6gYXw(rupT!3SG_bHoac(VRQ(xDc3;-Cr@!uX zHu}?BfByXA**oz0JKw+Z+uy(b_2mn{zkj*Ae&O!tvlqYn>6f*SNS~d4PaQaQ;M9Tt d$pN```_(faUt0g{tNI^lZ*!~j?X?eX{sU(co-zOc literal 0 HcmV?d00001 From 148cabb0e26b7cbd77a12e2e2b491c0453e02f92 Mon Sep 17 00:00:00 2001 From: KilaBash Date: Fri, 30 Jul 2021 01:33:17 +0800 Subject: [PATCH 26/58] os --- .../java/gregtech/api/gui/GuiTextures.java | 2 + .../api/terminal/app/AbstractApplication.java | 15 +++-- .../api/terminal/app/guide/GuideApp.java | 13 ++-- .../api/terminal/app/guide/ItemGuideApp.java | 5 ++ .../app/guide/MultiBlockGuideApp.java | 5 ++ .../app/guide/SimpleMachineGuideApp.java | 5 ++ .../terminal/app/guide/TutorialGuideApp.java | 5 ++ .../gui/widgets/CircleButtonWidget.java | 2 +- .../gui/widgets/os/TerminalMenuWidget.java | 4 ++ .../gui/widgets/os/TerminalOSWidget.java | 57 ++++++++++++------ .../behaviors/GuideTerminalBehaviour.java | 3 + .../textures/gui/terminal/terminal_home.png | Bin 0 -> 2882 bytes 12 files changed, 86 insertions(+), 30 deletions(-) create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/terminal_home.png diff --git a/src/main/java/gregtech/api/gui/GuiTextures.java b/src/main/java/gregtech/api/gui/GuiTextures.java index 70e4af8789e..00c06b527e5 100644 --- a/src/main/java/gregtech/api/gui/GuiTextures.java +++ b/src/main/java/gregtech/api/gui/GuiTextures.java @@ -171,5 +171,7 @@ public class GuiTextures { public static final TextureArea TERMINAL_FRAME = TextureArea.fullImage("textures/gui/terminal/terminal_frame.png"); public static final TextureArea TERMINAL_BACKGROUND = TextureArea.fullImage("textures/gui/terminal/terminal_background.png"); public static final TextureArea TERMINAL_MENU = TextureArea.fullImage("textures/gui/terminal/terminal_menu.png"); + public static final TextureArea TERMINAL_HOME = TextureArea.fullImage("textures/gui/terminal/terminal_home.png"); + } diff --git a/src/main/java/gregtech/api/terminal/app/AbstractApplication.java b/src/main/java/gregtech/api/terminal/app/AbstractApplication.java index b1d2fd1ffaf..da6ecf8a6c2 100644 --- a/src/main/java/gregtech/api/terminal/app/AbstractApplication.java +++ b/src/main/java/gregtech/api/terminal/app/AbstractApplication.java @@ -1,14 +1,17 @@ package gregtech.api.terminal.app; -import gregtech.api.gui.Widget; import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.util.Position; +import gregtech.api.util.Size; +import net.minecraft.nbt.NBTTagCompound; -public abstract class AbstractApplication { +public abstract class AbstractApplication extends WidgetGroup { protected final String name; protected final IGuiTexture icon; public AbstractApplication (String name, IGuiTexture icon) { + super(Position.ORIGIN, new Size(333, 232)); this.name = name; this.icon = icon; } @@ -21,12 +24,14 @@ public IGuiTexture getIcon() { return icon; } - public void loadApp(WidgetGroup group, boolean isClient) { + public abstract AbstractApplication openApp(boolean isClient, NBTTagCompound nbt); - } + public void closeApp(boolean isClient, NBTTagCompound nbt) { - public void unloadApp(boolean isClient) { + } + public boolean isBackgroundApp() { + return false; } } diff --git a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java index 3fffd971337..b07663f570c 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java @@ -12,6 +12,7 @@ import gregtech.api.terminal.gui.widgets.guide.*; import gregtech.api.terminal.util.TreeNode; import net.minecraft.client.Minecraft; +import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.ResourceLocation; import net.minecraft.util.Tuple; @@ -34,20 +35,24 @@ public GuideApp(String name, IGuiTexture icon) { super(name, icon); } + protected abstract GuideApp createAPP(); + @Override - public void loadApp(WidgetGroup group, boolean isClient) { + public GuideApp openApp(boolean isClient, NBTTagCompound nbt) { + GuideApp app = createAPP(); pageWidget = null; if (isClient && getTree() != null) { - group.addWidget( + app.addWidget( new TextTreeWidget<>(0, 0, 133, 232, getTree(), leaf -> { if (pageWidget != null) { - group.removeWidget(pageWidget); + app.removeWidget(pageWidget); } pageWidget = loadLeaf(leaf); - group.addWidget(pageWidget); + app.addWidget(pageWidget); }, this::itemIcon, this::itemName).setNodeTexture(GuiTextures.BORDERED_BACKGROUND).setLeafTexture(GuiTextures.SLOT_DARKENED) ); } + return app; } protected IGuiTexture itemIcon(T item) { diff --git a/src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java index a79e4d4acc6..ab11a1f1a8a 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java @@ -23,6 +23,11 @@ public ItemGuideApp() { super("Items Machines", new ItemStackTexture(MetaItems.SCANNER.getStackForm())); } + @Override + protected GuideApp> createAPP() { + return new ItemGuideApp(); + } + @Override protected TreeNode, JsonObject>> getTree() { return ROOT; diff --git a/src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java index 311e0dbec03..a68f32b377f 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java @@ -28,6 +28,11 @@ protected TreeNode> getTree() { return ROOT; } + @Override + protected GuideApp createAPP() { + return new MultiBlockGuideApp(); + } + @Override protected IGuiTexture itemIcon(MetaTileEntity item) { return new ItemStackTexture(item.getStackForm()); diff --git a/src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java index 633e4943ad9..06cef73351e 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java @@ -28,6 +28,11 @@ protected TreeNode> getTree() { return ROOT; } + @Override + protected GuideApp createAPP() { + return new SimpleMachineGuideApp(); + } + @Override protected IGuiTexture itemIcon(MetaTileEntity item) { return new ItemStackTexture(item.getStackForm()); diff --git a/src/main/java/gregtech/api/terminal/app/guide/TutorialGuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/TutorialGuideApp.java index 32aad915681..4d1c0e8b361 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/TutorialGuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/TutorialGuideApp.java @@ -39,6 +39,11 @@ public TutorialGuideApp() { super("Tutorials", new ItemStackTexture(Items.PAPER)); } + @Override + protected GuideApp createAPP() { + return new TutorialGuideApp(); + } + @Override protected TreeNode> getTree() { return ROOT; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java index 9eadc58360f..1f79d1ab114 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java @@ -91,7 +91,7 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender @Override public void drawInForeground(int mouseX, int mouseY) { - if (this.isMouseOverElement(mouseX, mouseY)) { + if (hoverText != null && this.isMouseOverElement(mouseX, mouseY)) { this.drawHoveringText(ItemStack.EMPTY, Collections.singletonList(I18n.format(hoverText)), 300, mouseX, mouseY); } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalMenuWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalMenuWidget.java index 83f5209e4fb..b3b427d1c51 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalMenuWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalMenuWidget.java @@ -62,6 +62,10 @@ public void hideMenu() { public void showMenu() { if (isHide && interpolator == null) { + if (activeButton != null) { + activeButton.setFillColors(0xffffffff); + } + activeButton = null; int y = getSelfPosition().y; interpolator = new Interpolator(getSelfPosition().x, getSelfPosition().x + getSize().width, 10, Eases.EaseLinear, value-> setSelfPosition(new Position(value.intValue(), y)), diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalOSWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalOSWidget.java index 24e531a82f8..db7f1fa7aa6 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalOSWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalOSWidget.java @@ -2,12 +2,14 @@ import gregtech.api.gui.GuiTextures; import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.Widget; import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.widgets.AbstractWidgetGroup; import gregtech.api.gui.widgets.WidgetGroup; import gregtech.api.terminal.app.AbstractApplication; import gregtech.api.terminal.gui.widgets.CircleButtonWidget; import gregtech.api.util.Position; +import gregtech.api.util.RenderUtil; import gregtech.api.util.Size; import gregtech.api.util.interpolate.Eases; import gregtech.api.util.interpolate.Interpolator; @@ -18,17 +20,19 @@ import java.util.ArrayList; import java.util.List; +import static gregtech.api.gui.impl.ModularUIGui.*; + public class TerminalOSWidget extends AbstractWidgetGroup { private IGuiTexture background; - private final List apps; + private final List openedApps; private final TerminalMenuWidget menu; private final TerminalDesktopWidget desktop; public TerminalOSWidget(int xPosition, int yPosition, int width, int height) { super(new Position(xPosition, yPosition), new Size(width, height)); - this.apps = new ArrayList<>(); - this.desktop = new TerminalDesktopWidget(new Position(0,0), new Size(333, 232), this); - this.menu = new TerminalMenuWidget(new Position(0,0), new Size(35, 232), this).setBackground(GuiTextures.TERMINAL_MENU); + this.openedApps = new ArrayList<>(); + this.desktop = new TerminalDesktopWidget(Position.ORIGIN, new Size(333, 232), this); + this.menu = new TerminalMenuWidget(Position.ORIGIN, new Size(35, 232), this).setBackground(GuiTextures.TERMINAL_MENU); this.addWidget(desktop); this.addWidget(menu); } @@ -39,39 +43,52 @@ public TerminalOSWidget setBackground(IGuiTexture background) { } public void installApplication(AbstractApplication application){ - apps.add(application); menu.addApp(application); } public void openApplication(AbstractApplication application, boolean isClient) { - desktop.clearAllWidgets(); - application.loadApp(desktop, isClient); + for (AbstractApplication app : openedApps) { + if (app.getClass() == application.getClass()) { + app.setVisible(true); + return; + } + } + AbstractApplication app = application.openApp(isClient, null); + openedApps.add(app); + desktop.addWidget(app); + menu.hideMenu(); } - public void backToHome() { + public void closeApplication(AbstractApplication application, boolean isClient) { + desktop.removeWidget(application); + application.closeApp(isClient, null); } - @Override - public boolean mouseClicked(int mouseX, int mouseY, int button) { - if (super.mouseClicked(mouseX, mouseY, button)) { - return true; - } else { - if (menu.isHide) { - menu.showMenu(); + public void backToHome() { + List close = new ArrayList<>(); + for (AbstractApplication app : openedApps) { + if (app.isBackgroundApp()) { + app.setVisible(false); } else { - menu.hideMenu(); + close.add(app); + closeApplication(app, isClientSide()); } } - return true; + close.forEach(openedApps::remove); + menu.showMenu(); } @Override public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + Position position = getPosition(); + Size size = getSize(); if( background != null) { - background.draw(this.getPosition().x, this.getPosition().y, this.getSize().width, this.getSize().height); + background.draw(position.x, position.y, size.width, size.height); } else { - drawGradientRect(this.getPosition().x, this.getPosition().y, this.getSize().width, this.getSize().height, -1, -1); + drawGradientRect(position.x, position.y, size.width, size.height, -1, -1); } - super.drawInBackground(mouseX, mouseY, partialTicks, context); + RenderUtil.useScissor(position.x, position.y, size.width, size.height, ()->{ + super.drawInBackground(mouseX, mouseY, partialTicks, context); + }); } } diff --git a/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java b/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java index 82d0d45dc11..c4bbe83c2b7 100644 --- a/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java +++ b/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java @@ -7,6 +7,7 @@ import gregtech.api.items.gui.PlayerInventoryHolder; import gregtech.api.items.metaitem.stats.IItemBehaviour; import gregtech.api.terminal.TerminalBuilder; +import gregtech.api.terminal.gui.widgets.CircleButtonWidget; import gregtech.api.terminal.gui.widgets.os.TerminalOSWidget; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; @@ -36,10 +37,12 @@ public void addInformation(ItemStack itemStack, List lines) { @Override public ModularUI createUI(PlayerInventoryHolder holder, EntityPlayer entityPlayer) { TerminalOSWidget os = new TerminalOSWidget(12, 11, 333, 232).setBackground(GuiTextures.TERMINAL_BACKGROUND); + CircleButtonWidget home = new CircleButtonWidget(362, 126, 12).setIcon(GuiTextures.TERMINAL_HOME).setFillColors(0xff9197A5).setClickListener(clickData -> os.backToHome()); TerminalBuilder.getApplications().forEach(os::installApplication); return ModularUI.builder(GuiTextures.TERMINAL_FRAME, 380, 256) .widget(os) .widget(new ImageWidget(0, 0, 380, 256, GuiTextures.TERMINAL_FRAME)) + .widget(home) .build(holder, entityPlayer); } } diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_home.png b/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_home.png new file mode 100644 index 0000000000000000000000000000000000000000..18829fb5fb4f947145a60f6b4b348d962423dc5a GIT binary patch literal 2882 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 literal 0 HcmV?d00001 From 4ae662382dc173d985742b34a7b31b9cc6ac974f Mon Sep 17 00:00:00 2001 From: Yefancy Date: Sat, 31 Jul 2021 00:54:13 +0800 Subject: [PATCH 27/58] guideeditor --- .../java/gregtech/api/gui/GuiTextures.java | 2 +- src/main/java/gregtech/api/gui/Widget.java | 16 ++- .../api/gui/resources/ItemStackTexture.java | 1 + .../api/gui/resources/RenderUtil.java | 2 - .../onlinepictexture/PictureTexture.java | 10 +- .../api/gui/widgets/AbstractWidgetGroup.java | 28 ++-- .../api/terminal/TerminalBuilder.java | 1 + .../api/terminal/app/AbstractApplication.java | 80 ++++++++++- .../api/terminal/app/GuideEditorApp.java | 22 +++ .../api/terminal/app/guide/GuideApp.java | 80 +++-------- .../api/terminal/app/guide/ItemGuideApp.java | 5 - .../app/guide/MultiBlockGuideApp.java | 5 - .../app/guide/SimpleMachineGuideApp.java | 5 - .../terminal/app/guide/TutorialGuideApp.java | 5 - .../gui/widgets/CircleButtonWidget.java | 16 ++- .../gui/widgets/guide/GuideEditor.java | 12 ++ .../widgets/guide/GuideEditorPageWidget.java | 127 ++++++++++++++++++ .../gui/widgets/guide/GuidePageWidget.java | 121 ++++++++++++++++- .../gui/widgets/guide/GuideWidget.java | 56 ++++++++ .../gui/widgets/guide/IGuideWidget.java | 1 + .../gui/widgets/guide/ImageWidget.java | 12 +- .../gui/widgets/guide/TextBoxWidget.java | 16 ++- .../gui/widgets/os/TerminalDesktopWidget.java | 35 +++++ .../gui/widgets/os/TerminalMenuWidget.java | 80 +++++++---- .../gui/widgets/os/TerminalOSWidget.java | 118 +++++++++++++--- .../api/util/interpolate/Interpolator.java | 3 +- .../behaviors/GuideTerminalBehaviour.java | 10 +- .../gui/terminal/guide_editor/icon.png | Bin 0 -> 32504 bytes .../textures/gui/terminal/terminal_close.png | Bin 0 -> 1798 bytes .../textures/gui/terminal/terminal_home.png | Bin 2882 -> 1496 bytes .../gui/terminal/terminal_minimum.png | Bin 0 -> 1672 bytes .../gui/terminal/terminal_setting.png | Bin 0 -> 1712 bytes 32 files changed, 703 insertions(+), 166 deletions(-) create mode 100644 src/main/java/gregtech/api/terminal/app/GuideEditorApp.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditor.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditorPageWidget.java create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/guide_editor/icon.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/terminal_close.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/terminal_minimum.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/terminal_setting.png diff --git a/src/main/java/gregtech/api/gui/GuiTextures.java b/src/main/java/gregtech/api/gui/GuiTextures.java index 00c06b527e5..a3414a5026d 100644 --- a/src/main/java/gregtech/api/gui/GuiTextures.java +++ b/src/main/java/gregtech/api/gui/GuiTextures.java @@ -172,6 +172,6 @@ public class GuiTextures { public static final TextureArea TERMINAL_BACKGROUND = TextureArea.fullImage("textures/gui/terminal/terminal_background.png"); public static final TextureArea TERMINAL_MENU = TextureArea.fullImage("textures/gui/terminal/terminal_menu.png"); public static final TextureArea TERMINAL_HOME = TextureArea.fullImage("textures/gui/terminal/terminal_home.png"); - + public static final TextureArea TERMINAL_SETTING = TextureArea.fullImage("textures/gui/terminal/terminal_setting.png"); } diff --git a/src/main/java/gregtech/api/gui/Widget.java b/src/main/java/gregtech/api/gui/Widget.java index 3538d352115..633b3f2b790 100644 --- a/src/main/java/gregtech/api/gui/Widget.java +++ b/src/main/java/gregtech/api/gui/Widget.java @@ -45,6 +45,7 @@ public abstract class Widget { private transient Position position; private transient Size size; private transient boolean isVisible; + private transient boolean isActive; public Widget(Position selfPosition, Size size) { Preconditions.checkNotNull(selfPosition, "selfPosition"); @@ -53,6 +54,7 @@ public Widget(Position selfPosition, Size size) { this.size = size; this.position = this.parentPosition.add(selfPosition); this.isVisible = true; + this.isActive = true; } public Widget(int x, int y, int width, int height) { @@ -77,7 +79,7 @@ public void setParentPosition(Position parentPosition) { recomputePosition(); } - protected void setSelfPosition(Position selfPosition) { + public void setSelfPosition(Position selfPosition) { Preconditions.checkNotNull(selfPosition, "selfPosition"); this.selfPosition = selfPosition; recomputePosition(); @@ -87,7 +89,7 @@ public Position getSelfPosition() { return selfPosition; } - protected void setSize(Size size) { + public void setSize(Size size) { Preconditions.checkNotNull(size, "size"); this.size = size; onSizeUpdate(); @@ -109,13 +111,21 @@ public void setVisible(boolean visible) { isVisible = visible; } + public boolean isActive() { + return isActive; + } + + public void setActive(boolean active) { + isActive = active; + } + public Rectangle toRectangleBox() { Position pos = getPosition(); Size size = getSize(); return new Rectangle(pos.x, pos.y, size.width, size.height); } - private void recomputePosition() { + protected void recomputePosition() { this.position = this.parentPosition.add(selfPosition); onPositionUpdate(); } diff --git a/src/main/java/gregtech/api/gui/resources/ItemStackTexture.java b/src/main/java/gregtech/api/gui/resources/ItemStackTexture.java index 1bcdc7a461d..bed8d58cccf 100644 --- a/src/main/java/gregtech/api/gui/resources/ItemStackTexture.java +++ b/src/main/java/gregtech/api/gui/resources/ItemStackTexture.java @@ -26,6 +26,7 @@ public void draw(double x, double y, int width, int height) { GlStateManager.translate(x * 16 / width, y * 16 / height, 0); RenderItem renderItem = Minecraft.getMinecraft().getRenderItem(); renderItem.renderItemAndEffectIntoGUI(itemStack, 0, 0); + GlStateManager.enableAlpha(); GlStateManager.popMatrix(); RenderHelper.disableStandardItemLighting(); } diff --git a/src/main/java/gregtech/api/gui/resources/RenderUtil.java b/src/main/java/gregtech/api/gui/resources/RenderUtil.java index b0dce74f99b..cf8a28ab440 100644 --- a/src/main/java/gregtech/api/gui/resources/RenderUtil.java +++ b/src/main/java/gregtech/api/gui/resources/RenderUtil.java @@ -139,7 +139,6 @@ public static void renderCircle(float x, float y, float r, int color, int segmen } tessellator.draw(); GlStateManager.enableTexture2D(); - GlStateManager.disableBlend(); } public static void renderSector(float x, float y, float r, int color, int segments, int from, int to) { @@ -159,7 +158,6 @@ public static void renderSector(float x, float y, float r, int color, int segmen } tessellator.draw(); GlStateManager.enableTexture2D(); - GlStateManager.disableBlend(); } public static void renderRect(float x, float y, float width, float height, float z, int color) { diff --git a/src/main/java/gregtech/api/gui/resources/onlinepictexture/PictureTexture.java b/src/main/java/gregtech/api/gui/resources/onlinepictexture/PictureTexture.java index 268734fb623..82efb803fae 100644 --- a/src/main/java/gregtech/api/gui/resources/onlinepictexture/PictureTexture.java +++ b/src/main/java/gregtech/api/gui/resources/onlinepictexture/PictureTexture.java @@ -24,7 +24,7 @@ public void draw(double x, double y, int width, int height) { render((float)x, (float)y, 1, 1, 0, width, height, false, false); } - public void render(float x, float y, float ux, float uv, float rotation, float sizeX, float sizeY, boolean flippedX, boolean flippedY) { + public void render(float x, float y, float width, float height, float rotation, float scaleX, float scaleY, boolean flippedX, boolean flippedY) { this.beforeRender(); GlStateManager.color(1,1,1,1); GlStateManager.enableBlend(); @@ -35,16 +35,16 @@ public void render(float x, float y, float ux, float uv, float rotation, float s GlStateManager.pushMatrix(); GL11.glRotated(rotation, 0, 0, 1); GlStateManager.enableRescaleNormal(); - GL11.glScaled(sizeX, sizeY, 1); + GL11.glScaled(scaleX, scaleY, 1); GL11.glBegin(GL11.GL_POLYGON); GL11.glTexCoord3f(flippedY ? 1 : 0, flippedX ? 1 : 0, 0); GL11.glVertex3f(x, y, 0.01f); GL11.glTexCoord3f(flippedY ? 1 : 0, flippedX ? 0 : 1, 0); - GL11.glVertex3f(x, y + uv, 0.01f); + GL11.glVertex3f(x, y + height, 0.01f); GL11.glTexCoord3f(flippedY ? 0 : 1, flippedX ? 0 : 1, 0); - GL11.glVertex3f(x + ux, y + uv, 0.01f); + GL11.glVertex3f(x + width, y + height, 0.01f); GL11.glTexCoord3f(flippedY ? 0 : 1, flippedX ? 1 : 0, 0); - GL11.glVertex3f(x + ux, y, 0.01f); + GL11.glVertex3f(x + width, y, 0.01f); GL11.glEnd(); GlStateManager.popMatrix(); GlStateManager.disableRescaleNormal(); diff --git a/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java b/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java index 42b63d80cab..25f85dab8a1 100644 --- a/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java +++ b/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java @@ -21,7 +21,7 @@ public class AbstractWidgetGroup extends Widget implements IGhostIngredientTarget, IIngredientSlot { - protected final List widgets = new ArrayList<>(); + public final List widgets = new ArrayList<>(); private final WidgetGroupUIAccess groupUIAccess = new WidgetGroupUIAccess(); private final boolean isDynamicSized; private boolean initialized = false; @@ -206,14 +206,18 @@ public Object getIngredientOverMouse(int mouseX, int mouseY) { @Override public void detectAndSendChanges() { for (Widget widget : widgets) { - widget.detectAndSendChanges(); + if (widget.isActive()) { + widget.detectAndSendChanges(); + } } } @Override public void updateScreen() { for (Widget widget : widgets) { - widget.updateScreen(); + if (widget.isActive()) { + widget.updateScreen(); + } } } @@ -238,8 +242,9 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender @Override public boolean mouseWheelMove(int mouseX, int mouseY, int wheelDelta) { - for (Widget widget : widgets) { - if(widget.mouseWheelMove(mouseX, mouseY, wheelDelta)) { + for (int i = widgets.size() - 1; i >= 0; i--) { + Widget widget = widgets.get(i); + if(widget.isVisible() && widget.mouseWheelMove(mouseX, mouseY, wheelDelta)) { return true; } } @@ -249,7 +254,8 @@ public boolean mouseWheelMove(int mouseX, int mouseY, int wheelDelta) { @Override public boolean mouseClicked(int mouseX, int mouseY, int button) { for (int i = widgets.size() - 1; i >= 0; i--) { - if(widgets.get(i).mouseClicked(mouseX, mouseY, button)) { + Widget widget = widgets.get(i); + if(widget.isVisible() && widget.mouseClicked(mouseX, mouseY, button)) { return true; } } @@ -258,8 +264,9 @@ public boolean mouseClicked(int mouseX, int mouseY, int button) { @Override public boolean mouseDragged(int mouseX, int mouseY, int button, long timeDragged) { - for (Widget widget : widgets) { - if(widget.mouseDragged(mouseX, mouseY, button, timeDragged)) { + for (int i = widgets.size() - 1; i >= 0; i--) { + Widget widget = widgets.get(i); + if(widget.isVisible() && widget.mouseDragged(mouseX, mouseY, button, timeDragged)) { return true; } } @@ -268,8 +275,9 @@ public boolean mouseDragged(int mouseX, int mouseY, int button, long timeDragged @Override public boolean mouseReleased(int mouseX, int mouseY, int button) { - for (Widget widget : widgets) { - if(widget.mouseReleased(mouseX, mouseY, button)) { + for (int i = widgets.size() - 1; i >= 0; i--) { + Widget widget = widgets.get(i); + if(widget.isVisible() && widget.mouseReleased(mouseX, mouseY, button)) { return true; } } diff --git a/src/main/java/gregtech/api/terminal/TerminalBuilder.java b/src/main/java/gregtech/api/terminal/TerminalBuilder.java index fb667768b4c..38b4f0a0cb2 100644 --- a/src/main/java/gregtech/api/terminal/TerminalBuilder.java +++ b/src/main/java/gregtech/api/terminal/TerminalBuilder.java @@ -17,6 +17,7 @@ public static void init() { appRegister.add(new MultiBlockGuideApp()); appRegister.add(new ItemGuideApp()); appRegister.add(new TutorialGuideApp()); + appRegister.add(new GuideEditorApp()); } public static List getApplications() { diff --git a/src/main/java/gregtech/api/terminal/app/AbstractApplication.java b/src/main/java/gregtech/api/terminal/app/AbstractApplication.java index da6ecf8a6c2..d2431be8a34 100644 --- a/src/main/java/gregtech/api/terminal/app/AbstractApplication.java +++ b/src/main/java/gregtech/api/terminal/app/AbstractApplication.java @@ -1,14 +1,23 @@ package gregtech.api.terminal.app; +import gregtech.api.gui.IRenderContext; import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.widgets.WidgetGroup; import gregtech.api.util.Position; import gregtech.api.util.Size; +import gregtech.api.util.interpolate.Eases; +import gregtech.api.util.interpolate.Interpolator; +import javafx.geometry.Pos; +import net.minecraft.client.renderer.GlStateManager; import net.minecraft.nbt.NBTTagCompound; +import java.util.function.Consumer; + public abstract class AbstractApplication extends WidgetGroup { + protected Interpolator interpolator; protected final String name; protected final IGuiTexture icon; + private float scale; public AbstractApplication (String name, IGuiTexture icon) { super(Position.ORIGIN, new Size(333, 232)); @@ -24,14 +33,81 @@ public IGuiTexture getIcon() { return icon; } - public abstract AbstractApplication openApp(boolean isClient, NBTTagCompound nbt); + public abstract AbstractApplication createApp(boolean isClient, NBTTagCompound nbt); - public void closeApp(boolean isClient, NBTTagCompound nbt) { + public void maximizeApp(Consumer callback) { + this.scale = 0; + setVisible(true); + interpolator = new Interpolator(0, 1, 10, Eases.EaseLinear, + value-> scale = value.floatValue(), + value-> { + interpolator = null; + if (callback != null) { + callback.accept(this); + } + }); + interpolator.start(); + } + public void minimizeApp(Consumer callback) { + this.scale = 1; + interpolator = new Interpolator(1, 0, 10, Eases.EaseLinear, + value-> scale = value.floatValue(), + value-> { + setVisible(false); + interpolator = null; + if (callback != null) { + callback.accept(this); + } + }); + interpolator.start(); + } + + public void closeApp(boolean isClient, NBTTagCompound nbt) { } public boolean isBackgroundApp() { return false; } + @Override + public void updateScreen() { + if (interpolator != null) { + interpolator.update(); + } + super.updateScreen(); + } + + @Override + public void drawInForeground(int mouseX, int mouseY) { + if (scale == 0) { + return; + } if (scale != 1) { + GlStateManager.pushMatrix(); + GlStateManager.translate((this.gui.getScreenWidth() - this.gui.getScreenWidth() * scale) / 2, + (this.gui.getScreenHeight() - this.gui.getScreenHeight() * scale) / 2, 0); + GlStateManager.scale(scale, scale, 1); + super.drawInForeground(0, 0); + GlStateManager.popMatrix(); + } else { + super.drawInForeground(mouseX, mouseY); + } + } + + @Override + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + if (scale == 0) { + return; + }if (scale != 1) { + GlStateManager.pushMatrix(); + GlStateManager.translate((this.gui.getScreenWidth() - this.gui.getScreenWidth() * scale) / 2, + (this.gui.getScreenHeight() - this.gui.getScreenHeight() * scale) / 2, 0); + GlStateManager.scale(scale, scale, 1); + super.drawInBackground(0, 0, partialTicks, context); + GlStateManager.popMatrix(); + } else { + super.drawInBackground(mouseX, mouseY, partialTicks, context); + } + + } } diff --git a/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java b/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java new file mode 100644 index 00000000000..a61fdb88298 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java @@ -0,0 +1,22 @@ +package gregtech.api.terminal.app; + +import gregtech.api.gui.resources.TextureArea; +import gregtech.api.terminal.gui.widgets.guide.GuideEditor; +import gregtech.api.terminal.gui.widgets.guide.GuideEditorPageWidget; +import net.minecraft.nbt.NBTTagCompound; + +public class GuideEditorApp extends AbstractApplication{ + public static final TextureArea ICON = TextureArea.fullImage("textures/gui/terminal/guide_editor/icon.png"); + + public GuideEditorApp() { + super("Guide Editor", ICON); + } + + @Override + public AbstractApplication createApp(boolean isClient, NBTTagCompound nbt) { + GuideEditorApp app = new GuideEditorApp(); + app.addWidget(new GuideEditor(0, 0, 133, 232)); + app.addWidget(new GuideEditorPageWidget(133, 0, 200, 232)); + return app; + } +} diff --git a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java index b07663f570c..3c59b2a9146 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java @@ -25,34 +25,34 @@ import java.util.Map; public abstract class GuideApp extends AbstractApplication { - private static final Map REGISTER_WIDGETS = new HashMap<>(); - static { //register guide widgets - REGISTER_WIDGETS.put("textbox", new TextBoxWidget()); - REGISTER_WIDGETS.put("image", new ImageWidget()); - } private GuidePageWidget pageWidget; public GuideApp(String name, IGuiTexture icon) { super(name, icon); } - protected abstract GuideApp createAPP(); - @Override - public GuideApp openApp(boolean isClient, NBTTagCompound nbt) { - GuideApp app = createAPP(); - pageWidget = null; - if (isClient && getTree() != null) { - app.addWidget( - new TextTreeWidget<>(0, 0, 133, 232, getTree(), leaf -> { - if (pageWidget != null) { - app.removeWidget(pageWidget); - } - pageWidget = loadLeaf(leaf); - app.addWidget(pageWidget); - }, this::itemIcon, this::itemName).setNodeTexture(GuiTextures.BORDERED_BACKGROUND).setLeafTexture(GuiTextures.SLOT_DARKENED) - ); + public AbstractApplication createApp(boolean isClient, NBTTagCompound nbt) { + try { + GuideApp app = this.getClass().newInstance(); + if (isClient && getTree() != null) { + app.addWidget( + new TextTreeWidget<>(0, 0, 133, 232, getTree(), leaf -> { + if (app.pageWidget != null) { + app.removeWidget(pageWidget); + } + app.pageWidget = new GuidePageWidget(133, 0, 200, 232); + if (leaf.isLeaf() && leaf.content != null) { + app.pageWidget.loadJsonConfig(leaf.content.getSecond()); + } + app.addWidget(pageWidget); + }, this::itemIcon, this::itemName).setNodeTexture(GuiTextures.BORDERED_BACKGROUND).setLeafTexture(GuiTextures.SLOT_DARKENED) + ); + } + return app; + } catch (Exception e) { + e.printStackTrace(); } - return app; + return null; } protected IGuiTexture itemIcon(T item) { @@ -78,42 +78,4 @@ public static JsonObject getConfig(String fileName) { return null; } } - - private GuidePageWidget loadLeaf(TreeNode> leaf) { - GuidePageWidget page = new GuidePageWidget(133, 0, 200, 232); - if (leaf.isLeaf() && leaf.content != null) { - JsonObject config = leaf.content.getSecond(); - // add title - Widget title = new TextBoxWidget(5, 2, 190, - Collections.singletonList(config.get("title").getAsString()), - 0, 15, 0xffffffff, 0x6fff0000, 0xff000000, - true, true); - page.addWidget(title); - - // add stream widgets - if (config.has("stream")) { - int y = title.getSize().height + 10; - for (JsonElement element : config.getAsJsonArray("stream")) { - JsonObject widgetConfig = element.getAsJsonObject(); - Widget widget = REGISTER_WIDGETS.get(widgetConfig.get("type").getAsString()).createStreamWidget(5, y, 190, widgetConfig); - y += widget.getSize().height + 5; - page.addWidget(widget); - } - } - // add fixed widgets - if (config.has("fixed")) { - for (JsonElement element : config.getAsJsonArray("fixed")) { - JsonObject widgetConfig = element.getAsJsonObject(); - Widget widget = REGISTER_WIDGETS.get(widgetConfig.get("type").getAsString()).createFixedWidget( - widgetConfig.get("x").getAsInt(), - widgetConfig.get("y").getAsInt(), - widgetConfig.get("width").getAsInt(), - widgetConfig.get("height").getAsInt(), - widgetConfig); - page.addWidget(widget); - } - } - } - return page; - } } diff --git a/src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java index ab11a1f1a8a..a79e4d4acc6 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java @@ -23,11 +23,6 @@ public ItemGuideApp() { super("Items Machines", new ItemStackTexture(MetaItems.SCANNER.getStackForm())); } - @Override - protected GuideApp> createAPP() { - return new ItemGuideApp(); - } - @Override protected TreeNode, JsonObject>> getTree() { return ROOT; diff --git a/src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java index a68f32b377f..311e0dbec03 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java @@ -28,11 +28,6 @@ protected TreeNode> getTree() { return ROOT; } - @Override - protected GuideApp createAPP() { - return new MultiBlockGuideApp(); - } - @Override protected IGuiTexture itemIcon(MetaTileEntity item) { return new ItemStackTexture(item.getStackForm()); diff --git a/src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java index 06cef73351e..633e4943ad9 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java @@ -28,11 +28,6 @@ protected TreeNode> getTree() { return ROOT; } - @Override - protected GuideApp createAPP() { - return new SimpleMachineGuideApp(); - } - @Override protected IGuiTexture itemIcon(MetaTileEntity item) { return new ItemStackTexture(item.getStackForm()); diff --git a/src/main/java/gregtech/api/terminal/app/guide/TutorialGuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/TutorialGuideApp.java index 4d1c0e8b361..32aad915681 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/TutorialGuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/TutorialGuideApp.java @@ -39,11 +39,6 @@ public TutorialGuideApp() { super("Tutorials", new ItemStackTexture(Items.PAPER)); } - @Override - protected GuideApp createAPP() { - return new TutorialGuideApp(); - } - @Override protected TreeNode> getTree() { return ROOT; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java index 1f79d1ab114..ccce2bcc7b7 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java @@ -6,6 +6,7 @@ import gregtech.api.gui.resources.RenderUtil; import gregtech.api.util.Position; import gregtech.api.util.Size; +import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.resources.I18n; import net.minecraft.item.ItemStack; import net.minecraft.network.PacketBuffer; @@ -16,10 +17,12 @@ import java.util.function.Consumer; public class CircleButtonWidget extends Widget { + private final int border; private int hoverTick; private boolean isHover; private String hoverText; private IGuiTexture icon; + private final int iconSize; private Consumer onPressCallback; private final int[] colors = { new Color(146, 146, 146).getRGB(), @@ -27,8 +30,14 @@ public class CircleButtonWidget extends Widget { new Color(255, 255, 255).getRGB(), }; - public CircleButtonWidget(int x, int y, int r) { + public CircleButtonWidget(int x, int y, int r, int border, int iconSize) { super(new Position(x - r, y - r), new Size(2 * r, 2 * r)); + this.border = border; + this.iconSize = iconSize; + } + + public CircleButtonWidget(int x, int y) { + this(x, y, 12, 2, 16); } public CircleButtonWidget setIcon(IGuiTexture icon) { @@ -83,9 +92,10 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender if (isHover || hoverTick != 0) { RenderUtil.renderSector(x, y, r, colors[1], segments, 0, (int) (segments * ((hoverTick + partialTicks) / 8))); } - RenderUtil.renderCircle(x, y, r - 2, colors[2], segments); + RenderUtil.renderCircle(x, y, r - border, colors[2], segments); if (icon != null) { - icon.draw(x - 8, y - 8, 16, 16); + GlStateManager.color(1,1,1,1); + icon.draw(x - iconSize / 2f, y - iconSize / 2f, iconSize, iconSize); } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditor.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditor.java new file mode 100644 index 00000000000..3783f0c4631 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditor.java @@ -0,0 +1,12 @@ +package gregtech.api.terminal.gui.widgets.guide; + +import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.util.Position; +import gregtech.api.util.Size; + +public class GuideEditor extends WidgetGroup { + public String json; + public GuideEditor(int x, int y, int width, int height) { + super(new Position(x, y), new Size(width, height)); + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditorPageWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditorPageWidget.java new file mode 100644 index 00000000000..6e08ac29673 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditorPageWidget.java @@ -0,0 +1,127 @@ +package gregtech.api.terminal.gui.widgets.guide; + + +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; +import com.google.gson.*; +import gregtech.api.gui.Widget; +import gregtech.api.util.Position; +import gregtech.api.util.interpolate.Eases; +import gregtech.api.util.interpolate.Interpolator; + +public class GuideEditorPageWidget extends GuidePageWidget { + private final BiMap configMap; + + public GuideEditorPageWidget(int xPosition, int yPosition, int width, int height) { + super(xPosition, yPosition, width, height); + configMap = HashBiMap.create(); + setTitle("Template"); + } + + public String getJsonString() { + JsonObject json = new JsonObject(); + json.addProperty("section", ""); + json.addProperty("title", title.content.get(0)); + if (stream != null) { + JsonArray array = new JsonArray(); + json.add("stream", array); + stream.forEach(widget -> array.add(configMap.get(widget))); + } + if (fixed != null) { + JsonArray array = new JsonArray(); + json.add("fixed", array); + fixed.forEach(widget -> array.add(configMap.get(widget))); + } + return new Gson().toJson(json); + } + + public JsonObject addGuideWidget(IGuideWidget widget, boolean isFixed) { + int pageWidth = this.getSize().width; + JsonObject widgetConfig = widget.getTemplate(isFixed); + Widget guideWidget; + if (isFixed) { + guideWidget = widget.createFixedWidget(widgetConfig.get("x").getAsInt(), + widgetConfig.get("y").getAsInt(), + widgetConfig.get("width").getAsInt(), + widgetConfig.get("height").getAsInt(), + widgetConfig); + this.addWidget(guideWidget); + fixed.add(guideWidget); + } else { + int y = getStreamBottom(); + guideWidget = widget.createStreamWidget(5, y + 5, pageWidth - 5, widgetConfig); + this.addWidget(guideWidget); + stream.add(guideWidget); + } + configMap.put(guideWidget, widgetConfig); + return widgetConfig; + } + + + public void moveUp(Widget widget) { + int index = stream.indexOf(widget); + if (index > 0) { + Widget target = stream.get(index - 1); + if (interpolator == null) { + int offset = widget.getPosition().y - target.getPosition().y; + int y1 = widget.getSelfPosition().y; + int y2 = target.getSelfPosition().y; + interpolator = new Interpolator(0, offset, 10, Eases.EaseLinear, value->{ + widget.setSelfPosition(new Position(widget.getSelfPosition().x, y1 - value.intValue())); + target.setSelfPosition(new Position(target.getSelfPosition().x, y2 + value.intValue())); + }, value->{ + interpolator = null; + stream.remove(widget); + stream.add(index - 1, widget); + }).start(); + } + } + } + + public void moveDown(Widget widget) { + int index = stream.indexOf(widget); + if (index >= 0 && index < stream.size() - 1) { + Widget target = stream.get(index + 1); + if (interpolator == null) { + int offset = target.getPosition().y - widget.getPosition().y; + int y1 = widget.getSelfPosition().y; + int y2 = target.getSelfPosition().y; + interpolator = new Interpolator(0, offset, 10, Eases.EaseLinear, value->{ + widget.setSelfPosition(new Position(widget.getSelfPosition().x, y1 + value.intValue())); + target.setSelfPosition(new Position(target.getSelfPosition().x, y2 - value.intValue())); + }, value->{ + interpolator = null; + stream.remove(widget); + stream.add(index + 1, widget); + }).start(); + } + } + } + + @Override + public void removeWidget(Widget widget) { + int index = stream.indexOf(widget); + if (index >= 0) { + int offset = widget.getSize().height + 5; + for (int i = stream.size() - 1; i > index; i--) { + Widget bottom = stream.get(i); + bottom.setSelfPosition(new Position(bottom.getSelfPosition().x, bottom.getSelfPosition().y - offset)); + } + stream.remove(widget); + } else { + fixed.remove(widget); + } + super.removeWidget(widget); + configMap.remove(widget); + } + + @Override + public boolean mouseClicked(int mouseX, int mouseY, int button) { + return super.mouseClicked(mouseX, mouseY, button); + } + + @Override + public boolean mouseDragged(int mouseX, int mouseY, int button, long timeDragged) { + return super.mouseDragged(mouseX, mouseY, button, timeDragged); + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java index 1cfaea846e4..d5faa04a902 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java @@ -1,27 +1,39 @@ package gregtech.api.terminal.gui.widgets.guide; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; import gregtech.api.gui.resources.IGuiTexture; -import gregtech.api.gui.resources.URLTexture; -import gregtech.api.gui.widgets.AbstractWidgetGroup; +import gregtech.api.gui.widgets.WidgetGroup; import gregtech.api.util.Position; import gregtech.api.util.RenderUtil; import gregtech.api.util.Size; import gregtech.api.util.interpolate.Eases; import gregtech.api.util.interpolate.Interpolator; -import javafx.geometry.Pos; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.util.math.MathHelper; +import java.util.*; + import static gregtech.api.gui.impl.ModularUIGui.*; -public class GuidePageWidget extends AbstractWidgetGroup { +public class GuidePageWidget extends WidgetGroup { + public static final Map REGISTER_WIDGETS = new HashMap<>(); + static { //register guide widgets + REGISTER_WIDGETS.put("textbox", new TextBoxWidget()); + REGISTER_WIDGETS.put("image", new ImageWidget()); + } + protected TextBoxWidget title; + protected List stream; + protected List fixed; + private IGuiTexture background; private int scrollYOffset; private int maxHeight; - private Interpolator interpolator; + protected Interpolator interpolator; public GuidePageWidget(int xPosition, int yPosition, int width, int height) { super(new Position(xPosition, yPosition), new Size(width, height)); @@ -32,6 +44,101 @@ public GuidePageWidget setBackground(IGuiTexture background) { return this; } + public void setTitle(String config) { + int height = 0; + if (title != null) { + height = title.getSize().height; + removeWidget(title); + } + title = new TextBoxWidget(5, 2, 190, + Collections.singletonList(config), + 0, 15, 0xffffffff, 0x6fff0000, 0xff000000, + true, true); + this.addWidget(title); + if (stream != null) { + int offset = title.getSize().height - height; + if (offset != 0) { + for (Widget widget : stream) { + widget.setSelfPosition(new Position(widget.getSelfPosition().x, widget.getSelfPosition().y + offset)); + } + } + } + } + + public String loadJsonConfig(String config) { + try { + loadJsonConfig(new JsonParser().parse(config).getAsJsonObject()); + } catch (Exception e) { + this.clearAllWidgets(); + return e.getMessage(); + } + return null; + } + + public void loadJsonConfig(JsonObject config) { + int pageWidth = this.getSize().width; + // add title + setTitle(config.get("title").getAsString()); + + // add stream widgets + if (config.has("stream")) { + stream = new ArrayList<>(); + int y = title.getSize().height + 10; + for (JsonElement element : config.getAsJsonArray("stream")) { + JsonObject widgetConfig = element.getAsJsonObject(); + Widget widget = REGISTER_WIDGETS.get(widgetConfig.get("type").getAsString()).createStreamWidget(5, y, pageWidth - 5, widgetConfig); + y += widget.getSize().height + 5; + this.addWidget(widget); + stream.add(widget); + } + } + // add fixed widgets + if (config.has("fixed")) { + fixed = new ArrayList<>(); + for (JsonElement element : config.getAsJsonArray("fixed")) { + JsonObject widgetConfig = element.getAsJsonObject(); + Widget widget = REGISTER_WIDGETS.get(widgetConfig.get("type").getAsString()).createFixedWidget( + widgetConfig.get("x").getAsInt(), + widgetConfig.get("y").getAsInt(), + widgetConfig.get("width").getAsInt(), + widgetConfig.get("height").getAsInt(), + widgetConfig); + this.addWidget(widget); + fixed.add(widget); + } + } + } + + public void onSizeUpdate(Widget widget, Size oldSize) { + int offset = widget.getSize().height - oldSize.height; + maxHeight = Math.max(maxHeight, widget.getSize().height + widget.getPosition().y); + if (stream != null) { + int index = stream.indexOf(widget); + for (int i = stream.size() - 1; i > index; i--) { + Widget nextWidget = stream.get(i); + nextWidget.setSelfPosition(new Position(nextWidget.getSelfPosition().x, nextWidget.getSelfPosition().y + offset)); + } + } + } + + public void onPositionUpdate(Widget widget, Position oldPosition) { + if (oldPosition.y + widget.getSize().height == maxHeight) { + maxHeight = 0; + for (Widget widget1 : widgets) { + maxHeight = Math.max(maxHeight, widget1.getSize().height + widget1.getPosition().y); + } + } + } + + protected int getStreamBottom() { + if (stream!= null && stream.size() > 0) { + Widget widget = stream.get(stream.size() - 1); + return widget.getSize().height + widget.getPosition().y; + } else { + return title.getSize().height + 10; + } + } + protected void setScrollYOffset(int scrollYOffset) { if (scrollYOffset == this.scrollYOffset) return; this.scrollYOffset = scrollYOffset; @@ -77,7 +184,9 @@ public void addWidget(Widget widget) { public boolean mouseWheelMove(int mouseX, int mouseY, int wheelDelta) { if (this.isMouseOverElement(mouseX, mouseY, true)) { int moveDelta = -MathHelper.clamp(wheelDelta, -1, 1) * 5; - setScrollYOffset(MathHelper.clamp(scrollYOffset + moveDelta, 0, Math.max(maxHeight - getSize().height, 0))); + if (maxHeight - getSize().height > 0) { + setScrollYOffset(MathHelper.clamp(scrollYOffset + moveDelta, 0, maxHeight - getSize().height + 5)); + } return true; } return false; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java index d35062750d8..f5eed7a7d6b 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java @@ -1,15 +1,21 @@ package gregtech.api.terminal.gui.widgets.guide; import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.sun.istack.internal.Nullable; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; import gregtech.api.util.Position; import gregtech.api.util.Size; +import javafx.geometry.Pos; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.item.ItemStack; +import net.minecraftforge.fml.common.ObfuscationReflectionHelper; +import net.minecraftforge.fml.relauncher.ReflectionHelper; +import java.lang.reflect.Field; import java.util.List; public abstract class GuideWidget extends Widget implements IGuideWidget { @@ -32,6 +38,56 @@ public GuideWidget(){ super(Position.ORIGIN, Size.ZERO); } + public void updateValue(String field, JsonElement value) { + try { + Field f = this.getClass().getDeclaredField(field); + f.set(this, new Gson().fromJson(value, f.getType())); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public void setSize(Size size) { + Size oldSize = this.getSize(); + super.setSize(size); + if (page != null) { + page.onSizeUpdate(this, oldSize); + } + } + + @Override + protected void recomputePosition() { + Position oldPosition = getPosition(); + super.recomputePosition(); + if (page != null) { + page.onPositionUpdate(this, oldPosition); + } + } + + @Override + public void setSelfPosition(Position selfPosition) { + super.setSelfPosition(selfPosition); + } + + @Override + public JsonObject getTemplate(boolean isFixed) { + JsonObject template = new JsonObject(); + if (isFixed) { + template.addProperty("x", 0); + template.addProperty("y", 0); + template.addProperty("width", 100); + template.addProperty("height", 100); + } + template.addProperty("ref", ref); + template.addProperty("stroke", stroke); + template.addProperty("stroke_width", stroke_width); + template.addProperty("fill", fill); + template.addProperty("link", link); + template.add("hover_text", new Gson().toJsonTree(hover_text)); + return template; + } + @Override public String getRef() { return ref; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java index 4d2b3808367..938d7c6c32d 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java @@ -8,4 +8,5 @@ public interface IGuideWidget { Widget createFixedWidget(int x, int y, int width, int height, JsonObject config); void setPage(GuidePageWidget page); String getRef(); + JsonObject getTemplate(boolean isFixed); } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java index b5a1d8127c0..5decb203734 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java @@ -21,7 +21,17 @@ public class ImageWidget extends GuideWidget{ public int width; public int height; - public IGuiTexture image; + public transient IGuiTexture image; + + @Override + public JsonObject getTemplate(boolean isFixed) { + JsonObject template = super.getTemplate(isFixed); + template.addProperty("form", "item"); + template.addProperty("source", "minecraft:ender_pearl"); + template.addProperty("width", 100); + template.addProperty("height", 100); + return template; + } @Override public void updateScreen() { diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java index 7f0d67d3e0a..3e16cb2ad3f 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java @@ -1,5 +1,6 @@ package gregtech.api.terminal.gui.widgets.guide; +import com.google.gson.Gson; import com.google.gson.JsonObject; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; @@ -12,6 +13,7 @@ import net.minecraft.client.resources.I18n; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; public class TextBoxWidget extends GuideWidget { @@ -23,7 +25,7 @@ public class TextBoxWidget extends GuideWidget { public boolean isShadow = false; public boolean isCenter = false; - private List textLines; + private transient List textLines; public TextBoxWidget(int x, int y, int width, List content, int space, int fontSize, int fontColor, int fill, int stroke, boolean isCenter, boolean isShadow) { super(x, y, width, 0); @@ -40,6 +42,18 @@ public TextBoxWidget(int x, int y, int width, List content, int space, i public TextBoxWidget() {} + @Override + public JsonObject getTemplate(boolean isFixed) { + JsonObject template = super.getTemplate(isFixed); + template.addProperty("space", space); + template.addProperty("fontSize", fontSize); + template.addProperty("fontColor", fontColor); + template.addProperty("isCenter", isCenter); + template.addProperty("isShadow", isShadow); + template.add("content", new Gson().toJsonTree(Arrays.asList("this is", "textbox!"))); + return template; + } + @Override protected Widget initFixed(int x, int y, int width, int height, JsonObject config) { this.textLines = new ArrayList<>(); diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalDesktopWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalDesktopWidget.java index ccdf5f1ede2..ccff0af79b3 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalDesktopWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalDesktopWidget.java @@ -1,13 +1,48 @@ package gregtech.api.terminal.gui.widgets.os; import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.terminal.app.AbstractApplication; +import gregtech.api.terminal.gui.widgets.CircleButtonWidget; import gregtech.api.util.Position; import gregtech.api.util.Size; +import java.awt.*; + public class TerminalDesktopWidget extends WidgetGroup { private final TerminalOSWidget os; + private final WidgetGroup appDiv; + public TerminalDesktopWidget(Position position, Size size, TerminalOSWidget os) { super(position, size); this.os = os; + this.appDiv = new WidgetGroup(); + this.addWidget(appDiv); + } + + public void installApplication(AbstractApplication application){ + int r = 12; + int index = appDiv.widgets.size(); + int x = this.getSize().width / 2 + (3 * r) * (index - 3); + int y = (index / 7) * (3 * r) + 40; + CircleButtonWidget button = new CircleButtonWidget(x,y) + .setColors(new Color(146, 146, 146, 126).getRGB(), + new Color(105, 224, 216).getRGB(), + new Color(206, 206, 206).getRGB()) + .setIcon(application.getIcon()) + .setHoverText(application.getName()); + button.setClickListener(clickData -> { + os.openApplication(application, clickData.isClient); + }); + appDiv.addWidget(button); + } + + public void showDesktop() { + appDiv.setActive(true); + appDiv.setVisible(true); + } + + public void hideDesktop() { + appDiv.setActive(false); + appDiv.setVisible(false); } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalMenuWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalMenuWidget.java index b3b427d1c51..935ce7f4948 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalMenuWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalMenuWidget.java @@ -1,9 +1,9 @@ package gregtech.api.terminal.gui.widgets.os; +import gregtech.api.gui.GuiTextures; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.widgets.WidgetGroup; -import gregtech.api.terminal.app.AbstractApplication; import gregtech.api.terminal.gui.widgets.CircleButtonWidget; import gregtech.api.util.Position; import gregtech.api.util.Size; @@ -11,11 +11,11 @@ import gregtech.api.util.interpolate.Interpolator; import net.minecraft.client.renderer.GlStateManager; +import java.awt.*; + public class TerminalMenuWidget extends WidgetGroup { private Interpolator interpolator; - private int appCount; private IGuiTexture background; - private CircleButtonWidget activeButton; private final TerminalOSWidget os; public boolean isHide; @@ -23,6 +23,31 @@ public class TerminalMenuWidget extends WidgetGroup { public TerminalMenuWidget(Position position, Size size, TerminalOSWidget os) { super(position, size); this.os = os; + this.addWidget(new CircleButtonWidget(5, 10, 4, 1, 0) + .setColors(new Color(255, 255, 255, 0).getRGB(), + new Color(255, 255, 255).getRGB(), + new Color(239, 105, 105).getRGB()) + .setHoverText("close") + .setClickListener(this::close)); + this.addWidget(new CircleButtonWidget(15, 10, 4, 1, 0) + .setColors(new Color(255, 255, 255, 0).getRGB(), + new Color(255, 255, 255).getRGB(), + new Color(243, 217, 117).getRGB()) + .setHoverText("minimize") + .setClickListener(this::minimize)); + this.addWidget(new CircleButtonWidget(25, 10, 4, 1, 0) + .setColors(new Color(255, 255, 255, 0).getRGB(), + new Color(255, 255, 255).getRGB(), + new Color(154, 243, 122).getRGB()) + .setHoverText("maximize") + .setClickListener(this::maximize)); + this.addWidget(new CircleButtonWidget(15, 40, 10, 1, 14) + .setColors(new Color(255, 255, 255, 0).getRGB(), + new Color(255, 255, 255).getRGB(), + new Color(80, 80, 80).getRGB()) + .setHoverText("setting") + .setIcon(GuiTextures.TERMINAL_SETTING) + .setClickListener(this::setting)); } public TerminalMenuWidget setBackground(IGuiTexture background) { @@ -30,23 +55,20 @@ public TerminalMenuWidget setBackground(IGuiTexture background) { return this; } - public void addApp(AbstractApplication application){ - int x = this.getSize().width / 2; - int r = 12; - int y = appCount * (2 * r + 4) + r + 20; - CircleButtonWidget button = new CircleButtonWidget(x,y,r).setIcon(application.getIcon()).setHoverText(application.getName()); - button.setClickListener(clickData -> { - if (button != activeButton) { - os.openApplication(application, clickData.isClient); - if (activeButton != null) { - activeButton.setFillColors(0xffffffff); - } - activeButton = button; - activeButton.setFillColors(0xFFAAF1DB); - } - }); - this.addWidget(button); - appCount++; + public void close(ClickData clickData) { + os.closeApplication(os.focusApp, clickData.isClient); + } + + public void minimize(ClickData clickData) { + os.minimizeApplication(os.focusApp, clickData.isClient); + } + + public void maximize(ClickData clickData) { + + } + + public void setting(ClickData clickData) { + } public void hideMenu() { @@ -54,24 +76,26 @@ public void hideMenu() { int y = getSelfPosition().y; interpolator = new Interpolator(getSelfPosition().x, getSelfPosition().x - getSize().width, 10, Eases.EaseLinear, value-> setSelfPosition(new Position(value.intValue(), y)), - value-> interpolator = null); + value-> { + setVisible(false); + interpolator = null; + isHide = true; + }); interpolator.start(); - isHide = true; } } public void showMenu() { if (isHide && interpolator == null) { - if (activeButton != null) { - activeButton.setFillColors(0xffffffff); - } - activeButton = null; + setVisible(true); int y = getSelfPosition().y; interpolator = new Interpolator(getSelfPosition().x, getSelfPosition().x + getSize().width, 10, Eases.EaseLinear, value-> setSelfPosition(new Position(value.intValue(), y)), - value-> interpolator = null); + value-> { + interpolator = null; + isHide = false; + }); interpolator.start(); - isHide = false; } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalOSWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalOSWidget.java index db7f1fa7aa6..00589d4ca61 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalOSWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalOSWidget.java @@ -16,25 +16,33 @@ import javafx.application.Application; import javafx.geometry.Pos; import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import static gregtech.api.gui.impl.ModularUIGui.*; public class TerminalOSWidget extends AbstractWidgetGroup { private IGuiTexture background; - private final List openedApps; - private final TerminalMenuWidget menu; - private final TerminalDesktopWidget desktop; + public final List openedApps; + public AbstractApplication focusApp; + public final TerminalMenuWidget menu; + public final TerminalDesktopWidget desktop; + public List waitToRemoved; + private NBTTagCompound tabletNBT; - public TerminalOSWidget(int xPosition, int yPosition, int width, int height) { + public TerminalOSWidget(int xPosition, int yPosition, int width, int height, NBTTagCompound tabletNBT) { super(new Position(xPosition, yPosition), new Size(width, height)); this.openedApps = new ArrayList<>(); this.desktop = new TerminalDesktopWidget(Position.ORIGIN, new Size(333, 232), this); - this.menu = new TerminalMenuWidget(Position.ORIGIN, new Size(35, 232), this).setBackground(GuiTextures.TERMINAL_MENU); + this.menu = new TerminalMenuWidget(Position.ORIGIN, new Size(31, 232), this).setBackground(GuiTextures.TERMINAL_MENU); this.addWidget(desktop); this.addWidget(menu); + this.waitToRemoved = new ArrayList<>(); + this.tabletNBT = tabletNBT; } public TerminalOSWidget setBackground(IGuiTexture background) { @@ -43,39 +51,87 @@ public TerminalOSWidget setBackground(IGuiTexture background) { } public void installApplication(AbstractApplication application){ - menu.addApp(application); + desktop.installApplication(application); } public void openApplication(AbstractApplication application, boolean isClient) { + if (focusApp != null ) { + closeApplication(focusApp, isClient); + } for (AbstractApplication app : openedApps) { if (app.getClass() == application.getClass()) { - app.setVisible(true); + focusApp = app; + maximizeApplication(app, isClient); return; } } - AbstractApplication app = application.openApp(isClient, null); - openedApps.add(app); - desktop.addWidget(app); - menu.hideMenu(); + String name = application.getName(); + if (!tabletNBT.hasKey(name)) { + tabletNBT.setTag(name, new NBTTagCompound()); + } + AbstractApplication app = application.createApp(isClient, tabletNBT.getCompoundTag(application.getName())); + if (app != null) { + openedApps.add(app); + desktop.addWidget(app); + focusApp = app; + maximizeApplication(app, isClient); + } + } + + public void maximizeApplication(AbstractApplication application, boolean isClient) { + application.setActive(true); + if (isClient) { + application.maximizeApp(app->desktop.hideDesktop()); + if (!menu.isHide) { + menu.hideMenu(); + } + } + desktop.hideDesktop(); + } + + public void minimizeApplication(AbstractApplication application, boolean isClient) { + if (application != null) { + if (application.isBackgroundApp()) { + application.setActive(false); + } + if (isClient) { + application.minimizeApp(null); + } + if(focusApp == application) { + focusApp = null; + } + desktop.showDesktop(); + } } public void closeApplication(AbstractApplication application, boolean isClient) { - desktop.removeWidget(application); - application.closeApp(isClient, null); + if (application != null) { + String name = application.getName(); + if (!tabletNBT.hasKey(name)) { + tabletNBT.setTag(name, new NBTTagCompound()); + } + application.closeApp(isClient, tabletNBT.getCompoundTag(name)); + if (isClient) { + application.minimizeApp(waitToRemoved::add); + } else { + waitToRemoved.add(application); + } + openedApps.remove(application); + if(focusApp == application) { + focusApp = null; + } + desktop.showDesktop(); + } } - public void backToHome() { - List close = new ArrayList<>(); - for (AbstractApplication app : openedApps) { - if (app.isBackgroundApp()) { - app.setVisible(false); + public void homeTrigger(boolean isClient) { + if(isClient) { + if (menu.isHide) { + menu.showMenu(); } else { - close.add(app); - closeApplication(app, isClientSide()); + menu.hideMenu(); } } - close.forEach(openedApps::remove); - menu.showMenu(); } @Override @@ -91,4 +147,22 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender super.drawInBackground(mouseX, mouseY, partialTicks, context); }); } + + @Override + public void updateScreen() { + if (waitToRemoved.size() > 0) { + waitToRemoved.forEach(desktop::removeWidget); + } + waitToRemoved.clear(); + super.updateScreen(); + } + + @Override + public void detectAndSendChanges() { + if (waitToRemoved.size() > 0) { + waitToRemoved.forEach(desktop::removeWidget); + } + waitToRemoved.clear(); + super.detectAndSendChanges(); + } } diff --git a/src/main/java/gregtech/api/util/interpolate/Interpolator.java b/src/main/java/gregtech/api/util/interpolate/Interpolator.java index 7e73e7a8e58..2c79a927ad0 100644 --- a/src/main/java/gregtech/api/util/interpolate/Interpolator.java +++ b/src/main/java/gregtech/api/util/interpolate/Interpolator.java @@ -35,8 +35,9 @@ public void reset() { tick = 0; } - public void start() { + public Interpolator start() { tick = 1; + return this; } public boolean isFinish(){ diff --git a/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java b/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java index c4bbe83c2b7..a451c053d23 100644 --- a/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java +++ b/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java @@ -16,6 +16,7 @@ import net.minecraft.util.EnumHand; import net.minecraft.world.World; +import java.awt.*; import java.util.List; public class GuideTerminalBehaviour implements IItemBehaviour, ItemUIFactory { @@ -36,8 +37,13 @@ public void addInformation(ItemStack itemStack, List lines) { @Override public ModularUI createUI(PlayerInventoryHolder holder, EntityPlayer entityPlayer) { - TerminalOSWidget os = new TerminalOSWidget(12, 11, 333, 232).setBackground(GuiTextures.TERMINAL_BACKGROUND); - CircleButtonWidget home = new CircleButtonWidget(362, 126, 12).setIcon(GuiTextures.TERMINAL_HOME).setFillColors(0xff9197A5).setClickListener(clickData -> os.backToHome()); + TerminalOSWidget os = new TerminalOSWidget(12, 11, 333, 232, holder.getCurrentItem().getOrCreateSubCompound("terminal")) + .setBackground(GuiTextures.TERMINAL_BACKGROUND); + CircleButtonWidget home = new CircleButtonWidget(362, 126).setIcon(GuiTextures.TERMINAL_HOME) + .setColors(new Color(82, 97, 93, 255).getRGB(), + new Color(39, 232, 141).getRGB(), + 0xff9197A5) + .setClickListener(clickData -> os.homeTrigger(clickData.isClient)); TerminalBuilder.getApplications().forEach(os::installApplication); return ModularUI.builder(GuiTextures.TERMINAL_FRAME, 380, 256) .widget(os) diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/guide_editor/icon.png b/src/main/resources/assets/gregtech/textures/gui/terminal/guide_editor/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..d9f2047fd1a93b399b8b4bd26266a3e17f055add GIT binary patch literal 32504 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

ZF7ts5!GU< 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 delta 2855 zcmV+?3)uA73&IwVIDZOFX+uL$P-t&-Z*ypGa3D!TLm+T+Z)Rz1WdHzp+MQE(Sd;e_ zKHv9c4^~3h@UfR{fdC>StO&>uS)ve<0AYj>5y@A0LT~suv4>S3ILP<0Bm`DLLvaF4FK%)Nj?Pt*r}7;7Xa9z9H|HZ zjR63eC`Tj$K!3XcU{!%qECRs70HCZuA}$2Lt^t5qwlYTofV~9(c8*w(4?ti5fSE!p z%m5%b0suoE6U_r4Oaq`W(!b!TUvP!ENC5!A%azTSOVTqGxRuZvck=My;vwR~Y_URN z7by^C3FIQ2mzyIKNaq7g&I|wm8u`(|{y0C7=jP<$=6`1AZ142NqW){}Zz4V+@!$Tu zi~3=fuAC~28EsPoqkpK{9G%|Vj005J}`Hw&=0RYXHq~ibpyyzHQ zsFW8>#s~laM4*8xut5h5!4#~(4xGUqyucR%VSffhKnx_nJP<+#?5=i zx(HVZgM=}{CnA%mPqZa^68XeSVKGG0roJ=O`kZsA{w~!BzPm=q|!{oOVI>m_MObMbS zQlyj;N;PFaO^>2$gY-Gd%Qm(Z8eYv>2*=jns=cMJ`N4THx>VkjAF8G9M07`GWOnM|ey z)0dgZR4~^v8<}UA514ONSSt1^d=-((5|uiYR+WC0=c-gyb5%dpd8!Lkt5pxHURHgk zMpd&=yOjAR1s%ETak!GFdam@h^#)@rS0t$wXH+Irf)+G6c;?H29p+V6F6oj{!|o%K3xI)C?d3A#4A zQM!e?+jY>uuIoY)~6ln+%&eo6EMSt(&dHcAIVA6yg+*DbgwR zQ*PQZ?ELHs?3(Nb?K$>g_9gah_Rk&691wl!-G{dRHsl(}4 zXB%gsbDi@w7p6;)%MzD%mlsoQr;4X;pL)xc%+^yMd)ZNTI#eJ*$ zO)i@o$z8)e??LqN_gLa_%;TM>o2SC_kmoO6c3xRt`@J4dvz#WL)-Y|z+r(Soy~}%G zIzByR`p)SCKE^%*pMQFvhrXu1BHul}BYxI?nSKZSp8Grc%l(h|zu|fE7V%C6U;)7a z8@mESk|3$_Skm zS{wQ>%qC18))9_|&j{ZTes8AvOzF(F2#DZEY>2oYX&IRp`G0*BDJn9mF6vRVQ*?23 z_bk?|G6C?@kiR8rC z#65}Qa{}jVnlqf_npBo_W3J`gqPZ95>CVfZcRX1&S&)1zB2~Schd65~Cxg+yU zRz%j`tk2nT*)2JgoRplSQVnUAv@6#zwiHuJf`1l#y^yd_xUjR>xOiFd;3B_8 zyA~shQx|tGF!j;$ ztoK>JuYXFtYC+Y|hVTuo8}W_h8((co-gKdQYW0rIw9U%R12tha?OV*YtlRRTHly}> zoqt`+R{gE3x4zjX+Sb3_cYE^=gB=w+-tUy`ytONMS8KgRef4hA?t0jufM;t32jm~jej0UI&kHifN$EH?V5MBa9S!3!a?Q1 zC*P)gd*e{(q0YnH!_D8Bf4B7r>qvPk(mKC&tSzH$pgp0z@92!9ogH2sN4~fJe(y2k zV|B+hk5`_cohUu=`Q(C=R&z?UQbnZ;IU-!xL z-hbzhUGThc^dk3S+apRi!(|`JEz}0it z_}4C7pLxCS#_SunZYJFvxFx#v_;&W~7k3KoOx#_1k9e>AzS{lj2l@}{f3*IwWx#FV z_+Y?b&%;>{?+yuvp8k~o(}&^GN6bgnBY#FCjgOrl9~%uCz4Bzvli{bbrxVZ0epdf^ z>vOB;-~HnIOV3#R*zgPai_gEVd8zYq@2jb=I>#f&AH2?aJ@Kaet(_`g8%^e|9=1g zfaw4Lbua(`>RI+y?e7jKeZ#YO-C0B=b|K~#9!V*LOAKLaIzg@J*ALHqwfoThv| zdKstY2R1p3Oh|l2QtpS$%Rmb!2S7$CZ41_lNOMoP0YU;r;_DIuU(MP2{^002ovPDHLk FV1j^`c)|bx diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_minimum.png b/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_minimum.png new file mode 100644 index 0000000000000000000000000000000000000000..12f30a4c85399253c917b847a2d7df143aeb021c GIT binary patch literal 1672 zcmb7FONit|7|tRN>+Z}lAc%O`kVaY2N-F7e9>r#d+4MNmV8&*)VaMB4S5>;hbW+(Q zGu<->5xuymhrNn7?}9f$L|hMo7s0zA2y^iuxL2jO(w&a8yR)xAl1kNA-~auO`g6Ox zy}5GXwF{CYt#r29JL0`s-shLZ^YXnZ7O$7mt@m?Dy7+Q=pOe1$@>NNC@vo@2TkHn! zBEn-8Q{HFlBu)idlCG{zQcU()A@|uJN<8K7?|x9^h?jk*1BuV|CnAc{b2= z*L5{$Xodj<0^~nB| zDlA=^0V%0*=|MJ{8K*>JBNnry$OTrfvFVT(JRkDMP}j>37!aWig4)KJTH?4ikrx|> z!i_2*XQK1oQOdL(mh*#*u#H0@vr&4JB0poe;8~CJ(IQdZg=E?H+#o=mBrkA6 zSf}kNA~b3gQDlb1?PF#ETQ>=?ZPNhQ4IN;(m_o;KEW-&G``erxlm$@kpPvQFiQxEO zp6j%1$0Y<1(;~oSrV091-vOi*I)-f+2BiH3+k06gjw2qOW-V1w!D#7(wrosGEjloX z$$;Bz5@5BQkiw>Ius$h^epW|lE6PQNkE&yIgWak|qez~W4#K275}rcJT3}SErlT|B z@l2Mh{o^4Mq)(`lx%Hff#TaL7eIR1@lp53?Cq2i9PZs`ciJU8XRQN+R`~1SIkdPrx z22Au;O(|W`$}Tidi1u)V27 zf2Y&67heDHw(|Q|OWmKPSLmfiqw&qHU(SE}!MEp5PEMvj-M#zCZ~y)Ak+= kym9B^(zVsimAySly7%WQ`Ti37r~FrRHn!VeU*G%aKEp8%ZvX%Q literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_setting.png b/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_setting.png new file mode 100644 index 0000000000000000000000000000000000000000..6300ad91847721d5e04189a359743b9cdeda9fe6 GIT binary patch literal 1712 zcmb7FOKjXk7?8 z$pKnUaNq*HP;o<4;!+8OdMH%%fIC^um<@mM!p+)CN; zt)&*-TBFF<4!xot9AHThF+tQp)QdAbsA@xAEXVn@uBk(aSgUHa+@QMJTvk1vGPPWC z05xn=by3N1ATsR(stFBOhpui|02&xN*h1>~(xkQ25AaI;=-8J0s%l*!60Ga}e!tYW zN<8i820}=Orf!-*B0#no3o-z4wr|2vXBkbyM1(w6b4JqU>!PYjr6U)jq@aznahPPl z^Z`k9qXcu8hCrVdxMV%;4UPL$XFV3NSY#4w6xgK81<$(t4%Ef+O$KCWo6W+;u3Dm~ zFp-J*4e7=>AiJWo)@H)=6_)Y!l(P8^DRW=$O@h6Y5y8_I=eBv8%CtV^d#2@g7g5VX4mAIp6TS<&+0uPcCFD3rEz(yyqCmae!GehH{%t z+=w$lV#*rzswP8I3PT?g({>RuAs}U!fp*0X06}I25QeDjRstgkM()b}bxzmw0?7A| z&VtXWL)#CNsP_K1Rpc+v8C$REMR53C)j0Rik+= zFkc%_hr7h%zATUT_q$Az-la-L)-xW6K1o@vBV%`u8r1J3JtG@;7k+<<94We8_$@X2 z|Ami3Lc1jHFxgvmEq6uFyU-{h`mMPduI=bp6S!=H`LO7}@}ubBESA)%?9cf8mA$gJ zuQlqmR^`L*ue~;XNqv0J)lYtfFa7iWA4f0mf2aMqI4nM1&|dBT&^Y(mb$#l}jq>4B z=M|tn@Wsi~A8CKSaQ)=WS3lQk)2F|jTb&Bd{`T;h+2=3T=k_R1e|zDV*{i26{J6LK jr1H}n-lYTE@1A`wJ7ySP|Gqt&|5F Date: Sat, 31 Jul 2021 15:20:37 +0800 Subject: [PATCH 28/58] scrollpanelwidgetgroup --- src/main/java/gregtech/api/gui/Widget.java | 4 +- .../api/gui/resources/ColorRectTexture.java | 49 ++++ .../api/gui/widgets/ScrollableListWidget.java | 4 +- .../gregtech/api/gui/widgets/TabGroup.java | 4 +- .../api/terminal/app/GuideEditorApp.java | 18 +- .../api/terminal/app/guide/GuideApp.java | 11 +- .../widgets/ScrollablePanelWidgetGroup.java | 271 ++++++++++++++++++ .../gui/widgets/guide/GuideEditor.java | 19 ++ .../widgets/guide/GuideEditorPageWidget.java | 9 - .../gui/widgets/guide/GuidePageWidget.java | 96 +------ 10 files changed, 382 insertions(+), 103 deletions(-) create mode 100644 src/main/java/gregtech/api/gui/resources/ColorRectTexture.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/ScrollablePanelWidgetGroup.java diff --git a/src/main/java/gregtech/api/gui/Widget.java b/src/main/java/gregtech/api/gui/Widget.java index 633b3f2b790..7ba6311f2f5 100644 --- a/src/main/java/gregtech/api/gui/Widget.java +++ b/src/main/java/gregtech/api/gui/Widget.java @@ -256,14 +256,14 @@ public List getNativeWidgets() { /** * Writes data to be sent to client's {@link #readUpdateInfo} */ - protected final void writeUpdateInfo(int id, Consumer packetBufferWriter) { + protected void writeUpdateInfo(int id, Consumer packetBufferWriter) { if (uiAccess != null && gui != null) { uiAccess.writeUpdateInfo(this, id, packetBufferWriter); } } @SideOnly(Side.CLIENT) - protected final void writeClientAction(int id, Consumer packetBufferWriter) { + protected void writeClientAction(int id, Consumer packetBufferWriter) { if (uiAccess != null) { uiAccess.writeClientAction(this, id, packetBufferWriter); } diff --git a/src/main/java/gregtech/api/gui/resources/ColorRectTexture.java b/src/main/java/gregtech/api/gui/resources/ColorRectTexture.java new file mode 100644 index 00000000000..d1b192f11b4 --- /dev/null +++ b/src/main/java/gregtech/api/gui/resources/ColorRectTexture.java @@ -0,0 +1,49 @@ +package gregtech.api.gui.resources; + +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; + +public class ColorRectTexture implements IGuiTexture{ + private final int color; + + public ColorRectTexture(int color) { + this.color = color; + } + + @Override + public void draw(double x, double y, int width, int height) { + double j; + double right = x + width; + double bottom = y + height; + if (x < right) { + j = x; + x = right; + right = j; + } + + if (y < bottom) { + j = y; + y = bottom; + bottom = j; + } + float f3 = (float)(color >> 24 & 255) / 255.0F; + float f = (float)(color >> 16 & 255) / 255.0F; + float f1 = (float)(color >> 8 & 255) / 255.0F; + float f2 = (float)(color & 255) / 255.0F; + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder bufferbuilder = tessellator.getBuffer(); + GlStateManager.enableBlend(); + GlStateManager.disableTexture2D(); + GlStateManager.tryBlendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO); + GlStateManager.color(f, f1, f2, f3); + bufferbuilder.begin(7, DefaultVertexFormats.POSITION); + bufferbuilder.pos(x, bottom, 0.0D).endVertex(); + bufferbuilder.pos(right, bottom, 0.0D).endVertex(); + bufferbuilder.pos(right, y, 0.0D).endVertex(); + bufferbuilder.pos(x, y, 0.0D).endVertex(); + tessellator.draw(); + GlStateManager.enableTexture2D(); + } +} diff --git a/src/main/java/gregtech/api/gui/widgets/ScrollableListWidget.java b/src/main/java/gregtech/api/gui/widgets/ScrollableListWidget.java index 14677eb98bd..8261ee648a8 100644 --- a/src/main/java/gregtech/api/gui/widgets/ScrollableListWidget.java +++ b/src/main/java/gregtech/api/gui/widgets/ScrollableListWidget.java @@ -85,7 +85,7 @@ public void drawInForeground(int mouseX, int mouseY) { } @Override - public void drawInBackground(int mouseX, int mouseY, IRenderContext context) { + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { //make sure mouse is not hovered on any element when outside of bounds if (!isPositionInsideScissor(mouseX, mouseY)) { mouseX = Integer.MAX_VALUE; @@ -107,7 +107,7 @@ public void drawInBackground(int mouseX, int mouseY, IRenderContext context) { drawGradientRect(scrollX + 1, scrollSliderY, paneSize - 2, scrollSliderHeight, 0xFF555555, 0xFF454545); RenderUtil.useScissor(position.x, position.y, size.width - paneSize, size.height, () -> - super.drawInBackground(finalMouseX, finalMouseY, context)); + super.drawInBackground(finalMouseX, finalMouseY, partialTicks, context)); GlStateManager.color(rColorForOverlay, gColorForOverlay, bColorForOverlay, 1.0F); } diff --git a/src/main/java/gregtech/api/gui/widgets/TabGroup.java b/src/main/java/gregtech/api/gui/widgets/TabGroup.java index d9741df338e..b18ee5089bf 100644 --- a/src/main/java/gregtech/api/gui/widgets/TabGroup.java +++ b/src/main/java/gregtech/api/gui/widgets/TabGroup.java @@ -68,8 +68,8 @@ public List getContainedWidgets(boolean includeHidden) { } @Override - public void drawInBackground(int mouseX, int mouseY, IRenderContext context) { - super.drawInBackground(mouseX, mouseY, context); + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + super.drawInBackground(mouseX, mouseY, partialTicks, context); this.tabListRenderer.renderTabs(getPosition(), tabInfos, sizes.getWidth(), sizes.getHeight(), selectedTabIndex); GlStateManager.color(rColorForOverlay, gColorForOverlay, bColorForOverlay, 1.0F); } diff --git a/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java b/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java index a61fdb88298..75fbbe49fea 100644 --- a/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java +++ b/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java @@ -4,6 +4,9 @@ import gregtech.api.terminal.gui.widgets.guide.GuideEditor; import gregtech.api.terminal.gui.widgets.guide.GuideEditorPageWidget; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.PacketBuffer; + +import java.util.function.Consumer; public class GuideEditorApp extends AbstractApplication{ public static final TextureArea ICON = TextureArea.fullImage("textures/gui/terminal/guide_editor/icon.png"); @@ -14,9 +17,16 @@ public GuideEditorApp() { @Override public AbstractApplication createApp(boolean isClient, NBTTagCompound nbt) { - GuideEditorApp app = new GuideEditorApp(); - app.addWidget(new GuideEditor(0, 0, 133, 232)); - app.addWidget(new GuideEditorPageWidget(133, 0, 200, 232)); - return app; + if (isClient) { + GuideEditorApp app = new GuideEditorApp(); + app.addWidget(new GuideEditor(0, 20, 133, 232)); + app.addWidget(new GuideEditorPageWidget(133, 0, 200, 232)); + return app; + } + return null; + } + + @Override + protected void writeClientAction(int id, Consumer packetBufferWriter) { } } diff --git a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java index 3c59b2a9146..dabcc3322a8 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java @@ -6,6 +6,7 @@ import gregtech.api.GTValues; import gregtech.api.gui.GuiTextures; import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.ColorRectTexture; import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.widgets.WidgetGroup; import gregtech.api.terminal.app.AbstractApplication; @@ -13,6 +14,7 @@ import gregtech.api.terminal.util.TreeNode; import net.minecraft.client.Minecraft; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.PacketBuffer; import net.minecraft.util.ResourceLocation; import net.minecraft.util.Tuple; @@ -23,6 +25,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.function.Consumer; public abstract class GuideApp extends AbstractApplication { private GuidePageWidget pageWidget; @@ -38,13 +41,13 @@ public AbstractApplication createApp(boolean isClient, NBTTagCompound nbt) { app.addWidget( new TextTreeWidget<>(0, 0, 133, 232, getTree(), leaf -> { if (app.pageWidget != null) { - app.removeWidget(pageWidget); + app.removeWidget(app.pageWidget); } app.pageWidget = new GuidePageWidget(133, 0, 200, 232); if (leaf.isLeaf() && leaf.content != null) { app.pageWidget.loadJsonConfig(leaf.content.getSecond()); } - app.addWidget(pageWidget); + app.addWidget(app.pageWidget); }, this::itemIcon, this::itemName).setNodeTexture(GuiTextures.BORDERED_BACKGROUND).setLeafTexture(GuiTextures.SLOT_DARKENED) ); } @@ -55,6 +58,10 @@ public AbstractApplication createApp(boolean isClient, NBTTagCompound nbt) { return null; } + @Override + protected void writeClientAction(int id, Consumer packetBufferWriter) { + } + protected IGuiTexture itemIcon(T item) { return null; } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/ScrollablePanelWidgetGroup.java b/src/main/java/gregtech/api/terminal/gui/widgets/ScrollablePanelWidgetGroup.java new file mode 100644 index 00000000000..245b12027ad --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/ScrollablePanelWidgetGroup.java @@ -0,0 +1,271 @@ +package gregtech.api.terminal.gui.widgets; + +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.util.Position; +import gregtech.api.util.RenderUtil; +import gregtech.api.util.Size; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.util.math.MathHelper; + +public class ScrollablePanelWidgetGroup extends WidgetGroup { + protected int scrollXOffset; + protected int scrollYOffset; + protected int xBarHeight; + protected int yBarWidth; + protected boolean draggable; + protected IGuiTexture background; + protected int maxHeight; + protected int maxWidth; + protected IGuiTexture xBarB; + protected IGuiTexture xBarF; + protected IGuiTexture yBarB; + protected IGuiTexture yBarF; + + private int lastMouseX; + private int lastMouseY; + private boolean draggedPanel; + private boolean draggedOnXScrollBar; + private boolean draggedOnYScrollBar; + + + public ScrollablePanelWidgetGroup(int x, int y, int width, int height) { + super(new Position(x, y), new Size(width, height)); + maxHeight = height; + maxWidth = width; + } + + public ScrollablePanelWidgetGroup availableXScrollBarHeight(int xBar) { + this.xBarHeight = xBar; + return this; + } + + public ScrollablePanelWidgetGroup availableYScrollBarWidth(int yBar) { + this.yBarWidth = yBar; + return this; + } + + public ScrollablePanelWidgetGroup setDraggable(boolean draggable) { + this.draggable = draggable; + return this; + } + + public ScrollablePanelWidgetGroup setBackground(IGuiTexture background) { + this.background = background; + return this; + } + + public ScrollablePanelWidgetGroup setXBarStyle(IGuiTexture background, IGuiTexture bar) { + this.xBarB = background; + this.xBarF = bar; + return this; + } + + public ScrollablePanelWidgetGroup setYBarStyle(IGuiTexture background, IGuiTexture bar) { + this.yBarB = background; + this.yBarF = bar; + return this; + } + + public int getScrollYOffset() { + return scrollYOffset; + } + + public int getScrollXOffset() { + return scrollXOffset; + } + + @Override + public void addWidget(Widget widget) { + maxHeight = Math.max(maxHeight, widget.getSize().height + widget.getSelfPosition().y); + maxWidth = Math.max(maxWidth, widget.getSize().width + widget.getSelfPosition().x); + super.addWidget(widget); + } + + @Override + public void removeWidget(Widget widget) { + super.removeWidget(widget); + computeMax(); + } + + @Override + public void clearAllWidgets() { + super.clearAllWidgets(); + computeMax(); + } + + @Override + public void setSize(Size size) { + super.setSize(size); + computeMax(); + } + + protected void computeMax() { + maxHeight = getSize().height; + maxWidth = getSize().width; + for (Widget widget : widgets) { + maxHeight = Math.max(maxHeight, widget.getSize().height + widget.getSelfPosition().y); + maxWidth = Math.max(maxWidth, widget.getSize().width + widget.getSelfPosition().x); + } + } + + protected int getMaxHeight() { + return maxHeight + xBarHeight; + } + + protected int getMaxWidth() { + return maxWidth + yBarWidth; + } + + protected void setScrollXOffset(int scrollXOffset) { + if (scrollXOffset == this.scrollXOffset) return; + this.scrollXOffset = scrollXOffset; + int minX = this.scrollXOffset + getPosition().x; + int maxX = minX + getSize().width; + for (Widget widget : widgets) { + widget.setVisible(widget.getPosition().x < maxX && widget.getPosition().x + widget.getSize().width > minX); + } + } + + protected void setScrollYOffset(int scrollYOffset) { + if (scrollYOffset == this.scrollYOffset) return; + this.scrollYOffset = scrollYOffset; + int minY = this.scrollYOffset + getPosition().y; + int maxY = minY + getSize().height; + for (Widget widget : widgets) { + widget.setVisible(widget.getPosition().y < maxY && widget.getPosition().y + widget.getSize().height > minY); + } + } + + private boolean isOnXScrollPane(int mouseX, int mouseY) { + Position pos = getPosition(); + Size size = getSize(); + return isMouseOver(pos.x, pos.y - xBarHeight, size.width, xBarHeight, mouseX, mouseY); + } + + private boolean isOnYScrollPane(int mouseX, int mouseY) { + Position pos = getPosition(); + Size size = getSize(); + return isMouseOver(pos.x + size.width - yBarWidth, pos.y, yBarWidth, size.height, mouseX, mouseY); + } + + @Override + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + Position position = getPosition(); + Size size = getSize(); + if (background != null) { + background.draw(position.x, position.y, size.width, size.height); + } + GlStateManager.translate(-scrollXOffset, -scrollYOffset, 0); + RenderUtil.useScissor(position.x, position.y, size.width - yBarWidth, size.height - xBarHeight, ()->{ + super.drawInBackground(mouseX +scrollXOffset, mouseY + scrollYOffset, partialTicks, context); + }); + GlStateManager.translate(scrollXOffset, scrollYOffset, 0); + if (xBarHeight > 0) { + if (xBarB != null) { + xBarB.draw(position.x, position.y - xBarHeight, size.width, xBarHeight); + } + if (xBarF != null) { + int barWidth = size.width / getMaxWidth(); + xBarF.draw(position.x + scrollXOffset, position.y - xBarHeight, barWidth, xBarHeight); + } + } + if (yBarWidth > 0) { + if (yBarB != null) { + yBarB.draw(position.x + size.width - yBarWidth, position.y, yBarWidth, size.height); + } + if (yBarF != null) { + int barHeight = (int) (size.height * 1.0f / getMaxHeight() * size.height); + yBarF.draw(position.x + size.width - yBarWidth, position.y + scrollYOffset * size.height * 1.0f / getMaxHeight(), yBarWidth, barHeight); + } + } + + } + + private void drawBar(Position position, Size size, int barSize, IGuiTexture barB, IGuiTexture barF, int anotherBarSize) { + if (barSize > 0) { + if (barB != null) { + barB.draw(position.x, position.y - barSize, size.width, barSize); + } + if (barF != null) { + int barWidth = (size.width + anotherBarSize) / getMaxWidth(); + barF.draw(position.x + scrollXOffset - barSize, position.y, barWidth, barSize); + } + } + } + + @Override + public void drawInForeground(int mouseX, int mouseY) { + GlStateManager.translate(-scrollXOffset, -scrollYOffset, 0); + super.drawInForeground(mouseX, mouseY + scrollYOffset); + GlStateManager.translate(scrollXOffset, scrollYOffset, 0); + } + + @Override + public boolean mouseClicked(int mouseX, int mouseY, int button) { + lastMouseX = mouseX; + lastMouseY = mouseY; + if (xBarHeight > 0 && isOnXScrollPane(mouseX, mouseY)) { + this.draggedOnXScrollBar = true; + return true; + } + else if (yBarWidth > 0 && isOnYScrollPane(mouseX, mouseY)) { + this.draggedOnYScrollBar = true; + return true; + } else if(isMouseOverElement(mouseX, mouseY)){ + if (super.mouseClicked(mouseX + scrollXOffset, mouseY + scrollYOffset, button)) { + return true; + } else if (draggable) { + this.draggedPanel = true; + return true; + } + } + return false; + } + + @Override + public boolean mouseWheelMove(int mouseX, int mouseY, int wheelDelta) { + if (this.isMouseOverElement(mouseX, mouseY, true)) { + if (super.mouseWheelMove(mouseX + scrollXOffset, mouseY + scrollYOffset, wheelDelta)) { + return true; + } + int moveDelta = -MathHelper.clamp(wheelDelta, -1, 1) * 5; + if (getMaxHeight() - getSize().height > 0) { + setScrollYOffset(MathHelper.clamp(scrollYOffset + moveDelta, 0, getMaxHeight() - getSize().height + 5)); + } + return true; + } + return false; + } + + @Override + public boolean mouseDragged(int mouseX, int mouseY, int button, long timeDragged) { + if (draggedOnXScrollBar) { + setScrollXOffset(MathHelper.clamp(scrollXOffset + (mouseX - lastMouseX) * getMaxWidth() / getSize().width, 0, Math.max(getMaxWidth() - getSize().width, 0))); + } else if (draggedOnYScrollBar) { + setScrollYOffset(MathHelper.clamp(scrollYOffset + (mouseY - lastMouseY) * getMaxHeight() / getSize().height, 0, Math.max(getMaxHeight() - getSize().height, 0))); + } else if (draggedPanel) { + setScrollXOffset(MathHelper.clamp(scrollXOffset + lastMouseX - mouseX, 0, Math.max(getMaxWidth() - yBarWidth - getSize().width, 0))); + setScrollYOffset(MathHelper.clamp(scrollYOffset + lastMouseY - mouseY, 0, Math.max(getMaxHeight() - xBarHeight - getSize().height, 0))); + } + lastMouseX = mouseX; + lastMouseY = mouseY; + return super.mouseDragged(mouseX + scrollXOffset, mouseY + scrollYOffset, button, timeDragged); + } + + @Override + public boolean mouseReleased(int mouseX, int mouseY, int button) { + if (draggedOnXScrollBar) { + draggedOnXScrollBar = false; + } else if (draggedOnYScrollBar) { + draggedOnYScrollBar = false; + } else if (draggedPanel) { + draggedPanel = false; + } else { + return super.mouseReleased(mouseX + scrollXOffset, mouseY + scrollYOffset, button); + } + return true; + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditor.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditor.java index 3783f0c4631..c937385b683 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditor.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditor.java @@ -1,12 +1,31 @@ package gregtech.api.terminal.gui.widgets.guide; +import gregtech.api.gui.widgets.AbstractWidgetGroup; +import gregtech.api.gui.widgets.LabelWidget; +import gregtech.api.gui.widgets.TabGroup; import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.gui.widgets.tab.ItemTabInfo; +import gregtech.api.terminal.gui.widgets.CircleButtonWidget; import gregtech.api.util.Position; import gregtech.api.util.Size; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; public class GuideEditor extends WidgetGroup { public String json; public GuideEditor(int x, int y, int width, int height) { super(new Position(x, y), new Size(width, height)); + TabGroup tabGroup = new TabGroup(TabGroup.TabLocation.HORIZONTAL_TOP_LEFT, Position.ORIGIN); + tabGroup.addTab(new ItemTabInfo("gregtech.machine.workbench.tab.workbench", new ItemStack(Blocks.CRAFTING_TABLE)), createItemListTab()); + tabGroup.addTab(new ItemTabInfo("gregtech.machine.workbench.tab.item_list", new ItemStack(Blocks.CHEST)), createItemListTab()); + this.addWidget(tabGroup); + } + + private AbstractWidgetGroup createItemListTab() { + WidgetGroup widgetGroup = new WidgetGroup(); + widgetGroup.addWidget(new LabelWidget(5, 20, "gregtech.machine.workbench.storage_note_1")); + widgetGroup.addWidget(new LabelWidget(5, 30, "gregtech.machine.workbench.storage_note_2")); + widgetGroup.addWidget(new CircleButtonWidget(10, 10)); + return widgetGroup; } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditorPageWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditorPageWidget.java index 6e08ac29673..0b216647e0b 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditorPageWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditorPageWidget.java @@ -115,13 +115,4 @@ public void removeWidget(Widget widget) { configMap.remove(widget); } - @Override - public boolean mouseClicked(int mouseX, int mouseY, int button) { - return super.mouseClicked(mouseX, mouseY, button); - } - - @Override - public boolean mouseDragged(int mouseX, int mouseY, int button, long timeDragged) { - return super.mouseDragged(mouseX, mouseY, button, timeDragged); - } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java index d5faa04a902..ab6f640e561 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java @@ -4,23 +4,19 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; -import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; -import gregtech.api.gui.resources.IGuiTexture; -import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.gui.resources.ColorRectTexture; +import gregtech.api.terminal.gui.widgets.ScrollablePanelWidgetGroup; import gregtech.api.util.Position; -import gregtech.api.util.RenderUtil; import gregtech.api.util.Size; import gregtech.api.util.interpolate.Eases; import gregtech.api.util.interpolate.Interpolator; -import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.util.math.MathHelper; +import java.awt.*; import java.util.*; +import java.util.List; -import static gregtech.api.gui.impl.ModularUIGui.*; - -public class GuidePageWidget extends WidgetGroup { +public class GuidePageWidget extends ScrollablePanelWidgetGroup { public static final Map REGISTER_WIDGETS = new HashMap<>(); static { //register guide widgets REGISTER_WIDGETS.put("textbox", new TextBoxWidget()); @@ -30,18 +26,15 @@ public class GuidePageWidget extends WidgetGroup { protected List stream; protected List fixed; - private IGuiTexture background; - private int scrollYOffset; - private int maxHeight; protected Interpolator interpolator; public GuidePageWidget(int xPosition, int yPosition, int width, int height) { - super(new Position(xPosition, yPosition), new Size(width, height)); - } - - public GuidePageWidget setBackground(IGuiTexture background) { - this.background = background; - return this; + super(xPosition, yPosition, width, height); + this.setBackground(new ColorRectTexture(-1)); + this.setDraggable(true); + this.availableYScrollBarWidth(4); + this.setYBarStyle(new ColorRectTexture(new Color(142, 142, 142).getRGB()) + , new ColorRectTexture(new Color(148, 226, 193).getRGB())); } public void setTitle(String config) { @@ -50,7 +43,7 @@ public void setTitle(String config) { height = title.getSize().height; removeWidget(title); } - title = new TextBoxWidget(5, 2, 190, + title = new TextBoxWidget(5, 2, this.getSize().width - yBarWidth - 10, Collections.singletonList(config), 0, 15, 0xffffffff, 0x6fff0000, 0xff000000, true, true); @@ -76,7 +69,7 @@ public String loadJsonConfig(String config) { } public void loadJsonConfig(JsonObject config) { - int pageWidth = this.getSize().width; + int pageWidth = this.getSize().width - yBarWidth; // add title setTitle(config.get("title").getAsString()); @@ -86,7 +79,7 @@ public void loadJsonConfig(JsonObject config) { int y = title.getSize().height + 10; for (JsonElement element : config.getAsJsonArray("stream")) { JsonObject widgetConfig = element.getAsJsonObject(); - Widget widget = REGISTER_WIDGETS.get(widgetConfig.get("type").getAsString()).createStreamWidget(5, y, pageWidth - 5, widgetConfig); + Widget widget = REGISTER_WIDGETS.get(widgetConfig.get("type").getAsString()).createStreamWidget(5, y, pageWidth - 10, widgetConfig); y += widget.getSize().height + 5; this.addWidget(widget); stream.add(widget); @@ -139,20 +132,6 @@ protected int getStreamBottom() { } } - protected void setScrollYOffset(int scrollYOffset) { - if (scrollYOffset == this.scrollYOffset) return; - this.scrollYOffset = scrollYOffset; - int minY = this.scrollYOffset + getPosition().y; - int maxY = minY + getSize().height; - for (Widget widget : widgets) { - widget.setVisible(widget.getPosition().y < maxY && widget.getPosition().y + widget.getSize().height > minY); - } - } - - public int getScrollYOffset() { - return scrollYOffset; - } - @Override public void updateScreen() { if (interpolator != null) interpolator.update(); @@ -173,56 +152,9 @@ public void jumpToRef(String ref){ @Override public void addWidget(Widget widget) { - maxHeight = Math.max(maxHeight, widget.getSize().height + widget.getPosition().y); super.addWidget(widget); if (widget instanceof IGuideWidget) { ((IGuideWidget) widget).setPage(this); } } - - @Override - public boolean mouseWheelMove(int mouseX, int mouseY, int wheelDelta) { - if (this.isMouseOverElement(mouseX, mouseY, true)) { - int moveDelta = -MathHelper.clamp(wheelDelta, -1, 1) * 5; - if (maxHeight - getSize().height > 0) { - setScrollYOffset(MathHelper.clamp(scrollYOffset + moveDelta, 0, maxHeight - getSize().height + 5)); - } - return true; - } - return false; - } - - @Override - public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { - Position position = getPosition(); - Size size = getSize(); - if (background != null) { - background.draw(position.x, position.y, size.width, size.height); - } else { - gregtech.api.gui.resources.RenderUtil.renderRect(position.x, position.y, size.width, size.height, 0, 0xffffffff); - } - GlStateManager.translate(0, -scrollYOffset, 0); - RenderUtil.useScissor(position.x, position.y, size.width, size.height, ()->{ - int offsetY = mouseY + scrollYOffset; - for (Widget widget : widgets) { - if (widget.isVisible()) { - widget.drawInBackground(mouseX, offsetY, partialTicks, context); - } - } - GlStateManager.color(rColorForOverlay, gColorForOverlay, bColorForOverlay, 1.0F); - }); - GlStateManager.translate(0, scrollYOffset, 0); - } - - @Override - public void drawInForeground(int mouseX, int mouseY) { - GlStateManager.translate(0, -scrollYOffset, 0); - super.drawInForeground(mouseX, mouseY + scrollYOffset); - GlStateManager.translate(0, scrollYOffset, 0); - } - - @Override - public boolean mouseClicked(int mouseX, int mouseY, int button) { - return super.mouseClicked(mouseX, mouseY + scrollYOffset, button); - } } From 0f2750462b25e63d88b4f8a6596326e6c04c580c Mon Sep 17 00:00:00 2001 From: Yefancy Date: Mon, 2 Aug 2021 13:35:25 +0800 Subject: [PATCH 29/58] editor... --- .../java/gregtech/api/gui/GuiTextures.java | 4 + src/main/java/gregtech/api/gui/Widget.java | 6 + .../api/gui/resources/ColorRectTexture.java | 6 + .../api/gui/resources/RenderUtil.java | 1 + .../api/gui/resources/TextTexture.java | 31 ++ .../api/gui/widgets/ClickButtonWidget.java | 9 + .../api/gui/widgets/SimpleTextWidget.java | 22 ++ .../gregtech/api/gui/widgets/TabGroup.java | 21 +- .../api/gui/widgets/TextFieldWidget.java | 9 + .../gui/widgets/tab/IGuiTextureTabInfo.java | 36 +++ .../api/gui/widgets/tab/ITabInfo.java | 4 +- .../api/gui/widgets/tab/ItemTabInfo.java | 15 +- .../api/terminal/app/GuideEditorApp.java | 12 +- .../terminal/gui/CustomTabListRenderer.java | 41 +++ .../gregtech/api/terminal/gui/IDraggable.java | 9 + .../gui/widgets/CircleButtonWidget.java | 29 +- ...va => DraggableScrollableWidgetGroup.java} | 177 +++++++---- .../gui/widgets/RectButtonWidget.java | 40 +++ .../gui/widgets/TextEditorWidget.java | 127 ++++++++ .../gui/widgets/guide/GuideConfigEditor.java | 126 ++++++++ .../gui/widgets/guide/GuideEditor.java | 31 -- .../widgets/guide/GuideEditorPageWidget.java | 118 ------- .../widgets/guide/GuidePageEditorWidget.java | 297 ++++++++++++++++++ .../gui/widgets/guide/GuidePageWidget.java | 57 ++-- .../gui/widgets/guide/GuideWidget.java | 64 +++- .../gui/widgets/guide/IGuideWidget.java | 8 + .../gui/widgets/guide/ImageWidget.java | 40 ++- .../gui/widgets/guide/TextBoxWidget.java | 30 +- .../guide/congiurator/ConfiguratorWidget.java | 96 ++++++ .../guide/congiurator/NumberConfigurator.java | 57 ++++ .../guide/congiurator/StringConfigurator.java | 44 +++ .../congiurator/TextListConfigurator.java | 54 ++++ .../textures/gui/terminal/terminal_add.png | Bin 0 -> 2273 bytes .../textures/gui/terminal/terminal_delete.png | Bin 0 -> 1987 bytes .../textures/gui/terminal/terminal_down.png | Bin 0 -> 1903 bytes .../textures/gui/terminal/terminal_up.png | Bin 0 -> 1899 bytes 36 files changed, 1347 insertions(+), 274 deletions(-) create mode 100644 src/main/java/gregtech/api/gui/resources/TextTexture.java create mode 100644 src/main/java/gregtech/api/gui/widgets/tab/IGuiTextureTabInfo.java create mode 100644 src/main/java/gregtech/api/terminal/gui/CustomTabListRenderer.java create mode 100644 src/main/java/gregtech/api/terminal/gui/IDraggable.java rename src/main/java/gregtech/api/terminal/gui/widgets/{ScrollablePanelWidgetGroup.java => DraggableScrollableWidgetGroup.java} (52%) create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/RectButtonWidget.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/TextEditorWidget.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java delete mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditor.java delete mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditorPageWidget.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/ConfiguratorWidget.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/NumberConfigurator.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/StringConfigurator.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/TextListConfigurator.java create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/terminal_add.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/terminal_delete.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/terminal_down.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/terminal_up.png diff --git a/src/main/java/gregtech/api/gui/GuiTextures.java b/src/main/java/gregtech/api/gui/GuiTextures.java index a3414a5026d..463718feade 100644 --- a/src/main/java/gregtech/api/gui/GuiTextures.java +++ b/src/main/java/gregtech/api/gui/GuiTextures.java @@ -173,5 +173,9 @@ public class GuiTextures { public static final TextureArea TERMINAL_MENU = TextureArea.fullImage("textures/gui/terminal/terminal_menu.png"); public static final TextureArea TERMINAL_HOME = TextureArea.fullImage("textures/gui/terminal/terminal_home.png"); public static final TextureArea TERMINAL_SETTING = TextureArea.fullImage("textures/gui/terminal/terminal_setting.png"); + public static final TextureArea TERMINAL_DELETE = TextureArea.fullImage("textures/gui/terminal/terminal_delete.png"); + public static final TextureArea TERMINAL_UP = TextureArea.fullImage("textures/gui/terminal/terminal_up.png"); + public static final TextureArea TERMINAL_DOWN = TextureArea.fullImage("textures/gui/terminal/terminal_down.png"); + public static final TextureArea TERMINAL_ADD = TextureArea.fullImage("textures/gui/terminal/terminal_add.png"); } diff --git a/src/main/java/gregtech/api/gui/Widget.java b/src/main/java/gregtech/api/gui/Widget.java index 7ba6311f2f5..ba29818c0ae 100644 --- a/src/main/java/gregtech/api/gui/Widget.java +++ b/src/main/java/gregtech/api/gui/Widget.java @@ -85,6 +85,12 @@ public void setSelfPosition(Position selfPosition) { recomputePosition(); } + public Position addSelfPosition(int addX, int addY) { + this.selfPosition = new Position(selfPosition.x + addX, selfPosition.y + addY); + recomputePosition(); + return this.selfPosition; + } + public Position getSelfPosition() { return selfPosition; } diff --git a/src/main/java/gregtech/api/gui/resources/ColorRectTexture.java b/src/main/java/gregtech/api/gui/resources/ColorRectTexture.java index d1b192f11b4..8c1683cd0c7 100644 --- a/src/main/java/gregtech/api/gui/resources/ColorRectTexture.java +++ b/src/main/java/gregtech/api/gui/resources/ColorRectTexture.java @@ -5,6 +5,8 @@ import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import java.awt.*; + public class ColorRectTexture implements IGuiTexture{ private final int color; @@ -12,6 +14,10 @@ public ColorRectTexture(int color) { this.color = color; } + public ColorRectTexture(Color color) { + this.color = color.getRGB(); + } + @Override public void draw(double x, double y, int width, int height) { double j; diff --git a/src/main/java/gregtech/api/gui/resources/RenderUtil.java b/src/main/java/gregtech/api/gui/resources/RenderUtil.java index cf8a28ab440..f5033a12b73 100644 --- a/src/main/java/gregtech/api/gui/resources/RenderUtil.java +++ b/src/main/java/gregtech/api/gui/resources/RenderUtil.java @@ -139,6 +139,7 @@ public static void renderCircle(float x, float y, float r, int color, int segmen } tessellator.draw(); GlStateManager.enableTexture2D(); + GlStateManager.color(1,1,1,1); } public static void renderSector(float x, float y, float r, int color, int segments, int from, int to) { diff --git a/src/main/java/gregtech/api/gui/resources/TextTexture.java b/src/main/java/gregtech/api/gui/resources/TextTexture.java new file mode 100644 index 00000000000..04f20a4e37f --- /dev/null +++ b/src/main/java/gregtech/api/gui/resources/TextTexture.java @@ -0,0 +1,31 @@ +package gregtech.api.gui.resources; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.resources.I18n; +import net.minecraftforge.fml.common.FMLCommonHandler; + +public class TextTexture implements IGuiTexture{ + private final String text; + private final int color; + private final int textWidth; + + public TextTexture(String text) { + this.text = text; + this.color = 0xff000000; + textWidth = FMLCommonHandler.instance().getSide().isClient()? Minecraft.getMinecraft().fontRenderer.getStringWidth(text):0; + } + + public TextTexture(String text, int color) { + this.text = text; + this.color = color; + textWidth = FMLCommonHandler.instance().getSide().isClient()? Minecraft.getMinecraft().fontRenderer.getStringWidth(text):0; + } + + + @Override + public void draw(double x, double y, int width, int height) { + FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer; + fontRenderer.drawString(I18n.format(text), (float) (x + (width - textWidth) / 2), (float) (y + (height - fontRenderer.FONT_HEIGHT) / 2 + 2), color, false); + } +} diff --git a/src/main/java/gregtech/api/gui/widgets/ClickButtonWidget.java b/src/main/java/gregtech/api/gui/widgets/ClickButtonWidget.java index 3b6f45f8b46..b9285632b55 100644 --- a/src/main/java/gregtech/api/gui/widgets/ClickButtonWidget.java +++ b/src/main/java/gregtech/api/gui/widgets/ClickButtonWidget.java @@ -24,6 +24,7 @@ public class ClickButtonWidget extends Widget { protected final String displayText; protected int textColor = 0xFFFFFF; protected final Consumer onPressCallback; + protected boolean shouldClientCallback; public ClickButtonWidget(int xPosition, int yPosition, int width, int height, String displayText, Consumer onPressed) { super(new Position(xPosition, yPosition), new Size(width, height)); @@ -31,6 +32,11 @@ public ClickButtonWidget(int xPosition, int yPosition, int width, int height, St this.onPressCallback = onPressed; } + public ClickButtonWidget setShouldClientCallback(boolean shouldClientCallback) { + this.shouldClientCallback = shouldClientCallback; + return this; + } + public ClickButtonWidget setButtonTexture(TextureArea buttonTexture) { this.buttonTexture = buttonTexture; return this; @@ -71,6 +77,9 @@ public boolean mouseClicked(int mouseX, int mouseY, int button) { protected void triggerButton() { ClickData clickData = new ClickData(Mouse.getEventButton(), isShiftDown(), isCtrlDown()); writeClientAction(1, clickData::writeToBuf); + if (shouldClientCallback) { + onPressCallback.accept(clickData); + } playButtonClickSound(); } diff --git a/src/main/java/gregtech/api/gui/widgets/SimpleTextWidget.java b/src/main/java/gregtech/api/gui/widgets/SimpleTextWidget.java index 7381d723882..aa2b296e984 100644 --- a/src/main/java/gregtech/api/gui/widgets/SimpleTextWidget.java +++ b/src/main/java/gregtech/api/gui/widgets/SimpleTextWidget.java @@ -24,6 +24,7 @@ public class SimpleTextWidget extends Widget { protected final int color; protected final Supplier textSupplier; protected String lastText = ""; + protected boolean clientWidget; public SimpleTextWidget(int xPosition, int yPosition, String formatLocale, int color, Supplier textSupplier) { super(new Position(xPosition, yPosition), Size.ZERO); @@ -32,6 +33,14 @@ public SimpleTextWidget(int xPosition, int yPosition, String formatLocale, int c this.textSupplier = textSupplier; } + public SimpleTextWidget(int xPosition, int yPosition, String formatLocale, int color, Supplier textSupplier, boolean clientWidget) { + super(new Position(xPosition, yPosition), Size.ZERO); + this.color = color; + this.formatLocale = formatLocale; + this.textSupplier = textSupplier; + this.clientWidget = clientWidget; + } + public SimpleTextWidget(int xPosition, int yPosition, String formatLocale, Supplier textSupplier) { this(xPosition, yPosition, formatLocale, 0x404040, textSupplier); } @@ -45,6 +54,19 @@ private void updateSize() { } } + @Override + public void updateScreen() { + super.updateScreen(); + if (clientWidget && textSupplier != null) { + String newString = textSupplier.get(); + if (!newString.equals(lastText)) { + lastText = newString; + updateSize(); + } + lastText = newString; + } + } + @Override public void drawInBackground(int mouseX, int mouseY, IRenderContext context) { FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer; diff --git a/src/main/java/gregtech/api/gui/widgets/TabGroup.java b/src/main/java/gregtech/api/gui/widgets/TabGroup.java index b18ee5089bf..7c92191048a 100644 --- a/src/main/java/gregtech/api/gui/widgets/TabGroup.java +++ b/src/main/java/gregtech/api/gui/widgets/TabGroup.java @@ -19,6 +19,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.function.BiConsumer; import java.util.function.Supplier; import static gregtech.api.gui.impl.ModularUIGui.*; @@ -27,8 +28,14 @@ public class TabGroup extends AbstractWidgetGroup { private final List tabInfos = new ArrayList<>(); private final Map tabWidgets = new HashMap<>(); - private int selectedTabIndex = 0; + protected int selectedTabIndex = 0; private final TabListRenderer tabListRenderer; + private BiConsumer onTabChanged; + + public TabGroup(int x, int y, TabListRenderer tabListRenderer) { + super(new Position(x, y)); + this.tabListRenderer = tabListRenderer; + } public TabGroup(TabLocation tabLocation, Position position) { super(position); @@ -39,12 +46,18 @@ public TabGroup(TabLocation tabLocation) { this(tabLocation, Position.ORIGIN); } - public void addTab(ITabInfo tabInfo, AbstractWidgetGroup tabWidget) { + public TabGroup addTab(ITabInfo tabInfo, AbstractWidgetGroup tabWidget) { this.tabInfos.add(tabInfo); int tabIndex = tabInfos.size() - 1; this.tabWidgets.put(tabIndex, tabWidget); tabWidget.setVisible(tabIndex == selectedTabIndex); addWidget(tabWidget); + return this; + } + + public TabGroup setOnTabChanged(BiConsumer onTabChanged) { + this.onTabChanged = onTabChanged; + return this; } @Override @@ -104,9 +117,13 @@ public boolean mouseClicked(int mouseX, int mouseY, int button) { } private void setSelectedTab(int tabIndex) { + int old = selectedTabIndex; this.tabWidgets.get(selectedTabIndex).setVisible(false); this.tabWidgets.get(tabIndex).setVisible(true); this.selectedTabIndex = tabIndex; + if (this.onTabChanged != null) { + onTabChanged.accept(old, tabIndex); + } } @Override diff --git a/src/main/java/gregtech/api/gui/widgets/TextFieldWidget.java b/src/main/java/gregtech/api/gui/widgets/TextFieldWidget.java index 2ee4448526e..1cad2d7abc2 100644 --- a/src/main/java/gregtech/api/gui/widgets/TextFieldWidget.java +++ b/src/main/java/gregtech/api/gui/widgets/TextFieldWidget.java @@ -41,6 +41,15 @@ public TextFieldWidget(int xPosition, int yPosition, int width, int height, bool this.textResponder = textResponder; } + public void setCurrentString(String currentString) { + this.currentString = currentString; + this.textField.setText(currentString); + } + + public String getCurrentString() { + return this.textField.getText(); + } + @Override protected void onPositionUpdate() { if (isClientSide() && textField != null) { diff --git a/src/main/java/gregtech/api/gui/widgets/tab/IGuiTextureTabInfo.java b/src/main/java/gregtech/api/gui/widgets/tab/IGuiTextureTabInfo.java new file mode 100644 index 00000000000..e254d652605 --- /dev/null +++ b/src/main/java/gregtech/api/gui/widgets/tab/IGuiTextureTabInfo.java @@ -0,0 +1,36 @@ +package gregtech.api.gui.widgets.tab; + +import com.google.common.collect.Lists; +import gregtech.api.gui.resources.IGuiTexture; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.resources.I18n; +import net.minecraftforge.fml.client.config.GuiUtils; + +import static gregtech.api.gui.impl.ModularUIGui.*; + +public class IGuiTextureTabInfo implements ITabInfo { + private final IGuiTexture texture; + private final String nameLocale; + + public IGuiTextureTabInfo(IGuiTexture texture, String nameLocale) { + this.texture = texture; + this.nameLocale = nameLocale; + } + + @Override + public void renderTab(IGuiTexture tabTexture, int posX, int posY, int xSize, int ySize, boolean isSelected) { + tabTexture.draw(posX, posY, xSize, ySize); + texture.draw(posX, posY, xSize, ySize); + GlStateManager.color(rColorForOverlay, gColorForOverlay, bColorForOverlay, 1.0F); + } + + @Override + public void renderHoverText(int posX, int posY, int xSize, int ySize, int guiWidth, int guiHeight, boolean isSelected, int mouseX, int mouseY) { + String localizedText = I18n.format(nameLocale); + Minecraft mc = Minecraft.getMinecraft(); + ScaledResolution resolution = new ScaledResolution(mc); + GuiUtils.drawHoveringText(Lists.newArrayList(localizedText), mouseX, mouseY, resolution.getScaledWidth(), resolution.getScaledHeight(), -1, mc.fontRenderer); + } +} diff --git a/src/main/java/gregtech/api/gui/widgets/tab/ITabInfo.java b/src/main/java/gregtech/api/gui/widgets/tab/ITabInfo.java index f5c7c961745..28fb8daace7 100644 --- a/src/main/java/gregtech/api/gui/widgets/tab/ITabInfo.java +++ b/src/main/java/gregtech/api/gui/widgets/tab/ITabInfo.java @@ -1,10 +1,10 @@ package gregtech.api.gui.widgets.tab; -import gregtech.api.gui.resources.TextureArea; +import gregtech.api.gui.resources.IGuiTexture; public interface ITabInfo { - void renderTab(TextureArea tabTexture, int posX, int posY, int xSize, int ySize, boolean isSelected); + void renderTab(IGuiTexture tabTexture, int posX, int posY, int xSize, int ySize, boolean isSelected); void renderHoverText(int posX, int posY, int xSize, int ySize, int guiWidth, int guiHeight, boolean isSelected, int mouseX, int mouseY); diff --git a/src/main/java/gregtech/api/gui/widgets/tab/ItemTabInfo.java b/src/main/java/gregtech/api/gui/widgets/tab/ItemTabInfo.java index 7d8266f1afa..d8ff74a3f4e 100644 --- a/src/main/java/gregtech/api/gui/widgets/tab/ItemTabInfo.java +++ b/src/main/java/gregtech/api/gui/widgets/tab/ItemTabInfo.java @@ -1,6 +1,7 @@ package gregtech.api.gui.widgets.tab; import com.google.common.collect.Lists; +import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.resources.TextureArea; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.ScaledResolution; @@ -23,7 +24,7 @@ public ItemTabInfo(String nameLocale, ItemStack iconStack) { } @Override - public void renderTab(TextureArea tabTexture, int posX, int posY, int xSize, int ySize, boolean isSelected) { + public void renderTab(IGuiTexture tabTexture, int posX, int posY, int xSize, int ySize, boolean isSelected) { tabTexture.draw(posX, posY, xSize, ySize); GlStateManager.enableRescaleNormal(); RenderHelper.enableGUIStandardItemLighting(); @@ -35,10 +36,12 @@ public void renderTab(TextureArea tabTexture, int posX, int posY, int xSize, int @Override public void renderHoverText(int posX, int posY, int xSize, int ySize, int guiWidth, int guiHeight, boolean isSelected, int mouseX, int mouseY) { - String localizedText = I18n.format(nameLocale); - Minecraft mc = Minecraft.getMinecraft(); - ScaledResolution resolution = new ScaledResolution(mc); - GuiUtils.drawHoveringText(Lists.newArrayList(localizedText), mouseX, mouseY, - resolution.getScaledWidth(), resolution.getScaledHeight(), -1, mc.fontRenderer); + if (nameLocale != null) { + String localizedText = I18n.format(nameLocale); + Minecraft mc = Minecraft.getMinecraft(); + ScaledResolution resolution = new ScaledResolution(mc); + GuiUtils.drawHoveringText(Lists.newArrayList(localizedText), mouseX, mouseY, + resolution.getScaledWidth(), resolution.getScaledHeight(), -1, mc.fontRenderer); + } } } diff --git a/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java b/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java index 75fbbe49fea..9ecb104de8d 100644 --- a/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java +++ b/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java @@ -1,8 +1,8 @@ package gregtech.api.terminal.app; import gregtech.api.gui.resources.TextureArea; -import gregtech.api.terminal.gui.widgets.guide.GuideEditor; -import gregtech.api.terminal.gui.widgets.guide.GuideEditorPageWidget; +import gregtech.api.terminal.gui.widgets.guide.GuideConfigEditor; +import gregtech.api.terminal.gui.widgets.guide.GuidePageEditorWidget; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.PacketBuffer; @@ -19,8 +19,12 @@ public GuideEditorApp() { public AbstractApplication createApp(boolean isClient, NBTTagCompound nbt) { if (isClient) { GuideEditorApp app = new GuideEditorApp(); - app.addWidget(new GuideEditor(0, 20, 133, 232)); - app.addWidget(new GuideEditorPageWidget(133, 0, 200, 232)); + GuideConfigEditor configEditor = new GuideConfigEditor(0, 0, 133, 232); + GuidePageEditorWidget pageEditor = new GuidePageEditorWidget(133, 0, 200, 232); + configEditor.setGuidePageEditorWidget(pageEditor); + pageEditor.setGuideConfigEditor(configEditor); + app.addWidget(pageEditor); + app.addWidget(configEditor); return app; } return null; diff --git a/src/main/java/gregtech/api/terminal/gui/CustomTabListRenderer.java b/src/main/java/gregtech/api/terminal/gui/CustomTabListRenderer.java new file mode 100644 index 00000000000..c84cfd66220 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/CustomTabListRenderer.java @@ -0,0 +1,41 @@ +package gregtech.api.terminal.gui; + +import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.widgets.tab.ITabInfo; +import gregtech.api.gui.widgets.tab.TabListRenderer; +import gregtech.api.util.Position; + +import java.util.List; + +public class CustomTabListRenderer extends TabListRenderer { + private final IGuiTexture unSelected; + private final IGuiTexture selected; + private final int width; + private final int height; + + public CustomTabListRenderer(IGuiTexture unSelected, IGuiTexture selected, int width, int height){ + this.unSelected = unSelected; + this.selected = selected; + this.width = width; + this.height = height; + } + + @Override + public void renderTabs(Position offset, List tabInfos, int guiWidth, int guiHeight, int selectedTabIndex) { + int y = offset.y - height; + for (int i = 0; i < tabInfos.size(); i++) { + int x = offset.x + i * width; + if (selectedTabIndex == i && selected != null) { + tabInfos.get(i).renderTab(selected, x, y, width, height, true); + } + if (selectedTabIndex != i && unSelected != null) { + tabInfos.get(i).renderTab(unSelected, x, y, width, height, false); + } + } + } + + @Override + public int[] getTabPos(int guiWidth, int guiHeight, int tabIndex) { + return new int[]{width * guiWidth, -height, width, height}; + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/IDraggable.java b/src/main/java/gregtech/api/terminal/gui/IDraggable.java new file mode 100644 index 00000000000..1c38550638e --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/IDraggable.java @@ -0,0 +1,9 @@ +package gregtech.api.terminal.gui; + +public interface IDraggable { + boolean setDraggable(boolean isDraggable); + boolean allowDrag(int mouseX, int mouseY, int button); + default void startDrag(int mouseX, int mouseY) {} + default boolean dragging(int mouseX, int mouseY, int deltaX, int deltaY) {return true;} + default void endDrag(int mouseX, int mouseY) {} +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java index ccce2bcc7b7..47c89d0f085 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java @@ -17,14 +17,14 @@ import java.util.function.Consumer; public class CircleButtonWidget extends Widget { - private final int border; - private int hoverTick; - private boolean isHover; - private String hoverText; - private IGuiTexture icon; - private final int iconSize; - private Consumer onPressCallback; - private final int[] colors = { + protected int border; + protected int hoverTick; + protected boolean isHover; + protected String hoverText; + protected IGuiTexture icon; + protected final int iconSize; + protected Consumer onPressCallback; + protected final int[] colors = { new Color(146, 146, 146).getRGB(), new Color(39, 232, 141).getRGB(), new Color(255, 255, 255).getRGB(), @@ -57,7 +57,17 @@ public CircleButtonWidget setColors(int stroke, int strokeAnima, int fill) { return this; } - public CircleButtonWidget setFillColors(int fill) { + public CircleButtonWidget setStroke(int stroke) { + colors[0] = stroke; + return this; + } + + public CircleButtonWidget setStrokeAnima(int strokeAnima) { + colors[1] = strokeAnima; + return this; + } + + public CircleButtonWidget setFill(int fill) { colors[2] = fill; return this; } @@ -94,7 +104,6 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender } RenderUtil.renderCircle(x, y, r - border, colors[2], segments); if (icon != null) { - GlStateManager.color(1,1,1,1); icon.draw(x - iconSize / 2f, y - iconSize / 2f, iconSize, iconSize); } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/ScrollablePanelWidgetGroup.java b/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java similarity index 52% rename from src/main/java/gregtech/api/terminal/gui/widgets/ScrollablePanelWidgetGroup.java rename to src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java index 245b12027ad..eb45dd3d8c0 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/ScrollablePanelWidgetGroup.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java @@ -4,13 +4,13 @@ import gregtech.api.gui.Widget; import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.terminal.gui.IDraggable; import gregtech.api.util.Position; import gregtech.api.util.RenderUtil; import gregtech.api.util.Size; -import net.minecraft.client.renderer.GlStateManager; import net.minecraft.util.math.MathHelper; -public class ScrollablePanelWidgetGroup extends WidgetGroup { +public class DraggableScrollableWidgetGroup extends WidgetGroup { protected int scrollXOffset; protected int scrollYOffset; protected int xBarHeight; @@ -23,47 +23,49 @@ public class ScrollablePanelWidgetGroup extends WidgetGroup { protected IGuiTexture xBarF; protected IGuiTexture yBarB; protected IGuiTexture yBarF; + protected boolean focus; private int lastMouseX; private int lastMouseY; private boolean draggedPanel; private boolean draggedOnXScrollBar; private boolean draggedOnYScrollBar; + private Widget draggedWidget; - public ScrollablePanelWidgetGroup(int x, int y, int width, int height) { + public DraggableScrollableWidgetGroup(int x, int y, int width, int height) { super(new Position(x, y), new Size(width, height)); maxHeight = height; maxWidth = width; } - public ScrollablePanelWidgetGroup availableXScrollBarHeight(int xBar) { + public DraggableScrollableWidgetGroup setXScrollBarHeight(int xBar) { this.xBarHeight = xBar; return this; } - public ScrollablePanelWidgetGroup availableYScrollBarWidth(int yBar) { + public DraggableScrollableWidgetGroup setYScrollBarWidth(int yBar) { this.yBarWidth = yBar; return this; } - public ScrollablePanelWidgetGroup setDraggable(boolean draggable) { + public DraggableScrollableWidgetGroup setDraggable(boolean draggable) { this.draggable = draggable; return this; } - public ScrollablePanelWidgetGroup setBackground(IGuiTexture background) { + public DraggableScrollableWidgetGroup setBackground(IGuiTexture background) { this.background = background; return this; } - public ScrollablePanelWidgetGroup setXBarStyle(IGuiTexture background, IGuiTexture bar) { + public DraggableScrollableWidgetGroup setXBarStyle(IGuiTexture background, IGuiTexture bar) { this.xBarB = background; this.xBarF = bar; return this; } - public ScrollablePanelWidgetGroup setYBarStyle(IGuiTexture background, IGuiTexture bar) { + public DraggableScrollableWidgetGroup setYBarStyle(IGuiTexture background, IGuiTexture bar) { this.yBarB = background; this.yBarF = bar; return this; @@ -81,6 +83,7 @@ public int getScrollXOffset() { public void addWidget(Widget widget) { maxHeight = Math.max(maxHeight, widget.getSize().height + widget.getSelfPosition().y); maxWidth = Math.max(maxWidth, widget.getSize().width + widget.getSelfPosition().x); + widget.addSelfPosition(- scrollXOffset, - scrollYOffset); super.addWidget(widget); } @@ -103,11 +106,50 @@ public void setSize(Size size) { } protected void computeMax() { - maxHeight = getSize().height; - maxWidth = getSize().width; + int mh = 0; + int mw = 0; for (Widget widget : widgets) { - maxHeight = Math.max(maxHeight, widget.getSize().height + widget.getSelfPosition().y); - maxWidth = Math.max(maxWidth, widget.getSize().width + widget.getSelfPosition().x); + mh = Math.max(mh, widget.getSize().height + widget.getSelfPosition().y + scrollYOffset); + mw = Math.max(mw, widget.getSize().width + widget.getSelfPosition().x + scrollXOffset); + } + int offsetY = 0; + int offsetX = 0; + if (mh > getSize().height && mh < maxHeight) { + offsetY = maxHeight - mh; + maxHeight = mh; + if (scrollYOffset - offsetY < 0) { + offsetY = scrollYOffset; + } + scrollYOffset -= offsetY; + } else if (mh < getSize().height) { + offsetY = maxHeight - getSize().height; + maxHeight = getSize().height; + if (scrollYOffset - offsetY < 0) { + offsetY = scrollYOffset; + } + scrollYOffset -= offsetY; + } + if (mw > getSize().width && mw < maxWidth) { + offsetX = maxWidth - mw; + maxWidth = mw; + if (scrollXOffset - offsetX < 0) { + offsetX = scrollXOffset; + } + scrollXOffset -= offsetX; + }else if (mw < getSize().width) { + offsetX = maxWidth - getSize().width; + maxWidth = getSize().width; + if (scrollXOffset - offsetX < 0) { + offsetX = scrollXOffset; + } + scrollXOffset -= offsetX; + } + if (offsetX != 0 || offsetY != 0) { + for (Widget widget : widgets) { + Position newPos = widget.addSelfPosition(offsetX, offsetY); + widget.setVisible(newPos.x < getSize().width - yBarWidth && newPos.x + widget.getSize().width > 0); + widget.setVisible(newPos.y < getSize().height - xBarHeight && newPos.y + widget.getSize().height > 0); + } } } @@ -119,23 +161,31 @@ protected int getMaxWidth() { return maxWidth + yBarWidth; } + public int getWidgetBottomHeight() { + int y = 0; + for (Widget widget : widgets) { + y = Math.max(y, widget.getSize().height + widget.getSelfPosition().y); + } + return y; + } + protected void setScrollXOffset(int scrollXOffset) { if (scrollXOffset == this.scrollXOffset) return; + int offset = scrollXOffset - this.scrollXOffset; this.scrollXOffset = scrollXOffset; - int minX = this.scrollXOffset + getPosition().x; - int maxX = minX + getSize().width; for (Widget widget : widgets) { - widget.setVisible(widget.getPosition().x < maxX && widget.getPosition().x + widget.getSize().width > minX); + Position newPos = widget.addSelfPosition( - offset, 0); + widget.setVisible(newPos.x < getSize().width - yBarWidth && newPos.x + widget.getSize().width > 0); } } protected void setScrollYOffset(int scrollYOffset) { if (scrollYOffset == this.scrollYOffset) return; + int offset = scrollYOffset - this.scrollYOffset; this.scrollYOffset = scrollYOffset; - int minY = this.scrollYOffset + getPosition().y; - int maxY = minY + getSize().height; for (Widget widget : widgets) { - widget.setVisible(widget.getPosition().y < maxY && widget.getPosition().y + widget.getSize().height > minY); + Position newPos = widget.addSelfPosition(0, - offset); + widget.setVisible(newPos.y < getSize().height - xBarHeight && newPos.y + widget.getSize().height > 0); } } @@ -151,6 +201,10 @@ private boolean isOnYScrollPane(int mouseX, int mouseY) { return isMouseOver(pos.x + size.width - yBarWidth, pos.y, yBarWidth, size.height, mouseX, mouseY); } + protected boolean hookDrawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + return false; + } + @Override public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { Position position = getPosition(); @@ -158,11 +212,11 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender if (background != null) { background.draw(position.x, position.y, size.width, size.height); } - GlStateManager.translate(-scrollXOffset, -scrollYOffset, 0); RenderUtil.useScissor(position.x, position.y, size.width - yBarWidth, size.height - xBarHeight, ()->{ - super.drawInBackground(mouseX +scrollXOffset, mouseY + scrollYOffset, partialTicks, context); + if(!hookDrawInBackground(mouseX, mouseY, partialTicks, context)) { + super.drawInBackground(mouseX, mouseY, partialTicks, context); + } }); - GlStateManager.translate(scrollXOffset, scrollYOffset, 0); if (xBarHeight > 0) { if (xBarB != null) { xBarB.draw(position.x, position.y - xBarHeight, size.width, xBarHeight); @@ -181,26 +235,6 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender yBarF.draw(position.x + size.width - yBarWidth, position.y + scrollYOffset * size.height * 1.0f / getMaxHeight(), yBarWidth, barHeight); } } - - } - - private void drawBar(Position position, Size size, int barSize, IGuiTexture barB, IGuiTexture barF, int anotherBarSize) { - if (barSize > 0) { - if (barB != null) { - barB.draw(position.x, position.y - barSize, size.width, barSize); - } - if (barF != null) { - int barWidth = (size.width + anotherBarSize) / getMaxWidth(); - barF.draw(position.x + scrollXOffset - barSize, position.y, barWidth, barSize); - } - } - } - - @Override - public void drawInForeground(int mouseX, int mouseY) { - GlStateManager.translate(-scrollXOffset, -scrollYOffset, 0); - super.drawInForeground(mouseX, mouseY + scrollYOffset); - GlStateManager.translate(scrollXOffset, scrollYOffset, 0); } @Override @@ -209,18 +243,43 @@ public boolean mouseClicked(int mouseX, int mouseY, int button) { lastMouseY = mouseY; if (xBarHeight > 0 && isOnXScrollPane(mouseX, mouseY)) { this.draggedOnXScrollBar = true; + focus = true; return true; } else if (yBarWidth > 0 && isOnYScrollPane(mouseX, mouseY)) { this.draggedOnYScrollBar = true; + focus = true; return true; } else if(isMouseOverElement(mouseX, mouseY)){ - if (super.mouseClicked(mouseX + scrollXOffset, mouseY + scrollYOffset, button)) { + focus = true; + if (checkClickedDragged(mouseX, mouseY, button)) { return true; - } else if (draggable) { + } + if (draggable) { this.draggedPanel = true; return true; } + return false; + } else if (checkClickedDragged(mouseX, mouseY, button)) { + return true; + } + focus = false; + return false; + } + + private boolean checkClickedDragged(int mouseX, int mouseY, int button) { + draggedWidget = null; + for (int i = widgets.size() - 1; i >= 0; i--) { + Widget widget = widgets.get(i); + if(widget.isVisible()) { + if(widget.mouseClicked(mouseX, mouseY, button)) { + return true; + } else if (widget instanceof IDraggable && ((IDraggable) widget).allowDrag(mouseX, mouseY, button)) { + draggedWidget = widget; + ((IDraggable) widget).startDrag(mouseX, mouseY); + return true; + } + } } return false; } @@ -228,7 +287,7 @@ else if (yBarWidth > 0 && isOnYScrollPane(mouseX, mouseY)) { @Override public boolean mouseWheelMove(int mouseX, int mouseY, int wheelDelta) { if (this.isMouseOverElement(mouseX, mouseY, true)) { - if (super.mouseWheelMove(mouseX + scrollXOffset, mouseY + scrollYOffset, wheelDelta)) { + if (super.mouseWheelMove(mouseX, mouseY, wheelDelta)) { return true; } int moveDelta = -MathHelper.clamp(wheelDelta, -1, 1) * 5; @@ -237,22 +296,31 @@ public boolean mouseWheelMove(int mouseX, int mouseY, int wheelDelta) { } return true; } + focus = false; return false; } @Override public boolean mouseDragged(int mouseX, int mouseY, int button, long timeDragged) { + int deltaX = mouseX - lastMouseX; + int deltaY = mouseY - lastMouseY; + lastMouseX = mouseX; + lastMouseY = mouseY; if (draggedOnXScrollBar) { - setScrollXOffset(MathHelper.clamp(scrollXOffset + (mouseX - lastMouseX) * getMaxWidth() / getSize().width, 0, Math.max(getMaxWidth() - getSize().width, 0))); + setScrollXOffset(MathHelper.clamp(scrollXOffset + deltaX * getMaxWidth() / getSize().width, 0, Math.max(getMaxWidth() - getSize().width, 0))); + return true; } else if (draggedOnYScrollBar) { - setScrollYOffset(MathHelper.clamp(scrollYOffset + (mouseY - lastMouseY) * getMaxHeight() / getSize().height, 0, Math.max(getMaxHeight() - getSize().height, 0))); + setScrollYOffset(MathHelper.clamp(scrollYOffset + deltaY * getMaxHeight() / getSize().height, 0, Math.max(getMaxHeight() - getSize().height, 0))); + return true; + } else if (draggedWidget != null && ((IDraggable)draggedWidget).dragging(mouseX, mouseY, deltaX, deltaY)) { + draggedWidget.addSelfPosition(deltaX, deltaY); + return true; } else if (draggedPanel) { - setScrollXOffset(MathHelper.clamp(scrollXOffset + lastMouseX - mouseX, 0, Math.max(getMaxWidth() - yBarWidth - getSize().width, 0))); - setScrollYOffset(MathHelper.clamp(scrollYOffset + lastMouseY - mouseY, 0, Math.max(getMaxHeight() - xBarHeight - getSize().height, 0))); + setScrollXOffset(MathHelper.clamp(scrollXOffset - deltaX, 0, Math.max(getMaxWidth() - yBarWidth - getSize().width, 0))); + setScrollYOffset(MathHelper.clamp(scrollYOffset - deltaY, 0, Math.max(getMaxHeight() - xBarHeight - getSize().height, 0))); + return true; } - lastMouseX = mouseX; - lastMouseY = mouseY; - return super.mouseDragged(mouseX + scrollXOffset, mouseY + scrollYOffset, button, timeDragged); + return super.mouseDragged(mouseX, mouseY, button, timeDragged); } @Override @@ -261,10 +329,13 @@ public boolean mouseReleased(int mouseX, int mouseY, int button) { draggedOnXScrollBar = false; } else if (draggedOnYScrollBar) { draggedOnYScrollBar = false; + } else if (draggedWidget != null) { + ((IDraggable)draggedWidget).endDrag(mouseX, mouseY); + draggedWidget = null; } else if (draggedPanel) { draggedPanel = false; } else { - return super.mouseReleased(mouseX + scrollXOffset, mouseY + scrollYOffset, button); + return super.mouseReleased(mouseX, mouseY, button); } return true; } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/RectButtonWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/RectButtonWidget.java new file mode 100644 index 00000000000..b20460798a3 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/RectButtonWidget.java @@ -0,0 +1,40 @@ +package gregtech.api.terminal.gui.widgets; + +import gregtech.api.gui.IRenderContext; +import gregtech.api.util.Position; +import gregtech.api.util.Size; + +public class RectButtonWidget extends CircleButtonWidget{ + public RectButtonWidget(int x, int y, int width, int height) { + this(x, y, width, height,2); + } + + public RectButtonWidget(int x, int y, int width, int height, int border) { + super(x, y); + setSelfPosition(new Position(x, y)); + setSize(new Size(width, height)); + this.border = border; + } + + @Override + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + int x = this.getPosition().x; + int y = this.getPosition().y; + int width = this.getSize().width; + int height = this.getSize().height; + + drawSolidRect(x, y, width, height, colors[0]); + isHover = this.isMouseOverElement(mouseX, mouseY); + if (isHover || hoverTick != 0) { + float per = Math. min ((hoverTick + partialTicks) / 8, 1); + drawSolidRect(x, y, (int) (width * per), border, colors[1]); + drawSolidRect(x + width - border, y, border, (int) (height * per), colors[1]); + drawSolidRect((int) ((1 - per) * width) + x, y + height - border, (int) (width * per), border, colors[1]); + drawSolidRect(x, (int) ((1 - per) * height) + y, border, (int) (height * per), colors[1]); + } + drawSolidRect(x + border, y + border, width - 2 * border, height - 2 * border, colors[2]); + if (icon != null) { + icon.draw(x + border, y + border, width - 2 * border, height - 2 * border); + } + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/TextEditorWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/TextEditorWidget.java new file mode 100644 index 00000000000..c64b17c15d8 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/TextEditorWidget.java @@ -0,0 +1,127 @@ +package gregtech.api.terminal.gui.widgets; + +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.util.Position; +import gregtech.api.util.Size; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.util.ChatAllowedCharacters; +import net.minecraft.util.text.TextFormatting; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +import java.awt.*; +import java.util.function.Consumer; + +public class TextEditorWidget extends WidgetGroup { + private final TextPanelWidget textPanelWidget; + public TextEditorWidget(int x, int y, int width, int height, String text, Consumer stringUpdate) { + super(new Position(x, y), new Size(width, height)); + textPanelWidget = new TextPanelWidget(0, 10, width, height-10, text, stringUpdate); + this.addWidget(new RectButtonWidget(0, 0, 20, 10, 1).setFill(new Color(109, 229, 154, 141).getRGB()).setHoverText("update").setClickListener(d->{ + if (stringUpdate != null) { + stringUpdate.accept(textPanelWidget.content); + } + })); + this.addWidget(textPanelWidget); + } + + public TextEditorWidget setBackground(IGuiTexture background) { + textPanelWidget.setBackground(background); + return this; + } + + private static class TextPanelWidget extends DraggableScrollableWidgetGroup { + private final static int SPACE = 0; + private int updateCount; + private String content; + private int textHeight; + private final Consumer stringUpdate; + @SideOnly(Side.CLIENT) + private FontRenderer fontRenderer; + + public TextPanelWidget(int x, int y, int width, int height, String text, Consumer stringUpdate) { + super(x, y, width, height); + this.stringUpdate = stringUpdate; + this.content = text == null ? "" : text; + if (isClientSide()) { + fontRenderer = Minecraft.getMinecraft().fontRenderer; + textHeight = fontRenderer.getWordWrappedHeight(content, width - yBarWidth); + } + } + + @Override + protected int getMaxHeight() { + return textHeight + SPACE + xBarHeight; + } + + public void updateScreen() { + super.updateScreen(); + ++this.updateCount; + } + + @Override + public boolean keyTyped(char typedChar, int keyCode) { + if(!focus) return false; + if (GuiScreen.isKeyComboCtrlV(keyCode)) { + this.pageInsertIntoCurrent(GuiScreen.getClipboardString()); + } else { + switch(keyCode) { + case 14: + if (!content.isEmpty()) { + this.pageSetCurrent(content.substring(0, content.length() - 1)); + } + return true; + case 28: + case 156: + this.pageInsertIntoCurrent("\n"); + return true; + default: + if (ChatAllowedCharacters.isAllowedCharacter(typedChar)) { + this.pageInsertIntoCurrent(Character.toString(typedChar)); + } + } + } + return true; + } + + private void pageSetCurrent(String string) { + if (!content.equals(string)) { + content = string; + if(stringUpdate != null) { + stringUpdate.accept(content); + } + textHeight = this.fontRenderer.getWordWrappedHeight(content + "" + TextFormatting.BLACK + "_", this.getSize().width - yBarWidth); + } + } + + private void pageInsertIntoCurrent(String string) { + content += string; + if(stringUpdate != null) { + stringUpdate.accept(content); + } + textHeight = this.fontRenderer.getWordWrappedHeight(content + "" + TextFormatting.BLACK + "_", this.getSize().width - yBarWidth); + } + + @Override + protected boolean hookDrawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + String contentString = content; + if (focus) { + if (this.fontRenderer.getBidiFlag()) { + contentString += "_"; + } else if (this.updateCount / 6 % 2 == 0) { + contentString += TextFormatting.BLACK + "_"; + } else { + contentString += TextFormatting.GRAY + "_"; + } + } + this.fontRenderer.drawSplitString(contentString, getPosition().x, getPosition().y+ SPACE, getSize().width - yBarWidth, 0); + return true; + } + } +} + + diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java new file mode 100644 index 00000000000..0ceb0a5512b --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java @@ -0,0 +1,126 @@ +package gregtech.api.terminal.gui.widgets.guide; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import gregtech.api.gui.GuiTextures; +import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.ColorRectTexture; +import gregtech.api.gui.resources.TextTexture; +import gregtech.api.gui.widgets.LabelWidget; +import gregtech.api.gui.widgets.TabGroup; +import gregtech.api.gui.widgets.tab.IGuiTextureTabInfo; +import gregtech.api.terminal.gui.CustomTabListRenderer; +import gregtech.api.terminal.gui.widgets.CircleButtonWidget; +import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; +import gregtech.api.util.Size; + +import java.awt.*; +import java.util.Map; + +public class GuideConfigEditor extends TabGroup { + public String json; + private IGuideWidget selected; + private GuidePageEditorWidget pageEditor; + private final DraggableScrollableWidgetGroup widgetSelector; + private final DraggableScrollableWidgetGroup widgetConfigurator; + + public GuideConfigEditor(int x, int y, int width, int height) { + super(x, y + 10, new CustomTabListRenderer( + new ColorRectTexture(new Color(175, 0, 0, 131)), + new ColorRectTexture(new Color(246, 120, 120, 190)), 30, 10)); + setSize(new Size(width, height)); + widgetSelector = createWidgetSelector(); + widgetConfigurator = createConfigurator(); + this.addTab(new IGuiTextureTabInfo(new TextTexture("W", -1), "widget"), widgetSelector); + this.addTab(new IGuiTextureTabInfo(new TextTexture("C", -1), "config"), widgetConfigurator); + this.addWidget(new CircleButtonWidget(100, -5, 5, 1, 3) + .setColors(new Color(255, 255, 255, 0).getRGB(), + new Color(255, 255, 255).getRGB(), + new Color(0, 115, 255).getRGB()) + .setIcon(GuiTextures.TERMINAL_ADD) + .setHoverText("add stream") + .setClickListener(this::addStream)); + this.addWidget(new CircleButtonWidget(120, -5, 5, 1, 3) + .setColors(new Color(255, 255, 255, 0).getRGB(), + new Color(255, 255, 255).getRGB(), + new Color(113, 27, 217).getRGB()) + .setIcon(GuiTextures.TERMINAL_ADD) + .setHoverText("add fixed") + .setClickListener(this::addFixed)); + } + + public void setGuidePageEditorWidget(GuidePageEditorWidget pageEditor) { + this.pageEditor = pageEditor; + } + + private DraggableScrollableWidgetGroup createWidgetSelector() { + DraggableScrollableWidgetGroup group = new DraggableScrollableWidgetGroup(0, 0, getSize().width, getSize().height - 10) + .setBackground(new ColorRectTexture(new Color(246, 120, 120, 190))) + .setYScrollBarWidth(4) + .setYBarStyle(null, new ColorRectTexture(new Color(148, 226, 193))); + int y = 10; //133 + for (Map.Entry entry : GuidePageWidget.REGISTER_WIDGETS.entrySet()) { + IGuideWidget widgetTemplate = entry.getValue(); + JsonObject template = widgetTemplate.getTemplate(false); +// template.addProperty("stroke", 0xFF7CA1FF); + Widget guideWidget = widgetTemplate.createStreamWidget(5, y + 10, getSize().width - 14, template); + group.addWidget(new LabelWidget(getSize().width / 2 - 1, y, entry.getKey(), -1).setXCentered(true)); + y += guideWidget.getSize().height + 25; + group.addWidget(guideWidget); + } + return group; + } + + private DraggableScrollableWidgetGroup createConfigurator() { + return new DraggableScrollableWidgetGroup(0, 0, getSize().width, getSize().height - 10) + .setBackground(new ColorRectTexture(new Color(246, 120, 120, 190))) + .setYScrollBarWidth(4) + .setYBarStyle(null, new ColorRectTexture(new Color(148, 226, 193))); + } + + public void loadConfigurator(IGuideWidget widget, JsonObject config, boolean isFixed) { + widgetConfigurator.clearAllWidgets(); + if (widget != null) { + widget.loadConfigurator(widgetConfigurator, config, isFixed, attr->{ + widget.updateValue(attr, config.get(attr)); + }); + } + } + + private void addFixed(ClickData data) { + if (pageEditor != null && selected != null) { + selected.setStroke(0); + pageEditor.addGuideWidget(selected, true); + selected.setStroke(0xFF7CA1FF); + } + } + + private void addStream(ClickData data) { + if (pageEditor != null && selected != null) { + selected.setStroke(0); + pageEditor.addGuideWidget(selected, false); + selected.setStroke(0xFF7CA1FF); + } + } + + @Override + public boolean mouseClicked(int mouseX, int mouseY, int button) { + boolean flag = super.mouseClicked(mouseX, mouseY, button); + if (selectedTabIndex == 0 && widgetSelector != null) { + for (Widget widget : widgetSelector.widgets) { + if (widget.isMouseOverElement(mouseX, mouseY)) { + if (widget instanceof IGuideWidget) { + if (selected != null) { + selected.setStroke(0); + } + ((IGuideWidget) widget).setStroke(0xFF7CA1FF); + selected = (IGuideWidget) widget; + } + playButtonClickSound(); + return true; + } + } + } + return flag; + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditor.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditor.java deleted file mode 100644 index c937385b683..00000000000 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditor.java +++ /dev/null @@ -1,31 +0,0 @@ -package gregtech.api.terminal.gui.widgets.guide; - -import gregtech.api.gui.widgets.AbstractWidgetGroup; -import gregtech.api.gui.widgets.LabelWidget; -import gregtech.api.gui.widgets.TabGroup; -import gregtech.api.gui.widgets.WidgetGroup; -import gregtech.api.gui.widgets.tab.ItemTabInfo; -import gregtech.api.terminal.gui.widgets.CircleButtonWidget; -import gregtech.api.util.Position; -import gregtech.api.util.Size; -import net.minecraft.init.Blocks; -import net.minecraft.item.ItemStack; - -public class GuideEditor extends WidgetGroup { - public String json; - public GuideEditor(int x, int y, int width, int height) { - super(new Position(x, y), new Size(width, height)); - TabGroup tabGroup = new TabGroup(TabGroup.TabLocation.HORIZONTAL_TOP_LEFT, Position.ORIGIN); - tabGroup.addTab(new ItemTabInfo("gregtech.machine.workbench.tab.workbench", new ItemStack(Blocks.CRAFTING_TABLE)), createItemListTab()); - tabGroup.addTab(new ItemTabInfo("gregtech.machine.workbench.tab.item_list", new ItemStack(Blocks.CHEST)), createItemListTab()); - this.addWidget(tabGroup); - } - - private AbstractWidgetGroup createItemListTab() { - WidgetGroup widgetGroup = new WidgetGroup(); - widgetGroup.addWidget(new LabelWidget(5, 20, "gregtech.machine.workbench.storage_note_1")); - widgetGroup.addWidget(new LabelWidget(5, 30, "gregtech.machine.workbench.storage_note_2")); - widgetGroup.addWidget(new CircleButtonWidget(10, 10)); - return widgetGroup; - } -} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditorPageWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditorPageWidget.java deleted file mode 100644 index 0b216647e0b..00000000000 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideEditorPageWidget.java +++ /dev/null @@ -1,118 +0,0 @@ -package gregtech.api.terminal.gui.widgets.guide; - - -import com.google.common.collect.BiMap; -import com.google.common.collect.HashBiMap; -import com.google.gson.*; -import gregtech.api.gui.Widget; -import gregtech.api.util.Position; -import gregtech.api.util.interpolate.Eases; -import gregtech.api.util.interpolate.Interpolator; - -public class GuideEditorPageWidget extends GuidePageWidget { - private final BiMap configMap; - - public GuideEditorPageWidget(int xPosition, int yPosition, int width, int height) { - super(xPosition, yPosition, width, height); - configMap = HashBiMap.create(); - setTitle("Template"); - } - - public String getJsonString() { - JsonObject json = new JsonObject(); - json.addProperty("section", ""); - json.addProperty("title", title.content.get(0)); - if (stream != null) { - JsonArray array = new JsonArray(); - json.add("stream", array); - stream.forEach(widget -> array.add(configMap.get(widget))); - } - if (fixed != null) { - JsonArray array = new JsonArray(); - json.add("fixed", array); - fixed.forEach(widget -> array.add(configMap.get(widget))); - } - return new Gson().toJson(json); - } - - public JsonObject addGuideWidget(IGuideWidget widget, boolean isFixed) { - int pageWidth = this.getSize().width; - JsonObject widgetConfig = widget.getTemplate(isFixed); - Widget guideWidget; - if (isFixed) { - guideWidget = widget.createFixedWidget(widgetConfig.get("x").getAsInt(), - widgetConfig.get("y").getAsInt(), - widgetConfig.get("width").getAsInt(), - widgetConfig.get("height").getAsInt(), - widgetConfig); - this.addWidget(guideWidget); - fixed.add(guideWidget); - } else { - int y = getStreamBottom(); - guideWidget = widget.createStreamWidget(5, y + 5, pageWidth - 5, widgetConfig); - this.addWidget(guideWidget); - stream.add(guideWidget); - } - configMap.put(guideWidget, widgetConfig); - return widgetConfig; - } - - - public void moveUp(Widget widget) { - int index = stream.indexOf(widget); - if (index > 0) { - Widget target = stream.get(index - 1); - if (interpolator == null) { - int offset = widget.getPosition().y - target.getPosition().y; - int y1 = widget.getSelfPosition().y; - int y2 = target.getSelfPosition().y; - interpolator = new Interpolator(0, offset, 10, Eases.EaseLinear, value->{ - widget.setSelfPosition(new Position(widget.getSelfPosition().x, y1 - value.intValue())); - target.setSelfPosition(new Position(target.getSelfPosition().x, y2 + value.intValue())); - }, value->{ - interpolator = null; - stream.remove(widget); - stream.add(index - 1, widget); - }).start(); - } - } - } - - public void moveDown(Widget widget) { - int index = stream.indexOf(widget); - if (index >= 0 && index < stream.size() - 1) { - Widget target = stream.get(index + 1); - if (interpolator == null) { - int offset = target.getPosition().y - widget.getPosition().y; - int y1 = widget.getSelfPosition().y; - int y2 = target.getSelfPosition().y; - interpolator = new Interpolator(0, offset, 10, Eases.EaseLinear, value->{ - widget.setSelfPosition(new Position(widget.getSelfPosition().x, y1 + value.intValue())); - target.setSelfPosition(new Position(target.getSelfPosition().x, y2 - value.intValue())); - }, value->{ - interpolator = null; - stream.remove(widget); - stream.add(index + 1, widget); - }).start(); - } - } - } - - @Override - public void removeWidget(Widget widget) { - int index = stream.indexOf(widget); - if (index >= 0) { - int offset = widget.getSize().height + 5; - for (int i = stream.size() - 1; i > index; i--) { - Widget bottom = stream.get(i); - bottom.setSelfPosition(new Position(bottom.getSelfPosition().x, bottom.getSelfPosition().y - offset)); - } - stream.remove(widget); - } else { - fixed.remove(widget); - } - super.removeWidget(widget); - configMap.remove(widget); - } - -} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java new file mode 100644 index 00000000000..7c1b6995cc2 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java @@ -0,0 +1,297 @@ +package gregtech.api.terminal.gui.widgets.guide; + + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import gregtech.api.gui.GuiTextures; +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.Widget; +import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.terminal.gui.IDraggable; +import gregtech.api.terminal.gui.widgets.CircleButtonWidget; +import gregtech.api.util.Position; +import gregtech.api.util.Size; +import gregtech.api.util.interpolate.Eases; +import gregtech.api.util.interpolate.Interpolator; +import net.minecraft.client.renderer.GlStateManager; + +import java.awt.*; +import java.util.HashMap; +import java.util.Map; + +import static gregtech.api.gui.impl.ModularUIGui.*; + +public class GuidePageEditorWidget extends GuidePageWidget { + private final Map configMap; + private Widget selected; + private final WidgetGroup toolButtons; + private GuideConfigEditor configEditor; + + public GuidePageEditorWidget(int xPosition, int yPosition, int width, int height) { + super(xPosition, yPosition, width, height); + this.setDraggable(false); + configMap = new HashMap<>(); + setTitle("Template"); + toolButtons = new WidgetGroup(Position.ORIGIN, Size.ZERO); + toolButtons.setVisible(false); + toolButtons.addWidget(new CircleButtonWidget(-20, -4, 8, 1, 12) + .setColors(new Color(255, 255, 255, 0).getRGB(), + new Color(88, 198, 88).getRGB(), + new Color(158, 238, 124).getRGB()) + .setIcon(GuiTextures.TERMINAL_UP) + .setHoverText("up") + .setClickListener(this::moveUp)); + toolButtons.addWidget(new CircleButtonWidget(0, -4, 8, 1, 12) + .setColors(new Color(255, 255, 255, 0).getRGB(), + new Color(255, 217, 0).getRGB(), + new Color(243, 217, 117).getRGB()) + .setIcon(GuiTextures.TERMINAL_DOWN) + .setHoverText("down") + .setClickListener(this::moveDown)); + toolButtons.addWidget(new CircleButtonWidget(20, -4, 8, 1, 12) + .setColors(new Color(255, 255, 255, 0).getRGB(), + new Color(238, 46, 46).getRGB(), + new Color(238, 116, 116).getRGB()) + .setIcon(GuiTextures.TERMINAL_DELETE) + .setHoverText("delete") + .setClickListener(this::delete)); + addWidget(toolButtons); + } + + public void setGuideConfigEditor(GuideConfigEditor configEditor) { + this.configEditor = configEditor; + } + + private void setToolButton(int x, int y, int width, int height) { + toolButtons.setVisible(true); + toolButtons.setSelfPosition(new Position(x + width / 2, y)); + } + + private void delete(ClickData clickData) { + removeWidget(selected); + selected = null; + configEditor.loadConfigurator(null, null, true); + toolButtons.setSelfPosition(new Position(0, 0)); + toolButtons.setVisible(false); + } + + private void moveUp(ClickData clickData) { + moveUp(selected); + } + + private void moveDown(ClickData clickData) { + moveDown(selected); + } + + public String getJsonString() { + JsonObject json = new JsonObject(); + json.addProperty("section", ""); + json.addProperty("title", title.content.get(0)); + JsonArray array = new JsonArray(); + json.add("stream", array); + stream.forEach(widget -> array.add(configMap.get(widget))); + + JsonArray array2 = new JsonArray(); + json.add("fixed", array2); + fixed.forEach(widget -> array2.add(configMap.get(widget))); + + return new Gson().toJson(json); + } + + public JsonObject addGuideWidget(IGuideWidget widget, boolean isFixed) { + int pageWidth = this.getSize().width - 5; + JsonObject widgetConfig = widget.getTemplate(isFixed); + Widget guideWidget; + if (isFixed) { + int width = widgetConfig.get("width").getAsInt(); + int height = widgetConfig.get("height").getAsInt(); + + guideWidget = widget.createFixedWidget( + (pageWidth - width) / 2 + 5, + this.scrollYOffset + (this.getSize().height - height) / 2, + width, + height, + widgetConfig); + fixed.add(guideWidget); + this.addWidget(guideWidget); + } else { + int y = getStreamBottom(); + guideWidget = widget.createStreamWidget(5, y + 5, pageWidth, widgetConfig); + stream.add(guideWidget); + this.addWidget(guideWidget); + } + configMap.put(guideWidget, widgetConfig); + return widgetConfig; + } + + + public void moveUp(Widget widget) { + int index = stream.indexOf(widget); + if (index > 0) { + Widget target = stream.get(index - 1); + if (interpolator == null) { + int offsetD = 5 + widget.getSize().height; + int offsetU = widget.getPosition().y - target.getPosition().y; + int y1 = widget.getSelfPosition().y; + int y2 = target.getSelfPosition().y; + interpolator = new Interpolator(0, 1, 10, Eases.EaseLinear, value->{ + widget.setSelfPosition(new Position(widget.getSelfPosition().x, (int) (y1 - value.floatValue() * offsetU))); + target.setSelfPosition(new Position(target.getSelfPosition().x, (int) (y2 + value.floatValue() * offsetD))); + if (widget == selected) { + setToolButton(selected.getSelfPosition().x, selected.getSelfPosition().y, selected.getSize().width, selected.getSize().height); + } + widget.setVisible(widget.getSelfPosition().y < scrollYOffset + getSize().height && widget.getSelfPosition().y + widget.getSize().height > 0); + target.setVisible(target.getSelfPosition().y < scrollYOffset + getSize().height && target.getSelfPosition().y + target.getSize().height > 0); + }, value->{ + interpolator = null; + stream.remove(widget); + stream.add(index - 1, widget); + }).start(); + } + } + } + + public void moveDown(Widget widget) { + int index = stream.indexOf(widget); + if (index >= 0 && index < stream.size() - 1) { + Widget target = stream.get(index + 1); + if (interpolator == null) { + int offsetD = 5 + target.getSize().height; + int offsetU = target.getPosition().y - widget.getPosition().y; + int y1 = widget.getSelfPosition().y; + int y2 = target.getSelfPosition().y; + interpolator = new Interpolator(0, 1, 10, Eases.EaseLinear, value->{ + widget.setSelfPosition(new Position(widget.getSelfPosition().x, (int) (y1 + value.floatValue() * offsetD))); + target.setSelfPosition(new Position(target.getSelfPosition().x, (int) (y2 - value.floatValue() * offsetU))); + if (widget == selected) { + setToolButton(selected.getSelfPosition().x, selected.getSelfPosition().y, selected.getSize().width, selected.getSize().height); + } + widget.setVisible(widget.getSelfPosition().y < getSize().height - xBarHeight && widget.getSelfPosition().y + widget.getSize().height > 0); + target.setVisible(target.getSelfPosition().y < getSize().height - xBarHeight && target.getSelfPosition().y + target.getSize().height > 0); + }, value->{ + interpolator = null; + stream.remove(widget); + stream.add(index + 1, widget); + }).start(); + } + } + } + + @Override + protected void setScrollYOffset(int scrollYOffset) { + if (scrollYOffset == this.scrollYOffset) return; + int offset = scrollYOffset - this.scrollYOffset; + this.scrollYOffset = scrollYOffset; + for (Widget widget : widgets) { + Position newPos = widget.addSelfPosition(0, -offset); + if (widget != toolButtons) { + widget.setVisible(newPos.y < getSize().height - xBarHeight && newPos.y + widget.getSize().height > 0); + } + } + } + + @Override + public void removeWidget(Widget widget) { + int index = stream.indexOf(widget); + if (index >= 0) { + int offset = widget.getSize().height + 5; + for (int i = stream.size() - 1; i > index; i--) { + Widget bottom = stream.get(i); + Position newPos = bottom.addSelfPosition(0, -offset); + bottom.setVisible(newPos.y < getSize().height - xBarHeight && newPos.y + widget.getSize().height > 0); + } + stream.remove(widget); + } else { + fixed.remove(widget); + } + super.removeWidget(widget); + configMap.remove(widget); + } + + @Override + public boolean mouseClicked(int mouseX, int mouseY, int button) { + boolean flag = false; + for (Widget widget : fixed) { + if (widget.isMouseOverElement(mouseX, mouseY)) { + if (widget instanceof IGuideWidget && widget != selected) { + configEditor.loadConfigurator((IGuideWidget) widget, configMap.get(widget), true); + selected = widget; + setToolButton(selected.getSelfPosition().x, selected.getSelfPosition().y, selected.getSize().width, selected.getSize().height); + } + playButtonClickSound(); + flag = true; + break; + } + } + for (Widget widget : stream) { + if (widget.isMouseOverElement(mouseX, mouseY)) { + if (widget instanceof IGuideWidget && widget != selected) { + configEditor.loadConfigurator((IGuideWidget) widget, configMap.get(widget), false); + selected = widget; + setToolButton(selected.getSelfPosition().x, selected.getSelfPosition().y, selected.getSize().width, selected.getSize().height); + } + playButtonClickSound(); + flag = true; + break; + } + } + if (super.mouseClicked(mouseX, mouseY, button)) { + return true; + } + return flag; + } + + @Override + protected boolean hookDrawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + Position position = getPosition(); + Size size = getSize(); + for (Widget widget : widgets) { + if (widget != toolButtons && widget.isVisible()) { + widget.drawInBackground(mouseX, mouseY, partialTicks, context); + if (widget.isMouseOverElement(mouseX, mouseY)) { + if (widget != selected) { + Position pos = widget.getPosition(); + Size s = widget.getSize(); + if (stream.contains(widget)) { + drawSolidRect(position.x, pos.y, size.width - yBarWidth, s.height, 0x6f000000); + } else { + drawSolidRect(pos.x, pos.y, s.width, s.height, 0x6f000000); + } + } + } + } + } + if (selected != null) { + Position pos = selected.getPosition(); + Size s = selected.getSize(); + if (stream.contains(selected)) { + drawSolidRect(position.x, pos.y, size.width - yBarWidth, s.height, 0x6f0000ff); + } else { + drawSolidRect(pos.x, pos.y, s.width, s.height, 0x6f0000ff); + } + } + if(toolButtons.isVisible()) { + toolButtons.drawInBackground(mouseX, mouseY, partialTicks, context); + } + GlStateManager.color(rColorForOverlay, gColorForOverlay, bColorForOverlay, 1.0F); + return true; + } + + @Override + public boolean mouseDragged(int mouseX, int mouseY, int button, long timeDragged) { + if (super.mouseDragged(mouseX, mouseY, button, timeDragged)) { + setToolButton(selected.getSelfPosition().x, selected.getSelfPosition().y, selected.getSize().width, selected.getSize().height); + return true; + } + return false; + } + + @Override + public void addWidget(Widget widget) { + super.addWidget(widget); + if(fixed.contains(widget) && widget instanceof IDraggable) { + ((IDraggable) widget).setDraggable(true); + } + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java index ab6f640e561..e952b622d61 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java @@ -6,7 +6,7 @@ import com.google.gson.JsonParser; import gregtech.api.gui.Widget; import gregtech.api.gui.resources.ColorRectTexture; -import gregtech.api.terminal.gui.widgets.ScrollablePanelWidgetGroup; +import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; import gregtech.api.util.Position; import gregtech.api.util.Size; import gregtech.api.util.interpolate.Eases; @@ -16,25 +16,27 @@ import java.util.*; import java.util.List; -public class GuidePageWidget extends ScrollablePanelWidgetGroup { +public class GuidePageWidget extends DraggableScrollableWidgetGroup { public static final Map REGISTER_WIDGETS = new HashMap<>(); static { //register guide widgets - REGISTER_WIDGETS.put("textbox", new TextBoxWidget()); - REGISTER_WIDGETS.put("image", new ImageWidget()); + REGISTER_WIDGETS.put(TextBoxWidget.NAME, new TextBoxWidget()); + REGISTER_WIDGETS.put(ImageWidget.NAME, new ImageWidget()); } protected TextBoxWidget title; - protected List stream; - protected List fixed; + protected List stream = new ArrayList<>(); + protected List fixed = new ArrayList<>(); +// protected int pageWdith; protected Interpolator interpolator; public GuidePageWidget(int xPosition, int yPosition, int width, int height) { super(xPosition, yPosition, width, height); - this.setBackground(new ColorRectTexture(-1)); - this.setDraggable(true); - this.availableYScrollBarWidth(4); - this.setYBarStyle(new ColorRectTexture(new Color(142, 142, 142).getRGB()) - , new ColorRectTexture(new Color(148, 226, 193).getRGB())); + this.setBackground(new ColorRectTexture(-1)) + .setDraggable(true) + .setYScrollBarWidth(4) + .setYBarStyle(new ColorRectTexture(new Color(142, 142, 142)), + new ColorRectTexture(new Color(148, 226, 193))); + } public void setTitle(String config) { @@ -48,12 +50,10 @@ public void setTitle(String config) { 0, 15, 0xffffffff, 0x6fff0000, 0xff000000, true, true); this.addWidget(title); - if (stream != null) { - int offset = title.getSize().height - height; - if (offset != 0) { - for (Widget widget : stream) { - widget.setSelfPosition(new Position(widget.getSelfPosition().x, widget.getSelfPosition().y + offset)); - } + int offset = title.getSize().height - height; + if (offset != 0) { + for (Widget widget : stream) { + widget.addSelfPosition(0, offset); } } } @@ -81,8 +81,8 @@ public void loadJsonConfig(JsonObject config) { JsonObject widgetConfig = element.getAsJsonObject(); Widget widget = REGISTER_WIDGETS.get(widgetConfig.get("type").getAsString()).createStreamWidget(5, y, pageWidth - 10, widgetConfig); y += widget.getSize().height + 5; - this.addWidget(widget); stream.add(widget); + this.addWidget(widget); } } // add fixed widgets @@ -96,21 +96,20 @@ public void loadJsonConfig(JsonObject config) { widgetConfig.get("width").getAsInt(), widgetConfig.get("height").getAsInt(), widgetConfig); - this.addWidget(widget); fixed.add(widget); + this.addWidget(widget); } } } public void onSizeUpdate(Widget widget, Size oldSize) { int offset = widget.getSize().height - oldSize.height; - maxHeight = Math.max(maxHeight, widget.getSize().height + widget.getPosition().y); - if (stream != null) { - int index = stream.indexOf(widget); - for (int i = stream.size() - 1; i > index; i--) { - Widget nextWidget = stream.get(i); - nextWidget.setSelfPosition(new Position(nextWidget.getSelfPosition().x, nextWidget.getSelfPosition().y + offset)); - } + maxHeight = Math.max(maxHeight, widget.getSize().height + widget.getSelfPosition().y); + int index = stream.indexOf(widget); + if (index < 0) return; + for (int i = stream.size() - 1; i > index; i--) { + Widget nextWidget = stream.get(i); + nextWidget.addSelfPosition(0, offset); } } @@ -118,7 +117,7 @@ public void onPositionUpdate(Widget widget, Position oldPosition) { if (oldPosition.y + widget.getSize().height == maxHeight) { maxHeight = 0; for (Widget widget1 : widgets) { - maxHeight = Math.max(maxHeight, widget1.getSize().height + widget1.getPosition().y); + maxHeight = Math.max(maxHeight, widget1.getSize().height + widget1.getSelfPosition().y); } } } @@ -126,7 +125,7 @@ public void onPositionUpdate(Widget widget, Position oldPosition) { protected int getStreamBottom() { if (stream!= null && stream.size() > 0) { Widget widget = stream.get(stream.size() - 1); - return widget.getSize().height + widget.getPosition().y; + return widget.getSize().height + widget.getSelfPosition().y; } else { return title.getSize().height + 10; } @@ -142,7 +141,7 @@ public void jumpToRef(String ref){ if (interpolator != null && !interpolator.isFinish()) return; for (Widget widget : widgets) { if (widget instanceof IGuideWidget && ref.equals(((IGuideWidget) widget).getRef())) { - interpolator = new Interpolator(scrollYOffset, widget.getSelfPosition().y, 20, Eases.EaseQuadOut, + interpolator = new Interpolator(scrollYOffset, widget.getSelfPosition().y + scrollYOffset, 20, Eases.EaseQuadOut, value-> setScrollYOffset(value.intValue()), value-> interpolator = null); interpolator.start(); diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java index f5eed7a7d6b..3e7f4b2d930 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java @@ -1,24 +1,26 @@ package gregtech.api.terminal.gui.widgets.guide; import com.google.gson.Gson; -import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.sun.istack.internal.Nullable; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; +import gregtech.api.terminal.gui.IDraggable; +import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; +import gregtech.api.terminal.gui.widgets.guide.congiurator.NumberConfigurator; +import gregtech.api.terminal.gui.widgets.guide.congiurator.StringConfigurator; +import gregtech.api.terminal.gui.widgets.guide.congiurator.TextListConfigurator; import gregtech.api.util.Position; import gregtech.api.util.Size; -import javafx.geometry.Pos; -import net.minecraft.client.renderer.GlStateManager; import net.minecraft.item.ItemStack; -import net.minecraftforge.fml.common.ObfuscationReflectionHelper; -import net.minecraftforge.fml.relauncher.ReflectionHelper; import java.lang.reflect.Field; +import java.util.ArrayList; import java.util.List; +import java.util.function.Consumer; -public abstract class GuideWidget extends Widget implements IGuideWidget { +public abstract class GuideWidget extends Widget implements IGuideWidget, IDraggable { //config public String ref; public int fill; @@ -28,6 +30,7 @@ public abstract class GuideWidget extends Widget implements IGuideWidget { public List hover_text; private static final Gson GSON = new Gson(); + public boolean allowDrag; protected transient GuidePageWidget page; public GuideWidget(int x, int y, int width, int height) { @@ -38,15 +41,28 @@ public GuideWidget(){ super(Position.ORIGIN, Size.ZERO); } + public abstract String getRegistryName(); + public void updateValue(String field, JsonElement value) { try { - Field f = this.getClass().getDeclaredField(field); - f.set(this, new Gson().fromJson(value, f.getType())); + Field f = this.getClass().getField(field); + if (value.isJsonNull()) { // default + f.set(this, f.get(GuidePageWidget.REGISTER_WIDGETS.get(getRegistryName()))); + } else { + f.set(this, new Gson().fromJson(value, f.getType())); + } } catch (Exception e) { e.printStackTrace(); } } + + + @Override + public void setStroke(int color) { + this.stroke = color; + } + @Override public void setSize(Size size) { Size oldSize = this.getSize(); @@ -88,6 +104,14 @@ public JsonObject getTemplate(boolean isFixed) { return template; } + @Override + public void loadConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, boolean isFixed, Consumer needUpdate) { + group.addWidget(new NumberConfigurator(5, group.getWidgetBottomHeight() + 5, config, "stroke_width").setOnUpdated(needUpdate)); + group.addWidget(new StringConfigurator(5, group.getWidgetBottomHeight() + 5, config, "ref", "").setOnUpdated(needUpdate)); + group.addWidget(new StringConfigurator(5, group.getWidgetBottomHeight() + 5, config, "link", "").setOnUpdated(needUpdate)); + group.addWidget(new TextListConfigurator(5, group.getWidgetBottomHeight() + 5, 40, config, "hover_text", true).setOnUpdated(needUpdate)); + } + @Override public String getRef() { return ref; @@ -129,11 +153,12 @@ public void drawInForeground(int mouseX, int mouseY) { Size size = getSize(); drawBorder(position.x, position.y, size.width, size.height, 0xff0000ff, stroke_width); } - if (hover_text != null && isMouseOverElement(mouseX, mouseY)) { - int scrollYOffset = page.getScrollYOffset(); - GlStateManager.translate(0, scrollYOffset, 0); - drawHoveringText(ItemStack.EMPTY, hover_text, 100, mouseX, mouseY - scrollYOffset); - GlStateManager.translate(0, -scrollYOffset, 0); + if ((hover_text != null || link != null) && isMouseOverElement(mouseX, mouseY)) { + List tooltip = hover_text == null ? new ArrayList<>() : new ArrayList<>(hover_text); + if (link != null) { + tooltip.add("§9Ctrl+Click§r §e(" + link + ")§r"); + } + drawHoveringText(ItemStack.EMPTY, tooltip, 100, mouseX, mouseY); } } @@ -151,10 +176,21 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender @Override public boolean mouseClicked(int mouseX, int mouseY, int button) { - if (link != null && isMouseOverElement(mouseX, mouseY)) { + if (link != null && isMouseOverElement(mouseX, mouseY) && isCtrlDown()) { page.jumpToRef(link); return true; } return false; } + + @Override + public boolean allowDrag(int mouseX, int mouseY, int button) { + return allowDrag && isMouseOverElement(mouseX, mouseY); + } + + @Override + public boolean setDraggable(boolean isDraggable) { + allowDrag = isDraggable; + return allowDrag; + } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java index 938d7c6c32d..f8ad46d95d4 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java @@ -1,12 +1,20 @@ package gregtech.api.terminal.gui.widgets.guide; +import com.google.gson.JsonElement; import com.google.gson.JsonObject; import gregtech.api.gui.Widget; +import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; + +import java.util.function.Consumer; public interface IGuideWidget { Widget createStreamWidget(int x, int y, int pageWidth, JsonObject config); Widget createFixedWidget(int x, int y, int width, int height, JsonObject config); void setPage(GuidePageWidget page); + void updateValue(String field, JsonElement value); String getRef(); JsonObject getTemplate(boolean isFixed); + void loadConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, boolean isFixed, Consumer needUpdate); + void setStroke(int color); } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java index 5decb203734..cc6c1fcb991 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java @@ -1,5 +1,6 @@ package gregtech.api.terminal.gui.widgets.guide; +import com.google.gson.JsonElement; import com.google.gson.JsonObject; import gregtech.api.GTValues; import gregtech.api.gui.IRenderContext; @@ -8,13 +9,19 @@ import gregtech.api.gui.resources.ItemStackTexture; import gregtech.api.gui.resources.TextureArea; import gregtech.api.gui.resources.URLTexture; +import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; +import gregtech.api.terminal.gui.widgets.guide.congiurator.NumberConfigurator; +import gregtech.api.terminal.gui.widgets.guide.congiurator.StringConfigurator; import gregtech.api.util.Position; import gregtech.api.util.Size; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.item.Item; import net.minecraft.util.ResourceLocation; +import java.util.function.Consumer; + public class ImageWidget extends GuideWidget{ + public final static String NAME = "image"; //config public String form; public String source; @@ -23,16 +30,41 @@ public class ImageWidget extends GuideWidget{ public transient IGuiTexture image; + @Override + public String getRegistryName() { + return NAME; + } + + @Override + public void updateValue(String field, JsonElement value) { + super.updateValue(field, value); + if (field.equals("width") || field.equals("height")) { + this.setSelfPosition(new Position(getSelfPosition().x - (width - getSize().width) / 2, getSelfPosition().y)); + this.setSize(new Size(width, height)); + } + if (field.equals("form") || field.equals("source")) { + initFixed(0,0,0,0,null); + } + } + @Override public JsonObject getTemplate(boolean isFixed) { JsonObject template = super.getTemplate(isFixed); template.addProperty("form", "item"); template.addProperty("source", "minecraft:ender_pearl"); - template.addProperty("width", 100); - template.addProperty("height", 100); + template.addProperty("width", 50); + template.addProperty("height", 50); return template; } + @Override + public void loadConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, boolean isFixed, Consumer needUpdate) { + super.loadConfigurator(group, config, isFixed, needUpdate); + group.addWidget(new StringConfigurator(5, group.getWidgetBottomHeight() + 5, config, "source").setOnUpdated(needUpdate)); + group.addWidget(new NumberConfigurator(5, group.getWidgetBottomHeight() + 5, config, "width").setOnUpdated(needUpdate)); + group.addWidget(new NumberConfigurator(5, group.getWidgetBottomHeight() + 5, config, "height").setOnUpdated(needUpdate)); + } + @Override public void updateScreen() { if (image != null) { @@ -51,7 +83,7 @@ protected Widget initStream(int x, int y, int pageWidth, JsonObject config) { protected Widget initFixed(int x, int y, int width, int height, JsonObject config) { switch (form) { case "url": - image = new URLTexture("https://i0.hdslb.com/bfs/article/bcd3d609c1899810113fdb90c8d0e1dd4aa8ed38.gif"); + image = new URLTexture(source); break; case "item": image = new ItemStackTexture(Item.getByNameOrId(source)); @@ -69,7 +101,7 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender super.drawInBackground(mouseX, mouseY, partialTicks,context); GlStateManager.color(1,1,1,1); Position position = getPosition(); - image.draw(position.x, position.y, width, height); + image.draw(position.x, position.y, getSize().width, getSize().height); } } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java index 3e16cb2ad3f..b38066bd686 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java @@ -1,10 +1,14 @@ package gregtech.api.terminal.gui.widgets.guide; import com.google.gson.Gson; +import com.google.gson.JsonElement; import com.google.gson.JsonObject; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; import gregtech.api.gui.resources.RenderUtil; +import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; +import gregtech.api.terminal.gui.widgets.guide.congiurator.NumberConfigurator; +import gregtech.api.terminal.gui.widgets.guide.congiurator.TextListConfigurator; import gregtech.api.util.Position; import gregtech.api.util.Size; import net.minecraft.client.Minecraft; @@ -15,8 +19,11 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.function.Consumer; public class TextBoxWidget extends GuideWidget { + public final static String NAME = "textbox"; + // config public List content; public int space = 1; @@ -42,6 +49,19 @@ public TextBoxWidget(int x, int y, int width, List content, int space, i public TextBoxWidget() {} + @Override + public String getRegistryName() { + return NAME; + } + + @Override + public void updateValue(String field, JsonElement value) { + super.updateValue(field, value); + if (field.equals("space") || field.equals("fontSize") || field.equals("content")) { + initFixed(getSelfPosition().x, getSelfPosition().y, getSize().width, getSize().height, null); + } + } + @Override public JsonObject getTemplate(boolean isFixed) { JsonObject template = super.getTemplate(isFixed); @@ -50,10 +70,18 @@ public JsonObject getTemplate(boolean isFixed) { template.addProperty("fontColor", fontColor); template.addProperty("isCenter", isCenter); template.addProperty("isShadow", isShadow); - template.add("content", new Gson().toJsonTree(Arrays.asList("this is", "textbox!"))); + template.add("content", new Gson().toJsonTree(Arrays.asList("this is a", "textbox!"))); return template; } + @Override + public void loadConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, boolean isFixed, Consumer needUpdate) { + super.loadConfigurator(group, config, isFixed, needUpdate); + group.addWidget(new NumberConfigurator(5, group.getWidgetBottomHeight() + 5, config, "space", 1).setOnUpdated(needUpdate)); + group.addWidget(new NumberConfigurator(5, group.getWidgetBottomHeight() + 5, config, "fontSize", 9).setOnUpdated(needUpdate)); + group.addWidget(new TextListConfigurator(5, group.getWidgetBottomHeight() + 5, 200, config, "content", false).setOnUpdated(needUpdate)); + } + @Override protected Widget initFixed(int x, int y, int width, int height, JsonObject config) { this.textLines = new ArrayList<>(); diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/ConfiguratorWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/ConfiguratorWidget.java new file mode 100644 index 00000000000..6ad16d559b9 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/ConfiguratorWidget.java @@ -0,0 +1,96 @@ +package gregtech.api.terminal.gui.widgets.guide.congiurator; + +import com.google.gson.JsonElement; +import com.google.gson.JsonNull; +import com.google.gson.JsonObject; +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.widgets.LabelWidget; +import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.util.Position; +import net.minecraft.client.Minecraft; +import net.minecraft.item.ItemStack; + +import java.util.Collections; +import java.util.function.Consumer; + +public class ConfiguratorWidget extends WidgetGroup { + protected String name; + protected boolean canDefault; + protected boolean isDefault; + protected JsonObject config; + + private int nameWidth; + private Consumer onUpdated; + + public ConfiguratorWidget(int x, int y, JsonObject config, String name, boolean canDefault) { + super(new Position(x, y)); + this.name = name; + this.canDefault = canDefault; + this.config = config; + if (canDefault && config.get(name).isJsonNull()) { + isDefault = true; + } + this.addWidget(new LabelWidget(0, 2, name, -1)); + if (isClientSide()) { + nameWidth = Minecraft.getMinecraft().fontRenderer.getStringWidth(name); + } + } + + public ConfiguratorWidget setOnUpdated(Consumer onUpdated) { + this.onUpdated = onUpdated; + return this; + } + + protected void update(){ + if (onUpdated != null) { + onUpdated.accept(name); + } + } + + @Override + public void drawInForeground(int mouseX, int mouseY) { + int x = getPosition().x; + int y = getPosition().y; + if (canDefault && isMouseOver(x + nameWidth + 4, y + 4, 5, 5, mouseX, mouseY)) { + drawHoveringText(ItemStack.EMPTY, Collections.singletonList("default the value"), 100, mouseX, mouseY); + } + super.drawInForeground(mouseX, mouseY); + } + + @Override + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + int x = getPosition().x; + int y = getPosition().y; + drawSolidRect(x, y, this.getSize().width, 1, -1); + if (canDefault) { + drawBorder(x + nameWidth + 4, y + 4, 5, 5, 0xff000000, 1); + if (isDefault) { + drawSolidRect(x + nameWidth + 5, y + 5, 3, 3, 0xff000000); + } + } + super.drawInBackground(mouseX, mouseY, partialTicks, context); + } + + @Override + public boolean mouseClicked(int mouseX, int mouseY, int button) { + int x = getPosition().x; + int y = getPosition().y; + if (!isDefault && super.mouseClicked(mouseX, mouseY, button)) { + return true; + } + if (canDefault && isMouseOver(x + nameWidth + 4, y + 4, 5, 5, mouseX, mouseY)) { + isDefault = !isDefault; + if (isDefault) { + config.addProperty(name, (String) null); + update(); + onDefault(); + } + playButtonClickSound(); + return true; + } + return false; + } + + protected void onDefault() { + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/NumberConfigurator.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/NumberConfigurator.java new file mode 100644 index 00000000000..cb52f8f9ead --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/NumberConfigurator.java @@ -0,0 +1,57 @@ +package gregtech.api.terminal.gui.widgets.guide.congiurator; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import gregtech.api.gui.GuiTextures; +import gregtech.api.gui.resources.TextTexture; +import gregtech.api.gui.widgets.ImageWidget; +import gregtech.api.gui.widgets.SimpleTextWidget; +import gregtech.api.terminal.gui.widgets.RectButtonWidget; + +public class NumberConfigurator extends ConfiguratorWidget{ + private int defaultValue; + + public NumberConfigurator(int x, int y, JsonObject config, String name) { + super(x, y, config, name, false); + init(0); + } + + public NumberConfigurator(int x, int y, JsonObject config, String name, int defaultValue) { + super(x, y, config, name, true); + init(defaultValue); + } + + private void init(int defaultValue){ + this.defaultValue = defaultValue; + this.addWidget(new RectButtonWidget(0, 11, 20, 20) + .setClickListener(data -> adjustTransferRate(data.isShiftClick ? -100 : -10)) + .setIcon(new TextTexture("-10"))); + this.addWidget(new RectButtonWidget(96, 11, 20, 20) + .setClickListener(data -> adjustTransferRate(data.isShiftClick ? +100 : +10)) + .setIcon(new TextTexture("+10"))); + this.addWidget(new RectButtonWidget(20, 11, 20, 20) + .setClickListener(data -> adjustTransferRate(data.isShiftClick ? -5 : -1)) + .setIcon(new TextTexture("-1"))); + this.addWidget(new RectButtonWidget(76, 11, 20, 20) + .setClickListener(data -> adjustTransferRate(data.isShiftClick ? +5 : +1)) + .setIcon(new TextTexture("+1"))); + this.addWidget(new ImageWidget(40, 11, 36, 20, GuiTextures.DISPLAY)); + this.addWidget(new SimpleTextWidget(58, 21, "", 0xFFFFFF, () -> { + JsonElement element = config.get(name); + if (element.isJsonNull()) { + return Integer.toString(defaultValue); + } + return element.getAsString(); + }, true)); + } + + private void adjustTransferRate(int added) { + JsonElement element = config.get(name); + int num = defaultValue; + if (!element.isJsonNull()) { + num = element.getAsInt(); + } + config.addProperty(name, num + added); + update(); + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/StringConfigurator.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/StringConfigurator.java new file mode 100644 index 00000000000..b4589dfdfd0 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/StringConfigurator.java @@ -0,0 +1,44 @@ +package gregtech.api.terminal.gui.widgets.guide.congiurator; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import gregtech.api.gui.resources.TextTexture; +import gregtech.api.gui.widgets.TextFieldWidget; +import gregtech.api.terminal.gui.widgets.RectButtonWidget; + +public class StringConfigurator extends ConfiguratorWidget{ + private String defaultValue = ""; + private TextFieldWidget textFieldWidget; + + public StringConfigurator(int x, int y, JsonObject config, String name) { + super(x, y, config, name, false); + init(); + textFieldWidget.setCurrentString(config.get(name).isJsonNull() ? defaultValue : config.get(name).getAsString()); + } + + public StringConfigurator(int x, int y, JsonObject config, String name, String defaultValue) { + super(x, y, config, name, true); + this.defaultValue = defaultValue; + init(); + textFieldWidget.setCurrentString(config.get(name).isJsonNull() ? defaultValue : config.get(name).getAsString()); + } + + private void init() { + this.addWidget(new RectButtonWidget(76, 11, 40, 20) + .setClickListener(data -> updateString()) + .setIcon(new TextTexture("Update"))); + textFieldWidget = new TextFieldWidget(0, 11, 76, 20, true, null, null) + .setValidator(s->true); + this.addWidget(textFieldWidget); + } + + private void updateString() { + config.addProperty(name, textFieldWidget.getCurrentString()); + update(); + } + + @Override + protected void onDefault() { + textFieldWidget.setCurrentString(defaultValue); + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/TextListConfigurator.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/TextListConfigurator.java new file mode 100644 index 00000000000..9645c440241 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/TextListConfigurator.java @@ -0,0 +1,54 @@ +package gregtech.api.terminal.gui.widgets.guide.congiurator; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import gregtech.api.gui.resources.ColorRectTexture; +import gregtech.api.terminal.gui.widgets.TextEditorWidget; + +import java.util.List; + +public class TextListConfigurator extends ConfiguratorWidget{ +// private TextEditorWidget textEditorWidget; + public TextListConfigurator(int x, int y, int height, JsonObject config, String name, boolean canDefault) { + super(x, y, config, name, canDefault); + JsonElement element = config.get(name); + if (element.isJsonNull()) { + init(height, ""); + } else { + List init = new Gson().fromJson(element, List.class); + StringBuilder s = new StringBuilder(); + for (int i = 0; i < init.size(); i++) { + s.append(init.get(i)); + if(i != init.size() - 1) { + s.append('\n'); + } + } + init(height, s.toString()); + } + } + +// public TextListConfigurator(int x, int y, int height, JsonObject config, String name, String defaultS) { +// super(x, y, config, name, false); +// StringBuilder s = new StringBuilder(); +// for (int i = 0; i < defaultS.size(); i++) { +// s.append(defaultS.get(i)); +// if(i != defaultS.size() - 1) { +// s.append('\n'); +// } +// } +// init(height, s.toString()); +// } + + private void init(int height, String init) { + this.addWidget(new TextEditorWidget(0, 11, 116, height, init, this::updateTextList).setBackground(new ColorRectTexture(-1))); + } + + private void updateTextList(String saved) { + JsonArray array = new JsonArray(); + array.add(saved); + config.add(name, array); + update(); + } +} diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_add.png b/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_add.png new file mode 100644 index 0000000000000000000000000000000000000000..dfaabb5e2c2f77b84aa60c6b7331f074505ac6b0 GIT binary patch literal 2273 zcmb_e3v3f*9KSI#$9Oo9Fd!Qo2Pz=fd$xByS0=QBb<#0Mb@M^wdiS-fYkTGH)^?K+ z#AS*&C37OrC4(%A;G)7nT?BaqjAM~8oDXCg$V>>3DFnyEfM2_=jyD>cdw$>Ve*fS9 z|NXx2>x#mHxx>@Ory&S3+@5DEg7@_3nVJHx6E9pB;cZAT?^z8&hCUQMlaO^A#v(|{ zPOq~>FLBHhB*kwKWyJ*y5q}V(5hOb&5)`E}prbC}@dhkdPs<(*^~x5k*ytb~K`SWr z=2fa-L1lqcsw|VtGL|zF&5j6=zz=j0jre^5O^8^q7_R`Iqs;_{#vpo`1)CKOh?Y1C zQLCZ?)Mzl_62;OeXEsnK(oC~6P@1GTg5(H_!AVLWO#)*^<39{WQ)RbMWSbL@1>Y=K zsjdeFf(VDhhA?ALR1ZO!&1Qn637W3r31(T}D9R zyvS0x#IqdkVr3pTag32+NY2c$rvC43ic}soK=k{*xgaYNJDBF?g`%mRi6 zG7tI_zg0LZ7~w(nd-mT8kC#L$6$2gs*H!}i@2T9MC;K$sl*+Bs@Bd1Lh%Tso-Xd82n1l2RJheNWL?{jAW7|Z+bkzv)A-KbK*tm5)q85r z^3^9-P5iu6Gk)eho$^N=z`}C^8A3ncjo~{p6qfh?*To4==sq2|cqS_4?*PU)e`@KhoT(j>=VRRiT!)r?$TP;OnROj8WB- zcK75I=bvc#?v+#gfyMLck}C>7qBBQiNr&5(4LhG(_QjW7`FnFSwXPmw;rHN^l5I&d zma&d$V^;ESN#mr|*z%$`rr1CBum7pDa~JDaS+J$9X{4>HcVmIWc8TlCnvh>RrS`qn zO~?_S>BZ2?mdnE0C4*8n28uUzbZouaP1|dO$6m5$9-3&Ahkf09T1S>#V-C3fDA$y? z+wvRJZ1Y2*rU@x~vwrCvS2HKOtLtF-iL~F_$4V&~8QtxX>}x0XIU1T*cWmGO^O&v) znJAX?+8TSAV~exs!sQo`ldVtIpX=G&oPvJ7+fZluc0=#glGV*u-dy`>D{`?iYZ*C= zOZukXgUo21J*{~}>i+cOJJ+_kBlU+iKj(iqqk2-9Gm!^Z;hpP}k;c(YXO2ETGiA+R z3o|awY^h24@zEXU5u~-d_OyOwP$X^JwngcK&zi>XN=AIgmtH*c*>7y>AY>`B{`7*MjtN;K2 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_delete.png b/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_delete.png new file mode 100644 index 0000000000000000000000000000000000000000..e5af7a69b06e9655b7dce5cebc0fe75b8da56ec7 GIT binary patch literal 1987 zcmb_dZD<@t7~Te2YfVJdqEscz2E@|N?auDrevz|HZqMel7ejKIG(~Z4clK_{-OjqZ zm%9W+Y}GVi17azn1(8M(e-u;{N(*B3pGu|pS*n&I_Ma_?h$zI_`!Y?_55;9aW@nyx z-{*bbXJ+O{hIjOA*tCIRn4avAIZD5`#LxP5^xgaG5~80Q{h?hU!`yUR{H$SKIdmt( ztoy*tPec>BorXm!31pK3PSh(tMKetQwz`k3DIBo{Ty(t@cj4HF9P8RCZakS2a()_@ z+@aY3kIfF}t=TC{x4CWiv;B308mQn1vGq#X3ype;YuGhtJMQK=wgHKzQrtl7ke$el zuxS!tHknX>1!a*{^#oJ|U6i-7q5xH1PUZSlB_E7*%diiI7lUm_6+OXLcsJHwYa zpsCH}IzCqAQmJ%Ygi&UihS5sMs^~C3<70jlhol-5XUXkfpB!k zAe+sk6{sr;5EHOLHMi&H5NcTzquA{Vo@9a&?^)i$13O=kY&XNxFG956EzVivSK+XDIrI(+SVQp zT)G@ldAZe?l}#+;;1Un^m1^eQT8x(SIB)lh&3iZplE&>(*$ z>LHrGI&lr@7-AIz=%@nF961SSF%hkVY|B^@v8~~D;FlAZjU>HcTeJV3cq=7V33)|K z_g0?!@1b0uCYu~rgmU@v`@cfr;|;Z`EqX*CUIdEj~Ai7666drH;(@_z4^~O)_ytn#fin<&$qsP^yksvQpbP%V`1Rf_VZ`HIq`ni z?mhb!7c%D;*Uo>|?cCej#hm@&_kHl3eo|iOd--UV`?~u5tuGxv_{PQ8UR?i3X47sn zZ%%&l=!NY!Sf^fn(>;Cm_AUK`+8Jio)EZ_lJfM~azTJPi`q;)v@9@&nPI7S`yztE4 R{LS$(o6QWHM+TqR^EcG+g&hC@ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_down.png b/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_down.png new file mode 100644 index 0000000000000000000000000000000000000000..99441b8e0b17caad32ce466214a4bb227350a699 GIT binary patch literal 1903 zcmb_dONbmr817YA)|H6F91<@!or8+jbX9jxzsMwRdS7@!-LW;NupAoFoRkC^-tjpx`ZN^}O6{HV?(7AJtV~{r~s> z_5D@vHyfu8EIzv^Nz#G(N_ACypDvz-dGUVkkH4_^Jdv!N$t3B?XNqS|`uLN>k~IHi z*jmrm{a0PWqY|dP%}RqP5ok#|c4ClVvcYn>%{pORQGWaC8$}LjMLAvep`UoH8?J1p zY;C*IBHJ6pp~{Kl^09#{3`8u)@*wKPnLDT`BfG9>7u~8Nk0AL*MOi8w%Ikhp_IS$V za>)b)8JcW4C1gTJGhUW8h%6OaD$)T&E;L=;ktdfTyrnd7SF6htU*fN#bn`rMRkh#m zm->2%ryUhJj-x_N)ifXwARERx9)LJII<-(`8A-z=4|yyX7IB+z<`qRS9fuGlGqZ6v zNs~yJI>3pFO0WoN1f*n!OE%Nq$T=k{>#>N%c_y%EhE2LW=UJEE$MkIYE(apDzCZJ^ zFPA8qxybU`mIz~#kbTivYnU)~m1TT0C9Jk3XdW%1Nn9^wIOl1L^WJo!np4WM=gBXe z4r9vu*^9g2tcr71Q8cI_04<=y7J_cscA@n1wXU1_pK@TEuK?M0b!w9CJFq%E@LS zfMWi*7APme#y|8N9oodO+ki3)1FRWsU}Itdi&_xc79=PjQ){oKp(sb(+ikUAMTJF6 z(~%8z9keObfz1pZIBlB&&Co2Wi`%xeLi8gYxhr8NR(Lomqc!%{q}2=Mk#t;4ijt@( zq|gGR%A`BoCm)aGc{0D>Wy0tKR5JFS@gVQxlr42c?jE8+^?uYdy!Bw>Hg*_d76T}- zpjbnr3>-r&f?*icV7kVr&8C6hOWbhF;zm=={(It+l#nitJ521Ys`B4Mc{ELqIqnJN z-tzmuLQ#tib*wFQuk1!+yEb33h@&pCqZiHDQ6he3hY^cKmQr!lT(u8eZ!| z{lT@hvy0!tg&)2kzuvj{;hoP8?fkfN9{lp&#dn)m9=r6^@`bnMcb@+`yY0>O&)xX0 zHvIGE>o=~?*{he242~aMs42fUUTIvFsu#{)_OH!<4{rZ-_@na&Z=FjX&%7%?-@3GX Qq&O1mwMO;xlW*?)4IT?w2mk;8 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_up.png b/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_up.png new file mode 100644 index 0000000000000000000000000000000000000000..7325b52ab4fcec7ccc50ea1172f07d38ff8c3fdd GIT binary patch literal 1899 zcmb_dONbmr814v$7+o;Lfbn9}0pB%U{q8O@F1ypa*+FNsOa`(d!d6#R&on#T)pqyp z%r2tfMS|oYIVqkz{5IihvtwAF&Gw847O(sss9 zZ7+Ao_B!#XGW)cAe29dBm=#za#{DEm!@4rEi$uHZRuy>!Dc0-CTe{teV{MD6SQKU#!2ZKRv zVAOclRW;A^RH&=E4g><^TS2yt4OP4Y>a zM8eb|PF1Z2%aBGuN-A8sk@ZK;DN$LU#Vjdufz>K(+T#V!d;BJ*tKsV$h}5=Pm5)8S z#Bt>!FBUdM7?XtTiOxG)DO1}l=NlPe3!8%Gu`-$zH8O?^o^?3yPZw%sN?C3+Wyg zTQDUkx6f9P2(ux(=Kz_hUk9K+NB4u}p&Xjq}kEUGybo0C~2$`SW>S}j>oVbReI z&4q>m0tyY_GSdKF;4+|_x3~vH1HdVo5&J(rP+T^e3BB6z&Gxw2SW*0yD`R+dtSs!0I_x=NGQZbL(7w+pE@y)Yey?*G2M_)U9`PVDw zzr8Cx>BCRITfFqbx%1z@NiSYrf9BdxKOP Date: Tue, 3 Aug 2021 14:35:20 +0800 Subject: [PATCH 30/58] bool, color, common selectors --- src/main/java/gregtech/api/gui/Widget.java | 90 +++++- .../api/gui/resources/RenderUtil.java | 109 -------- .../api/gui/widgets/AbstractWidgetGroup.java | 5 +- .../gregtech/api/gui/widgets/ImageWidget.java | 5 +- .../gregtech/api/gui/widgets/LabelWidget.java | 11 +- .../api/gui/widgets/TextFieldWidget.java | 74 ++++- .../gui/widgets/CircleButtonWidget.java | 7 +- .../api/terminal/gui/widgets/ColorWidget.java | 262 ++++++++++++++++++ .../DraggableScrollableWidgetGroup.java | 5 +- .../gui/widgets/RectButtonWidget.java | 91 +++++- .../terminal/gui/widgets/SelectorWidget.java | 118 ++++++++ .../widgets/guide/GuidePageEditorWidget.java | 6 +- .../gui/widgets/guide/GuideWidget.java | 11 +- .../gui/widgets/guide/ImageWidget.java | 10 +- .../gui/widgets/guide/TextBoxWidget.java | 10 +- .../gui/widgets/guide/TextTreeWidget.java | 6 +- .../configurator/BooleanConfigurator.java | 43 +++ .../guide/configurator/ColorConfigurator.java | 34 +++ .../ConfiguratorWidget.java | 28 +- .../NumberConfigurator.java | 38 ++- .../configurator/SelectorConfigurator.java | 49 ++++ .../StringConfigurator.java | 17 +- .../TextListConfigurator.java | 18 +- 23 files changed, 855 insertions(+), 192 deletions(-) create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/ColorWidget.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/SelectorWidget.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/BooleanConfigurator.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ColorConfigurator.java rename src/main/java/gregtech/api/terminal/gui/widgets/guide/{congiurator => configurator}/ConfiguratorWidget.java (74%) rename src/main/java/gregtech/api/terminal/gui/widgets/guide/{congiurator => configurator}/NumberConfigurator.java (53%) create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/SelectorConfigurator.java rename src/main/java/gregtech/api/terminal/gui/widgets/guide/{congiurator => configurator}/StringConfigurator.java (67%) rename src/main/java/gregtech/api/terminal/gui/widgets/guide/{congiurator => configurator}/TextListConfigurator.java (63%) diff --git a/src/main/java/gregtech/api/gui/Widget.java b/src/main/java/gregtech/api/gui/Widget.java index ba29818c0ae..00f5e3825fa 100644 --- a/src/main/java/gregtech/api/gui/Widget.java +++ b/src/main/java/gregtech/api/gui/Widget.java @@ -1,6 +1,7 @@ package gregtech.api.gui; import com.google.common.base.Preconditions; +import gregtech.api.gui.resources.RenderUtil; import gregtech.api.gui.widgets.WidgetUIAccess; import gregtech.api.util.Position; import gregtech.api.util.Size; @@ -8,10 +9,8 @@ import net.minecraft.client.audio.PositionedSoundRecord; import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.gui.Gui; -import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.client.renderer.OpenGlHelper; -import net.minecraft.client.renderer.RenderHelper; -import net.minecraft.client.renderer.RenderItem; +import net.minecraft.client.renderer.*; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.client.util.ITooltipFlag; import net.minecraft.init.SoundEvents; import net.minecraft.item.ItemStack; @@ -29,6 +28,7 @@ import java.util.List; import java.util.function.Consumer; import java.util.function.Supplier; +import org.lwjgl.opengl.GL11; /** * Widget is functional element of ModularUI @@ -365,8 +365,88 @@ protected static void drawSolidRect(int x, int y, int width, int height, int col @SideOnly(Side.CLIENT) protected static void drawGradientRect(int x, int y, int width, int height, int startColor, int endColor) { - GuiUtils.drawGradientRect(0, x, y, x + width, y + height, startColor, endColor); + drawGradientRect(x, y, width, height, startColor, endColor, false); + } + + @SideOnly(Side.CLIENT) + public static void drawGradientRect(float x, float y, float width, float height, int startColor, int endColor, boolean horizontal) { + float startAlpha = (float) (startColor >> 24 & 255) / 255.0F; + float startRed = (float) (startColor >> 16 & 255) / 255.0F; + float startGreen = (float) (startColor >> 8 & 255) / 255.0F; + float startBlue = (float) (startColor & 255) / 255.0F; + float endAlpha = (float) (endColor >> 24 & 255) / 255.0F; + float endRed = (float) (endColor >> 16 & 255) / 255.0F; + float endGreen = (float) (endColor >> 8 & 255) / 255.0F; + float endBlue = (float) (endColor & 255) / 255.0F; + GlStateManager.disableTexture2D(); GlStateManager.enableBlend(); + GlStateManager.disableAlpha(); + GlStateManager.tryBlendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO); + GlStateManager.shadeModel(GL11.GL_SMOOTH); + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder buffer = tessellator.getBuffer(); + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR); + if (horizontal) { + buffer.pos(x + width, y, 0).color(endRed, endGreen, endBlue, endAlpha).endVertex(); + buffer.pos(x, y, 0).color(startRed, startGreen, startBlue, startAlpha).endVertex(); + buffer.pos(x, y + height, 0).color(startRed, startGreen, startBlue, startAlpha).endVertex(); + buffer.pos(x + width, y + height, 0).color(endRed, endGreen, endBlue, endAlpha).endVertex(); + tessellator.draw(); + } else { + buffer.pos(x + width, y, 0).color(startRed, startGreen, startBlue, startAlpha).endVertex(); + buffer.pos(x, y, 0).color(startRed, startGreen, startBlue, startAlpha).endVertex(); + buffer.pos(x, y + height, 0).color(endRed, endGreen, endBlue, endAlpha).endVertex(); + buffer.pos(x + width, y + height, 0).color(endRed, endGreen, endBlue, endAlpha).endVertex(); + tessellator.draw(); + } + GlStateManager.shadeModel(GL11.GL_FLAT); + GlStateManager.enableAlpha(); + GlStateManager.enableTexture2D(); + } + + @SideOnly(Side.CLIENT) + public static void setColor(int color) { // ARGB + GlStateManager.color((color >> 16 & 255) / 255.0F, + (color >> 8 & 255) / 255.0F, + (color & 255) / 255.0F, + (color >> 24 & 255) / 255.0F); + } + + @SideOnly(Side.CLIENT) + public static void renderCircle(float x, float y, float r, int color, int segments) { + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder bufferbuilder = tessellator.getBuffer(); + GlStateManager.enableBlend(); + GlStateManager.disableTexture2D(); + GlStateManager.tryBlendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO); + setColor(color); + bufferbuilder.begin(GL11.GL_POLYGON, DefaultVertexFormats.POSITION); + for (int i = 0; i < segments; i++) { + bufferbuilder.pos(x + r * Math.cos(-2 * Math.PI * i / segments), y + r * Math.sin(-2 * Math.PI * i / segments), 0.0D).endVertex(); + } + tessellator.draw(); + GlStateManager.enableTexture2D(); + GlStateManager.color(1,1,1,1); + } + + @SideOnly(Side.CLIENT) + public static void renderSector(float x, float y, float r, int color, int segments, int from, int to) { + if (from > to || from < 0) return; + if(to > segments) to = segments; + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder bufferbuilder = tessellator.getBuffer(); + GlStateManager.enableBlend(); + GlStateManager.disableTexture2D(); + GlStateManager.tryBlendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO); + setColor(color); + bufferbuilder.begin(GL11.GL_TRIANGLES, DefaultVertexFormats.POSITION); + for (int i = from; i < to; i++) { + bufferbuilder.pos(x + r * Math.cos(-2 * Math.PI * i / segments), y + r * Math.sin(-2 * Math.PI * i / segments), 0.0D).endVertex(); + bufferbuilder.pos(x + r * Math.cos(-2 * Math.PI * (i + 1) / segments), y + r * Math.sin(-2 * Math.PI * (i + 1) / segments), 0.0D).endVertex(); + bufferbuilder.pos(x, y, 0.0D).endVertex(); + } + tessellator.draw(); + GlStateManager.enableTexture2D(); } @SideOnly(Side.CLIENT) diff --git a/src/main/java/gregtech/api/gui/resources/RenderUtil.java b/src/main/java/gregtech/api/gui/resources/RenderUtil.java index f5033a12b73..63960272bdc 100644 --- a/src/main/java/gregtech/api/gui/resources/RenderUtil.java +++ b/src/main/java/gregtech/api/gui/resources/RenderUtil.java @@ -107,113 +107,4 @@ private static void drawFluidTexture(double xCoord, double yCoord, TextureAtlasS buffer.pos(xCoord, yCoord + maskTop, zLevel).tex(uMin, vMin).endVertex(); tessellator.draw(); } - - public static void renderItemOverLay(float x, float y, float z, float scale, ItemStack itemStack) { - net.minecraft.client.renderer.RenderHelper.enableStandardItemLighting(); - GlStateManager.pushMatrix(); - GlStateManager.scale(scale, scale, 0.0001f); - GlStateManager.translate(x * 16, y * 16, z * 16); - RenderItem renderItem = Minecraft.getMinecraft().getRenderItem(); - renderItem.renderItemAndEffectIntoGUI(itemStack, 0, 0 ); - GlStateManager.popMatrix(); - net.minecraft.client.renderer.RenderHelper.disableStandardItemLighting(); - } - - public static void setColor(int color) { // ARGB - GlStateManager.color((color >> 16 & 255) / 255.0F, - (color >> 8 & 255) / 255.0F, - (color & 255) / 255.0F, - (color >> 24 & 255) / 255.0F); - } - - public static void renderCircle(float x, float y, float r, int color, int segments) { - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder bufferbuilder = tessellator.getBuffer(); - GlStateManager.enableBlend(); - GlStateManager.disableTexture2D(); - GlStateManager.tryBlendFuncSeparate(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ZERO); - setColor(color); - bufferbuilder.begin(GL11.GL_POLYGON, DefaultVertexFormats.POSITION); - for (int i = 0; i < segments; i++) { - bufferbuilder.pos(x + r * Math.cos(-2 * Math.PI * i / segments), y + r * Math.sin(-2 * Math.PI * i / segments), 0.0D).endVertex(); - } - tessellator.draw(); - GlStateManager.enableTexture2D(); - GlStateManager.color(1,1,1,1); - } - - public static void renderSector(float x, float y, float r, int color, int segments, int from, int to) { - if (from > to || from < 0) return; - if(to > segments) to = segments; - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder bufferbuilder = tessellator.getBuffer(); - GlStateManager.enableBlend(); - GlStateManager.disableTexture2D(); - GlStateManager.tryBlendFuncSeparate(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ZERO); - setColor(color); - bufferbuilder.begin(GL11.GL_TRIANGLES, DefaultVertexFormats.POSITION); - for (int i = from; i < to; i++) { - bufferbuilder.pos(x + r * Math.cos(-2 * Math.PI * i / segments), y + r * Math.sin(-2 * Math.PI * i / segments), 0.0D).endVertex(); - bufferbuilder.pos(x + r * Math.cos(-2 * Math.PI * (i + 1) / segments), y + r * Math.sin(-2 * Math.PI * (i + 1) / segments), 0.0D).endVertex(); - bufferbuilder.pos(x, y, 0.0D).endVertex(); - } - tessellator.draw(); - GlStateManager.enableTexture2D(); - } - - public static void renderRect(float x, float y, float width, float height, float z, int color) { - renderGradientRect(x, y, width, height, z, color, color, false); - } - - public static void renderGradientRect(float x, float y, float width, float height, float z, int startColor, int endColor, boolean horizontal) { - float startAlpha = (float) (startColor >> 24 & 255) / 255.0F; - float startRed = (float) (startColor >> 16 & 255) / 255.0F; - float startGreen = (float) (startColor >> 8 & 255) / 255.0F; - float startBlue = (float) (startColor & 255) / 255.0F; - float endAlpha = (float) (endColor >> 24 & 255) / 255.0F; - float endRed = (float) (endColor >> 16 & 255) / 255.0F; - float endGreen = (float) (endColor >> 8 & 255) / 255.0F; - float endBlue = (float) (endColor & 255) / 255.0F; - GlStateManager.disableTexture2D(); - GlStateManager.enableBlend(); - GlStateManager.disableAlpha(); - GlStateManager.tryBlendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO); - GlStateManager.shadeModel(GL11.GL_SMOOTH); - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder buffer = tessellator.getBuffer(); - buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR); - if (horizontal) { - buffer.pos(x + width, y, z).color(endRed, endGreen, endBlue, endAlpha).endVertex(); - buffer.pos(x, y, z).color(startRed, startGreen, startBlue, startAlpha).endVertex(); - buffer.pos(x, y + height, z).color(startRed, startGreen, startBlue, startAlpha).endVertex(); - buffer.pos(x + width, y + height, z).color(endRed, endGreen, endBlue, endAlpha).endVertex(); - tessellator.draw(); - } else { - buffer.pos(x + width, y, z).color(startRed, startGreen, startBlue, startAlpha).endVertex(); - buffer.pos(x, y, z).color(startRed, startGreen, startBlue, startAlpha).endVertex(); - buffer.pos(x, y + height, z).color(endRed, endGreen, endBlue, endAlpha).endVertex(); - buffer.pos(x + width, y + height, z).color(endRed, endGreen, endBlue, endAlpha).endVertex(); - tessellator.draw(); - } - GlStateManager.shadeModel(GL11.GL_FLAT); - GlStateManager.disableBlend(); - GlStateManager.enableAlpha(); - GlStateManager.enableTexture2D(); - } - - public static void renderTextureArea(TextureArea textureArea, float x, float y, float width, float height, float z) { - double imageU = textureArea.offsetX; - double imageV = textureArea.offsetY; - double imageWidth = textureArea.imageWidth; - double imageHeight = textureArea.imageHeight; - Minecraft.getMinecraft().renderEngine.bindTexture(textureArea.imageLocation); - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder bufferbuilder = tessellator.getBuffer(); - bufferbuilder.begin(7, DefaultVertexFormats.POSITION_TEX); - bufferbuilder.pos(x, y + height, z).tex(imageU, imageV + imageHeight).endVertex(); - bufferbuilder.pos(x + width, y + height, z).tex(imageU + imageWidth, imageV + imageHeight).endVertex(); - bufferbuilder.pos(x + width, y, z).tex(imageU + imageWidth, imageV).endVertex(); - bufferbuilder.pos(x, y, z).tex(imageU, imageV).endVertex(); - tessellator.draw(); - } } diff --git a/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java b/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java index 25f85dab8a1..1c7042b01c7 100644 --- a/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java +++ b/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java @@ -286,8 +286,9 @@ public boolean mouseReleased(int mouseX, int mouseY, int button) { @Override public boolean keyTyped(char charTyped, int keyCode) { - for (Widget widget : widgets) { - if(widget.keyTyped(charTyped, keyCode)) { + for (int i = widgets.size() - 1; i >= 0; i--) { + Widget widget = widgets.get(i); + if(widget.isVisible() && widget.keyTyped(charTyped, keyCode)) { return true; } } diff --git a/src/main/java/gregtech/api/gui/widgets/ImageWidget.java b/src/main/java/gregtech/api/gui/widgets/ImageWidget.java index 7f1cb903702..c6f5af688b9 100644 --- a/src/main/java/gregtech/api/gui/widgets/ImageWidget.java +++ b/src/main/java/gregtech/api/gui/widgets/ImageWidget.java @@ -2,6 +2,7 @@ import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.resources.TextureArea; import gregtech.api.util.Position; import gregtech.api.util.Size; @@ -16,7 +17,7 @@ public class ImageWidget extends Widget { - protected TextureArea area; + protected IGuiTexture area; private BooleanSupplier predicate; private boolean isVisible = true; @@ -25,7 +26,7 @@ public ImageWidget(int xPosition, int yPosition, int width, int height) { super(new Position(xPosition, yPosition), new Size(width, height)); } - public ImageWidget(int xPosition, int yPosition, int width, int height, TextureArea area) { + public ImageWidget(int xPosition, int yPosition, int width, int height, IGuiTexture area) { this(xPosition, yPosition, width, height); this.area = area; } diff --git a/src/main/java/gregtech/api/gui/widgets/LabelWidget.java b/src/main/java/gregtech/api/gui/widgets/LabelWidget.java index 2086ce2b9a7..206cb6e0103 100644 --- a/src/main/java/gregtech/api/gui/widgets/LabelWidget.java +++ b/src/main/java/gregtech/api/gui/widgets/LabelWidget.java @@ -20,6 +20,7 @@ public class LabelWidget extends Widget { protected final String text; protected final Object[] formatting; private final int color; + private boolean dropShadow; public LabelWidget(int xPosition, int yPosition, String text, Object... formatting) { this(xPosition, yPosition, text, 0x404040, formatting); @@ -37,6 +38,11 @@ public LabelWidget(int xPosition, int yPosition, String text, int color, Object[ recomputeSize(); } + public LabelWidget setShadow(boolean dropShadow){ + this.dropShadow = dropShadow; + return this; + } + private String getResultText() { return I18n.format(text, formatting); } @@ -64,10 +70,9 @@ public void drawInBackground(int mouseX, int mouseY, IRenderContext context) { FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer; Position pos = getPosition(); if (!xCentered) { - fontRenderer.drawString(resultText, pos.x, pos.y, color); + fontRenderer.drawString(resultText, pos.x, pos.y, color, dropShadow); } else { - fontRenderer.drawString(resultText, - pos.x - fontRenderer.getStringWidth(resultText) / 2, pos.y, color); + fontRenderer.drawString(resultText, pos.x - fontRenderer.getStringWidth(resultText) / 2.0f, pos.y, color, dropShadow); } GlStateManager.color(rColorForOverlay, gColorForOverlay, bColorForOverlay, 1.0F); } diff --git a/src/main/java/gregtech/api/gui/widgets/TextFieldWidget.java b/src/main/java/gregtech/api/gui/widgets/TextFieldWidget.java index 1cad2d7abc2..68aff5b092c 100644 --- a/src/main/java/gregtech/api/gui/widgets/TextFieldWidget.java +++ b/src/main/java/gregtech/api/gui/widgets/TextFieldWidget.java @@ -2,6 +2,7 @@ import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.util.MCGuiUtil; import gregtech.api.util.Position; import gregtech.api.util.Size; @@ -23,15 +24,23 @@ public class TextFieldWidget extends Widget { protected int maxStringLength = 32; protected Predicate textValidator; - protected final Supplier textSupplier; - protected final Consumer textResponder; + protected Supplier textSupplier; + protected Consumer textResponder; protected String currentString; + private IGuiTexture background; + private boolean enableBackground; + private boolean isClient; public TextFieldWidget(int xPosition, int yPosition, int width, int height, boolean enableBackground, Supplier textSupplier, Consumer textResponder) { super(new Position(xPosition, yPosition), new Size(width, height)); if (isClientSide()) { + this.enableBackground = enableBackground; FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer; - this.textField = new GuiTextField(0, fontRenderer, xPosition, yPosition, width, height); + if (enableBackground) { + this.textField = new GuiTextField(0, fontRenderer, xPosition, yPosition, width, height); + } else { + this.textField = new GuiTextField(0, fontRenderer, xPosition + 1, yPosition + (height - fontRenderer.FONT_HEIGHT) / 2 + 1, width - 2, height); + } this.textField.setCanLoseFocus(true); this.textField.setEnableBackgroundDrawing(enableBackground); this.textField.setMaxStringLength(maxStringLength); @@ -41,6 +50,34 @@ public TextFieldWidget(int xPosition, int yPosition, int width, int height, bool this.textResponder = textResponder; } + public TextFieldWidget(int xPosition, int yPosition, int width, int height, IGuiTexture background, Supplier textSupplier, Consumer textResponder) { + super(new Position(xPosition, yPosition), new Size(width, height)); + if (isClientSide()) { + this.enableBackground = false; + FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer; + this.textField = new GuiTextField(0, fontRenderer, xPosition + 1, yPosition + (height - fontRenderer.FONT_HEIGHT) / 2 + 1, width - 2, height); + this.textField.setCanLoseFocus(true); + this.textField.setEnableBackgroundDrawing(false); + this.textField.setMaxStringLength(maxStringLength); + this.textField.setGuiResponder(MCGuiUtil.createTextFieldResponder(this::onTextChanged)); + } + this.background = background; + this.textSupplier = textSupplier; + this.textResponder = textResponder; + } + + public TextFieldWidget setTextSupplier(Supplier textSupplier, boolean isClient) { + this.isClient = isClient; + this.textSupplier = textSupplier; + return this; + } + + public TextFieldWidget setTextResponder(Consumer textResponder, boolean isClient) { + this.isClient = isClient; + this.textResponder = textResponder; + return this; + } + public void setCurrentString(String currentString) { this.currentString = currentString; this.textField.setText(currentString); @@ -53,26 +90,37 @@ public String getCurrentString() { @Override protected void onPositionUpdate() { if (isClientSide() && textField != null) { + FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer; Position position = getPosition(); + Size size = getSize(); GuiTextField textField = this.textField; - textField.x = position.x; - textField.y = position.y; + textField.x = enableBackground ? position.x : position.x + 1; + textField.y = enableBackground ? position.y : position.y + (size.height - fontRenderer.FONT_HEIGHT) / 2 + 1; } } @Override protected void onSizeUpdate() { if (isClientSide() && textField != null) { + FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer; + Position position = getPosition(); Size size = getSize(); GuiTextField textField = this.textField; - textField.width = size.width; + textField.width = enableBackground ? size.width : size.width - 2; textField.height = size.height; + textField.y = enableBackground ? position.y : position.y + (getSize().height - fontRenderer.FONT_HEIGHT) / 2 + 1; + } } @Override public void drawInBackground(int mouseX, int mouseY, IRenderContext context) { super.drawInBackground(mouseX, mouseY, context); + if (background != null) { + Position position = getPosition(); + Size size = getSize(); + background.draw(position.x, position.y, size.width, size.height); + } this.textField.drawTextBox(); } @@ -86,6 +134,14 @@ public boolean keyTyped(char charTyped, int keyCode) { return this.textField.textboxKeyTyped(charTyped, keyCode); } + @Override + public void updateScreen() { + if (textSupplier != null && isClient) { + this.currentString = textSupplier.get(); + this.textField.setText(currentString); + } + } + @Override public void detectAndSendChanges() { super.detectAndSendChanges(); @@ -106,7 +162,11 @@ public void readUpdateInfo(int id, PacketBuffer buffer) { protected void onTextChanged(String newTextString) { if (textValidator.test(newTextString)) { - writeClientAction(1, buffer -> buffer.writeString(newTextString)); + if (isClient && textResponder != null) { + textResponder.accept(newTextString); + } else { + writeClientAction(1, buffer -> buffer.writeString(newTextString)); + } } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java index 47c89d0f085..4b84b6707ab 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java @@ -15,6 +15,7 @@ import java.awt.*; import java.util.Collections; import java.util.function.Consumer; +import java.util.function.Supplier; public class CircleButtonWidget extends Widget { protected int border; @@ -97,12 +98,12 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender int y = this.getPosition().y + r; int segments = 24; - RenderUtil.renderCircle(x, y, r, colors[0], segments); + renderCircle(x, y, r, colors[0], segments); isHover = this.isMouseOverElement(mouseX, mouseY); if (isHover || hoverTick != 0) { - RenderUtil.renderSector(x, y, r, colors[1], segments, 0, (int) (segments * ((hoverTick + partialTicks) / 8))); + renderSector(x, y, r, colors[1], segments, 0, (int) (segments * ((hoverTick + partialTicks) / 8))); } - RenderUtil.renderCircle(x, y, r - border, colors[2], segments); + renderCircle(x, y, r - border, colors[2], segments); if (icon != null) { icon.draw(x - iconSize / 2f, y - iconSize / 2f, iconSize, iconSize); } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/ColorWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/ColorWidget.java new file mode 100644 index 00000000000..2f9580e405a --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/ColorWidget.java @@ -0,0 +1,262 @@ +package gregtech.api.terminal.gui.widgets; + +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.ColorRectTexture; +import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.widgets.TextFieldWidget; +import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.util.Position; +import gregtech.api.util.Size; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.math.MathHelper; + +import java.util.function.Consumer; +import java.util.function.Supplier; + +public class ColorWidget extends WidgetGroup { + private int red = 255; + private int green = 255; + private int blue = 255; + private int alpha = 255; + private Consumer onColorChanged; + private final int barWidth; + private final int barHeight; + private final CircleButtonWidget redButton; + private final CircleButtonWidget greenButton; + private final CircleButtonWidget blueButton; + private final CircleButtonWidget alphaButton; + private int lastMouseX; + private CircleButtonWidget dragged; + private Supplier colorSupplier; + private boolean isClient; + + public ColorWidget(int x, int y, int barWidth, int barHeight){ + super(new Position(x, y), new Size(barWidth + 35, 3 * (barHeight + 5) + 10)); + this.barWidth = barWidth; + this.barHeight= barHeight; + IGuiTexture textFieldBackground = new ColorRectTexture(0x9f000000); + TextFieldWidget redField = new TextFieldWidget(barWidth + 5, 0, 30, barHeight, textFieldBackground, null, null) + .setTextResponder((t) -> setRed(t.isEmpty()? 0 : Integer.parseInt(t)), true) + .setTextSupplier(() -> Integer.toString(red), true) + .setValidator(this::checkValid); + TextFieldWidget greenField = new TextFieldWidget(barWidth + 5, barHeight + 5, 30, barHeight, textFieldBackground, null, null) + .setTextResponder((t) -> setGreen(t.isEmpty()? 0 : Integer.parseInt(t)), true) + .setTextSupplier(() -> Integer.toString(green), true) + .setValidator(this::checkValid); + TextFieldWidget blueField = new TextFieldWidget(barWidth + 5, (barHeight + 5) * 2, 30, barHeight, textFieldBackground, null, null) + .setTextResponder((t) -> setBlue(t.isEmpty()? 0 : Integer.parseInt(t)), true) + .setTextSupplier(() -> Integer.toString(blue), true) + .setValidator(this::checkValid); + TextFieldWidget alphaField = new TextFieldWidget(barWidth + 5, (barHeight + 5) * 3, 30, barHeight, textFieldBackground, null, null) + .setTextResponder((t) -> setAlpha(t.isEmpty()? 0 : Integer.parseInt(t)), true) + .setTextSupplier(() -> Integer.toString(alpha), true) + .setValidator(this::checkValid); + this.addWidget(redField); + this.addWidget(greenField); + this.addWidget(blueField); + this.addWidget(alphaField); + redButton = new CircleButtonWidget(barWidth, barHeight / 2, 4, 1, 0).setFill(0xffff0000).setStrokeAnima(-1); + greenButton = new CircleButtonWidget(barWidth, barHeight / 2 + barHeight + 5, 4, 1, 0).setFill(0xff00ff00).setStrokeAnima(-1); + blueButton = new CircleButtonWidget(barWidth, barHeight / 2 + 2 * (barHeight + 5), 4, 1, 0).setFill(0xff0000ff).setStrokeAnima(-1); + alphaButton = new CircleButtonWidget(barWidth, barHeight / 2 + 3 * (barHeight + 5), 4, 1, 0).setFill(-1).setStrokeAnima(-1); + this.addWidget(redButton); + this.addWidget(greenButton); + this.addWidget(blueButton); + this.addWidget(alphaButton); + } + + public ColorWidget setOnColorChanged(Consumer onColorChanged) { + this.onColorChanged = onColorChanged; + return this; + } + + public ColorWidget setColorSupplier(Supplier colorSupplier, boolean isClient) { + this.colorSupplier = colorSupplier; + this.isClient = isClient; + return this; + } + + @Override + public void detectAndSendChanges() { + super.detectAndSendChanges(); + if (!isClient && colorSupplier!= null) { + int c = colorSupplier.get(); + int r = (c & 0x00ff0000) >> 16; + int g = (c & 0x0000ff00) >> 8; + int b = (c & 0x000000ff); + int a = (c & 0xff000000) >> 24; + if (r != red || g != green || b != blue || a ==alpha) { + setRed(r); + setGreen(g); + setBlue(b); + setAlpha(a); + writeUpdateInfo(2, buffer -> buffer.writeInt(c)); + } + } + } + + @Override + public void updateScreen() { + super.updateScreen(); + if (isClient && colorSupplier!= null) { + int c = colorSupplier.get(); + int r = (c & 0x00ff0000) >> 16; + int g = (c & 0x0000ff00) >> 8; + int b = (c & 0x000000ff); + int a = (c & 0xff000000) >> 24; + if (r != red || g != green || b != blue || a ==alpha) { + setRed(r); + setGreen(g); + setBlue(b); + setAlpha(a); + writeClientAction(2, buffer -> buffer.writeInt(c)); + } + } + } + + @Override + public void readUpdateInfo(int id, PacketBuffer buffer) { + handleColor(id, buffer); + } + + private void handleColor(int id, PacketBuffer buffer) { + if (id == 2) { + int c = buffer.readInt(); + int r = (c & 0x00ff0000) >> 16; + int g = (c & 0x0000ff00) >> 8; + int b = (c & 0x000000ff); + int a = (c & 0xff000000) >> 24; + if (r != red || g != green || b != blue || a ==alpha) { + setRed(r); + setGreen(g); + setBlue(b); + setAlpha(a); + } + } + } + + @Override + public void handleClientAction(int id, PacketBuffer buffer) { + handleColor(id, buffer); + } + + private void setRed(int red) { + if (this.red != red) { + this.red = red; + redButton.setSelfPosition(new Position(red * barWidth / 255 - 4, redButton.getSelfPosition().y)); + if (onColorChanged != null) { + onColorChanged.accept((alpha << 24) | (red << 16) | (green << 8) | (blue)); + } + } + } + + private void setGreen(int green) { + if (this.green != green) { + this.green = green; + greenButton.setSelfPosition(new Position(green * barWidth / 255 - 4, greenButton.getSelfPosition().y)); + if (onColorChanged != null) { + onColorChanged.accept((alpha << 24) | (red << 16) | (green << 8) | (blue)); + } + } + } + + private void setBlue(int blue) { + if (this.blue != blue) { + this.blue = blue; + blueButton.setSelfPosition(new Position(blue * barWidth / 255 - 4, blueButton.getSelfPosition().y)); + if (onColorChanged != null) { + onColorChanged.accept((alpha << 24) | (red << 16) | (green << 8) | (blue)); + } + } + } + + private void setAlpha(int alpha) { + if (this.alpha != alpha) { + this.alpha = alpha; + alphaButton.setSelfPosition(new Position(alpha * barWidth / 255 - 4, alphaButton.getSelfPosition().y)); + if (onColorChanged != null) { + onColorChanged.accept((alpha << 24) | (red << 16) | (green << 8) | (blue)); + } + } + } + + private boolean checkValid(String input) { + if (input.length() > 3) return false; + if (input.isEmpty()) return true; + try { + int value = Integer.parseInt(input); + if(value >= 0 && value <= 255) { + return true; + } + } catch (Exception e) { + return false; + } + return false; + } + + @Override + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + int x = getPosition().x; + int y = getPosition().y; + drawGradientRect(x, y + 2, barWidth, 5, 0xFF000000, 0xFFFF0000, true); + drawGradientRect(x, y + barHeight + 5 + 2, barWidth, 5, 0xFF000000, 0xFF00ff00, true); + drawGradientRect(x, y + 2 * (barHeight + 5) + 2, barWidth, 5, 0xFF000000, 0xFF0000ff, true); + drawGradientRect(x, y + 3 * (barHeight + 5) + 2, barWidth, 5, (0) | (red << 16) | (green << 8) | (blue), (255 << 24) | (red << 16) | (green << 8) | (blue), true); + super.drawInBackground(mouseX, mouseY, partialTicks, context); + } + + @Override + public boolean mouseClicked(int mouseX, int mouseY, int button) { + lastMouseX = mouseX; + dragged = null; + if (redButton.isMouseOverElement(mouseX, mouseY)) { + dragged = redButton; + return true; + } else if (greenButton.isMouseOverElement(mouseX, mouseY)) { + dragged = greenButton; + return true; + } else if (blueButton.isMouseOverElement(mouseX, mouseY)) { + dragged = blueButton; + return true; + } else if (alphaButton.isMouseOverElement(mouseX, mouseY)) { + dragged = alphaButton; + return true; + } + boolean flag = false; + for (int i = widgets.size() - 1; i >= 0; i--) { + Widget widget = widgets.get(i); + if(widget.isVisible() && widget.mouseClicked(mouseX, mouseY, button)) { + flag = true; + } + } + return flag; + } + + @Override + public boolean mouseDragged(int mouseX, int mouseY, int button, long timeDragged) { + int xDelta = mouseX - lastMouseX; + lastMouseX = mouseX; + if (dragged != null) { + int newX = MathHelper.clamp(dragged.getSelfPosition().x + 4 + xDelta, 0, barWidth); + if (dragged == redButton) { + setRed(newX * 255 / barWidth); + } else if (dragged == greenButton) { + setGreen(newX * 255 / barWidth); + } else if (dragged == blueButton) { + setBlue(newX * 255 / barWidth); + } else if (dragged == alphaButton) { + setAlpha(newX * 255 / barWidth); + } + dragged.setSelfPosition(new Position(newX - 4, dragged.getSelfPosition().y)); + return true; + } + return super.mouseDragged(mouseX, mouseY, button, timeDragged); + } + + @Override + public boolean mouseReleased(int mouseX, int mouseY, int button) { + dragged = null; + return super.mouseReleased(mouseX, mouseY, button); + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java b/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java index eb45dd3d8c0..ec0c752e39d 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java @@ -96,7 +96,10 @@ public void removeWidget(Widget widget) { @Override public void clearAllWidgets() { super.clearAllWidgets(); - computeMax(); + maxHeight = getSize().height; + maxWidth = getSize().width; + scrollXOffset = 0; + scrollYOffset = 0; } @Override diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/RectButtonWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/RectButtonWidget.java index b20460798a3..a4060c2986e 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/RectButtonWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/RectButtonWidget.java @@ -1,10 +1,23 @@ package gregtech.api.terminal.gui.widgets; import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.util.Position; import gregtech.api.util.Size; +import net.minecraft.network.PacketBuffer; +import org.lwjgl.input.Mouse; + +import java.util.function.BiConsumer; +import java.util.function.Supplier; public class RectButtonWidget extends CircleButtonWidget{ + private IGuiTexture pressedIcon; + private BiConsumer onPressed; + private boolean isPressed; + private Supplier supplier; + private boolean isClient; + + public RectButtonWidget(int x, int y, int width, int height) { this(x, y, width, height,2); } @@ -16,6 +29,78 @@ public RectButtonWidget(int x, int y, int width, int height, int border) { this.border = border; } + public RectButtonWidget setToggleButton(IGuiTexture pressedIcon, BiConsumer onPressed) { + this.pressedIcon = pressedIcon; + this.onPressed = onPressed; + return this; + } + + public RectButtonWidget setValueSupplier(boolean isClient, Supplier supplier) { + this.isClient = isClient; + this.supplier = supplier; + return this; + } + + @Override + public void updateScreen() { + super.updateScreen(); + if (isClient && supplier != null) { + isPressed = supplier.get(); + } + } + + @Override + public void detectAndSendChanges() { + if (!isClient && supplier != null) { + if(supplier.get() != isPressed) { + isPressed = !isPressed; + writeUpdateInfo(1, buffer -> buffer.writeBoolean(isPressed)); + } + } + } + + @Override + public void readUpdateInfo(int id, PacketBuffer buffer) { + if (id == 1) { + isPressed = buffer.readBoolean(); + } + } + + @Override + public boolean mouseClicked(int mouseX, int mouseY, int button) { + if (onPressed == null) { + return super.mouseClicked(mouseX, mouseY, button); + } else { + if (isMouseOverElement(mouseX, mouseY)) { + isPressed = !isPressed; + ClickData clickData = new ClickData(Mouse.getEventButton(), isShiftDown(), isCtrlDown(), false); + writeClientAction(1, buffer -> { + clickData.writeToBuf(buffer); + buffer.writeBoolean(isPressed); + }); + playButtonClickSound(); + onPressed.accept(new ClickData(Mouse.getEventButton(), isShiftDown(), isCtrlDown(), true), isPressed); + return true; + } + return false; + } + } + + @Override + public void handleClientAction(int id, PacketBuffer buffer) { + if (onPressed == null) { + super.handleClientAction(id, buffer); + } else { + if (id == 1) { + ClickData clickData = ClickData.readFromBuf(buffer); + isPressed = buffer.readBoolean(); + if (onPressCallback != null) { + onPressed.accept(clickData, isPressed); + } + } + } + } + @Override public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { int x = this.getPosition().x; @@ -33,7 +118,11 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender drawSolidRect(x, (int) ((1 - per) * height) + y, border, (int) (height * per), colors[1]); } drawSolidRect(x + border, y + border, width - 2 * border, height - 2 * border, colors[2]); - if (icon != null) { + if (isPressed) { + if (pressedIcon != null) { + pressedIcon.draw(x + border, y + border, width - 2 * border, height - 2 * border); + } + } else if (icon != null) { icon.draw(x + border, y + border, width - 2 * border, height - 2 * border); } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/SelectorWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/SelectorWidget.java new file mode 100644 index 00000000000..6f8b0efbef2 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/SelectorWidget.java @@ -0,0 +1,118 @@ +package gregtech.api.terminal.gui.widgets; + +import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.widgets.SimpleTextWidget; +import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.util.Position; +import gregtech.api.util.Size; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.network.PacketBuffer; + +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Supplier; + +public class SelectorWidget extends WidgetGroup { + protected RectButtonWidget button; + protected List candidates; + protected boolean isShow; + private IGuiTexture background; + private Consumer onChanged; + private boolean isUp; + private final int fontColor; + + public SelectorWidget(int x, int y, int width, int height, List candidates, int fontColor, Supplier supplier, boolean isClient) { + super(new Position(x, y), new Size(width, height)); + this.button = new RectButtonWidget(0,0,width,height); + this.candidates = candidates; + this.fontColor = fontColor; + button.setClickListener(d->isShow = !isShow); + this.addWidget(button); + this.addWidget(new SimpleTextWidget(width / 2, height / 2, "", fontColor, supplier, isClient)); + } + + public SelectorWidget setIsUp(boolean isUp) { + this.isUp = isUp; + return this; + } + + public SelectorWidget setOnChanged(Consumer onChanged) { + this.onChanged = onChanged; + return this; + } + + public SelectorWidget setColors(int stroke, int anima, int fill) { + button.setColors(stroke, anima, fill); + return this; + } + + public SelectorWidget setButtonBackground(IGuiTexture guiTexture) { + button.setIcon(guiTexture); + return this; + } + + public SelectorWidget setBackground(IGuiTexture background) { + this.background = background; + return this; + } + + @Override + public void drawInForeground(int mouseX, int mouseY) { + super.drawInForeground(mouseX, mouseY); + if(isShow) { + int x = getPosition().x; + int width = getSize().width; + int height = getSize().height; + int y = (isUp ? -candidates.size(): (candidates.size() + 1)) * height + getPosition().y; + for (String candidate : candidates) { + if (background != null) { + background.draw(x, y, width, height); + } else { + drawSolidRect(x, y, width, height, 0xAA000000); + } + FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer; + fontRenderer.drawString(candidate, x + 4, y + (height - fontRenderer.FONT_HEIGHT) / 2 + 1, fontColor); + y += height; + } + y = (isUp ? -candidates.size(): (candidates.size() + 1)) * height + getPosition().y; + for (String ignored : candidates) { + if (isMouseOver(x, y, width, height, mouseX, mouseY)) { + drawBorder(x, y, width, height, -1, 1); + } + y += height; + } + } + } + + @Override + public boolean mouseClicked(int mouseX, int mouseY, int button) { + if (isShow) { + int x = getPosition().x; + int width = getSize().width; + int height = getSize().height; + int y = (isUp ? -candidates.size(): (candidates.size() + 1)) * height + getPosition().y; + for (String candidate : candidates) { + if (isMouseOver(x, y, width, height, mouseX, mouseY)) { + if (onChanged != null) { + onChanged.accept(candidate); + } + writeClientAction(2, buffer -> buffer.writeString(candidate)); + } + y += height; + } + } + isShow = false; + return super.mouseClicked(mouseX, mouseY, button); + } + + @Override + public void handleClientAction(int id, PacketBuffer buffer) { + super.handleClientAction(id, buffer); + if (id == 2) { + if (onChanged != null) { + onChanged.accept(buffer.readString(Short.MAX_VALUE)); + } + } + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java index 7c1b6995cc2..0f61ead4b95 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java @@ -100,7 +100,7 @@ public String getJsonString() { } public JsonObject addGuideWidget(IGuideWidget widget, boolean isFixed) { - int pageWidth = this.getSize().width - 5; + int pageWidth = this.getSize().width - yBarWidth; JsonObject widgetConfig = widget.getTemplate(isFixed); Widget guideWidget; if (isFixed) { @@ -117,7 +117,7 @@ public JsonObject addGuideWidget(IGuideWidget widget, boolean isFixed) { this.addWidget(guideWidget); } else { int y = getStreamBottom(); - guideWidget = widget.createStreamWidget(5, y + 5, pageWidth, widgetConfig); + guideWidget = widget.createStreamWidget(5, y + 5, pageWidth - 10, widgetConfig); stream.add(guideWidget); this.addWidget(guideWidget); } @@ -280,7 +280,7 @@ protected boolean hookDrawInBackground(int mouseX, int mouseY, float partialTick @Override public boolean mouseDragged(int mouseX, int mouseY, int button, long timeDragged) { - if (super.mouseDragged(mouseX, mouseY, button, timeDragged)) { + if (super.mouseDragged(mouseX, mouseY, button, timeDragged) && toolButtons.isVisible()) { setToolButton(selected.getSelfPosition().x, selected.getSelfPosition().y, selected.getSize().width, selected.getSize().height); return true; } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java index 3e7f4b2d930..9dfe19aaab1 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java @@ -8,9 +8,10 @@ import gregtech.api.gui.Widget; import gregtech.api.terminal.gui.IDraggable; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; -import gregtech.api.terminal.gui.widgets.guide.congiurator.NumberConfigurator; -import gregtech.api.terminal.gui.widgets.guide.congiurator.StringConfigurator; -import gregtech.api.terminal.gui.widgets.guide.congiurator.TextListConfigurator; +import gregtech.api.terminal.gui.widgets.guide.configurator.ColorConfigurator; +import gregtech.api.terminal.gui.widgets.guide.configurator.NumberConfigurator; +import gregtech.api.terminal.gui.widgets.guide.configurator.StringConfigurator; +import gregtech.api.terminal.gui.widgets.guide.configurator.TextListConfigurator; import gregtech.api.util.Position; import gregtech.api.util.Size; import net.minecraft.item.ItemStack; @@ -106,7 +107,9 @@ public JsonObject getTemplate(boolean isFixed) { @Override public void loadConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, boolean isFixed, Consumer needUpdate) { - group.addWidget(new NumberConfigurator(5, group.getWidgetBottomHeight() + 5, config, "stroke_width").setOnUpdated(needUpdate)); + group.addWidget(new ColorConfigurator(5, group.getWidgetBottomHeight() + 5, config, "fill", 0).setOnUpdated(needUpdate)); + group.addWidget(new ColorConfigurator(5, group.getWidgetBottomHeight() + 5, config, "stroke", 0).setOnUpdated(needUpdate)); + group.addWidget(new NumberConfigurator(5, group.getWidgetBottomHeight() + 5, config, "stroke_width", 1).setOnUpdated(needUpdate)); group.addWidget(new StringConfigurator(5, group.getWidgetBottomHeight() + 5, config, "ref", "").setOnUpdated(needUpdate)); group.addWidget(new StringConfigurator(5, group.getWidgetBottomHeight() + 5, config, "link", "").setOnUpdated(needUpdate)); group.addWidget(new TextListConfigurator(5, group.getWidgetBottomHeight() + 5, 40, config, "hover_text", true).setOnUpdated(needUpdate)); diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java index cc6c1fcb991..6bfe5b8aaed 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java @@ -2,7 +2,6 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import gregtech.api.GTValues; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; import gregtech.api.gui.resources.IGuiTexture; @@ -10,14 +9,16 @@ import gregtech.api.gui.resources.TextureArea; import gregtech.api.gui.resources.URLTexture; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; -import gregtech.api.terminal.gui.widgets.guide.congiurator.NumberConfigurator; -import gregtech.api.terminal.gui.widgets.guide.congiurator.StringConfigurator; +import gregtech.api.terminal.gui.widgets.guide.configurator.NumberConfigurator; +import gregtech.api.terminal.gui.widgets.guide.configurator.SelectorConfigurator; +import gregtech.api.terminal.gui.widgets.guide.configurator.StringConfigurator; import gregtech.api.util.Position; import gregtech.api.util.Size; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.item.Item; import net.minecraft.util.ResourceLocation; +import java.util.Arrays; import java.util.function.Consumer; public class ImageWidget extends GuideWidget{ @@ -39,7 +40,7 @@ public String getRegistryName() { public void updateValue(String field, JsonElement value) { super.updateValue(field, value); if (field.equals("width") || field.equals("height")) { - this.setSelfPosition(new Position(getSelfPosition().x - (width - getSize().width) / 2, getSelfPosition().y)); + this.addSelfPosition(- (width - getSize().width) / 2, 0); this.setSize(new Size(width, height)); } if (field.equals("form") || field.equals("source")) { @@ -60,6 +61,7 @@ public JsonObject getTemplate(boolean isFixed) { @Override public void loadConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, boolean isFixed, Consumer needUpdate) { super.loadConfigurator(group, config, isFixed, needUpdate); + group.addWidget(new SelectorConfigurator(5, group.getWidgetBottomHeight() + 5, config, "form", Arrays.asList("url", "item", "resource")).setOnUpdated(needUpdate)); group.addWidget(new StringConfigurator(5, group.getWidgetBottomHeight() + 5, config, "source").setOnUpdated(needUpdate)); group.addWidget(new NumberConfigurator(5, group.getWidgetBottomHeight() + 5, config, "width").setOnUpdated(needUpdate)); group.addWidget(new NumberConfigurator(5, group.getWidgetBottomHeight() + 5, config, "height").setOnUpdated(needUpdate)); diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java index b38066bd686..cb7a8fdc126 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java @@ -5,10 +5,11 @@ import com.google.gson.JsonObject; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; -import gregtech.api.gui.resources.RenderUtil; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; -import gregtech.api.terminal.gui.widgets.guide.congiurator.NumberConfigurator; -import gregtech.api.terminal.gui.widgets.guide.congiurator.TextListConfigurator; +import gregtech.api.terminal.gui.widgets.guide.configurator.BooleanConfigurator; +import gregtech.api.terminal.gui.widgets.guide.configurator.ColorConfigurator; +import gregtech.api.terminal.gui.widgets.guide.configurator.NumberConfigurator; +import gregtech.api.terminal.gui.widgets.guide.configurator.TextListConfigurator; import gregtech.api.util.Position; import gregtech.api.util.Size; import net.minecraft.client.Minecraft; @@ -79,6 +80,9 @@ public void loadConfigurator(DraggableScrollableWidgetGroup group, JsonObject co super.loadConfigurator(group, config, isFixed, needUpdate); group.addWidget(new NumberConfigurator(5, group.getWidgetBottomHeight() + 5, config, "space", 1).setOnUpdated(needUpdate)); group.addWidget(new NumberConfigurator(5, group.getWidgetBottomHeight() + 5, config, "fontSize", 9).setOnUpdated(needUpdate)); + group.addWidget(new ColorConfigurator(5, group.getWidgetBottomHeight() + 5, config, "fontColor", 0xff000000).setOnUpdated(needUpdate)); + group.addWidget(new BooleanConfigurator(5, group.getWidgetBottomHeight() + 5, config, "isShadow", false).setOnUpdated(needUpdate)); + group.addWidget(new BooleanConfigurator(5, group.getWidgetBottomHeight() + 5, config, "isCenter", false).setOnUpdated(needUpdate)); group.addWidget(new TextListConfigurator(5, group.getWidgetBottomHeight() + 5, 200, config, "content", false).setOnUpdated(needUpdate)); } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java index e7e96cdb565..da993835380 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java @@ -96,7 +96,7 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender if (leafTexture != null) { leafTexture.draw(position.x, y, size.width, ITEM_HEIGHT); } else { - gregtech.api.gui.resources.RenderUtil.renderRect(position.x, y, size.width, ITEM_HEIGHT, 0, 0xffff0000); + drawSolidRect(position.x, y, size.width, ITEM_HEIGHT, 0xffff0000); } if (node.content != null) { String nameS = nameSupplier.apply(node.content.getFirst()); @@ -110,11 +110,11 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender if (nodeTexture != null) { nodeTexture.draw(position.x, y, size.width, ITEM_HEIGHT); } else { - gregtech.api.gui.resources.RenderUtil.renderRect(position.x, y, size.width, ITEM_HEIGHT, 0, 0xffffff00); + drawSolidRect(position.x, y, size.width, ITEM_HEIGHT, 0xffffff00); } } if (node == selected) { - gregtech.api.gui.resources.RenderUtil.renderRect(position.x, y, size.width, ITEM_HEIGHT, 0, 0x7f000000); + drawSolidRect(position.x, y, size.width, ITEM_HEIGHT, 0x7f000000); } fr.drawString(I18n.format(name), x, y + 2, 0xff000000); } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/BooleanConfigurator.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/BooleanConfigurator.java new file mode 100644 index 00000000000..2b4c4ae2ca8 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/BooleanConfigurator.java @@ -0,0 +1,43 @@ +package gregtech.api.terminal.gui.widgets.guide.configurator; + +import com.google.gson.JsonObject; +import gregtech.api.gui.GuiTextures; +import gregtech.api.gui.resources.ColorRectTexture; +import gregtech.api.terminal.gui.widgets.RectButtonWidget; + +import java.awt.*; + +public class BooleanConfigurator extends ConfiguratorWidget{ + private boolean defaultValue; + + public BooleanConfigurator(int x, int y, JsonObject config, String name) { + super(x, y, config, name, false); + init(); + } + + public BooleanConfigurator(int x, int y, JsonObject config, String name, boolean defaultValue) { + super(x, y, config, name, true); + this.defaultValue = defaultValue; + init(); + } + + private void init(){ + this.addWidget(new RectButtonWidget(0, 15, 10, 10, 2) + .setToggleButton(new ColorRectTexture(new Color(198, 198, 198).getRGB()), (c, p)-> update(p)) + .setValueSupplier(true, ()->{ + if(config.get(name).isJsonNull()) { + return defaultValue; + } + return config.get(name).getAsBoolean(); + }) + .setColors(new Color(0, 0, 0, 74).getRGB(), + new Color(128, 255, 128).getRGB(), + new Color(255, 255, 255, 0).getRGB()) + .setIcon(new ColorRectTexture(new Color(0, 0, 0, 74).getRGB()))); + } + + private void update(boolean bool) { + config.addProperty(name, bool); + update(); + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ColorConfigurator.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ColorConfigurator.java new file mode 100644 index 00000000000..f52019325ec --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ColorConfigurator.java @@ -0,0 +1,34 @@ +package gregtech.api.terminal.gui.widgets.guide.configurator; + +import com.google.gson.JsonObject; +import gregtech.api.terminal.gui.widgets.ColorWidget; + +public class ColorConfigurator extends ConfiguratorWidget{ + private int defaultValue; + + public ColorConfigurator(int x, int y, JsonObject config, String name, int defaultValue) { + super(x, y, config, name, true); + this.defaultValue = defaultValue; + init(); + } + + public ColorConfigurator(int x, int y, JsonObject config, String name) { + super(x, y, config, name, false); + init(); + } + + private void init(){ + this.addWidget(new ColorWidget(0, 15, 85, 10).setColorSupplier(()->{ + if(config.get(name).isJsonNull()) { + return defaultValue; + } + return config.get(name).getAsInt(); + },true).setOnColorChanged(this::update)); + } + + private void update(int color) { + config.addProperty(name, color); + update(); + } + +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/ConfiguratorWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ConfiguratorWidget.java similarity index 74% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/ConfiguratorWidget.java rename to src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ConfiguratorWidget.java index 6ad16d559b9..42b25898006 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/ConfiguratorWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ConfiguratorWidget.java @@ -1,7 +1,5 @@ -package gregtech.api.terminal.gui.widgets.guide.congiurator; +package gregtech.api.terminal.gui.widgets.guide.configurator; -import com.google.gson.JsonElement; -import com.google.gson.JsonNull; import com.google.gson.JsonObject; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.widgets.LabelWidget; @@ -30,7 +28,7 @@ public ConfiguratorWidget(int x, int y, JsonObject config, String name, boolean if (canDefault && config.get(name).isJsonNull()) { isDefault = true; } - this.addWidget(new LabelWidget(0, 2, name, -1)); + this.addWidget(new LabelWidget(0, 4, name, -1).setShadow(true)); if (isClientSide()) { nameWidth = Minecraft.getMinecraft().fontRenderer.getStringWidth(name); } @@ -51,10 +49,12 @@ protected void update(){ public void drawInForeground(int mouseX, int mouseY) { int x = getPosition().x; int y = getPosition().y; - if (canDefault && isMouseOver(x + nameWidth + 4, y + 4, 5, 5, mouseX, mouseY)) { - drawHoveringText(ItemStack.EMPTY, Collections.singletonList("default the value"), 100, mouseX, mouseY); + if (canDefault && isMouseOver(x + nameWidth + 4, y + 6, 5, 5, mouseX, mouseY)) { + drawHoveringText(ItemStack.EMPTY, Collections.singletonList("default value"), 100, mouseX, mouseY); + } + if (!isDefault) { + super.drawInForeground(mouseX, mouseY); } - super.drawInForeground(mouseX, mouseY); } @Override @@ -63,12 +63,18 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender int y = getPosition().y; drawSolidRect(x, y, this.getSize().width, 1, -1); if (canDefault) { - drawBorder(x + nameWidth + 4, y + 4, 5, 5, 0xff000000, 1); + drawBorder(x + nameWidth + 4, y + 6, 5, 5, -1, 1); if (isDefault) { - drawSolidRect(x + nameWidth + 5, y + 5, 3, 3, 0xff000000); + drawSolidRect(x + nameWidth + 5, y + 7, 3, 3, -1); } } - super.drawInBackground(mouseX, mouseY, partialTicks, context); + if (canDefault && isDefault) { + super.drawInBackground(-100, -100, partialTicks, context); + drawSolidRect(x, y + 15, this.getSize().width, this.getSize().height - 15, 0x99000000); + } else { + super.drawInBackground(mouseX, mouseY, partialTicks, context); + } + } @Override @@ -78,7 +84,7 @@ public boolean mouseClicked(int mouseX, int mouseY, int button) { if (!isDefault && super.mouseClicked(mouseX, mouseY, button)) { return true; } - if (canDefault && isMouseOver(x + nameWidth + 4, y + 4, 5, 5, mouseX, mouseY)) { + if (canDefault && isMouseOver(x + nameWidth + 4, y + 6, 5, 5, mouseX, mouseY)) { isDefault = !isDefault; if (isDefault) { config.addProperty(name, (String) null); diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/NumberConfigurator.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/NumberConfigurator.java similarity index 53% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/NumberConfigurator.java rename to src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/NumberConfigurator.java index cb52f8f9ead..58c4c8fb059 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/NumberConfigurator.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/NumberConfigurator.java @@ -1,13 +1,16 @@ -package gregtech.api.terminal.gui.widgets.guide.congiurator; +package gregtech.api.terminal.gui.widgets.guide.configurator; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import gregtech.api.gui.GuiTextures; +import gregtech.api.gui.resources.ColorRectTexture; import gregtech.api.gui.resources.TextTexture; import gregtech.api.gui.widgets.ImageWidget; import gregtech.api.gui.widgets.SimpleTextWidget; import gregtech.api.terminal.gui.widgets.RectButtonWidget; +import java.awt.*; + public class NumberConfigurator extends ConfiguratorWidget{ private int defaultValue; @@ -23,20 +26,33 @@ public NumberConfigurator(int x, int y, JsonObject config, String name, int defa private void init(int defaultValue){ this.defaultValue = defaultValue; - this.addWidget(new RectButtonWidget(0, 11, 20, 20) + int y = 15; + this.addWidget(new RectButtonWidget(0, y, 20, 20) + .setColors(new Color(0, 0, 0, 74).getRGB(), + new Color(128, 255, 128).getRGB(), + new Color(255, 255, 255, 0).getRGB()) .setClickListener(data -> adjustTransferRate(data.isShiftClick ? -100 : -10)) - .setIcon(new TextTexture("-10"))); - this.addWidget(new RectButtonWidget(96, 11, 20, 20) + .setIcon(new TextTexture("-10", -1))); + this.addWidget(new RectButtonWidget(96, y, 20, 20) + .setColors(new Color(0, 0, 0, 74).getRGB(), + new Color(128, 255, 128).getRGB(), + new Color(255, 255, 255, 0).getRGB()) .setClickListener(data -> adjustTransferRate(data.isShiftClick ? +100 : +10)) - .setIcon(new TextTexture("+10"))); - this.addWidget(new RectButtonWidget(20, 11, 20, 20) + .setIcon(new TextTexture("+10", -1))); + this.addWidget(new RectButtonWidget(20, y, 20, 20) + .setColors(new Color(0, 0, 0, 74).getRGB(), + new Color(128, 255, 128).getRGB(), + new Color(255, 255, 255, 0).getRGB()) .setClickListener(data -> adjustTransferRate(data.isShiftClick ? -5 : -1)) - .setIcon(new TextTexture("-1"))); - this.addWidget(new RectButtonWidget(76, 11, 20, 20) + .setIcon(new TextTexture("-1", -1))); + this.addWidget(new RectButtonWidget(76, y, 20, 20) + .setColors(new Color(0, 0, 0, 74).getRGB(), + new Color(128, 255, 128).getRGB(), + new Color(255, 255, 255, 0).getRGB()) .setClickListener(data -> adjustTransferRate(data.isShiftClick ? +5 : +1)) - .setIcon(new TextTexture("+1"))); - this.addWidget(new ImageWidget(40, 11, 36, 20, GuiTextures.DISPLAY)); - this.addWidget(new SimpleTextWidget(58, 21, "", 0xFFFFFF, () -> { + .setIcon(new TextTexture("+1", -1))); + this.addWidget(new ImageWidget(40, y, 36, 20, new ColorRectTexture(0x9f000000))); + this.addWidget(new SimpleTextWidget(58, 25, "", 0xFFFFFF, () -> { JsonElement element = config.get(name); if (element.isJsonNull()) { return Integer.toString(defaultValue); diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/SelectorConfigurator.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/SelectorConfigurator.java new file mode 100644 index 00000000000..eaeec766e7f --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/SelectorConfigurator.java @@ -0,0 +1,49 @@ +package gregtech.api.terminal.gui.widgets.guide.configurator; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import gregtech.api.gui.GuiTextures; +import gregtech.api.gui.resources.TextTexture; +import gregtech.api.gui.widgets.ImageWidget; +import gregtech.api.gui.widgets.SimpleTextWidget; +import gregtech.api.terminal.gui.widgets.RectButtonWidget; +import gregtech.api.terminal.gui.widgets.SelectorWidget; + +import java.awt.*; +import java.util.List; + +public class SelectorConfigurator extends ConfiguratorWidget{ + private final List candidates; + private String defaultValue; + public SelectorConfigurator(int x, int y, JsonObject config, String name, List candidates, String defaultValue) { + super(x, y, config, name, true); + this.defaultValue = defaultValue; + this.candidates = candidates; + init(); + } + + public SelectorConfigurator(int x, int y, JsonObject config, String name, List candidates) { + super(x, y, config, name, false); + this.candidates = candidates; + init(); + } + + private void init(){ + this.addWidget(new SelectorWidget(0, 15, 80, 20, candidates, -1, ()->{ + if(config.get(name).isJsonNull()) { + return defaultValue; + } + return config.get(name).getAsString(); + }, true) + .setColors(new Color(0, 0, 0, 74).getRGB(), + new Color(128, 255, 128).getRGB(), + new Color(255, 255, 255, 0).getRGB()) + .setIsUp(true) + .setOnChanged(this::updateValue)); + } + + private void updateValue(String selected) { + config.addProperty(name, selected); + update(); + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/StringConfigurator.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/StringConfigurator.java similarity index 67% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/StringConfigurator.java rename to src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/StringConfigurator.java index b4589dfdfd0..3ffba684148 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/StringConfigurator.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/StringConfigurator.java @@ -1,11 +1,14 @@ -package gregtech.api.terminal.gui.widgets.guide.congiurator; +package gregtech.api.terminal.gui.widgets.guide.configurator; -import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import gregtech.api.gui.resources.ColorRectTexture; +import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.resources.TextTexture; import gregtech.api.gui.widgets.TextFieldWidget; import gregtech.api.terminal.gui.widgets.RectButtonWidget; +import java.awt.*; + public class StringConfigurator extends ConfiguratorWidget{ private String defaultValue = ""; private TextFieldWidget textFieldWidget; @@ -24,10 +27,14 @@ public StringConfigurator(int x, int y, JsonObject config, String name, String d } private void init() { - this.addWidget(new RectButtonWidget(76, 11, 40, 20) + this.addWidget(new RectButtonWidget(76, 15, 40, 20) + .setColors(new Color(0, 0, 0, 74).getRGB(), + new Color(128, 255, 128).getRGB(), + new Color(255, 255, 255, 0).getRGB()) .setClickListener(data -> updateString()) - .setIcon(new TextTexture("Update"))); - textFieldWidget = new TextFieldWidget(0, 11, 76, 20, true, null, null) + .setIcon(new TextTexture("Update", -1))); + textFieldWidget = new TextFieldWidget(0, 15, 76, 20, new ColorRectTexture(0x9f000000), null, null) + .setMaxStringLength(Integer.MAX_VALUE) .setValidator(s->true); this.addWidget(textFieldWidget); } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/TextListConfigurator.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/TextListConfigurator.java similarity index 63% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/TextListConfigurator.java rename to src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/TextListConfigurator.java index 9645c440241..9ec086e11f3 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/congiurator/TextListConfigurator.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/TextListConfigurator.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.gui.widgets.guide.congiurator; +package gregtech.api.terminal.gui.widgets.guide.configurator; import com.google.gson.Gson; import com.google.gson.JsonArray; @@ -10,7 +10,7 @@ import java.util.List; public class TextListConfigurator extends ConfiguratorWidget{ -// private TextEditorWidget textEditorWidget; + public TextListConfigurator(int x, int y, int height, JsonObject config, String name, boolean canDefault) { super(x, y, config, name, canDefault); JsonElement element = config.get(name); @@ -29,20 +29,8 @@ public TextListConfigurator(int x, int y, int height, JsonObject config, String } } -// public TextListConfigurator(int x, int y, int height, JsonObject config, String name, String defaultS) { -// super(x, y, config, name, false); -// StringBuilder s = new StringBuilder(); -// for (int i = 0; i < defaultS.size(); i++) { -// s.append(defaultS.get(i)); -// if(i != defaultS.size() - 1) { -// s.append('\n'); -// } -// } -// init(height, s.toString()); -// } - private void init(int height, String init) { - this.addWidget(new TextEditorWidget(0, 11, 116, height, init, this::updateTextList).setBackground(new ColorRectTexture(-1))); + this.addWidget(new TextEditorWidget(0, 15, 116, height, init, this::updateTextList).setBackground(new ColorRectTexture(0xA3FFFFFF))); } private void updateTextList(String saved) { From 8e8d3e81c8de553c8ee1466d3c6cbb574661f9fc Mon Sep 17 00:00:00 2001 From: Yefancy Date: Tue, 3 Aug 2021 22:00:12 +0800 Subject: [PATCH 31/58] CustomDragSizePos --- .../api/terminal/app/GuideEditorApp.java | 2 +- .../api/terminal/app/guide/GuideApp.java | 2 +- .../gregtech/api/terminal/gui/IDraggable.java | 1 - .../gui/widgets/CustomPositionSizeWidget.java | 211 ++++++++++++++++++ .../DraggableScrollableWidgetGroup.java | 14 +- .../widgets/guide/GuidePageEditorWidget.java | 116 ++++++---- .../gui/widgets/guide/GuidePageWidget.java | 19 +- .../gui/widgets/guide/GuideWidget.java | 41 ++-- .../gui/widgets/guide/IGuideWidget.java | 4 + .../gui/widgets/guide/ImageWidget.java | 28 +-- .../gui/widgets/guide/TextBoxWidget.java | 14 +- 11 files changed, 349 insertions(+), 103 deletions(-) create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/CustomPositionSizeWidget.java diff --git a/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java b/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java index 9ecb104de8d..a5bbbc889d0 100644 --- a/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java +++ b/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java @@ -20,7 +20,7 @@ public AbstractApplication createApp(boolean isClient, NBTTagCompound nbt) { if (isClient) { GuideEditorApp app = new GuideEditorApp(); GuideConfigEditor configEditor = new GuideConfigEditor(0, 0, 133, 232); - GuidePageEditorWidget pageEditor = new GuidePageEditorWidget(133, 0, 200, 232); + GuidePageEditorWidget pageEditor = new GuidePageEditorWidget(133, 0, 200, 232, 5); configEditor.setGuidePageEditorWidget(pageEditor); pageEditor.setGuideConfigEditor(configEditor); app.addWidget(pageEditor); diff --git a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java index dabcc3322a8..67568dc5fcf 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java @@ -43,7 +43,7 @@ public AbstractApplication createApp(boolean isClient, NBTTagCompound nbt) { if (app.pageWidget != null) { app.removeWidget(app.pageWidget); } - app.pageWidget = new GuidePageWidget(133, 0, 200, 232); + app.pageWidget = new GuidePageWidget(133, 0, 200, 232, 5); if (leaf.isLeaf() && leaf.content != null) { app.pageWidget.loadJsonConfig(leaf.content.getSecond()); } diff --git a/src/main/java/gregtech/api/terminal/gui/IDraggable.java b/src/main/java/gregtech/api/terminal/gui/IDraggable.java index 1c38550638e..5366276a536 100644 --- a/src/main/java/gregtech/api/terminal/gui/IDraggable.java +++ b/src/main/java/gregtech/api/terminal/gui/IDraggable.java @@ -1,7 +1,6 @@ package gregtech.api.terminal.gui; public interface IDraggable { - boolean setDraggable(boolean isDraggable); boolean allowDrag(int mouseX, int mouseY, int button); default void startDrag(int mouseX, int mouseY) {} default boolean dragging(int mouseX, int mouseY, int deltaX, int deltaY) {return true;} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/CustomPositionSizeWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/CustomPositionSizeWidget.java new file mode 100644 index 00000000000..4868795681e --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/CustomPositionSizeWidget.java @@ -0,0 +1,211 @@ +package gregtech.api.terminal.gui.widgets; + +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.Widget; +import gregtech.api.terminal.gui.IDraggable; +import gregtech.api.util.Position; +import gregtech.api.util.Size; +import javafx.geometry.Pos; + +import java.util.function.BiConsumer; + +public class CustomPositionSizeWidget extends Widget implements IDraggable { + private Widget controlled; + private final int borderColor; + private final int hoverColor; + private final int border; + private boolean dragUp; + private boolean dragDown; + private boolean dragLeft; + private boolean dragRight; + private boolean dragPos; + + private BiConsumer onUpdated; + + + public CustomPositionSizeWidget(Widget controlled, int borderColor, int hoverColor, int border) { + super(controlled.getSelfPosition(), controlled.getSize()); + this.controlled = controlled; + this.borderColor = borderColor; + this.hoverColor = hoverColor; + this.border = border; + } + + public CustomPositionSizeWidget(int borderColor, int hoverColor, int border) { + super(Position.ORIGIN, Size.ZERO); + this.borderColor = borderColor; + this.hoverColor = hoverColor; + this.border = border; + } + + public CustomPositionSizeWidget setControlled(Widget controlled) { + this.controlled = controlled; + if (controlled != null) { + this.setSelfPosition(controlled.getSelfPosition()); + this.setSize(controlled.getSize()); + } + return this; + } + + public Widget getControlled() { + return controlled; + } + + public CustomPositionSizeWidget setOnUpdated(BiConsumer onUpdated) { + this.onUpdated = onUpdated; + return this; + } + + @Override + public void updateScreen() { + if (controlled != null) { + Position pos = controlled.getSelfPosition(); + Size size = controlled.getSize(); + if (!this.getSelfPosition().equals(pos)) { + this.setSelfPosition(pos); + } + if (this.getSize().equals(size)) { + this.setSize(size); + } + } + } + + @Override + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + if (controlled == null) return; + int x = controlled.getPosition().x; + int y = controlled.getPosition().y; + int width = controlled.getSize().width; + int height = controlled.getSize().height; + + boolean hoverUp = false; + boolean hoverDown = false; + boolean hoverLeft = false; + boolean hoverRight = false; + // UP + if (isMouseOver(x, y, width / 5, border, mouseX, mouseY) || + isMouseOver(x + width * 2 / 5, y, width / 5, border, mouseX, mouseY) || + isMouseOver(x + width * 4 / 5, y, width / 5, border, mouseX, mouseY) || + isMouseOver(x, y, border, height / 5, mouseX, mouseY) || + isMouseOver(x + width - border, y, border, height / 5, mouseX, mouseY)) { + hoverUp = true; + } + if (isMouseOver(x, y + height - border, width / 5, border, mouseX, mouseY) || + isMouseOver(x + width * 2 / 5, y + height - border, width / 5, border, mouseX, mouseY) || + isMouseOver(x + width * 4 / 5, y + height - border, width / 5, border, mouseX, mouseY) || + isMouseOver(x, y + height * 4 / 5, border, height / 5, mouseX, mouseY) || + isMouseOver(x + width - border, y + height * 4 / 5, border, height / 5, mouseX, mouseY)) { + hoverDown = true; + } + if (isMouseOver(x, y, border, height / 5, mouseX, mouseY) || + isMouseOver(x, y + height * 2 / 5, border, height / 5, mouseX, mouseY) || + isMouseOver(x, y + height * 4 / 5, border, height / 5, mouseX, mouseY) || + isMouseOver(x, y, width / 5, border, mouseX, mouseY) || + isMouseOver(x, y + height - border, width / 5, border, mouseX, mouseY)) { + hoverLeft = true; + } + if (isMouseOver(x + width - border, y, border, height / 5, mouseX, mouseY) || + isMouseOver(x + width - border, y + height * 2 / 5, border, height / 5, mouseX, mouseY) || + isMouseOver(x + width - border, y + height * 4 / 5, border, height / 5, mouseX, mouseY) || + isMouseOver(x + width * 4 / 5, y, width / 5, border, mouseX, mouseY) || + isMouseOver(x + width * 4 / 5, y + height - border, width / 5, border, mouseX, mouseY)) { + hoverRight = true; + } + drawSolidRect(x, y, width / 5, border, hoverUp ? hoverColor : borderColor); + drawSolidRect(x + width * 2 / 5, y, width / 5, border, hoverUp ? hoverColor : borderColor); + drawSolidRect(x + width * 4 / 5, y, width / 5, border, hoverUp ? hoverColor : borderColor); + // DOWN + drawSolidRect(x, y + height - border, width / 5, border, hoverDown ? hoverColor : borderColor); + drawSolidRect(x + width * 2 / 5, y + height - border, width / 5, border, hoverDown ? hoverColor : borderColor); + drawSolidRect(x + width * 4 / 5, y + height - border, width / 5, border, hoverDown ? hoverColor : borderColor); + // LEFT + drawSolidRect(x, y, border, height / 5, hoverLeft ? hoverColor : borderColor); + drawSolidRect(x, y + height * 2 / 5, border, height / 5, hoverLeft ? hoverColor : borderColor); + drawSolidRect(x, y + height * 4 / 5, border, height / 5, hoverLeft ? hoverColor : borderColor); + // RIGHT + drawSolidRect(x + width - border, y, border, height / 5, hoverRight ? hoverColor : borderColor); + drawSolidRect(x + width - border, y + height * 2 / 5, border, height / 5, hoverRight ? hoverColor : borderColor); + drawSolidRect(x + width - border, y + height * 4 / 5, border, height / 5, hoverRight ? hoverColor : borderColor); + } + + @Override + public boolean allowDrag(int mouseX, int mouseY, int button) { + if (controlled == null) return false; + int x = controlled.getPosition().x; + int y = controlled.getPosition().y; + int width = controlled.getSize().width; + int height = controlled.getSize().height; + if (isMouseOver(x, y, width, height, mouseX, mouseY)) { + // UP + dragUp = isMouseOver(x, y, width / 5, border, mouseX, mouseY) || + isMouseOver(x + width * 2 / 5, y, width / 5, border, mouseX, mouseY) || + isMouseOver(x + width * 4 / 5, y, width / 5, border, mouseX, mouseY) || + isMouseOver(x, y, border, height / 5, mouseX, mouseY) || + isMouseOver(x + width - border, y, border, height / 5, mouseX, mouseY); + // DOWN + dragDown = isMouseOver(x, y + height - border, width / 5, border, mouseX, mouseY) || + isMouseOver(x + width * 2 / 5, y + height - border, width / 5, border, mouseX, mouseY) || + isMouseOver(x + width * 4 / 5, y + height - border, width / 5, border, mouseX, mouseY) || + isMouseOver(x, y + height * 4 / 5, border, height / 5, mouseX, mouseY) || + isMouseOver(x + width - border, y + height * 4 / 5, border, height / 5, mouseX, mouseY); + // LEFT + dragLeft = isMouseOver(x, y, border, height / 5, mouseX, mouseY) || + isMouseOver(x, y + height * 2 / 5, border, height / 5, mouseX, mouseY) || + isMouseOver(x, y + height * 4 / 5, border, height / 5, mouseX, mouseY) || + isMouseOver(x, y, width / 5, border, mouseX, mouseY) || + isMouseOver(x, y + height - border, width / 5, border, mouseX, mouseY); + // RIGHT + dragRight = isMouseOver(x + width - border, y, border, height / 5, mouseX, mouseY) || + isMouseOver(x + width - border, y + height * 2 / 5, border, height / 5, mouseX, mouseY) || + isMouseOver(x + width - border, y + height * 4 / 5, border, height / 5, mouseX, mouseY) || + isMouseOver(x + width * 4 / 5, y, width / 5, border, mouseX, mouseY) || + isMouseOver(x + width * 4 / 5, y + height - border, width / 5, border, mouseX, mouseY); + dragPos = !dragUp && !dragDown && !dragLeft && !dragRight; + return true; + } + return false; + } + + @Override + public boolean dragging(int mouseX, int mouseY, int deltaX, int deltaY) { + if (controlled == null) return false; + int width = controlled.getSize().width; + int height = controlled.getSize().height; + int addX = 0, addY = 0; + if (!dragPos) { + if (dragUp) { + addY = deltaY; + height -= deltaY; + } + if (dragDown) { + height += deltaY; + } + if (dragLeft) { + addX = deltaX; + width -= deltaX; + } + if (dragRight) { + width += deltaX; + } + controlled.addSelfPosition(addX, addY); + controlled.setSize(new Size(width, height)); + } else { + controlled.addSelfPosition(deltaX, deltaY); + } + if (onUpdated != null) { + onUpdated.accept(controlled.getSelfPosition(), controlled.getSize()); + } + this.setSelfPosition(controlled.getSelfPosition()); + this.setSize(controlled.getSize()); + return false; + } + + @Override + public void endDrag(int mouseX, int mouseY) { + dragDown = false; + dragUp = false; + dragLeft = false; + dragRight = false; + dragPos = false; + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java b/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java index ec0c752e39d..8ceea9e6414 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java @@ -280,7 +280,7 @@ private boolean checkClickedDragged(int mouseX, int mouseY, int button) { } else if (widget instanceof IDraggable && ((IDraggable) widget).allowDrag(mouseX, mouseY, button)) { draggedWidget = widget; ((IDraggable) widget).startDrag(mouseX, mouseY); - return true; + return false; } } } @@ -294,8 +294,8 @@ public boolean mouseWheelMove(int mouseX, int mouseY, int wheelDelta) { return true; } int moveDelta = -MathHelper.clamp(wheelDelta, -1, 1) * 5; - if (getMaxHeight() - getSize().height > 0) { - setScrollYOffset(MathHelper.clamp(scrollYOffset + moveDelta, 0, getMaxHeight() - getSize().height + 5)); + if (getMaxHeight() - getSize().height > 0 || scrollYOffset > getMaxHeight() - getSize().height) { + setScrollYOffset(MathHelper.clamp(scrollYOffset + moveDelta, 0, getMaxHeight() - getSize().height)); } return true; } @@ -309,11 +309,11 @@ public boolean mouseDragged(int mouseX, int mouseY, int button, long timeDragged int deltaY = mouseY - lastMouseY; lastMouseX = mouseX; lastMouseY = mouseY; - if (draggedOnXScrollBar) { - setScrollXOffset(MathHelper.clamp(scrollXOffset + deltaX * getMaxWidth() / getSize().width, 0, Math.max(getMaxWidth() - getSize().width, 0))); + if (draggedOnXScrollBar && (getMaxWidth() - getSize().width > 0 || scrollYOffset > getMaxWidth() - getSize().width)) { + setScrollXOffset(MathHelper.clamp(scrollXOffset + deltaX * getMaxWidth() / getSize().width, 0, getMaxWidth() - getSize().width)); return true; - } else if (draggedOnYScrollBar) { - setScrollYOffset(MathHelper.clamp(scrollYOffset + deltaY * getMaxHeight() / getSize().height, 0, Math.max(getMaxHeight() - getSize().height, 0))); + } else if (draggedOnYScrollBar && (getMaxHeight() - getSize().height > 0 || scrollYOffset > getMaxHeight() - getSize().height)) { + setScrollYOffset(MathHelper.clamp(scrollYOffset + deltaY * getMaxHeight() / getSize().height, 0, getMaxHeight() - getSize().height)); return true; } else if (draggedWidget != null && ((IDraggable)draggedWidget).dragging(mouseX, mouseY, deltaX, deltaY)) { draggedWidget.addSelfPosition(deltaX, deltaY); diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java index 0f61ead4b95..293e128d34f 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java @@ -8,8 +8,8 @@ import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; import gregtech.api.gui.widgets.WidgetGroup; -import gregtech.api.terminal.gui.IDraggable; import gregtech.api.terminal.gui.widgets.CircleButtonWidget; +import gregtech.api.terminal.gui.widgets.CustomPositionSizeWidget; import gregtech.api.util.Position; import gregtech.api.util.Size; import gregtech.api.util.interpolate.Eases; @@ -26,13 +26,15 @@ public class GuidePageEditorWidget extends GuidePageWidget { private final Map configMap; private Widget selected; private final WidgetGroup toolButtons; + private final CustomPositionSizeWidget customPositionSizeWidget; private GuideConfigEditor configEditor; - public GuidePageEditorWidget(int xPosition, int yPosition, int width, int height) { - super(xPosition, yPosition, width, height); + public GuidePageEditorWidget(int xPosition, int yPosition, int width, int height, int margin) { + super(xPosition, yPosition, width, height, margin); this.setDraggable(false); configMap = new HashMap<>(); setTitle("Template"); + customPositionSizeWidget = new CustomPositionSizeWidget(0xff0000ff, 0xffff0000, 2).setOnUpdated(this::onPosSizeChanged); toolButtons = new WidgetGroup(Position.ORIGIN, Size.ZERO); toolButtons.setVisible(false); toolButtons.addWidget(new CircleButtonWidget(-20, -4, 8, 1, 12) @@ -56,23 +58,33 @@ public GuidePageEditorWidget(int xPosition, int yPosition, int width, int height .setIcon(GuiTextures.TERMINAL_DELETE) .setHoverText("delete") .setClickListener(this::delete)); + addWidget(customPositionSizeWidget); addWidget(toolButtons); } + private void onPosSizeChanged(Position pos, Size size) { + if (customPositionSizeWidget.getControlled() instanceof IGuideWidget) { + ((IGuideWidget) customPositionSizeWidget.getControlled()).onFixedPositionSizeChanged(pos, size); + } + toolButtons.setSelfPosition(new Position(pos.x + size.width / 2, pos.y)); + } + public void setGuideConfigEditor(GuideConfigEditor configEditor) { this.configEditor = configEditor; } - private void setToolButton(int x, int y, int width, int height) { + private void setToolButton(Widget widget) { + customPositionSizeWidget.setControlled(widget); toolButtons.setVisible(true); - toolButtons.setSelfPosition(new Position(x + width / 2, y)); + toolButtons.setSelfPosition(new Position(widget.getSelfPosition().x + widget.getSize().width / 2, widget.getSelfPosition().y)); } private void delete(ClickData clickData) { removeWidget(selected); selected = null; configEditor.loadConfigurator(null, null, true); - toolButtons.setSelfPosition(new Position(0, 0)); + toolButtons.setSelfPosition(new Position(-scrollYOffset, -scrollYOffset)); + customPositionSizeWidget.setControlled(null); toolButtons.setVisible(false); } @@ -100,7 +112,8 @@ public String getJsonString() { } public JsonObject addGuideWidget(IGuideWidget widget, boolean isFixed) { - int pageWidth = this.getSize().width - yBarWidth; + int pageWidth = getPageWidth(); + int margin = getMargin(); JsonObject widgetConfig = widget.getTemplate(isFixed); Widget guideWidget; if (isFixed) { @@ -117,7 +130,7 @@ public JsonObject addGuideWidget(IGuideWidget widget, boolean isFixed) { this.addWidget(guideWidget); } else { int y = getStreamBottom(); - guideWidget = widget.createStreamWidget(5, y + 5, pageWidth - 10, widgetConfig); + guideWidget = widget.createStreamWidget(margin, y + 5, pageWidth - 2 * margin, widgetConfig); stream.add(guideWidget); this.addWidget(guideWidget); } @@ -139,7 +152,7 @@ public void moveUp(Widget widget) { widget.setSelfPosition(new Position(widget.getSelfPosition().x, (int) (y1 - value.floatValue() * offsetU))); target.setSelfPosition(new Position(target.getSelfPosition().x, (int) (y2 + value.floatValue() * offsetD))); if (widget == selected) { - setToolButton(selected.getSelfPosition().x, selected.getSelfPosition().y, selected.getSize().width, selected.getSize().height); + setToolButton(selected); } widget.setVisible(widget.getSelfPosition().y < scrollYOffset + getSize().height && widget.getSelfPosition().y + widget.getSize().height > 0); target.setVisible(target.getSelfPosition().y < scrollYOffset + getSize().height && target.getSelfPosition().y + target.getSize().height > 0); @@ -165,7 +178,7 @@ public void moveDown(Widget widget) { widget.setSelfPosition(new Position(widget.getSelfPosition().x, (int) (y1 + value.floatValue() * offsetD))); target.setSelfPosition(new Position(target.getSelfPosition().x, (int) (y2 - value.floatValue() * offsetU))); if (widget == selected) { - setToolButton(selected.getSelfPosition().x, selected.getSelfPosition().y, selected.getSize().width, selected.getSize().height); + setToolButton(selected); } widget.setVisible(widget.getSelfPosition().y < getSize().height - xBarHeight && widget.getSelfPosition().y + widget.getSize().height > 0); target.setVisible(target.getSelfPosition().y < getSize().height - xBarHeight && target.getSelfPosition().y + target.getSize().height > 0); @@ -211,34 +224,36 @@ public void removeWidget(Widget widget) { @Override public boolean mouseClicked(int mouseX, int mouseY, int button) { + if (super.mouseClicked(mouseX, mouseY, button)) { + return true; + } boolean flag = false; for (Widget widget : fixed) { if (widget.isMouseOverElement(mouseX, mouseY)) { if (widget instanceof IGuideWidget && widget != selected) { configEditor.loadConfigurator((IGuideWidget) widget, configMap.get(widget), true); selected = widget; - setToolButton(selected.getSelfPosition().x, selected.getSelfPosition().y, selected.getSize().width, selected.getSize().height); + setToolButton(selected); } playButtonClickSound(); flag = true; break; } } - for (Widget widget : stream) { - if (widget.isMouseOverElement(mouseX, mouseY)) { - if (widget instanceof IGuideWidget && widget != selected) { - configEditor.loadConfigurator((IGuideWidget) widget, configMap.get(widget), false); - selected = widget; - setToolButton(selected.getSelfPosition().x, selected.getSelfPosition().y, selected.getSize().width, selected.getSize().height); + if (!flag) { + for (Widget widget : stream) { + if (widget.isMouseOverElement(mouseX, mouseY)) { + if (widget instanceof IGuideWidget && widget != selected) { + configEditor.loadConfigurator((IGuideWidget) widget, configMap.get(widget), false); + selected = widget; + setToolButton(selected); + } + playButtonClickSound(); + flag = true; + break; } - playButtonClickSound(); - flag = true; - break; } } - if (super.mouseClicked(mouseX, mouseY, button)) { - return true; - } return flag; } @@ -246,8 +261,18 @@ public boolean mouseClicked(int mouseX, int mouseY, int button) { protected boolean hookDrawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { Position position = getPosition(); Size size = getSize(); - for (Widget widget : widgets) { - if (widget != toolButtons && widget.isVisible()) { + if(title.isVisible()) { + title.drawInBackground(mouseX, mouseY, partialTicks, context); + } + for (Widget widget : stream) { + if (widget.isVisible()) { + widget.drawInBackground(mouseX, mouseY, partialTicks, context); + } + } + + boolean flag = false; + for (Widget widget : fixed) { + if (widget.isVisible()) { widget.drawInBackground(mouseX, mouseY, partialTicks, context); if (widget.isMouseOverElement(mouseX, mouseY)) { if (widget != selected) { @@ -255,23 +280,40 @@ protected boolean hookDrawInBackground(int mouseX, int mouseY, float partialTick Size s = widget.getSize(); if (stream.contains(widget)) { drawSolidRect(position.x, pos.y, size.width - yBarWidth, s.height, 0x6f000000); + } else { drawSolidRect(pos.x, pos.y, s.width, s.height, 0x6f000000); } } + flag = true; } } } - if (selected != null) { - Position pos = selected.getPosition(); - Size s = selected.getSize(); - if (stream.contains(selected)) { - drawSolidRect(position.x, pos.y, size.width - yBarWidth, s.height, 0x6f0000ff); - } else { - drawSolidRect(pos.x, pos.y, s.width, s.height, 0x6f0000ff); + if (!flag) { + for (Widget widget : stream) { + if (widget.isVisible() && widget != selected && widget.isMouseOverElement(mouseX, mouseY)) { + Position pos = widget.getPosition(); + Size s = widget.getSize(); + if (stream.contains(widget)) { + drawSolidRect(position.x, pos.y, size.width - yBarWidth, s.height, 0x6f000000); + } else { + drawSolidRect(pos.x, pos.y, s.width, s.height, 0x6f000000); + } + } } } + + if (selected != null) { +// Position pos = selected.getPosition(); +// Size s = selected.getSize(); +// if (stream.contains(selected)) { +// drawSolidRect(position.x, pos.y, size.width - yBarWidth, s.height, 0x6f0000ff); +// } else { +// drawSolidRect(pos.x, pos.y, s.width, s.height, 0x6f0000ff); +// } + } if(toolButtons.isVisible()) { + customPositionSizeWidget.drawInBackground(mouseX, mouseY, partialTicks, context); toolButtons.drawInBackground(mouseX, mouseY, partialTicks, context); } GlStateManager.color(rColorForOverlay, gColorForOverlay, bColorForOverlay, 1.0F); @@ -281,17 +323,9 @@ protected boolean hookDrawInBackground(int mouseX, int mouseY, float partialTick @Override public boolean mouseDragged(int mouseX, int mouseY, int button, long timeDragged) { if (super.mouseDragged(mouseX, mouseY, button, timeDragged) && toolButtons.isVisible()) { - setToolButton(selected.getSelfPosition().x, selected.getSelfPosition().y, selected.getSize().width, selected.getSize().height); + setToolButton(selected); return true; } return false; } - - @Override - public void addWidget(Widget widget) { - super.addWidget(widget); - if(fixed.contains(widget) && widget instanceof IDraggable) { - ((IDraggable) widget).setDraggable(true); - } - } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java index e952b622d61..6ad34a1117e 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java @@ -25,12 +25,12 @@ public class GuidePageWidget extends DraggableScrollableWidgetGroup { protected TextBoxWidget title; protected List stream = new ArrayList<>(); protected List fixed = new ArrayList<>(); -// protected int pageWdith; - protected Interpolator interpolator; + private final int margin; - public GuidePageWidget(int xPosition, int yPosition, int width, int height) { + public GuidePageWidget(int xPosition, int yPosition, int width, int height, int margin) { super(xPosition, yPosition, width, height); + this.margin = margin; this.setBackground(new ColorRectTexture(-1)) .setDraggable(true) .setYScrollBarWidth(4) @@ -39,6 +39,14 @@ public GuidePageWidget(int xPosition, int yPosition, int width, int height) { } + public int getPageWidth() { + return this.getSize().width - yBarWidth; + } + + public int getMargin() { + return margin; + } + public void setTitle(String config) { int height = 0; if (title != null) { @@ -69,7 +77,8 @@ public String loadJsonConfig(String config) { } public void loadJsonConfig(JsonObject config) { - int pageWidth = this.getSize().width - yBarWidth; + int pageWidth = getPageWidth(); + int margin = getMargin(); // add title setTitle(config.get("title").getAsString()); @@ -79,7 +88,7 @@ public void loadJsonConfig(JsonObject config) { int y = title.getSize().height + 10; for (JsonElement element : config.getAsJsonArray("stream")) { JsonObject widgetConfig = element.getAsJsonObject(); - Widget widget = REGISTER_WIDGETS.get(widgetConfig.get("type").getAsString()).createStreamWidget(5, y, pageWidth - 10, widgetConfig); + Widget widget = REGISTER_WIDGETS.get(widgetConfig.get("type").getAsString()).createStreamWidget(margin, y, pageWidth - 2 * margin, widgetConfig); y += widget.getSize().height + 5; stream.add(widget); this.addWidget(widget); diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java index 9dfe19aaab1..2111f319a7a 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java @@ -3,10 +3,8 @@ import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import com.sun.istack.internal.Nullable; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; -import gregtech.api.terminal.gui.IDraggable; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; import gregtech.api.terminal.gui.widgets.guide.configurator.ColorConfigurator; import gregtech.api.terminal.gui.widgets.guide.configurator.NumberConfigurator; @@ -21,7 +19,7 @@ import java.util.List; import java.util.function.Consumer; -public abstract class GuideWidget extends Widget implements IGuideWidget, IDraggable { +public abstract class GuideWidget extends Widget implements IGuideWidget { //config public String ref; public int fill; @@ -31,7 +29,7 @@ public abstract class GuideWidget extends Widget implements IGuideWidget, IDragg public List hover_text; private static final Gson GSON = new Gson(); - public boolean allowDrag; + private transient boolean isFixed; protected transient GuidePageWidget page; public GuideWidget(int x, int y, int width, int height) { @@ -52,12 +50,24 @@ public void updateValue(String field, JsonElement value) { } else { f.set(this, new Gson().fromJson(value, f.getType())); } + if (isFixed) { + initFixed(); + } else { + initStream(); + } } catch (Exception e) { e.printStackTrace(); } } + public boolean isFixed() { + return isFixed; + } + @Override + public void onFixedPositionSizeChanged(Position position, Size size) { + this.initFixed(); + } @Override public void setStroke(int color) { @@ -123,24 +133,26 @@ public String getRef() { @Override public Widget createStreamWidget(int x, int y, int pageWidth, JsonObject config) { GuideWidget widget = GSON.fromJson(config, this.getClass()); + widget.isFixed = false; widget.setSelfPosition(new Position(x, y)); widget.setSize(new Size(pageWidth, 0)); - return widget.initStream(x, y, pageWidth, config); + return widget.initStream(); } @Override public Widget createFixedWidget(int x, int y, int width, int height, JsonObject config) { GuideWidget widget = GSON.fromJson(config, this.getClass()); + widget.isFixed = true; widget.setSelfPosition(new Position(x, y)); widget.setSize(new Size(width, height)); - return widget.initFixed(x, y, width, height, config); + return widget.initFixed(); } - protected Widget initStream(int x, int y, int pageWidth, @Nullable JsonObject config) { - return initFixed(x, y, pageWidth, 0, config); + protected Widget initStream() { + return initFixed(); } - protected Widget initFixed(int x, int y, int width, int height, @Nullable JsonObject config) { + protected Widget initFixed() { return this; } @@ -185,15 +197,4 @@ public boolean mouseClicked(int mouseX, int mouseY, int button) { } return false; } - - @Override - public boolean allowDrag(int mouseX, int mouseY, int button) { - return allowDrag && isMouseOverElement(mouseX, mouseY); - } - - @Override - public boolean setDraggable(boolean isDraggable) { - allowDrag = isDraggable; - return allowDrag; - } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java index f8ad46d95d4..25f10636c6a 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java @@ -4,7 +4,10 @@ import com.google.gson.JsonObject; import gregtech.api.gui.Widget; import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.terminal.gui.IDraggable; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; +import gregtech.api.util.Position; +import gregtech.api.util.Size; import java.util.function.Consumer; @@ -17,4 +20,5 @@ public interface IGuideWidget { JsonObject getTemplate(boolean isFixed); void loadConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, boolean isFixed, Consumer needUpdate); void setStroke(int color); + void onFixedPositionSizeChanged(Position position, Size size); } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java index 6bfe5b8aaed..e9162a24121 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java @@ -1,6 +1,5 @@ package gregtech.api.terminal.gui.widgets.guide; -import com.google.gson.JsonElement; import com.google.gson.JsonObject; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; @@ -36,18 +35,6 @@ public String getRegistryName() { return NAME; } - @Override - public void updateValue(String field, JsonElement value) { - super.updateValue(field, value); - if (field.equals("width") || field.equals("height")) { - this.addSelfPosition(- (width - getSize().width) / 2, 0); - this.setSize(new Size(width, height)); - } - if (field.equals("form") || field.equals("source")) { - initFixed(0,0,0,0,null); - } - } - @Override public JsonObject getTemplate(boolean isFixed) { JsonObject template = super.getTemplate(isFixed); @@ -75,14 +62,23 @@ public void updateScreen() { } @Override - protected Widget initStream(int x, int y, int pageWidth, JsonObject config) { + protected Widget initStream() { + int pageWidth = getSize().width; + int x = getSelfPosition().x; + int y = getSelfPosition().y; + if (page != null) { + x = page.getMargin(); + pageWidth = page.getPageWidth() - 2 * x; + } this.setSelfPosition(new Position(x + (pageWidth - width) / 2, y)); this.setSize(new Size(width, height)); - return super.initStream(x, y, pageWidth, config); + return initFixed(); } @Override - protected Widget initFixed(int x, int y, int width, int height, JsonObject config) { + protected Widget initFixed() { + width = getSize().width; + height = getSize().height; switch (form) { case "url": image = new URLTexture(source); diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java index cb7a8fdc126..e6c2d7be156 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java @@ -45,7 +45,7 @@ public TextBoxWidget(int x, int y, int width, List content, int space, i this.stroke = stroke; this.isCenter = isCenter; this.isShadow = isShadow; - this.initFixed(x, y, width, 0, null); + this.initFixed(); } public TextBoxWidget() {} @@ -55,14 +55,6 @@ public String getRegistryName() { return NAME; } - @Override - public void updateValue(String field, JsonElement value) { - super.updateValue(field, value); - if (field.equals("space") || field.equals("fontSize") || field.equals("content")) { - initFixed(getSelfPosition().x, getSelfPosition().y, getSize().width, getSize().height, null); - } - } - @Override public JsonObject getTemplate(boolean isFixed) { JsonObject template = super.getTemplate(isFixed); @@ -87,12 +79,12 @@ public void loadConfigurator(DraggableScrollableWidgetGroup group, JsonObject co } @Override - protected Widget initFixed(int x, int y, int width, int height, JsonObject config) { + protected Widget initFixed() { this.textLines = new ArrayList<>(); FontRenderer font = Minecraft.getMinecraft().fontRenderer; this.space = Math.max(space, 0); this.fontSize = Math.max(fontSize, 1); - int wrapWidth = width * font.FONT_HEIGHT / fontSize; + int wrapWidth = getSize().width * font.FONT_HEIGHT / fontSize; if (content != null) { for (String textLine : content) { this.textLines.addAll(font.listFormattedStringToWidth(I18n.format(textLine), wrapWidth)); From a89f293bd7dbfd5156b5d6c2597e59168eb2c164 Mon Sep 17 00:00:00 2001 From: Yefancy Date: Wed, 4 Aug 2021 13:09:14 +0800 Subject: [PATCH 32/58] details --- .../api/terminal/gui/widgets/ColorWidget.java | 76 +++++++----- .../gui/widgets/CustomPositionSizeWidget.java | 109 +++++++++--------- .../gui/widgets/TextEditorWidget.java | 2 +- .../gui/widgets/guide/GuideConfigEditor.java | 78 ++++++++++--- .../widgets/guide/GuidePageEditorWidget.java | 54 ++++++--- .../gui/widgets/guide/GuidePageWidget.java | 10 +- .../gui/widgets/guide/GuideWidget.java | 50 +++++--- .../gui/widgets/guide/IGuideWidget.java | 4 +- .../gui/widgets/guide/ImageWidget.java | 15 ++- .../gui/widgets/guide/TextBoxWidget.java | 10 +- 10 files changed, 262 insertions(+), 146 deletions(-) diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/ColorWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/ColorWidget.java index 2f9580e405a..58b88ed577a 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/ColorWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/ColorWidget.java @@ -37,19 +37,39 @@ public ColorWidget(int x, int y, int barWidth, int barHeight){ this.barHeight= barHeight; IGuiTexture textFieldBackground = new ColorRectTexture(0x9f000000); TextFieldWidget redField = new TextFieldWidget(barWidth + 5, 0, 30, barHeight, textFieldBackground, null, null) - .setTextResponder((t) -> setRed(t.isEmpty()? 0 : Integer.parseInt(t)), true) + .setTextResponder((t) -> { + setRed(t.isEmpty()? 0 : Integer.parseInt(t)); + if (onColorChanged != null) { + onColorChanged.accept((alpha << 24) | (red << 16) | (green << 8) | (blue)); + } + }, true) .setTextSupplier(() -> Integer.toString(red), true) .setValidator(this::checkValid); TextFieldWidget greenField = new TextFieldWidget(barWidth + 5, barHeight + 5, 30, barHeight, textFieldBackground, null, null) - .setTextResponder((t) -> setGreen(t.isEmpty()? 0 : Integer.parseInt(t)), true) + .setTextResponder((t) -> { + setGreen(t.isEmpty()? 0 : Integer.parseInt(t)); + if (onColorChanged != null) { + onColorChanged.accept((alpha << 24) | (red << 16) | (green << 8) | (blue)); + } + }, true) .setTextSupplier(() -> Integer.toString(green), true) .setValidator(this::checkValid); TextFieldWidget blueField = new TextFieldWidget(barWidth + 5, (barHeight + 5) * 2, 30, barHeight, textFieldBackground, null, null) - .setTextResponder((t) -> setBlue(t.isEmpty()? 0 : Integer.parseInt(t)), true) + .setTextResponder((t) -> { + setBlue(t.isEmpty()? 0 : Integer.parseInt(t)); + if (onColorChanged != null) { + onColorChanged.accept((alpha << 24) | (red << 16) | (green << 8) | (blue)); + } + }, true) .setTextSupplier(() -> Integer.toString(blue), true) .setValidator(this::checkValid); TextFieldWidget alphaField = new TextFieldWidget(barWidth + 5, (barHeight + 5) * 3, 30, barHeight, textFieldBackground, null, null) - .setTextResponder((t) -> setAlpha(t.isEmpty()? 0 : Integer.parseInt(t)), true) + .setTextResponder((t) -> { + setAlpha(t.isEmpty()? 0 : Integer.parseInt(t)); + if (onColorChanged != null) { + onColorChanged.accept((alpha << 24) | (red << 16) | (green << 8) | (blue)); + } + }, true) .setTextSupplier(() -> Integer.toString(alpha), true) .setValidator(this::checkValid); this.addWidget(redField); @@ -82,11 +102,11 @@ public void detectAndSendChanges() { super.detectAndSendChanges(); if (!isClient && colorSupplier!= null) { int c = colorSupplier.get(); - int r = (c & 0x00ff0000) >> 16; - int g = (c & 0x0000ff00) >> 8; + int r = (c & 0x00ff0000) >>> 16; + int g = (c & 0x0000ff00) >>> 8; int b = (c & 0x000000ff); - int a = (c & 0xff000000) >> 24; - if (r != red || g != green || b != blue || a ==alpha) { + int a = (c & 0xff000000) >>> 24; + if (r != red || g != green || b != blue || a !=alpha) { setRed(r); setGreen(g); setBlue(b); @@ -101,11 +121,11 @@ public void updateScreen() { super.updateScreen(); if (isClient && colorSupplier!= null) { int c = colorSupplier.get(); - int r = (c & 0x00ff0000) >> 16; - int g = (c & 0x0000ff00) >> 8; + int r = (c & 0x00ff0000) >>> 16; + int g = (c & 0x0000ff00) >>> 8; int b = (c & 0x000000ff); - int a = (c & 0xff000000) >> 24; - if (r != red || g != green || b != blue || a ==alpha) { + int a = (c & 0xff000000) >>> 24; + if (r != red || g != green || b != blue || a != alpha) { setRed(r); setGreen(g); setBlue(b); @@ -123,15 +143,18 @@ public void readUpdateInfo(int id, PacketBuffer buffer) { private void handleColor(int id, PacketBuffer buffer) { if (id == 2) { int c = buffer.readInt(); - int r = (c & 0x00ff0000) >> 16; - int g = (c & 0x0000ff00) >> 8; + int r = (c & 0x00ff0000) >>> 16; + int g = (c & 0x0000ff00) >>> 8; int b = (c & 0x000000ff); - int a = (c & 0xff000000) >> 24; - if (r != red || g != green || b != blue || a ==alpha) { + int a = (c & 0xff000000) >>> 24; + if (r != red || g != green || b != blue || a != alpha) { setRed(r); setGreen(g); setBlue(b); setAlpha(a); + if (onColorChanged != null) { + onColorChanged.accept((alpha << 24) | (red << 16) | (green << 8) | (blue)); + } } } } @@ -145,9 +168,6 @@ private void setRed(int red) { if (this.red != red) { this.red = red; redButton.setSelfPosition(new Position(red * barWidth / 255 - 4, redButton.getSelfPosition().y)); - if (onColorChanged != null) { - onColorChanged.accept((alpha << 24) | (red << 16) | (green << 8) | (blue)); - } } } @@ -155,9 +175,6 @@ private void setGreen(int green) { if (this.green != green) { this.green = green; greenButton.setSelfPosition(new Position(green * barWidth / 255 - 4, greenButton.getSelfPosition().y)); - if (onColorChanged != null) { - onColorChanged.accept((alpha << 24) | (red << 16) | (green << 8) | (blue)); - } } } @@ -165,9 +182,6 @@ private void setBlue(int blue) { if (this.blue != blue) { this.blue = blue; blueButton.setSelfPosition(new Position(blue * barWidth / 255 - 4, blueButton.getSelfPosition().y)); - if (onColorChanged != null) { - onColorChanged.accept((alpha << 24) | (red << 16) | (green << 8) | (blue)); - } } } @@ -175,9 +189,6 @@ private void setAlpha(int alpha) { if (this.alpha != alpha) { this.alpha = alpha; alphaButton.setSelfPosition(new Position(alpha * barWidth / 255 - 4, alphaButton.getSelfPosition().y)); - if (onColorChanged != null) { - onColorChanged.accept((alpha << 24) | (red << 16) | (green << 8) | (blue)); - } } } @@ -199,9 +210,9 @@ private boolean checkValid(String input) { public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { int x = getPosition().x; int y = getPosition().y; - drawGradientRect(x, y + 2, barWidth, 5, 0xFF000000, 0xFFFF0000, true); - drawGradientRect(x, y + barHeight + 5 + 2, barWidth, 5, 0xFF000000, 0xFF00ff00, true); - drawGradientRect(x, y + 2 * (barHeight + 5) + 2, barWidth, 5, 0xFF000000, 0xFF0000ff, true); + drawGradientRect(x, y + 2, barWidth, 5, (255 << 24) | (0) | (green << 8) | (blue), (255 << 24) | (255 << 16) | (green << 8) | (blue), true); + drawGradientRect(x, y + barHeight + 5 + 2, barWidth, 5, (255 << 24) | (red << 16) | (0) | (blue), (255 << 24) | (red << 16) | (255 << 8) | (blue), true); + drawGradientRect(x, y + 2 * (barHeight + 5) + 2, barWidth, 5, (255 << 24) | (red << 16) | (green << 8) | (0), (255 << 24) | (red << 16) | (green << 8) | (255), true); drawGradientRect(x, y + 3 * (barHeight + 5) + 2, barWidth, 5, (0) | (red << 16) | (green << 8) | (blue), (255 << 24) | (red << 16) | (green << 8) | (blue), true); super.drawInBackground(mouseX, mouseY, partialTicks, context); } @@ -248,6 +259,9 @@ public boolean mouseDragged(int mouseX, int mouseY, int button, long timeDragged } else if (dragged == alphaButton) { setAlpha(newX * 255 / barWidth); } + if (onColorChanged != null) { + onColorChanged.accept((alpha << 24) | (red << 16) | (green << 8) | (blue)); + } dragged.setSelfPosition(new Position(newX - 4, dragged.getSelfPosition().y)); return true; } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/CustomPositionSizeWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/CustomPositionSizeWidget.java index 4868795681e..6bd708f2e5b 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/CustomPositionSizeWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/CustomPositionSizeWidget.java @@ -70,6 +70,38 @@ public void updateScreen() { } } + private boolean hoverUp(int x, int y, int width, int height, int mouseX, int mouseY) { + return isMouseOver(x, y, width / 5, border, mouseX, mouseY) || + isMouseOver(x + width * 2 / 5, y, width / 5, border, mouseX, mouseY) || + isMouseOver(x + width * 4 / 5, y, width / 5, border, mouseX, mouseY) || + isMouseOver(x, y, border, height / 5, mouseX, mouseY) || + isMouseOver(x + width - border, y, border, height / 5, mouseX, mouseY); + } + + private boolean hoverDown(int x, int y, int width, int height, int mouseX, int mouseY) { + return isMouseOver(x, y + height - border, width / 5, border, mouseX, mouseY) || + isMouseOver(x + width * 2 / 5, y + height - border, width / 5, border, mouseX, mouseY) || + isMouseOver(x + width * 4 / 5, y + height - border, width / 5, border, mouseX, mouseY) || + isMouseOver(x, y + height * 4 / 5, border, height / 5, mouseX, mouseY) || + isMouseOver(x + width - border, y + height * 4 / 5, border, height / 5, mouseX, mouseY); + } + + private boolean hoverLeft(int x, int y, int width, int height, int mouseX, int mouseY) { + return isMouseOver(x, y, border, height / 5, mouseX, mouseY) || + isMouseOver(x, y + height * 2 / 5, border, height / 5, mouseX, mouseY) || + isMouseOver(x, y + height * 4 / 5, border, height / 5, mouseX, mouseY) || + isMouseOver(x, y, width / 5, border, mouseX, mouseY) || + isMouseOver(x, y + height - border, width / 5, border, mouseX, mouseY); + } + + private boolean hoverRight(int x, int y, int width, int height, int mouseX, int mouseY) { + return isMouseOver(x + width - border, y, border, height / 5, mouseX, mouseY) || + isMouseOver(x + width - border, y + height * 2 / 5, border, height / 5, mouseX, mouseY) || + isMouseOver(x + width - border, y + height * 4 / 5, border, height / 5, mouseX, mouseY) || + isMouseOver(x + width * 4 / 5, y, width / 5, border, mouseX, mouseY) || + isMouseOver(x + width * 4 / 5, y + height - border, width / 5, border, mouseX, mouseY); + } + @Override public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { if (controlled == null) return; @@ -83,83 +115,52 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender boolean hoverLeft = false; boolean hoverRight = false; // UP - if (isMouseOver(x, y, width / 5, border, mouseX, mouseY) || - isMouseOver(x + width * 2 / 5, y, width / 5, border, mouseX, mouseY) || - isMouseOver(x + width * 4 / 5, y, width / 5, border, mouseX, mouseY) || - isMouseOver(x, y, border, height / 5, mouseX, mouseY) || - isMouseOver(x + width - border, y, border, height / 5, mouseX, mouseY)) { + if (dragUp || hoverUp(x, y, width, height, mouseX, mouseY)) { hoverUp = true; } - if (isMouseOver(x, y + height - border, width / 5, border, mouseX, mouseY) || - isMouseOver(x + width * 2 / 5, y + height - border, width / 5, border, mouseX, mouseY) || - isMouseOver(x + width * 4 / 5, y + height - border, width / 5, border, mouseX, mouseY) || - isMouseOver(x, y + height * 4 / 5, border, height / 5, mouseX, mouseY) || - isMouseOver(x + width - border, y + height * 4 / 5, border, height / 5, mouseX, mouseY)) { + if (dragDown || hoverDown(x, y, width, height, mouseX, mouseY)) { hoverDown = true; } - if (isMouseOver(x, y, border, height / 5, mouseX, mouseY) || - isMouseOver(x, y + height * 2 / 5, border, height / 5, mouseX, mouseY) || - isMouseOver(x, y + height * 4 / 5, border, height / 5, mouseX, mouseY) || - isMouseOver(x, y, width / 5, border, mouseX, mouseY) || - isMouseOver(x, y + height - border, width / 5, border, mouseX, mouseY)) { + if (dragLeft || hoverLeft(x, y, width, height, mouseX, mouseY)) { hoverLeft = true; } - if (isMouseOver(x + width - border, y, border, height / 5, mouseX, mouseY) || - isMouseOver(x + width - border, y + height * 2 / 5, border, height / 5, mouseX, mouseY) || - isMouseOver(x + width - border, y + height * 4 / 5, border, height / 5, mouseX, mouseY) || - isMouseOver(x + width * 4 / 5, y, width / 5, border, mouseX, mouseY) || - isMouseOver(x + width * 4 / 5, y + height - border, width / 5, border, mouseX, mouseY)) { + if (dragRight || hoverRight(x, y, width, height, mouseX, mouseY)) { hoverRight = true; } - drawSolidRect(x, y, width / 5, border, hoverUp ? hoverColor : borderColor); - drawSolidRect(x + width * 2 / 5, y, width / 5, border, hoverUp ? hoverColor : borderColor); - drawSolidRect(x + width * 4 / 5, y, width / 5, border, hoverUp ? hoverColor : borderColor); + // UP + drawSolidRect(x, y, width / 5, border, hoverUp && !hoverRight ? hoverColor : borderColor); + drawSolidRect(x + width * 2 / 5, y, width / 5, border, hoverUp && !hoverLeft && !hoverRight ? hoverColor : borderColor); + drawSolidRect(x + width * 4 / 5, y, width / 5, border, hoverUp && !hoverLeft ? hoverColor : borderColor); // DOWN - drawSolidRect(x, y + height - border, width / 5, border, hoverDown ? hoverColor : borderColor); - drawSolidRect(x + width * 2 / 5, y + height - border, width / 5, border, hoverDown ? hoverColor : borderColor); - drawSolidRect(x + width * 4 / 5, y + height - border, width / 5, border, hoverDown ? hoverColor : borderColor); + drawSolidRect(x, y + height - border, width / 5, border, hoverDown && !hoverRight ? hoverColor : borderColor); + drawSolidRect(x + width * 2 / 5, y + height - border, width / 5, border, hoverDown && !hoverLeft && !hoverRight ? hoverColor : borderColor); + drawSolidRect(x + width * 4 / 5, y + height - border, width / 5, border, hoverDown && !hoverLeft ? hoverColor : borderColor); // LEFT - drawSolidRect(x, y, border, height / 5, hoverLeft ? hoverColor : borderColor); - drawSolidRect(x, y + height * 2 / 5, border, height / 5, hoverLeft ? hoverColor : borderColor); - drawSolidRect(x, y + height * 4 / 5, border, height / 5, hoverLeft ? hoverColor : borderColor); + drawSolidRect(x, y, border, height / 5, hoverLeft && !hoverDown ? hoverColor : borderColor); + drawSolidRect(x, y + height * 2 / 5, border, height / 5, hoverLeft && !hoverDown && !hoverUp ? hoverColor : borderColor); + drawSolidRect(x, y + height * 4 / 5, border, height / 5, hoverLeft && !hoverUp ? hoverColor : borderColor); // RIGHT - drawSolidRect(x + width - border, y, border, height / 5, hoverRight ? hoverColor : borderColor); - drawSolidRect(x + width - border, y + height * 2 / 5, border, height / 5, hoverRight ? hoverColor : borderColor); - drawSolidRect(x + width - border, y + height * 4 / 5, border, height / 5, hoverRight ? hoverColor : borderColor); + drawSolidRect(x + width - border, y, border, height / 5, hoverRight && !hoverDown ? hoverColor : borderColor); + drawSolidRect(x + width - border, y + height * 2 / 5, border, height / 5, hoverRight && !hoverDown && !hoverUp ? hoverColor : borderColor); + drawSolidRect(x + width - border, y + height * 4 / 5, border, height / 5, hoverRight && !hoverUp ? hoverColor : borderColor); } @Override public boolean allowDrag(int mouseX, int mouseY, int button) { - if (controlled == null) return false; + if (controlled == null || !isActive()) return false; int x = controlled.getPosition().x; int y = controlled.getPosition().y; int width = controlled.getSize().width; int height = controlled.getSize().height; if (isMouseOver(x, y, width, height, mouseX, mouseY)) { // UP - dragUp = isMouseOver(x, y, width / 5, border, mouseX, mouseY) || - isMouseOver(x + width * 2 / 5, y, width / 5, border, mouseX, mouseY) || - isMouseOver(x + width * 4 / 5, y, width / 5, border, mouseX, mouseY) || - isMouseOver(x, y, border, height / 5, mouseX, mouseY) || - isMouseOver(x + width - border, y, border, height / 5, mouseX, mouseY); + dragUp = hoverUp(x, y, width, height, mouseX, mouseY); // DOWN - dragDown = isMouseOver(x, y + height - border, width / 5, border, mouseX, mouseY) || - isMouseOver(x + width * 2 / 5, y + height - border, width / 5, border, mouseX, mouseY) || - isMouseOver(x + width * 4 / 5, y + height - border, width / 5, border, mouseX, mouseY) || - isMouseOver(x, y + height * 4 / 5, border, height / 5, mouseX, mouseY) || - isMouseOver(x + width - border, y + height * 4 / 5, border, height / 5, mouseX, mouseY); + dragDown = hoverDown(x, y, width, height, mouseX, mouseY); // LEFT - dragLeft = isMouseOver(x, y, border, height / 5, mouseX, mouseY) || - isMouseOver(x, y + height * 2 / 5, border, height / 5, mouseX, mouseY) || - isMouseOver(x, y + height * 4 / 5, border, height / 5, mouseX, mouseY) || - isMouseOver(x, y, width / 5, border, mouseX, mouseY) || - isMouseOver(x, y + height - border, width / 5, border, mouseX, mouseY); + dragLeft = hoverLeft(x, y, width, height, mouseX, mouseY); // RIGHT - dragRight = isMouseOver(x + width - border, y, border, height / 5, mouseX, mouseY) || - isMouseOver(x + width - border, y + height * 2 / 5, border, height / 5, mouseX, mouseY) || - isMouseOver(x + width - border, y + height * 4 / 5, border, height / 5, mouseX, mouseY) || - isMouseOver(x + width * 4 / 5, y, width / 5, border, mouseX, mouseY) || - isMouseOver(x + width * 4 / 5, y + height - border, width / 5, border, mouseX, mouseY); + dragRight = hoverRight(x, y, width, height, mouseX, mouseY); dragPos = !dragUp && !dragDown && !dragLeft && !dragRight; return true; } @@ -168,7 +169,7 @@ public boolean allowDrag(int mouseX, int mouseY, int button) { @Override public boolean dragging(int mouseX, int mouseY, int deltaX, int deltaY) { - if (controlled == null) return false; + if (controlled == null || !isActive()) return false; int width = controlled.getSize().width; int height = controlled.getSize().height; int addX = 0, addY = 0; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/TextEditorWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/TextEditorWidget.java index c64b17c15d8..e719f2422c4 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/TextEditorWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/TextEditorWidget.java @@ -118,7 +118,7 @@ protected boolean hookDrawInBackground(int mouseX, int mouseY, float partialTick contentString += TextFormatting.GRAY + "_"; } } - this.fontRenderer.drawSplitString(contentString, getPosition().x, getPosition().y+ SPACE, getSize().width - yBarWidth, 0); + this.fontRenderer.drawSplitString(contentString, getPosition().x, getPosition().y + SPACE, getSize().width - yBarWidth, 0); return true; } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java index 0ceb0a5512b..5de5d4214aa 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java @@ -1,17 +1,19 @@ package gregtech.api.terminal.gui.widgets.guide; -import com.google.gson.JsonElement; import com.google.gson.JsonObject; import gregtech.api.gui.GuiTextures; import gregtech.api.gui.Widget; import gregtech.api.gui.resources.ColorRectTexture; import gregtech.api.gui.resources.TextTexture; +import gregtech.api.gui.widgets.ImageWidget; import gregtech.api.gui.widgets.LabelWidget; import gregtech.api.gui.widgets.TabGroup; +import gregtech.api.gui.widgets.TextFieldWidget; import gregtech.api.gui.widgets.tab.IGuiTextureTabInfo; import gregtech.api.terminal.gui.CustomTabListRenderer; import gregtech.api.terminal.gui.widgets.CircleButtonWidget; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; +import gregtech.api.terminal.gui.widgets.TextEditorWidget; import gregtech.api.util.Size; import java.awt.*; @@ -23,36 +25,81 @@ public class GuideConfigEditor extends TabGroup { private GuidePageEditorWidget pageEditor; private final DraggableScrollableWidgetGroup widgetSelector; private final DraggableScrollableWidgetGroup widgetConfigurator; + private final CircleButtonWidget[] addButton; public GuideConfigEditor(int x, int y, int width, int height) { super(x, y + 10, new CustomTabListRenderer( new ColorRectTexture(new Color(175, 0, 0, 131)), new ColorRectTexture(new Color(246, 120, 120, 190)), 30, 10)); setSize(new Size(width, height)); + addButton = new CircleButtonWidget[2]; widgetSelector = createWidgetSelector(); widgetConfigurator = createConfigurator(); - this.addTab(new IGuiTextureTabInfo(new TextTexture("W", -1), "widget"), widgetSelector); - this.addTab(new IGuiTextureTabInfo(new TextTexture("C", -1), "config"), widgetConfigurator); - this.addWidget(new CircleButtonWidget(100, -5, 5, 1, 3) + this.addTab(new IGuiTextureTabInfo(new TextTexture("P", -1), "Page Config"), createPageConfig()); + this.addTab(new IGuiTextureTabInfo(new TextTexture("W", -1), "Widgets Box"), widgetSelector); + this.addTab(new IGuiTextureTabInfo(new TextTexture("C", -1), "Widget Config"), widgetConfigurator); + this.setOnTabChanged((oldIndex, newIndex)->{ + if (newIndex == 1) { + addButton[0].setVisible(true); + addButton[1].setVisible(true); + } else { + addButton[0].setVisible(false); + addButton[1].setVisible(false); + } + }); +// addButton[0] = new CircleButtonWidget(100, -5, 5, 1, 3) +// .setColors(new Color(255, 255, 255, 0).getRGB(), +// new Color(255, 255, 255).getRGB(), +// new Color(146, 253, 118).getRGB()) +// .setIcon(GuiTextures.TERMINAL_ADD) +// .setHoverText("add stream") +// .setClickListener(this::getJson); + addButton[0] = new CircleButtonWidget(115, 15, 8, 1, 8) .setColors(new Color(255, 255, 255, 0).getRGB(), new Color(255, 255, 255).getRGB(), new Color(0, 115, 255).getRGB()) .setIcon(GuiTextures.TERMINAL_ADD) .setHoverText("add stream") - .setClickListener(this::addStream)); - this.addWidget(new CircleButtonWidget(120, -5, 5, 1, 3) + .setClickListener(this::addStream); + addButton[1] = new CircleButtonWidget(115, 35, 8, 1, 8) .setColors(new Color(255, 255, 255, 0).getRGB(), new Color(255, 255, 255).getRGB(), new Color(113, 27, 217).getRGB()) .setIcon(GuiTextures.TERMINAL_ADD) .setHoverText("add fixed") - .setClickListener(this::addFixed)); + .setClickListener(this::addFixed); + this.addWidget(addButton[0]); + this.addWidget(addButton[1]); } public void setGuidePageEditorWidget(GuidePageEditorWidget pageEditor) { this.pageEditor = pageEditor; } + private DraggableScrollableWidgetGroup createPageConfig() { + DraggableScrollableWidgetGroup group = new DraggableScrollableWidgetGroup(0, 0, getSize().width, getSize().height - 10) + .setBackground(new ColorRectTexture(new Color(246, 120, 120, 190))) + .setYScrollBarWidth(4) + .setYBarStyle(null, new ColorRectTexture(new Color(148, 226, 193))); + group.addWidget(new LabelWidget(5, 5, "section", -1).setShadow(true)); + group.addWidget(new TextFieldWidget(5, 15, 116, 20, new ColorRectTexture(0x9f000000), null, null) + .setTextResponder(s->{ + if (pageEditor != null) { + pageEditor.setSection(s); + } + }, true) + .setMaxStringLength(Integer.MAX_VALUE) + .setValidator(s->true)); + group.addWidget(new ImageWidget(5, 48,116, 1, new ColorRectTexture(-1))); + group.addWidget(new LabelWidget(5, 55, "title", -1).setShadow(true)); + group.addWidget(new TextEditorWidget(5, 65, 116, 40, "Template", s->{ + if (pageEditor != null) { + pageEditor.setTitle(s); + } + }).setBackground(new ColorRectTexture(0xA3FFFFFF))); + return group; + } + private DraggableScrollableWidgetGroup createWidgetSelector() { DraggableScrollableWidgetGroup group = new DraggableScrollableWidgetGroup(0, 0, getSize().width, getSize().height - 10) .setBackground(new ColorRectTexture(new Color(246, 120, 120, 190))) @@ -62,9 +109,8 @@ private DraggableScrollableWidgetGroup createWidgetSelector() { for (Map.Entry entry : GuidePageWidget.REGISTER_WIDGETS.entrySet()) { IGuideWidget widgetTemplate = entry.getValue(); JsonObject template = widgetTemplate.getTemplate(false); -// template.addProperty("stroke", 0xFF7CA1FF); Widget guideWidget = widgetTemplate.createStreamWidget(5, y + 10, getSize().width - 14, template); - group.addWidget(new LabelWidget(getSize().width / 2 - 1, y, entry.getKey(), -1).setXCentered(true)); + group.addWidget(new LabelWidget(getSize().width / 2 - 1, y - 3, entry.getKey(), -1).setXCentered(true).setShadow(true)); y += guideWidget.getSize().height + 25; group.addWidget(guideWidget); } @@ -78,12 +124,16 @@ private DraggableScrollableWidgetGroup createConfigurator() { .setYBarStyle(null, new ColorRectTexture(new Color(148, 226, 193))); } - public void loadConfigurator(IGuideWidget widget, JsonObject config, boolean isFixed) { + public void loadConfigurator(IGuideWidget widget) { widgetConfigurator.clearAllWidgets(); if (widget != null) { - widget.loadConfigurator(widgetConfigurator, config, isFixed, attr->{ - widget.updateValue(attr, config.get(attr)); - }); + widget.loadConfigurator(widgetConfigurator, widget.getConfig(), widget.isFixed(), widget::updateValue); + } + } + + private void getJson(ClickData data) { + if(pageEditor != null) { + System.out.println(pageEditor.getJsonString()); } } @@ -106,7 +156,7 @@ private void addStream(ClickData data) { @Override public boolean mouseClicked(int mouseX, int mouseY, int button) { boolean flag = super.mouseClicked(mouseX, mouseY, button); - if (selectedTabIndex == 0 && widgetSelector != null) { + if (selectedTabIndex == 1 && widgetSelector != null) { for (Widget widget : widgetSelector.widgets) { if (widget.isMouseOverElement(mouseX, mouseY)) { if (widget instanceof IGuideWidget) { diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java index 293e128d34f..bdf2b1dfb59 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java @@ -17,22 +17,19 @@ import net.minecraft.client.renderer.GlStateManager; import java.awt.*; -import java.util.HashMap; -import java.util.Map; import static gregtech.api.gui.impl.ModularUIGui.*; public class GuidePageEditorWidget extends GuidePageWidget { - private final Map configMap; private Widget selected; private final WidgetGroup toolButtons; private final CustomPositionSizeWidget customPositionSizeWidget; private GuideConfigEditor configEditor; + private String section = "default"; public GuidePageEditorWidget(int xPosition, int yPosition, int width, int height, int margin) { super(xPosition, yPosition, width, height, margin); this.setDraggable(false); - configMap = new HashMap<>(); setTitle("Template"); customPositionSizeWidget = new CustomPositionSizeWidget(0xff0000ff, 0xffff0000, 2).setOnUpdated(this::onPosSizeChanged); toolButtons = new WidgetGroup(Position.ORIGIN, Size.ZERO); @@ -62,9 +59,31 @@ public GuidePageEditorWidget(int xPosition, int yPosition, int width, int height addWidget(toolButtons); } + public void setSection(String section) { + this.section = section; + } + private void onPosSizeChanged(Position pos, Size size) { - if (customPositionSizeWidget.getControlled() instanceof IGuideWidget) { - ((IGuideWidget) customPositionSizeWidget.getControlled()).onFixedPositionSizeChanged(pos, size); + Widget widget = customPositionSizeWidget.getControlled(); + if (widget instanceof IGuideWidget && ((IGuideWidget) widget).isFixed()) { + JsonObject config = ((IGuideWidget) widget).getConfig(); + if (config.has("x")) { + config.addProperty("x", pos.x + scrollXOffset); + ((IGuideWidget) widget).updateValue("x"); + } + if (config.has("y")) { + config.addProperty("y", pos.y + scrollYOffset); + ((IGuideWidget) widget).updateValue("y"); + } + if (config.has("width")) { + config.addProperty("width", size.width); + ((IGuideWidget) widget).updateValue("width"); + } + if (config.has("height")) { + config.addProperty("height", size.height); + ((IGuideWidget) widget).updateValue("height"); + } + ((IGuideWidget) widget).onFixedPositionSizeChanged(pos, size); } toolButtons.setSelfPosition(new Position(pos.x + size.width / 2, pos.y)); } @@ -75,6 +94,7 @@ public void setGuideConfigEditor(GuideConfigEditor configEditor) { private void setToolButton(Widget widget) { customPositionSizeWidget.setControlled(widget); + customPositionSizeWidget.setActive(!(widget instanceof IGuideWidget) || ((IGuideWidget) widget).isFixed()); toolButtons.setVisible(true); toolButtons.setSelfPosition(new Position(widget.getSelfPosition().x + widget.getSize().width / 2, widget.getSelfPosition().y)); } @@ -82,7 +102,7 @@ private void setToolButton(Widget widget) { private void delete(ClickData clickData) { removeWidget(selected); selected = null; - configEditor.loadConfigurator(null, null, true); + configEditor.loadConfigurator(null); toolButtons.setSelfPosition(new Position(-scrollYOffset, -scrollYOffset)); customPositionSizeWidget.setControlled(null); toolButtons.setVisible(false); @@ -98,15 +118,23 @@ private void moveDown(ClickData clickData) { public String getJsonString() { JsonObject json = new JsonObject(); - json.addProperty("section", ""); + json.addProperty("section", section); json.addProperty("title", title.content.get(0)); JsonArray array = new JsonArray(); json.add("stream", array); - stream.forEach(widget -> array.add(configMap.get(widget))); + stream.forEach(widget -> { + if (widget instanceof IGuideWidget) { + array.add(((IGuideWidget) widget).getConfig()); + } + }); JsonArray array2 = new JsonArray(); json.add("fixed", array2); - fixed.forEach(widget -> array2.add(configMap.get(widget))); + fixed.forEach(widget -> { + if (widget instanceof IGuideWidget) { + array2.add(((IGuideWidget) widget).getConfig()); + } + }); return new Gson().toJson(json); } @@ -134,7 +162,6 @@ public JsonObject addGuideWidget(IGuideWidget widget, boolean isFixed) { stream.add(guideWidget); this.addWidget(guideWidget); } - configMap.put(guideWidget, widgetConfig); return widgetConfig; } @@ -219,7 +246,6 @@ public void removeWidget(Widget widget) { fixed.remove(widget); } super.removeWidget(widget); - configMap.remove(widget); } @Override @@ -231,7 +257,7 @@ public boolean mouseClicked(int mouseX, int mouseY, int button) { for (Widget widget : fixed) { if (widget.isMouseOverElement(mouseX, mouseY)) { if (widget instanceof IGuideWidget && widget != selected) { - configEditor.loadConfigurator((IGuideWidget) widget, configMap.get(widget), true); + configEditor.loadConfigurator((IGuideWidget) widget); selected = widget; setToolButton(selected); } @@ -244,7 +270,7 @@ public boolean mouseClicked(int mouseX, int mouseY, int button) { for (Widget widget : stream) { if (widget.isMouseOverElement(mouseX, mouseY)) { if (widget instanceof IGuideWidget && widget != selected) { - configEditor.loadConfigurator((IGuideWidget) widget, configMap.get(widget), false); + configEditor.loadConfigurator((IGuideWidget) widget); selected = widget; setToolButton(selected); } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java index 6ad34a1117e..61669ee62d3 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java @@ -48,16 +48,22 @@ public int getMargin() { } public void setTitle(String config) { + int x = 5; + int y = 2; + int width = this.getSize().width - yBarWidth - 10; int height = 0; if (title != null) { height = title.getSize().height; + x = title.getSelfPosition().x; + y = title.getSelfPosition().y; removeWidget(title); } - title = new TextBoxWidget(5, 2, this.getSize().width - yBarWidth - 10, + title = new TextBoxWidget(5, 2, width, Collections.singletonList(config), 0, 15, 0xffffffff, 0x6fff0000, 0xff000000, true, true); this.addWidget(title); + title.setSelfPosition(new Position(x, y)); int offset = title.getSize().height - height; if (offset != 0) { for (Widget widget : stream) { @@ -126,7 +132,7 @@ public void onPositionUpdate(Widget widget, Position oldPosition) { if (oldPosition.y + widget.getSize().height == maxHeight) { maxHeight = 0; for (Widget widget1 : widgets) { - maxHeight = Math.max(maxHeight, widget1.getSize().height + widget1.getSelfPosition().y); + maxHeight = Math.max(maxHeight, widget1.getSize().height + widget1.getSelfPosition().y + scrollYOffset); } } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java index 2111f319a7a..1d6cfa26d20 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java @@ -31,6 +31,7 @@ public abstract class GuideWidget extends Widget implements IGuideWidget { private static final Gson GSON = new Gson(); private transient boolean isFixed; protected transient GuidePageWidget page; + protected transient JsonObject config; public GuideWidget(int x, int y, int width, int height) { super(x, y, width, height); @@ -42,24 +43,32 @@ public GuideWidget(){ public abstract String getRegistryName(); - public void updateValue(String field, JsonElement value) { - try { - Field f = this.getClass().getField(field); - if (value.isJsonNull()) { // default - f.set(this, f.get(GuidePageWidget.REGISTER_WIDGETS.get(getRegistryName()))); - } else { - f.set(this, new Gson().fromJson(value, f.getType())); + public void updateValue(String field) { + if (config != null && config.has(field)) { + try { + Field f = this.getClass().getField(field); + JsonElement value = config.get(field); + if (value.isJsonNull()) { // default + f.set(this, f.get(GuidePageWidget.REGISTER_WIDGETS.get(getRegistryName()))); + } else { + f.set(this, new Gson().fromJson(value, f.getType())); + } + if (isFixed) { + initFixed(); + } else { + initStream(); + } + } catch (Exception e) { } - if (isFixed) { - initFixed(); - } else { - initStream(); - } - } catch (Exception e) { - e.printStackTrace(); } } + @Override + public JsonObject getConfig() { + return config; + } + + @Override public boolean isFixed() { return isFixed; } @@ -100,17 +109,18 @@ public void setSelfPosition(Position selfPosition) { @Override public JsonObject getTemplate(boolean isFixed) { JsonObject template = new JsonObject(); + template.addProperty("type", getRegistryName()); if (isFixed) { template.addProperty("x", 0); template.addProperty("y", 0); template.addProperty("width", 100); template.addProperty("height", 100); } - template.addProperty("ref", ref); - template.addProperty("stroke", stroke); - template.addProperty("stroke_width", stroke_width); - template.addProperty("fill", fill); - template.addProperty("link", link); + template.addProperty("ref", (String) null); + template.addProperty("stroke", (String) null); + template.addProperty("stroke_width", (String) null); + template.addProperty("fill", (String) null); + template.addProperty("link", (String) null); template.add("hover_text", new Gson().toJsonTree(hover_text)); return template; } @@ -136,6 +146,7 @@ public Widget createStreamWidget(int x, int y, int pageWidth, JsonObject config) widget.isFixed = false; widget.setSelfPosition(new Position(x, y)); widget.setSize(new Size(pageWidth, 0)); + widget.config = config; return widget.initStream(); } @@ -145,6 +156,7 @@ public Widget createFixedWidget(int x, int y, int width, int height, JsonObject widget.isFixed = true; widget.setSelfPosition(new Position(x, y)); widget.setSize(new Size(width, height)); + widget.config = config; return widget.initFixed(); } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java index 25f10636c6a..bbdb75acb2c 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java @@ -12,10 +12,12 @@ import java.util.function.Consumer; public interface IGuideWidget { + JsonObject getConfig(); + boolean isFixed(); Widget createStreamWidget(int x, int y, int pageWidth, JsonObject config); Widget createFixedWidget(int x, int y, int width, int height, JsonObject config); void setPage(GuidePageWidget page); - void updateValue(String field, JsonElement value); + void updateValue(String field); String getRef(); JsonObject getTemplate(boolean isFixed); void loadConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, boolean isFixed, Consumer needUpdate); diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java index e9162a24121..ccdee1f6ace 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java @@ -50,8 +50,10 @@ public void loadConfigurator(DraggableScrollableWidgetGroup group, JsonObject co super.loadConfigurator(group, config, isFixed, needUpdate); group.addWidget(new SelectorConfigurator(5, group.getWidgetBottomHeight() + 5, config, "form", Arrays.asList("url", "item", "resource")).setOnUpdated(needUpdate)); group.addWidget(new StringConfigurator(5, group.getWidgetBottomHeight() + 5, config, "source").setOnUpdated(needUpdate)); - group.addWidget(new NumberConfigurator(5, group.getWidgetBottomHeight() + 5, config, "width").setOnUpdated(needUpdate)); - group.addWidget(new NumberConfigurator(5, group.getWidgetBottomHeight() + 5, config, "height").setOnUpdated(needUpdate)); + if (!isFixed) { + group.addWidget(new NumberConfigurator(5, group.getWidgetBottomHeight() + 5, config, "width").setOnUpdated(needUpdate)); + group.addWidget(new NumberConfigurator(5, group.getWidgetBottomHeight() + 5, config, "height").setOnUpdated(needUpdate)); + } } @Override @@ -61,6 +63,11 @@ public void updateScreen() { } } + @Override + public void onFixedPositionSizeChanged(Position position, Size size) { + super.onFixedPositionSizeChanged(position, size); + } + @Override protected Widget initStream() { int pageWidth = getSize().width; @@ -71,14 +78,12 @@ protected Widget initStream() { pageWidth = page.getPageWidth() - 2 * x; } this.setSelfPosition(new Position(x + (pageWidth - width) / 2, y)); - this.setSize(new Size(width, height)); return initFixed(); } @Override protected Widget initFixed() { - width = getSize().width; - height = getSize().height; + this.setSize(new Size(width, height)); switch (form) { case "url": image = new URLTexture(source); diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java index e6c2d7be156..02eb98e8e9e 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java @@ -58,11 +58,11 @@ public String getRegistryName() { @Override public JsonObject getTemplate(boolean isFixed) { JsonObject template = super.getTemplate(isFixed); - template.addProperty("space", space); - template.addProperty("fontSize", fontSize); - template.addProperty("fontColor", fontColor); - template.addProperty("isCenter", isCenter); - template.addProperty("isShadow", isShadow); + template.addProperty("space", (String) null); + template.addProperty("fontSize", (String) null); + template.addProperty("fontColor", (String) null); + template.addProperty("isCenter", (String) null); + template.addProperty("isShadow", (String) null); template.add("content", new Gson().toJsonTree(Arrays.asList("this is a", "textbox!"))); return template; } From 5aa47ca69c4aa1e7f05b8c5d4c5ba9a0cecd7db0 Mon Sep 17 00:00:00 2001 From: Yefancy Date: Wed, 4 Aug 2021 23:13:01 +0800 Subject: [PATCH 33/58] translate + metaitem + simple machine --- src/main/java/gregtech/api/GregTechAPI.java | 17 +- .../gregtech/api/items/metaitem/MetaItem.java | 15 ++ .../api/terminal/app/guide/GuideApp.java | 8 +- .../api/terminal/app/guide/ItemGuideApp.java | 49 +++- .../app/guide/MultiBlockGuideApp.java | 42 ++- .../app/guide/SimpleMachineGuideApp.java | 39 ++- .../terminal/app/guide/TutorialGuideApp.java | 41 ++- .../DraggableScrollableWidgetGroup.java | 1 + .../gui/widgets/TextEditorWidget.java | 243 ++++++++++++++++-- .../gui/widgets/guide/GuideConfigEditor.java | 43 +++- .../widgets/guide/GuidePageEditorWidget.java | 5 + .../gui/widgets/guide/GuideWidget.java | 1 + .../gui/widgets/guide/IGuideWidget.java | 3 - .../gui/widgets/guide/ImageWidget.java | 1 + .../gui/widgets/guide/TextTreeWidget.java | 20 +- .../configurator/TextListConfigurator.java | 10 +- .../{ => en_us}/api_0_guidepage.json | 0 .../tutorials/{ => en_us}/api_1_widget.json | 0 .../tutorials/{ => en_us}/api_2_textbox.json | 0 .../tutorials/{ => en_us}/api_3_image.json | 0 .../textures/gui/widget/formatting.png | Bin 0 -> 1890 bytes .../gregtech/textures/gui/widget/palette.png | Bin 0 -> 1921 bytes 22 files changed, 450 insertions(+), 88 deletions(-) rename src/main/resources/assets/gregtech/terminal/guide/tutorials/{ => en_us}/api_0_guidepage.json (100%) rename src/main/resources/assets/gregtech/terminal/guide/tutorials/{ => en_us}/api_1_widget.json (100%) rename src/main/resources/assets/gregtech/terminal/guide/tutorials/{ => en_us}/api_2_textbox.json (100%) rename src/main/resources/assets/gregtech/terminal/guide/tutorials/{ => en_us}/api_3_image.json (100%) create mode 100644 src/main/resources/assets/gregtech/textures/gui/widget/formatting.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/widget/palette.png diff --git a/src/main/java/gregtech/api/GregTechAPI.java b/src/main/java/gregtech/api/GregTechAPI.java index e376c035c18..a3031b46495 100644 --- a/src/main/java/gregtech/api/GregTechAPI.java +++ b/src/main/java/gregtech/api/GregTechAPI.java @@ -4,6 +4,7 @@ import gregtech.api.metatileentity.MetaTileEntity; import gregtech.api.metatileentity.multiblock.MultiblockControllerBase; import gregtech.api.terminal.app.guide.MultiBlockGuideApp; +import gregtech.api.terminal.app.guide.SimpleMachineGuideApp; import gregtech.api.unification.OreDictUnifier; import gregtech.api.unification.material.Material; import gregtech.api.unification.material.Materials; @@ -14,6 +15,8 @@ import gregtech.api.util.IBlockOre; import gregtech.common.items.MetaItems; import gregtech.common.metatileentities.electric.multiblockpart.MetaTileEntityMultiblockPart; +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.I18n; import net.minecraft.util.ResourceLocation; import java.util.HashMap; @@ -36,7 +39,19 @@ public class GregTechAPI { public static T registerMetaTileEntity(int id, T sampleMetaTileEntity) { META_TILE_ENTITY_REGISTRY.register(id, sampleMetaTileEntity.metaTileEntityId, sampleMetaTileEntity); if (sampleMetaTileEntity instanceof MultiblockControllerBase || sampleMetaTileEntity instanceof MetaTileEntityMultiblockPart) { - MultiBlockGuideApp.registerMultiBlock(sampleMetaTileEntity); + MultiBlockGuideApp.registerMultiBlock(sampleMetaTileEntity, "default"); + } else { + SimpleMachineGuideApp.registerSimpleMachine(sampleMetaTileEntity, "default"); + } + return sampleMetaTileEntity; + } + + public static T registerMetaTileEntity(int id, T sampleMetaTileEntity, String section) { + META_TILE_ENTITY_REGISTRY.register(id, sampleMetaTileEntity.metaTileEntityId, sampleMetaTileEntity); + if (sampleMetaTileEntity instanceof MultiblockControllerBase || sampleMetaTileEntity instanceof MetaTileEntityMultiblockPart) { + MultiBlockGuideApp.registerMultiBlock(sampleMetaTileEntity, section); + } else { + SimpleMachineGuideApp.registerSimpleMachine(sampleMetaTileEntity, section); } return sampleMetaTileEntity; } diff --git a/src/main/java/gregtech/api/items/metaitem/MetaItem.java b/src/main/java/gregtech/api/items/metaitem/MetaItem.java index 24f989f3058..cfbd293d99d 100644 --- a/src/main/java/gregtech/api/items/metaitem/MetaItem.java +++ b/src/main/java/gregtech/api/items/metaitem/MetaItem.java @@ -18,6 +18,7 @@ import gregtech.api.items.gui.PlayerInventoryHolder; import gregtech.api.items.metaitem.stats.*; import gregtech.api.recipes.ingredients.IntCircuitIngredient; +import gregtech.api.terminal.app.guide.ItemGuideApp; import gregtech.api.unification.OreDictUnifier; import gregtech.api.unification.material.Material; import gregtech.api.unification.ore.OrePrefix; @@ -220,6 +221,20 @@ public final T addItem(int metaValue, String unlocalizedName) { } metaItems.put((short) metaValue, metaValueItem); names.put(unlocalizedName, metaValueItem); + ItemGuideApp.registerItem(metaValueItem, "default"); + return metaValueItem; + } + + public final T addItem(int metaValue, String unlocalizedName, String section) { + Validate.inclusiveBetween(0, Short.MAX_VALUE - 1, metaValue + metaItemOffset, "MetaItem ID should be in range from 0 to Short.MAX_VALUE-1"); + T metaValueItem = constructMetaValueItem((short) metaValue, unlocalizedName); + if (metaItems.containsKey((short) metaValue)) { + T registeredItem = metaItems.get((short) metaValue); + throw new IllegalArgumentException(String.format("MetaId %d is already occupied by item %s (requested by item %s)", metaValue, registeredItem.unlocalizedName, unlocalizedName)); + } + metaItems.put((short) metaValue, metaValueItem); + names.put(unlocalizedName, metaValueItem); + ItemGuideApp.registerItem(metaValueItem, section); return metaValueItem; } diff --git a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java index 67568dc5fcf..63bde426b50 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java @@ -45,7 +45,10 @@ public AbstractApplication createApp(boolean isClient, NBTTagCompound nbt) { } app.pageWidget = new GuidePageWidget(133, 0, 200, 232, 5); if (leaf.isLeaf() && leaf.content != null) { - app.pageWidget.loadJsonConfig(leaf.content.getSecond()); + JsonObject page = getPage(leaf.content); + if (page != null) { + app.pageWidget.loadJsonConfig(page); + } } app.addWidget(app.pageWidget); }, this::itemIcon, this::itemName).setNodeTexture(GuiTextures.BORDERED_BACKGROUND).setLeafTexture(GuiTextures.SLOT_DARKENED) @@ -70,8 +73,9 @@ protected String itemName(T item) { return null; } + protected abstract JsonObject getPage(T item); - protected abstract TreeNode> getTree(); + protected abstract TreeNode getTree(); public static JsonObject getConfig(String fileName) { try { diff --git a/src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java index a79e4d4acc6..56d01160792 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java @@ -1,34 +1,71 @@ package gregtech.api.terminal.app.guide; import com.google.gson.JsonObject; +import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.resources.ItemStackTexture; import gregtech.api.items.metaitem.MetaItem; import gregtech.api.metatileentity.MetaTileEntity; import gregtech.api.terminal.util.TreeNode; import gregtech.common.items.MetaItems; +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.Language; import net.minecraft.util.Tuple; import net.minecraftforge.fml.common.FMLCommonHandler; -public class ItemGuideApp extends GuideApp> { - private static TreeNode, JsonObject>> ROOT; +import java.util.HashMap; +import java.util.Map; + +public class ItemGuideApp extends GuideApp.MetaValueItem> { + private static TreeNode.MetaValueItem> ROOT; + private static Map.MetaValueItem, JsonObject> MAP; + private static Language language; + private static JsonObject DEFAULT; static { if (FMLCommonHandler.instance().getSide().isClient()) { ROOT = new TreeNode<>(0,"root"); DEFAULT = getConfig("terminal/guide/items/default.json"); + MAP = new HashMap<>(); } } public ItemGuideApp() { - super("Items Machines", new ItemStackTexture(MetaItems.SCANNER.getStackForm())); + super("Items", new ItemStackTexture(MetaItems.SCANNER.getStackForm())); } @Override - protected TreeNode, JsonObject>> getTree() { - return ROOT; + protected IGuiTexture itemIcon(MetaItem.MetaValueItem item) { + return new ItemStackTexture(item.getStackForm()); + } + + @Override + protected JsonObject getPage(MetaItem.MetaValueItem item) { + Language currentLanguage = Minecraft.getMinecraft().getLanguageManager().getCurrentLanguage(); + if (!currentLanguage.equals(language)) { + language = currentLanguage; + MAP.clear(); + } + if (!MAP.containsKey(item)) { + JsonObject config = getConfig("terminal/guide/items/" + currentLanguage.getLanguageCode() + "/" + item.unlocalizedName + ".json"); + if (config == null && !currentLanguage.getLanguageCode().equals("en_us")) { + config = getConfig("terminal/guide/items/" + "en_us/" + item.unlocalizedName + ".json"); + } + MAP.put(item, config); + } + if (MAP.get(item) == null) { + return DEFAULT; + } + return MAP.get(item); } - public static void registerItem(MetaTileEntity mte) { + @Override + protected TreeNode.MetaValueItem> getTree() { + return ROOT; + } + public static void registerItem(MetaItem.MetaValueItem item, String section) { + if (FMLCommonHandler.instance().getSide().isClient()) { + ROOT.getOrCreateChild(section).addContent(String.format("metaitem.%s.name", item.unlocalizedName), item); + } } } diff --git a/src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java index 311e0dbec03..3324866003d 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java @@ -6,16 +6,25 @@ import gregtech.api.metatileentity.MetaTileEntity; import gregtech.api.terminal.util.TreeNode; import gregtech.common.metatileentities.MetaTileEntities; +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.Language; import net.minecraft.util.Tuple; import net.minecraftforge.fml.common.FMLCommonHandler; +import java.util.HashMap; +import java.util.Map; + public class MultiBlockGuideApp extends GuideApp { - private static TreeNode> ROOT; + private static TreeNode ROOT; + private static Map MAP; + private static Language language; + private static JsonObject DEFAULT; static { if (FMLCommonHandler.instance().getSide().isClient()) { ROOT = new TreeNode<>(0, "root"); DEFAULT = getConfig("terminal/guide/multiblocks/default.json"); + MAP = new HashMap<>(); } } @@ -24,7 +33,7 @@ public MultiBlockGuideApp() { } @Override - protected TreeNode> getTree() { + protected TreeNode getTree() { return ROOT; } @@ -33,14 +42,29 @@ protected IGuiTexture itemIcon(MetaTileEntity item) { return new ItemStackTexture(item.getStackForm()); } - public static void registerMultiBlock(MetaTileEntity mte) { - if (FMLCommonHandler.instance().getSide().isClient()) { - JsonObject config = getConfig("terminal/guide/multiblocks/" + mte.metaTileEntityId.getPath() + ".json"); - if (config == null) { - ROOT.getOrCreateChild("default").addContent(mte.getMetaFullName(), new Tuple<>(mte, DEFAULT)); - } else { - ROOT.getOrCreateChild(config.get("section").getAsString()).addContent(mte.getMetaFullName(), new Tuple<>(mte, config)); + @Override + protected JsonObject getPage(MetaTileEntity mte) { + Language currentLanguage = Minecraft.getMinecraft().getLanguageManager().getCurrentLanguage(); + if (!currentLanguage.equals(language)) { + language = currentLanguage; + MAP.clear(); + } + if (!MAP.containsKey(mte)) { + JsonObject config = getConfig("terminal/guide/multiblocks/" + currentLanguage.getLanguageCode() + "/" + mte.metaTileEntityId.getPath() + ".json"); + if (config == null && !currentLanguage.getLanguageCode().equals("en_us")) { + config = getConfig("terminal/guide/multiblocks/" + "en_us/" + mte.metaTileEntityId.getPath() + ".json"); } + MAP.put(mte, config); + } + if (MAP.get(mte) == null) { + return DEFAULT; + } + return MAP.get(mte); + } + + public static void registerMultiBlock(MetaTileEntity mte, String section) { + if (FMLCommonHandler.instance().getSide().isClient()) { + ROOT.getOrCreateChild(section).addContent(mte.getMetaFullName(), mte); } } diff --git a/src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java index 633e4943ad9..1447f5cce7f 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java @@ -6,16 +6,25 @@ import gregtech.api.metatileentity.MetaTileEntity; import gregtech.api.terminal.util.TreeNode; import gregtech.common.metatileentities.MetaTileEntities; +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.Language; import net.minecraft.util.Tuple; import net.minecraftforge.fml.common.FMLCommonHandler; +import java.util.HashMap; +import java.util.Map; + public class SimpleMachineGuideApp extends GuideApp { - private static TreeNode> ROOT; + private static TreeNode ROOT; + private static Map MAP; + private static Language language; + private static JsonObject DEFAULT; static { if (FMLCommonHandler.instance().getSide().isClient()) { ROOT = new TreeNode<>(0,"root"); DEFAULT = getConfig("terminal/guide/simplemachines/default.json"); + MAP = new HashMap<>(); } } @@ -24,7 +33,7 @@ public SimpleMachineGuideApp() { } @Override - protected TreeNode> getTree() { + protected TreeNode getTree() { return ROOT; } @@ -33,14 +42,26 @@ protected IGuiTexture itemIcon(MetaTileEntity item) { return new ItemStackTexture(item.getStackForm()); } - public static void registerSimpleMachine(MetaTileEntity mte) { - if (FMLCommonHandler.instance().getSide().isClient()) { - JsonObject config = getConfig("terminal/guide/simplemachines/" + mte.metaTileEntityId.getPath() + ".json"); - if (config == null) { - ROOT.getOrCreateChild("default").addContent(mte.getMetaFullName(), new Tuple<>(mte, DEFAULT)); - } else { - ROOT.getOrCreateChild(config.get("section").getAsString()).addContent(mte.getMetaFullName(), new Tuple<>(mte, config)); + @Override + protected JsonObject getPage(MetaTileEntity mte) { + Language currentLanguage = Minecraft.getMinecraft().getLanguageManager().getCurrentLanguage(); + if (!currentLanguage.equals(language)) { + language = currentLanguage; + MAP.clear(); + } + if (!MAP.containsKey(mte)) { + JsonObject config = getConfig("terminal/guide/simplemachines/" + currentLanguage.getLanguageCode() + "/" + mte.metaTileEntityId.getPath() + ".json"); + if (config == null && !currentLanguage.getLanguageCode().equals("en_us")) { + config = getConfig("terminal/guide/simplemachines/" + "en_us/" + mte.metaTileEntityId.getPath() + ".json"); } + MAP.put(mte, config); + } + return MAP.get(mte); + } + + public static void registerSimpleMachine(MetaTileEntity mte, String section) { + if (FMLCommonHandler.instance().getSide().isClient()) { + ROOT.getOrCreateChild(section).addContent(mte.getMetaFullName(), mte); } } } diff --git a/src/main/java/gregtech/api/terminal/app/guide/TutorialGuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/TutorialGuideApp.java index 32aad915681..da723eb8f9d 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/TutorialGuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/TutorialGuideApp.java @@ -3,7 +3,10 @@ import com.google.gson.JsonObject; import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.resources.ItemStackTexture; +import gregtech.api.metatileentity.MetaTileEntity; import gregtech.api.terminal.util.TreeNode; +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.Language; import net.minecraft.init.Items; import net.minecraft.util.Tuple; import net.minecraftforge.fml.common.FMLCommonHandler; @@ -12,22 +15,29 @@ import java.io.IOException; import java.io.InputStreamReader; import java.net.URL; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; + +public class TutorialGuideApp extends GuideApp { + private static TreeNode ROOT; + private static Map MAP; + private static Language language; -public class TutorialGuideApp extends GuideApp { - private static TreeNode> ROOT; static { if (FMLCommonHandler.instance().getSide().isClient()) { ROOT = new TreeNode<>(0,"root"); + MAP = new HashMap<>(); try { - URL folder = ClassLoader.getSystemClassLoader().getResource("assets/gregtech/terminal/guide/tutorials"); + URL folder = ClassLoader.getSystemClassLoader().getResource("assets/gregtech/terminal/guide/tutorials/en_us"); if (folder != null) { new BufferedReader(new InputStreamReader(folder.openStream())).lines().forEach(file->{ - JsonObject config = getConfig("terminal/guide/tutorials/" + file); + JsonObject config = getConfig("terminal/guide/tutorials/en_us/" + file); if (config != null) { - ROOT.getOrCreateChild(config.get("section").getAsString()).addContent(config.get("title").getAsString(), new Tuple<>(null, config)); + ROOT.getOrCreateChild(config.get("section").getAsString()).addContent(config.get("title").getAsString(), file); + MAP.put(file, config); } }); - } } catch (IOException e) { e.printStackTrace(); @@ -40,7 +50,24 @@ public TutorialGuideApp() { } @Override - protected TreeNode> getTree() { + protected JsonObject getPage(String file) { + Language currentLanguage = Minecraft.getMinecraft().getLanguageManager().getCurrentLanguage(); + if (!currentLanguage.equals(language)) { + language = currentLanguage; + MAP.clear(); + } + if (!MAP.containsKey(file)) { + JsonObject config = getConfig("terminal/guide/tutorials/" + currentLanguage.getLanguageCode() + "/" + file); + if (config == null && !currentLanguage.getLanguageCode().equals("en_us")) { + config = getConfig("terminal/guide/tutorials/" + "en_us/" + file); + } + MAP.put(file, config); + } + return MAP.get(file); + } + + @Override + protected TreeNode getTree() { return ROOT; } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java b/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java index 8ceea9e6414..a00cfa35efe 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java @@ -184,6 +184,7 @@ protected void setScrollXOffset(int scrollXOffset) { protected void setScrollYOffset(int scrollYOffset) { if (scrollYOffset == this.scrollYOffset) return; + if (scrollYOffset < 0) scrollYOffset = 0; int offset = scrollYOffset - this.scrollYOffset; this.scrollYOffset = scrollYOffset; for (Widget widget : widgets) { diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/TextEditorWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/TextEditorWidget.java index e719f2422c4..98622a29dbe 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/TextEditorWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/TextEditorWidget.java @@ -2,6 +2,7 @@ import gregtech.api.gui.IRenderContext; import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.resources.TextureArea; import gregtech.api.gui.widgets.WidgetGroup; import gregtech.api.util.Position; import gregtech.api.util.Size; @@ -13,20 +14,24 @@ import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; -import java.awt.*; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class TextEditorWidget extends WidgetGroup { + private static final TextureArea PALETTE = TextureArea.fullImage("textures/gui/widget/palette.png"); + private static final TextureArea STYLE = TextureArea.fullImage("textures/gui/widget/formatting.png"); private final TextPanelWidget textPanelWidget; - public TextEditorWidget(int x, int y, int width, int height, String text, Consumer stringUpdate) { - super(new Position(x, y), new Size(width, height)); - textPanelWidget = new TextPanelWidget(0, 10, width, height-10, text, stringUpdate); - this.addWidget(new RectButtonWidget(0, 0, 20, 10, 1).setFill(new Color(109, 229, 154, 141).getRGB()).setHoverText("update").setClickListener(d->{ - if (stringUpdate != null) { - stringUpdate.accept(textPanelWidget.content); - } - })); + + public TextEditorWidget(int x, int y, int width, int height, String initText,Consumer stringUpdate, boolean allowToolBox) { + super(new Position(x, y), new Size(Math.max(width, allowToolBox ? 80 : width), Math.max(height, allowToolBox ? 32 : height))); + textPanelWidget = new TextPanelWidget(0, 32, Math.max(width, allowToolBox ? 80 : width), Math.max(height, allowToolBox ? 32 : height) - 32, initText, stringUpdate); this.addWidget(textPanelWidget); + if (allowToolBox) { + initToolBox(); + } } public TextEditorWidget setBackground(IGuiTexture background) { @@ -34,14 +39,69 @@ public TextEditorWidget setBackground(IGuiTexture background) { return this; } + @Override + public void setActive(boolean active) { + super.setActive(active); + textPanelWidget.setActive(active); + } + + private void initToolBox() { + TextFormatting[] formatting = TextFormatting.values(); + // palette + for (int y = 0; y < 4; y++) { + for (int x = 0; x < 4; x++) { + TextFormatting colorFormatting = formatting[y * 4 + x]; + this.addWidget(new RectButtonWidget(x * 8, y * 8, 8, 8, 1) + .setToggleButton(PALETTE.getSubArea(0.5 + x * 0.125, y * 0.25, 0.125, 0.25), + (cd, pressed)-> { + if (pressed) { + textPanelWidget.addFormatting(colorFormatting); + } else { + textPanelWidget.removeFormatting(colorFormatting); + } + }) + .setValueSupplier(true, ()-> colorFormatting == textPanelWidget.getFrontColorFormatting()) + .setIcon(PALETTE.getSubArea(x * 0.125, y * 0.25, 0.125, 0.25)) + .setColors(0, -1, 0)); + } + } + // style + for (int y = 0; y < 2; y++) { + for (int x = 0; x < 3; x++) { + TextFormatting styleFormatting = formatting[16 + y * 3 + x]; + if (styleFormatting == TextFormatting.RESET) return; + this.addWidget(new RectButtonWidget(x * 16 + 32, y * 16, 16, 16, 1) + .setToggleButton(STYLE.getSubArea(0.5 + x * 1.0 / 6, y * 0.5, 1.0 / 6, 0.5), + (cd, pressed)-> { + if (pressed) { + textPanelWidget.addFormatting(styleFormatting); + } else { + textPanelWidget.removeFormatting(styleFormatting); + } + }) + .setValueSupplier(true, ()-> textPanelWidget.getFrontStyleFormatting().contains(styleFormatting)) + .setIcon(STYLE.getSubArea(x * 1.0 / 6, y * 0.5, 1.0 / 6, 0.5)) + .setColors(0, -1, 0)); + } + } + } + private static class TextPanelWidget extends DraggableScrollableWidgetGroup { - private final static int SPACE = 0; - private int updateCount; - private String content; - private int textHeight; - private final Consumer stringUpdate; + public final static int SPACE = 0; + public int updateCount; + public String content; + public int textHeight; + public final Consumer stringUpdate; + public TextFormatting frontColor; + public List frontStyle; + @SideOnly(Side.CLIENT) - private FontRenderer fontRenderer; + public FontRenderer fontRenderer; + @SideOnly(Side.CLIENT) + private static final Pattern R_CODE_PATTERN = Pattern.compile("(?i)§[R]"); + @SideOnly(Side.CLIENT) + private static final Pattern COLOR_CODE_PATTERN = Pattern.compile("(?i)§[0-9A-F]"); + public TextPanelWidget(int x, int y, int width, int height, String text, Consumer stringUpdate) { super(x, y, width, height); @@ -50,11 +110,13 @@ public TextPanelWidget(int x, int y, int width, int height, String text, Consume if (isClientSide()) { fontRenderer = Minecraft.getMinecraft().fontRenderer; textHeight = fontRenderer.getWordWrappedHeight(content, width - yBarWidth); + frontColor = null; + frontStyle = new ArrayList<>(); } } @Override - protected int getMaxHeight() { + public int getMaxHeight() { return textHeight + SPACE + xBarHeight; } @@ -65,32 +127,156 @@ public void updateScreen() { @Override public boolean keyTyped(char typedChar, int keyCode) { - if(!focus) return false; + if(!focus || !isActive()) return false; if (GuiScreen.isKeyComboCtrlV(keyCode)) { this.pageInsertIntoCurrent(GuiScreen.getClipboardString()); + findFrontFormatting(); } else { switch(keyCode) { case 14: if (!content.isEmpty()) { this.pageSetCurrent(content.substring(0, content.length() - 1)); } - return true; + break; case 28: case 156: this.pageInsertIntoCurrent("\n"); - return true; + break; default: if (ChatAllowedCharacters.isAllowedCharacter(typedChar)) { this.pageInsertIntoCurrent(Character.toString(typedChar)); } } } + if (getMaxHeight() > getSize().height) { + setScrollYOffset(getMaxHeight() - getSize().height); + } else { + setScrollYOffset(0); + } return true; } - private void pageSetCurrent(String string) { + private static TextFormatting lookAheadChars(final String content, int index) { + if (index > 1 && content.charAt(index - 2) == '§') { + int t = content.charAt(index - 1); + if ('0' <= t && t <= '9'){ + return TextFormatting.values()[t - '0']; + } else if ('a' <= t && t <= 'f'){ + return TextFormatting.values()[t - 'a' + 10]; + } else if ('k' <= t && t <= 'o') { + return TextFormatting.values()[t - 'k' + 16]; + } else if (t == 'r') { + return TextFormatting.values()[21]; + } + } + return null; + } + + public static String cleanUpFormatting(final String content) { + Set removed = new HashSet<>(); + Matcher marcher = R_CODE_PATTERN.matcher(content); + while (marcher.find()) { + int index = marcher.start(); + while (index > 1) { + TextFormatting ahead = lookAheadChars(content, index); + if (ahead != null) { + removed.add(index - 2); + } else { + break; + } + index -= 2; + } + } + marcher = COLOR_CODE_PATTERN.matcher(content); + while (marcher.find()) { + int index = marcher.start(); + while (index > 1) { + TextFormatting ahead = lookAheadChars(content, index); + if (ahead == null) { + break; + } else if (TextFormatting.RESET != ahead){ + if (!removed.add(index - 2)) { + break; + } + } else { + break; + } + index -= 2; + } + } + StringBuilder builder = new StringBuilder(); + AtomicInteger start = new AtomicInteger(); + removed.stream().sorted().forEach(remove->{ + builder.append(content, start.get(), remove); + start.set(remove + 2); + }); + builder.append(content, start.get(), content.length()); + return builder.toString(); + } + + private void findFrontFormatting() { + int lastReset = content.lastIndexOf("§r"); + int lastColor = -1; + frontColor = null; + frontStyle.clear(); + for (TextFormatting value : TextFormatting.values()) { + int index = content.lastIndexOf(value.toString()); + if (index > lastReset) { + if (value.isColor()) { + if (index > lastColor) { + lastColor = index; + frontColor = value; + } + } else if (value.isFancyStyling() && index > lastColor) { + frontStyle.add(value); + } + } + } + } + + public void addFormatting(TextFormatting formatting) { + if (formatting.isColor()) { + frontColor = formatting; + pageInsertIntoCurrent(formatting.toString()); + for (TextFormatting style : frontStyle) { + pageInsertIntoCurrent(style.toString()); + } + } else if (formatting.isFancyStyling()){ + if (frontStyle.contains(formatting)) { + return; + } + frontStyle.add(formatting); + pageInsertIntoCurrent(formatting.toString()); + } + } + + public void removeFormatting(TextFormatting formatting) { + if (formatting.isColor()) { + frontColor = null; + pageInsertIntoCurrent(TextFormatting.RESET.toString()); + frontStyle.forEach(style->pageInsertIntoCurrent(style.toString())); + } else if (formatting.isFancyStyling()) { + pageInsertIntoCurrent(TextFormatting.RESET.toString()); + if (frontColor != null) { + pageInsertIntoCurrent(frontColor.toString()); + } + frontStyle.remove(formatting); + frontStyle.forEach(style->pageInsertIntoCurrent(style.toString())); + } + } + + public TextFormatting getFrontColorFormatting() { + return frontColor; + } + + public List getFrontStyleFormatting() { + return frontStyle; + } + + public void pageSetCurrent(String string) { if (!content.equals(string)) { - content = string; + content = cleanUpFormatting(string); + findFrontFormatting(); if(stringUpdate != null) { stringUpdate.accept(content); } @@ -98,8 +284,8 @@ private void pageSetCurrent(String string) { } } - private void pageInsertIntoCurrent(String string) { - content += string; + public void pageInsertIntoCurrent(String string) { + content = cleanUpFormatting(content + string); if(stringUpdate != null) { stringUpdate.accept(content); } @@ -107,9 +293,9 @@ private void pageInsertIntoCurrent(String string) { } @Override - protected boolean hookDrawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + public boolean hookDrawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { String contentString = content; - if (focus) { + if (focus && isActive()) { if (this.fontRenderer.getBidiFlag()) { contentString += "_"; } else if (this.updateCount / 6 % 2 == 0) { @@ -118,7 +304,12 @@ protected boolean hookDrawInBackground(int mouseX, int mouseY, float partialTick contentString += TextFormatting.GRAY + "_"; } } - this.fontRenderer.drawSplitString(contentString, getPosition().x, getPosition().y + SPACE, getSize().width - yBarWidth, 0); + int x = getPosition().x - scrollXOffset; + int y = getPosition().y + SPACE - scrollYOffset; + for (String textLine : this.fontRenderer.listFormattedStringToWidth(contentString, getSize().width - yBarWidth)) { + fontRenderer.drawString(textLine, x, y, 0xff000000, false); + y += fontRenderer.FONT_HEIGHT; + } return true; } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java index 5de5d4214aa..10dfee6a877 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java @@ -47,13 +47,20 @@ public GuideConfigEditor(int x, int y, int width, int height) { addButton[1].setVisible(false); } }); -// addButton[0] = new CircleButtonWidget(100, -5, 5, 1, 3) -// .setColors(new Color(255, 255, 255, 0).getRGB(), -// new Color(255, 255, 255).getRGB(), -// new Color(146, 253, 118).getRGB()) -// .setIcon(GuiTextures.TERMINAL_ADD) -// .setHoverText("add stream") -// .setClickListener(this::getJson); + this.addWidget(new CircleButtonWidget(100, -5, 5, 1, 3) + .setColors(new Color(255, 255, 255, 0).getRGB(), + new Color(255, 255, 255).getRGB(), + new Color(243, 208, 116).getRGB()) + .setIcon(GuiTextures.TERMINAL_ADD) + .setHoverText("Import Guide") + .setClickListener(this::loadJson)); + this.addWidget(new CircleButtonWidget(120, -5, 5, 1, 3) + .setColors(new Color(255, 255, 255, 0).getRGB(), + new Color(255, 255, 255).getRGB(), + new Color(146, 253, 118).getRGB()) + .setIcon(GuiTextures.TERMINAL_ADD) + .setHoverText("Export Config") + .setClickListener(this::getJson)); addButton[0] = new CircleButtonWidget(115, 15, 8, 1, 8) .setColors(new Color(255, 255, 255, 0).getRGB(), new Color(255, 255, 255).getRGB(), @@ -68,6 +75,8 @@ public GuideConfigEditor(int x, int y, int width, int height) { .setIcon(GuiTextures.TERMINAL_ADD) .setHoverText("add fixed") .setClickListener(this::addFixed); + addButton[0].setVisible(false); + addButton[1].setVisible(false); this.addWidget(addButton[0]); this.addWidget(addButton[1]); } @@ -92,11 +101,21 @@ private DraggableScrollableWidgetGroup createPageConfig() { .setValidator(s->true)); group.addWidget(new ImageWidget(5, 48,116, 1, new ColorRectTexture(-1))); group.addWidget(new LabelWidget(5, 55, "title", -1).setShadow(true)); - group.addWidget(new TextEditorWidget(5, 65, 116, 40, "Template", s->{ + group.addWidget(new TextEditorWidget(5, 65, 116, 70, "Template", s->{ if (pageEditor != null) { pageEditor.setTitle(s); } - }).setBackground(new ColorRectTexture(0xA3FFFFFF))); + }, true).setBackground(new ColorRectTexture(0xA3FFFFFF))); +// group.addWidget(new ImageWidget(5, 148,116, 1, new ColorRectTexture(-1))); +// group.addWidget(new LabelWidget(5, 155, "translate key", -1).setShadow(true)); +// group.addWidget(new TextFieldWidget(5, 165, 116, 20, new ColorRectTexture(0x9f000000), null, null) +// .setTextResponder(s->{ +// if (pageEditor != null) { +// pageEditor.setTranslateKey(s); +// } +// }, true) +// .setMaxStringLength(Integer.MAX_VALUE) +// .setValidator(s->true)); return group; } @@ -131,6 +150,12 @@ public void loadConfigurator(IGuideWidget widget) { } } + private void loadJson(ClickData data) { + if(pageEditor != null) { + System.out.println(pageEditor.getJsonString()); + } + } + private void getJson(ClickData data) { if(pageEditor != null) { System.out.println(pageEditor.getJsonString()); diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java index bdf2b1dfb59..15df7a65329 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java @@ -26,6 +26,7 @@ public class GuidePageEditorWidget extends GuidePageWidget { private final CustomPositionSizeWidget customPositionSizeWidget; private GuideConfigEditor configEditor; private String section = "default"; +// private String translateKey = ""; public GuidePageEditorWidget(int xPosition, int yPosition, int width, int height, int margin) { super(xPosition, yPosition, width, height, margin); @@ -63,6 +64,10 @@ public void setSection(String section) { this.section = section; } +// public void setTranslateKey(String translateKey) { +// this.translateKey = translateKey; +// } + private void onPosSizeChanged(Position pos, Size size) { Widget widget = customPositionSizeWidget.getControlled(); if (widget instanceof IGuideWidget && ((IGuideWidget) widget).isFixed()) { diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java index 1d6cfa26d20..4adc3648aa6 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java @@ -17,6 +17,7 @@ import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.function.Consumer; public abstract class GuideWidget extends Widget implements IGuideWidget { diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java index bbdb75acb2c..99c387e7a83 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java @@ -1,10 +1,7 @@ package gregtech.api.terminal.gui.widgets.guide; -import com.google.gson.JsonElement; import com.google.gson.JsonObject; import gregtech.api.gui.Widget; -import gregtech.api.gui.widgets.WidgetGroup; -import gregtech.api.terminal.gui.IDraggable; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; import gregtech.api.util.Position; import gregtech.api.util.Size; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java index ccdee1f6ace..2a45c6d6530 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java @@ -14,6 +14,7 @@ import gregtech.api.util.Position; import gregtech.api.util.Size; import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.resources.I18n; import net.minecraft.item.Item; import net.minecraft.util.ResourceLocation; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java index da993835380..d7dca38ab5d 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java @@ -23,18 +23,18 @@ public class TextTreeWidget extends Widget { private static final int ITEM_HEIGHT = 11; protected int scrollOffset; - protected List>> list; - protected TreeNode> selected; + protected List> list; + protected TreeNode selected; protected IGuiTexture background; protected IGuiTexture nodeTexture; protected IGuiTexture leafTexture; - protected Consumer>> onSelected; + protected Consumer> onSelected; protected Function iconSupplier; protected Function nameSupplier; public TextTreeWidget(int xPosition, int yPosition, int width, int height, - TreeNode> root, - Consumer>> onSelected, + TreeNode root, + Consumer> onSelected, Function iconSupplier, Function nameSupplier) { super(new Position(xPosition, yPosition), new Size(width, height)); @@ -88,7 +88,7 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender for (int i = minToRender; i < maxToRender; i++) { GlStateManager.color(1,1,1,1); - TreeNode> node = list.get(i); + TreeNode node = list.get(i); int x = position.x + 10 * node.dimension; int y = position.y - scrollOffset + i * ITEM_HEIGHT; String name = node.key; @@ -99,9 +99,9 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender drawSolidRect(position.x, y, size.width, ITEM_HEIGHT, 0xffff0000); } if (node.content != null) { - String nameS = nameSupplier.apply(node.content.getFirst()); + String nameS = nameSupplier.apply(node.content); name = nameS == null ? name : nameS; - IGuiTexture icon = iconSupplier.apply(node.content.getFirst()); + IGuiTexture icon = iconSupplier.apply(node.content); if (icon != null) { icon.draw(x - 9, y + 1, 8, 8); } @@ -126,14 +126,14 @@ public boolean mouseClicked(int mouseX, int mouseY, int button) { if (this.isMouseOverElement(mouseX, mouseY)) { int index = ((mouseY - getPosition().y) + scrollOffset) / ITEM_HEIGHT; if (index < list.size()) { - TreeNode> node = list.get(index); + TreeNode node = list.get(index); if (node.isLeaf()) { if (node != this.selected) { this.selected = node; onSelected.accept(node); } } else if (node.children.size() > 0 && list.contains(node.children.get(0))){ - for (TreeNode> child : node.children) { + for (TreeNode child : node.children) { list.remove(child); } } else { diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/TextListConfigurator.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/TextListConfigurator.java index 9ec086e11f3..23a12ac1ead 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/TextListConfigurator.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/TextListConfigurator.java @@ -1,11 +1,9 @@ package gregtech.api.terminal.gui.widgets.guide.configurator; -import com.google.gson.Gson; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; +import com.google.gson.*; import gregtech.api.gui.resources.ColorRectTexture; import gregtech.api.terminal.gui.widgets.TextEditorWidget; +import net.minecraft.client.resources.I18n; import java.util.List; @@ -20,7 +18,7 @@ public TextListConfigurator(int x, int y, int height, JsonObject config, String List init = new Gson().fromJson(element, List.class); StringBuilder s = new StringBuilder(); for (int i = 0; i < init.size(); i++) { - s.append(init.get(i)); + s.append(I18n.format(init.get(i).toString())); if(i != init.size() - 1) { s.append('\n'); } @@ -30,7 +28,7 @@ public TextListConfigurator(int x, int y, int height, JsonObject config, String } private void init(int height, String init) { - this.addWidget(new TextEditorWidget(0, 15, 116, height, init, this::updateTextList).setBackground(new ColorRectTexture(0xA3FFFFFF))); + this.addWidget(new TextEditorWidget(0, 15, 116, height, init, this::updateTextList, true).setBackground(new ColorRectTexture(0xA3FFFFFF))); } private void updateTextList(String saved) { diff --git a/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_0_guidepage.json b/src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_0_guidepage.json similarity index 100% rename from src/main/resources/assets/gregtech/terminal/guide/tutorials/api_0_guidepage.json rename to src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_0_guidepage.json diff --git a/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_1_widget.json b/src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_1_widget.json similarity index 100% rename from src/main/resources/assets/gregtech/terminal/guide/tutorials/api_1_widget.json rename to src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_1_widget.json diff --git a/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_2_textbox.json b/src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_2_textbox.json similarity index 100% rename from src/main/resources/assets/gregtech/terminal/guide/tutorials/api_2_textbox.json rename to src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_2_textbox.json diff --git a/src/main/resources/assets/gregtech/terminal/guide/tutorials/api_3_image.json b/src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_3_image.json similarity index 100% rename from src/main/resources/assets/gregtech/terminal/guide/tutorials/api_3_image.json rename to src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_3_image.json diff --git a/src/main/resources/assets/gregtech/textures/gui/widget/formatting.png b/src/main/resources/assets/gregtech/textures/gui/widget/formatting.png new file mode 100644 index 0000000000000000000000000000000000000000..b6841a6f00f64a2b79ac2d2b747cdda210e90cfc GIT binary patch literal 1890 zcmcIle{9rL9Pf;5lK>8I7(uiY|3F!uShgb!{}A4_?{3}h+OF+( zH$*VNAE1dw7bgB78qt7Dwy6PPLKFf6bb?4CQw-S*8t@-sC>j#S;_LmA7{L8wlh^lN z`+1-5=li4I?rdzRn>l^{bb=seM(U*|JOex`%1iORabV(OJUw96ud@ka){r|&b}gN? zfFPzF)1oa-i@ZuyjFbneMhtl}DHEd!qI!A8gi1Sd$QVj!dWgDq_y|R6YKU6vlYwl8 zQL9$J(L&7|8=}g_b|t7%%a@VW84(ktkORp~DyiFICPZa-#x+Q` z$c<#!un_6<_-TdZy<{NhVf`TJ<*P_9U;_*YFf2y{Rs?>L3zGSZ!qzM`E;dOk^S1CV zM727ODKbnto%W}B3bhal=YMTqRlxCJqjjuh}?p-TAMh8Fl1WNsY{woCp=S(nFNurWmPI{;_t4 z=uJ&$jyBzjFzG##pM%*(+(|LE$#oC@O(&>R;VWsZkY__ zy27~4C6^H9-?_@ZyR8uw;JCZF%VJx_n_^=|I;OU8+pRfq;9G(ySs9UPqV+ouu3`1# zU`BOm!}_24$G&OvOuHeJtlRG!`(oa^%@dVfAN4=wOMNxa`O=J6tDD~2^u(H4`Nr7e zYv%Gqg~Im$uH?SiOSmH!r29{k}UR_4IAsF>>tW`L@G^cXard*T?2;yWTeV2RiWcvU$UGfz78n&Pyj7iCbIx zmL477J~Yw+9_*jJzvYx#K@25l4V@l5Ua{U=_VN#7sw1Czdefmx?c--JADv&-T|Kw% zrd;_6*mE&hcJ0EO-gvO}fkw(mXh-KEtFzn@-p?yB#dXC~h7+aZ;IeWqvh+HR?r qTXd%K!=AC{hbIRk4Sx;WKb9S$KP`LY{K0MRUocYJAPub8u=Q_&5QaJc literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/widget/palette.png b/src/main/resources/assets/gregtech/textures/gui/widget/palette.png new file mode 100644 index 0000000000000000000000000000000000000000..7accd700da76292a2da375d4e8ab73a4e66132f4 GIT binary patch literal 1921 zcmcIlTWs4@7CnDx4`?!6Ne7N$2P6`83REa7p!3$ zuXa3wAZ4G+;V!c)bbuGtq)U+02yms78bl*VOws0QI<7T%;Hp^>QwXB{`aT9HmLhOORfIa^ob$lPvG%(87g5Yq}KWJAzLX zY{8Wui<_p#6GSSNa;4lZRgV!A$8iKn6EuxO1a4#$Q%K{Av8Tuo1cs=~nklOaYB35C zwcqq(P-)(Uq*kI;j6#@Tz=*V<5tNIxTq*)Xq4lB3WC?AUO#{$MLGN9Ojc`T-L8#eTCvu)jA^{R031J2lMwLuyan)3fxOxviO4}uGG(MmM!Bq9I zswRqwYA>>&fdE={P*x;0W$d-|6yP8zn81(GBu(L@4=0&0#qbQrd)R8y$CG3p8iG|I z38t_yuqw&X%toN05Z|I0rl5$RCFsYXD3>ftycCsKw~wQ7Ho`=3hGyKj&j$qDO+`GS zo2D2x3Ua#O`JgKHTfwu==ZjWSMaWT#4==Hi2*jU1_(`wVd!l&0X3oOAytAgcU!d#*`XKBvH=s9DSREB;Q7KVA)~pH;|0;GbU!9q zDFzZ&crD*0dK=T3r%lBHBwZ)@d6=O_&6J>nh8T?Wf0Pz+FX@Ibu)gq(rTu>sUI?ie z7nB%)Et9}3R|u=QtJ6E~AI~q|D4!fH*Ewxp+C^crFKx!Sf-AnzpM-jvZ3%?;8 zAGta~wa(Sw-*g3i^Tp%)s=8f`(~AB8ADnNB4^+C|aA6PEZha{5QRlB_7R?OZTsbj0 zb>Zf&v5D8;UzypDleSly&mEp-;!|r2gnx8XG!)WpV9tw$AhS zuH}liXE)!N8-44{^zI|Jvpb}|`;K;_&z)Tnwd<3^+v+ztsupaOTGrm!P5!iMw~tr; z`33jAQ_Ef~+_010xIN^1j~hHqRsC@GtgnzFjj$)GgvsykYjhvh|Z}X=)9gY3zOB9|UQG A_W%F@ literal 0 HcmV?d00001 From cf5ac0d0e261d1ed83c2d0679af31bd8709e8c57 Mon Sep 17 00:00:00 2001 From: Yefancy Date: Wed, 4 Aug 2021 23:28:57 +0800 Subject: [PATCH 34/58] auto missing title --- .../java/gregtech/api/terminal/app/guide/ItemGuideApp.java | 1 + .../gregtech/api/terminal/app/guide/MultiBlockGuideApp.java | 1 + .../api/terminal/app/guide/SimpleMachineGuideApp.java | 4 ++++ 3 files changed, 6 insertions(+) diff --git a/src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java index 56d01160792..901524ab46a 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java @@ -53,6 +53,7 @@ protected JsonObject getPage(MetaItem.MetaValueItem item) { MAP.put(item, config); } if (MAP.get(item) == null) { + DEFAULT.addProperty("title", "Missing: §4" + item.unlocalizedName + ".json"); return DEFAULT; } return MAP.get(item); diff --git a/src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java index 3324866003d..599fcbc8848 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java @@ -57,6 +57,7 @@ protected JsonObject getPage(MetaTileEntity mte) { MAP.put(mte, config); } if (MAP.get(mte) == null) { + DEFAULT.addProperty("title", "Missing: §4" + mte.metaTileEntityId.getPath() + ".json"); return DEFAULT; } return MAP.get(mte); diff --git a/src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java index 1447f5cce7f..c72f24f7542 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java @@ -56,6 +56,10 @@ protected JsonObject getPage(MetaTileEntity mte) { } MAP.put(mte, config); } + if (MAP.get(mte) == null) { + DEFAULT.addProperty("title", "Missing: §4" + mte.metaTileEntityId.getPath() + ".json"); + return DEFAULT; + } return MAP.get(mte); } From de87098ae206b2ad088855b3a5ebae87661b36c7 Mon Sep 17 00:00:00 2001 From: Yefancy Date: Sat, 7 Aug 2021 21:19:43 +0800 Subject: [PATCH 35/58] dd --- src/main/java/gregtech/api/gui/Widget.java | 7 +- .../api/gui/widgets/AbstractWidgetGroup.java | 38 ++- .../api/gui/widgets/PhantomFluidWidget.java | 33 ++- .../api/gui/widgets/PhantomSlotWidget.java | 2 + .../gregtech/api/gui/widgets/SlotWidget.java | 22 +- .../gregtech/api/gui/widgets/TabGroup.java | 3 + .../gregtech/api/gui/widgets/TankWidget.java | 12 +- .../api/gui/widgets/TextFieldWidget.java | 14 +- .../gregtech/api/gui/widgets/WidgetGroup.java | 11 + .../api/terminal/app/AbstractApplication.java | 89 +----- .../api/terminal/app/GuideEditorApp.java | 7 +- .../api/terminal/app/guide/GuideApp.java | 19 +- .../gui/widgets/AnimaWidgetGroup.java | 101 +++++++ .../gui/widgets/CircleButtonWidget.java | 9 + .../api/terminal/gui/widgets/ColorWidget.java | 21 +- .../gui/widgets/CustomPositionSizeWidget.java | 8 +- .../DraggableScrollableWidgetGroup.java | 40 ++- .../gui/widgets/RectButtonWidget.java | 3 + .../gui/widgets/TextEditorWidget.java | 13 +- .../terminal/gui/widgets/TreeListWidget.java | 198 +++++++++++++ .../gui/widgets/guide/CardWidget.java | 108 +++++++ .../gui/widgets/guide/GuideConfigEditor.java | 65 +++-- .../widgets/guide/GuidePageEditorWidget.java | 66 +++-- .../gui/widgets/guide/GuidePageWidget.java | 15 +- .../gui/widgets/guide/GuideWidget.java | 72 ++--- .../gui/widgets/guide/GuideWidgetGroup.java | 195 +++++++++++++ .../gui/widgets/guide/IGuideWidget.java | 33 ++- .../gui/widgets/guide/ImageWidget.java | 21 +- .../gui/widgets/guide/SlotListWidget.java | 126 ++++++++ .../gui/widgets/guide/TankListWidget.java | 119 ++++++++ .../gui/widgets/guide/TextBoxWidget.java | 12 +- .../gui/widgets/guide/TextTreeWidget.java | 150 ---------- .../configurator/BooleanConfigurator.java | 24 +- .../guide/configurator/ColorConfigurator.java | 23 +- .../configurator/ConfiguratorWidget.java | 35 ++- .../configurator/FluidStackConfigurator.java | 97 +++++++ .../configurator/ItemStackConfigurator.java | 101 +++++++ .../configurator/NumberConfigurator.java | 24 +- .../configurator/SelectorConfigurator.java | 32 +-- .../configurator/StringConfigurator.java | 22 +- .../configurator/TextListConfigurator.java | 48 ++-- .../gui/widgets/os/TerminalDialogWidget.java | 270 ++++++++++++++++++ .../gui/widgets/os/TerminalMenuWidget.java | 8 +- .../gui/widgets/os/TerminalOSWidget.java | 64 ++--- .../gregtech/api/terminal/util/FileTree.java | 65 +++++ .../gregtech/api/terminal/util/IContent.java | 4 - .../gregtech/api/terminal/util/TreeNode.java | 21 +- src/main/java/gregtech/api/util/SlotUtil.java | 3 +- .../textures/gui/terminal/cancel_disable.png | Bin 0 -> 3159 bytes .../textures/gui/terminal/cancel_hover.png | Bin 0 -> 3070 bytes .../textures/gui/terminal/cancel_normal.png | Bin 0 -> 3082 bytes .../textures/gui/terminal/ok_disable.png | Bin 0 -> 3322 bytes .../textures/gui/terminal/ok_hover.png | Bin 0 -> 3261 bytes .../textures/gui/terminal/ok_normal.png | Bin 0 -> 3278 bytes .../textures/gui/terminal/terminal_dialog.png | Bin 0 -> 5193 bytes 55 files changed, 1909 insertions(+), 564 deletions(-) create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/AnimaWidgetGroup.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/TreeListWidget.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/CardWidget.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidgetGroup.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/SlotListWidget.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/TankListWidget.java delete mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/FluidStackConfigurator.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ItemStackConfigurator.java create mode 100644 src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalDialogWidget.java create mode 100644 src/main/java/gregtech/api/terminal/util/FileTree.java delete mode 100644 src/main/java/gregtech/api/terminal/util/IContent.java create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/cancel_disable.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/cancel_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/cancel_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/ok_disable.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/ok_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/ok_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/terminal_dialog.png diff --git a/src/main/java/gregtech/api/gui/Widget.java b/src/main/java/gregtech/api/gui/Widget.java index 00f5e3825fa..14c15f2502d 100644 --- a/src/main/java/gregtech/api/gui/Widget.java +++ b/src/main/java/gregtech/api/gui/Widget.java @@ -414,6 +414,7 @@ public static void setColor(int color) { // ARGB @SideOnly(Side.CLIENT) public static void renderCircle(float x, float y, float r, int color, int segments) { + if (color == 0) return; Tessellator tessellator = Tessellator.getInstance(); BufferBuilder bufferbuilder = tessellator.getBuffer(); GlStateManager.enableBlend(); @@ -431,7 +432,7 @@ public static void renderCircle(float x, float y, float r, int color, int segmen @SideOnly(Side.CLIENT) public static void renderSector(float x, float y, float r, int color, int segments, int from, int to) { - if (from > to || from < 0) return; + if (from > to || from < 0 || color == 0) return; if(to > segments) to = segments; Tessellator tessellator = Tessellator.getInstance(); BufferBuilder bufferbuilder = tessellator.getBuffer(); @@ -464,6 +465,10 @@ protected boolean isCtrlDown() { return Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) || Keyboard.isKeyDown(Keyboard.KEY_RCONTROL); } + protected boolean isRemote() { + return gui.holder.isRemote(); + } + protected static boolean isClientSide() { return FMLCommonHandler.instance().getSide().isClient(); } diff --git a/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java b/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java index 1c7042b01c7..17cd3be18f2 100644 --- a/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java +++ b/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java @@ -21,10 +21,12 @@ public class AbstractWidgetGroup extends Widget implements IGhostIngredientTarget, IIngredientSlot { - public final List widgets = new ArrayList<>(); - private final WidgetGroupUIAccess groupUIAccess = new WidgetGroupUIAccess(); - private final boolean isDynamicSized; - private boolean initialized = false; + public transient final List widgets = new ArrayList<>(); + private transient final WidgetGroupUIAccess groupUIAccess = new WidgetGroupUIAccess(); + private transient final boolean isDynamicSized; + private transient boolean initialized = false; + protected transient List waitToRemoved; + public AbstractWidgetGroup(Position position) { super(position, Size.ZERO); @@ -94,6 +96,9 @@ protected Size computeDynamicSize() { } public void setVisible(boolean visible) { + if (this.isVisible() == visible) { + return; + } super.setVisible(visible); widgets.stream().flatMap(it -> it.getNativeWidgets().stream()).forEach(it -> it.setEnabled(visible)); } @@ -119,6 +124,13 @@ protected void addWidget(Widget widget) { } } + protected void waitToRemoved(Widget widget) { + if (waitToRemoved == null) { + waitToRemoved = new ArrayList<>(); + } + waitToRemoved.add(widget); + } + protected void removeWidget(Widget widget) { if (!widgets.contains(widget)) { throw new IllegalArgumentException("Not added"); @@ -210,6 +222,10 @@ public void detectAndSendChanges() { widget.detectAndSendChanges(); } } + if (waitToRemoved != null) { + waitToRemoved.forEach(this::removeWidget); + waitToRemoved = null; + } } @Override @@ -219,6 +235,10 @@ public void updateScreen() { widget.updateScreen(); } } + if (waitToRemoved != null) { + waitToRemoved.forEach(this::removeWidget); + waitToRemoved = null; + } } @Override @@ -244,7 +264,7 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender public boolean mouseWheelMove(int mouseX, int mouseY, int wheelDelta) { for (int i = widgets.size() - 1; i >= 0; i--) { Widget widget = widgets.get(i); - if(widget.isVisible() && widget.mouseWheelMove(mouseX, mouseY, wheelDelta)) { + if(widget.isVisible() && widget.isActive() && widget.mouseWheelMove(mouseX, mouseY, wheelDelta)) { return true; } } @@ -255,7 +275,7 @@ public boolean mouseWheelMove(int mouseX, int mouseY, int wheelDelta) { public boolean mouseClicked(int mouseX, int mouseY, int button) { for (int i = widgets.size() - 1; i >= 0; i--) { Widget widget = widgets.get(i); - if(widget.isVisible() && widget.mouseClicked(mouseX, mouseY, button)) { + if(widget.isVisible() && widget.isActive() && widget.mouseClicked(mouseX, mouseY, button)) { return true; } } @@ -266,7 +286,7 @@ public boolean mouseClicked(int mouseX, int mouseY, int button) { public boolean mouseDragged(int mouseX, int mouseY, int button, long timeDragged) { for (int i = widgets.size() - 1; i >= 0; i--) { Widget widget = widgets.get(i); - if(widget.isVisible() && widget.mouseDragged(mouseX, mouseY, button, timeDragged)) { + if(widget.isVisible() && widget.isActive() && widget.mouseDragged(mouseX, mouseY, button, timeDragged)) { return true; } } @@ -277,7 +297,7 @@ public boolean mouseDragged(int mouseX, int mouseY, int button, long timeDragged public boolean mouseReleased(int mouseX, int mouseY, int button) { for (int i = widgets.size() - 1; i >= 0; i--) { Widget widget = widgets.get(i); - if(widget.isVisible() && widget.mouseReleased(mouseX, mouseY, button)) { + if(widget.isVisible() && widget.isActive() && widget.mouseReleased(mouseX, mouseY, button)) { return true; } } @@ -288,7 +308,7 @@ public boolean mouseReleased(int mouseX, int mouseY, int button) { public boolean keyTyped(char charTyped, int keyCode) { for (int i = widgets.size() - 1; i >= 0; i--) { Widget widget = widgets.get(i); - if(widget.isVisible() && widget.keyTyped(charTyped, keyCode)) { + if(widget.isVisible() && widget.isActive() && widget.keyTyped(charTyped, keyCode)) { return true; } } diff --git a/src/main/java/gregtech/api/gui/widgets/PhantomFluidWidget.java b/src/main/java/gregtech/api/gui/widgets/PhantomFluidWidget.java index 518f20674a4..b4fbc668b9f 100644 --- a/src/main/java/gregtech/api/gui/widgets/PhantomFluidWidget.java +++ b/src/main/java/gregtech/api/gui/widgets/PhantomFluidWidget.java @@ -6,6 +6,7 @@ import gregtech.api.gui.Widget; import gregtech.api.gui.ingredient.IGhostIngredientTarget; import gregtech.api.gui.ingredient.IIngredientSlot; +import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.resources.RenderUtil; import gregtech.api.gui.resources.TextureArea; import gregtech.api.util.Position; @@ -31,10 +32,11 @@ public class PhantomFluidWidget extends Widget implements IIngredientSlot, IGhostIngredientTarget { - protected TextureArea backgroundTexture = GuiTextures.FLUID_SLOT; + protected IGuiTexture backgroundTexture = GuiTextures.FLUID_SLOT; private final Supplier fluidStackSupplier; private final Consumer fluidStackUpdater; + private boolean isClient; protected FluidStack lastFluidStack; public PhantomFluidWidget(int xPosition, int yPosition, int width, int height, Supplier fluidStackSupplier, Consumer fluidStackUpdater) { @@ -53,6 +55,18 @@ private FluidStack drainFrom(Object ingredient) { return null; } + public PhantomFluidWidget setFluidStackSupplier(Supplier fluidStackSupplier, boolean isClient) { + this.fluidStackSupplier = fluidStackSupplier; + this.isClient = isClient; + return this; + } + + public PhantomFluidWidget setFluidStackUpdater(Consumer fluidStackUpdater, boolean isClient) { + this.fluidStackUpdater = fluidStackUpdater; + this.isClient = isClient; + return this; + } + @Override public List> getPhantomTargets(Object ingredient) { if (!(ingredient instanceof FluidStack) && drainFrom(ingredient) == null) { @@ -79,6 +93,10 @@ public void accept(@Nonnull Object ingredient) { NBTTagCompound tagCompound = ingredientStack.writeToNBT(new NBTTagCompound()); writeClientAction(2, buffer -> buffer.writeCompoundTag(tagCompound)); } + + if (isClient && fluidStackUpdater != null) { + fluidStackUpdater.accept(ingredientStack); + } } }); } @@ -91,11 +109,19 @@ public Object getIngredientOverMouse(int mouseX, int mouseY) { return null; } - public PhantomFluidWidget setBackgroundTexture(TextureArea backgroundTexture) { + public PhantomFluidWidget setBackgroundTexture(IGuiTexture backgroundTexture) { this.backgroundTexture = backgroundTexture; return this; } + @Override + public void updateScreen() { + super.updateScreen(); + if (isClient && fluidStackSupplier != null) { + this.lastFluidStack = fluidStackSupplier.get(); + } + } + @Override public void detectAndSendChanges() { FluidStack currentStack = fluidStackSupplier.get(); @@ -157,6 +183,9 @@ public boolean mouseClicked(int mouseX, int mouseY, int button) { if (isMouseOverElement(mouseX, mouseY)) { writeClientAction(1, buffer -> { }); + if (isClient && fluidStackUpdater != null) { + fluidStackUpdater.accept(null); + } return true; } return false; diff --git a/src/main/java/gregtech/api/gui/widgets/PhantomSlotWidget.java b/src/main/java/gregtech/api/gui/widgets/PhantomSlotWidget.java index b8824f995da..df3a8bfa465 100644 --- a/src/main/java/gregtech/api/gui/widgets/PhantomSlotWidget.java +++ b/src/main/java/gregtech/api/gui/widgets/PhantomSlotWidget.java @@ -53,6 +53,8 @@ public void accept(@Nonnull Object ingredient) { if (ingredient instanceof ItemStack) { int mouseButton = Mouse.getEventButton(); boolean shiftDown = Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) || Keyboard.isKeyDown(Keyboard.KEY_RSHIFT); + ClickType clickType = shiftDown ? ClickType.QUICK_MOVE : ClickType.PICKUP; + SlotUtil.slotClickPhantom(slotReference, mouseButton, clickType, (ItemStack)ingredient); writeClientAction(1, buffer -> { buffer.writeItemStack((ItemStack) ingredient); buffer.writeVarInt(mouseButton); diff --git a/src/main/java/gregtech/api/gui/widgets/SlotWidget.java b/src/main/java/gregtech/api/gui/widgets/SlotWidget.java index 041c84ca0d5..c6a83527d48 100644 --- a/src/main/java/gregtech/api/gui/widgets/SlotWidget.java +++ b/src/main/java/gregtech/api/gui/widgets/SlotWidget.java @@ -1,9 +1,11 @@ package gregtech.api.gui.widgets; -import gregtech.api.gui.INativeWidget; -import gregtech.api.gui.IRenderContext; -import gregtech.api.gui.IScissored; -import gregtech.api.gui.Widget; +import java.awt.Rectangle; + +import javax.annotation.Nonnull; + +import gregtech.api.gui.*; +import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.resources.TextureArea; import gregtech.api.util.Position; import gregtech.api.util.Size; @@ -30,7 +32,7 @@ public class SlotWidget extends Widget implements INativeWidget { protected final boolean canPutItems; protected SlotLocationInfo locationInfo = new SlotLocationInfo(false, false); - protected TextureArea[] backgroundTexture; + protected IGuiTexture[] backgroundTexture; protected Runnable changeListener; protected Rectangle scissor; @@ -49,6 +51,12 @@ public SlotWidget(IItemHandler itemHandler, int slotIndex, int xPosition, int yP this.slotReference = createSlot(itemHandler, slotIndex); } + @Override + public void setSizes(ISizeProvider sizes) { + super.setSizes(sizes); + onPositionUpdate(); + } + protected Slot createSlot(IInventory inventory, int index) { return new WidgetSlot(inventory, index, 0, 0); } @@ -63,7 +71,7 @@ public void drawInBackground(int mouseX, int mouseY, IRenderContext context) { if (isEnabled() && backgroundTexture != null) { Position pos = getPosition(); Size size = getSize(); - for (TextureArea backgroundTexture : this.backgroundTexture) { + for (IGuiTexture backgroundTexture : this.backgroundTexture) { backgroundTexture.draw(pos.x, pos.y, size.width, size.height); } } @@ -109,7 +117,7 @@ public SlotWidget(IInventory inventory, int slotIndex, int xPosition, int yPosit * Sets array of background textures used by slot * they are drawn on top of each other */ - public SlotWidget setBackgroundTexture(TextureArea... backgroundTexture) { + public SlotWidget setBackgroundTexture(IGuiTexture... backgroundTexture) { this.backgroundTexture = backgroundTexture; return this; } diff --git a/src/main/java/gregtech/api/gui/widgets/TabGroup.java b/src/main/java/gregtech/api/gui/widgets/TabGroup.java index 7c92191048a..ec42c11bde2 100644 --- a/src/main/java/gregtech/api/gui/widgets/TabGroup.java +++ b/src/main/java/gregtech/api/gui/widgets/TabGroup.java @@ -51,6 +51,7 @@ public TabGroup addTab(ITabInfo tabInfo, AbstractWidgetGroup tabWidget) { int tabIndex = tabInfos.size() - 1; this.tabWidgets.put(tabIndex, tabWidget); tabWidget.setVisible(tabIndex == selectedTabIndex); + tabWidget.setActive(tabIndex == selectedTabIndex); addWidget(tabWidget); return this; } @@ -119,7 +120,9 @@ public boolean mouseClicked(int mouseX, int mouseY, int button) { private void setSelectedTab(int tabIndex) { int old = selectedTabIndex; this.tabWidgets.get(selectedTabIndex).setVisible(false); + this.tabWidgets.get(selectedTabIndex).setActive(false); this.tabWidgets.get(tabIndex).setVisible(true); + this.tabWidgets.get(tabIndex).setActive(true); this.selectedTabIndex = tabIndex; if (this.onTabChanged != null) { onTabChanged.accept(old, tabIndex); diff --git a/src/main/java/gregtech/api/gui/widgets/TankWidget.java b/src/main/java/gregtech/api/gui/widgets/TankWidget.java index 149b1699543..1a1c17a0081 100644 --- a/src/main/java/gregtech/api/gui/widgets/TankWidget.java +++ b/src/main/java/gregtech/api/gui/widgets/TankWidget.java @@ -4,8 +4,8 @@ import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; import gregtech.api.gui.ingredient.IIngredientSlot; +import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.resources.RenderUtil; -import gregtech.api.gui.resources.TextureArea; import gregtech.api.util.FluidTooltipUtil; import gregtech.api.util.Position; import gregtech.api.util.Size; @@ -44,8 +44,8 @@ public class TankWidget extends Widget implements IIngredientSlot { private boolean allowClickFilling; private boolean allowClickEmptying; - private TextureArea[] backgroundTexture; - private TextureArea overlayTexture; + private IGuiTexture[] backgroundTexture; + private IGuiTexture overlayTexture; private FluidStack lastFluidInTank; private int lastTankCapacity; @@ -65,12 +65,12 @@ public TankWidget setAlwaysShowFull(boolean alwaysShowFull) { return this; } - public TankWidget setBackgroundTexture(TextureArea... backgroundTexture) { + public TankWidget setBackgroundTexture(IGuiTexture... backgroundTexture) { this.backgroundTexture = backgroundTexture; return this; } - public TankWidget setOverlayTexture(TextureArea overlayTexture) { + public TankWidget setOverlayTexture(IGuiTexture overlayTexture) { this.overlayTexture = overlayTexture; return this; } @@ -109,7 +109,7 @@ public void drawInBackground(int mouseX, int mouseY, IRenderContext context) { Position pos = getPosition(); Size size = getSize(); if (backgroundTexture != null) { - for (TextureArea textureArea : backgroundTexture) { + for (IGuiTexture textureArea : backgroundTexture) { textureArea.draw(pos.x, pos.y, size.width, size.height); } } diff --git a/src/main/java/gregtech/api/gui/widgets/TextFieldWidget.java b/src/main/java/gregtech/api/gui/widgets/TextFieldWidget.java index 68aff5b092c..2f89b089fb3 100644 --- a/src/main/java/gregtech/api/gui/widgets/TextFieldWidget.java +++ b/src/main/java/gregtech/api/gui/widgets/TextFieldWidget.java @@ -9,6 +9,7 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.gui.GuiTextField; +import net.minecraft.client.renderer.GlStateManager; import net.minecraft.network.PacketBuffer; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; @@ -84,7 +85,10 @@ public void setCurrentString(String currentString) { } public String getCurrentString() { - return this.textField.getText(); + if (isRemote()) { + return this.textField.getText(); + } + return this.currentString; } @Override @@ -122,6 +126,8 @@ public void drawInBackground(int mouseX, int mouseY, IRenderContext context) { background.draw(position.x, position.y, size.width, size.height); } this.textField.drawTextBox(); + GlStateManager.enableBlend(); + GlStateManager.color(1,1,1,1); } @Override @@ -145,7 +151,7 @@ public void updateScreen() { @Override public void detectAndSendChanges() { super.detectAndSendChanges(); - if (!textSupplier.get().equals(currentString)) { + if (textSupplier != null && !textSupplier.get().equals(currentString)) { this.currentString = textSupplier.get(); writeUpdateInfo(1, buffer -> buffer.writeString(currentString)); } @@ -178,7 +184,9 @@ public void handleClientAction(int id, PacketBuffer buffer) { clientText = clientText.substring(0, Math.min(clientText.length(), maxStringLength)); if (textValidator.test(clientText)) { this.currentString = clientText; - this.textResponder.accept(clientText); + if (textResponder != null) { + this.textResponder.accept(clientText); + } } } } diff --git a/src/main/java/gregtech/api/gui/widgets/WidgetGroup.java b/src/main/java/gregtech/api/gui/widgets/WidgetGroup.java index 9cd81ffd057..5bfef5d0d26 100644 --- a/src/main/java/gregtech/api/gui/widgets/WidgetGroup.java +++ b/src/main/java/gregtech/api/gui/widgets/WidgetGroup.java @@ -4,6 +4,8 @@ import gregtech.api.util.Position; import gregtech.api.util.Size; +import java.util.ArrayList; + public class WidgetGroup extends AbstractWidgetGroup { public WidgetGroup() { @@ -18,6 +20,10 @@ public WidgetGroup(Position position, Size size) { super(position, size); } + public WidgetGroup(int x, int y, int width, int height) { + super(new Position(x, y), new Size(width, height)); + } + @Override public void addWidget(Widget widget) { super.addWidget(widget); @@ -28,6 +34,11 @@ public void removeWidget(Widget widget) { super.removeWidget(widget); } + @Override + public void waitToRemoved(Widget widget) { + super.waitToRemoved(widget); + } + @Override public void clearAllWidgets() { super.clearAllWidgets(); diff --git a/src/main/java/gregtech/api/terminal/app/AbstractApplication.java b/src/main/java/gregtech/api/terminal/app/AbstractApplication.java index d2431be8a34..3a93dc51108 100644 --- a/src/main/java/gregtech/api/terminal/app/AbstractApplication.java +++ b/src/main/java/gregtech/api/terminal/app/AbstractApplication.java @@ -1,23 +1,16 @@ package gregtech.api.terminal.app; -import gregtech.api.gui.IRenderContext; import gregtech.api.gui.resources.IGuiTexture; -import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.terminal.gui.widgets.AnimaWidgetGroup; +import gregtech.api.terminal.gui.widgets.os.TerminalOSWidget; import gregtech.api.util.Position; import gregtech.api.util.Size; -import gregtech.api.util.interpolate.Eases; -import gregtech.api.util.interpolate.Interpolator; -import javafx.geometry.Pos; -import net.minecraft.client.renderer.GlStateManager; import net.minecraft.nbt.NBTTagCompound; -import java.util.function.Consumer; - -public abstract class AbstractApplication extends WidgetGroup { - protected Interpolator interpolator; +public abstract class AbstractApplication extends AnimaWidgetGroup { protected final String name; protected final IGuiTexture icon; - private float scale; + protected TerminalOSWidget os; public AbstractApplication (String name, IGuiTexture icon) { super(Position.ORIGIN, new Size(333, 232)); @@ -25,6 +18,11 @@ public AbstractApplication (String name, IGuiTexture icon) { this.icon = icon; } + public AbstractApplication setOs(TerminalOSWidget os) { + this.os = os; + return this; + } + public String getName() { return name; } @@ -35,34 +33,6 @@ public IGuiTexture getIcon() { public abstract AbstractApplication createApp(boolean isClient, NBTTagCompound nbt); - public void maximizeApp(Consumer callback) { - this.scale = 0; - setVisible(true); - interpolator = new Interpolator(0, 1, 10, Eases.EaseLinear, - value-> scale = value.floatValue(), - value-> { - interpolator = null; - if (callback != null) { - callback.accept(this); - } - }); - interpolator.start(); - } - - public void minimizeApp(Consumer callback) { - this.scale = 1; - interpolator = new Interpolator(1, 0, 10, Eases.EaseLinear, - value-> scale = value.floatValue(), - value-> { - setVisible(false); - interpolator = null; - if (callback != null) { - callback.accept(this); - } - }); - interpolator.start(); - } - public void closeApp(boolean isClient, NBTTagCompound nbt) { } @@ -70,44 +40,7 @@ public boolean isBackgroundApp() { return false; } - @Override - public void updateScreen() { - if (interpolator != null) { - interpolator.update(); - } - super.updateScreen(); - } - - @Override - public void drawInForeground(int mouseX, int mouseY) { - if (scale == 0) { - return; - } if (scale != 1) { - GlStateManager.pushMatrix(); - GlStateManager.translate((this.gui.getScreenWidth() - this.gui.getScreenWidth() * scale) / 2, - (this.gui.getScreenHeight() - this.gui.getScreenHeight() * scale) / 2, 0); - GlStateManager.scale(scale, scale, 1); - super.drawInForeground(0, 0); - GlStateManager.popMatrix(); - } else { - super.drawInForeground(mouseX, mouseY); - } - } - - @Override - public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { - if (scale == 0) { - return; - }if (scale != 1) { - GlStateManager.pushMatrix(); - GlStateManager.translate((this.gui.getScreenWidth() - this.gui.getScreenWidth() * scale) / 2, - (this.gui.getScreenHeight() - this.gui.getScreenHeight() * scale) / 2, 0); - GlStateManager.scale(scale, scale, 1); - super.drawInBackground(0, 0, partialTicks, context); - GlStateManager.popMatrix(); - } else { - super.drawInBackground(mouseX, mouseY, partialTicks, context); - } - + public TerminalOSWidget getOs() { + return os; } } diff --git a/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java b/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java index a5bbbc889d0..3dd11f4b5cc 100644 --- a/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java +++ b/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java @@ -17,17 +17,16 @@ public GuideEditorApp() { @Override public AbstractApplication createApp(boolean isClient, NBTTagCompound nbt) { + GuideEditorApp app = new GuideEditorApp(); if (isClient) { - GuideEditorApp app = new GuideEditorApp(); - GuideConfigEditor configEditor = new GuideConfigEditor(0, 0, 133, 232); + GuideConfigEditor configEditor = new GuideConfigEditor(0, 0, 133, 232, app); GuidePageEditorWidget pageEditor = new GuidePageEditorWidget(133, 0, 200, 232, 5); configEditor.setGuidePageEditorWidget(pageEditor); pageEditor.setGuideConfigEditor(configEditor); app.addWidget(pageEditor); app.addWidget(configEditor); - return app; } - return null; + return app; } @Override diff --git a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java index 63bde426b50..6c394c2c530 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java @@ -5,26 +5,20 @@ import com.google.gson.JsonObject; import gregtech.api.GTValues; import gregtech.api.gui.GuiTextures; -import gregtech.api.gui.Widget; -import gregtech.api.gui.resources.ColorRectTexture; import gregtech.api.gui.resources.IGuiTexture; -import gregtech.api.gui.widgets.WidgetGroup; import gregtech.api.terminal.app.AbstractApplication; +import gregtech.api.terminal.gui.widgets.TreeListWidget; import gregtech.api.terminal.gui.widgets.guide.*; import gregtech.api.terminal.util.TreeNode; import net.minecraft.client.Minecraft; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.PacketBuffer; import net.minecraft.util.ResourceLocation; -import net.minecraft.util.Tuple; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; import java.util.function.Consumer; public abstract class GuideApp extends AbstractApplication { @@ -39,19 +33,22 @@ public AbstractApplication createApp(boolean isClient, NBTTagCompound nbt) { GuideApp app = this.getClass().newInstance(); if (isClient && getTree() != null) { app.addWidget( - new TextTreeWidget<>(0, 0, 133, 232, getTree(), leaf -> { + new TreeListWidget<>(0, 0, 133, 232, getTree(), leaf -> { if (app.pageWidget != null) { app.removeWidget(app.pageWidget); } app.pageWidget = new GuidePageWidget(133, 0, 200, 232, 5); - if (leaf.isLeaf() && leaf.content != null) { - JsonObject page = getPage(leaf.content); + if (leaf.isLeaf() && leaf.getContent() != null) { + JsonObject page = getPage(leaf.getContent()); if (page != null) { app.pageWidget.loadJsonConfig(page); } } app.addWidget(app.pageWidget); - }, this::itemIcon, this::itemName).setNodeTexture(GuiTextures.BORDERED_BACKGROUND).setLeafTexture(GuiTextures.SLOT_DARKENED) + }).setContentIconSupplier(this::itemIcon) + .setContentNameSupplier(this::itemName) + .setNodeTexture(GuiTextures.BORDERED_BACKGROUND) + .setLeafTexture(GuiTextures.SLOT_DARKENED) ); } return app; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/AnimaWidgetGroup.java b/src/main/java/gregtech/api/terminal/gui/widgets/AnimaWidgetGroup.java new file mode 100644 index 00000000000..cc040f489a2 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/AnimaWidgetGroup.java @@ -0,0 +1,101 @@ +package gregtech.api.terminal.gui.widgets; + +import gregtech.api.gui.INativeWidget; +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.util.Position; +import gregtech.api.util.Size; +import gregtech.api.util.interpolate.Eases; +import gregtech.api.util.interpolate.Interpolator; +import net.minecraft.client.renderer.GlStateManager; + +import java.util.function.Consumer; + +public abstract class AnimaWidgetGroup extends WidgetGroup { + protected Interpolator interpolator; + protected float scale; + + public AnimaWidgetGroup(Position position, Size size) { + super(position, size); + } + + public AnimaWidgetGroup(int x, int y, int width, int height) { + super(new Position(x, y), new Size(width, height)); + } + + @Override + public void updateScreen() { + if (interpolator != null) { + interpolator.update(); + } + super.updateScreen(); + } + + public void maximizeWidget(Consumer callback) { + this.scale = 0; + setVisible(true); + interpolator = new Interpolator(0, 1, 10, Eases.EaseLinear, + value-> scale = value.floatValue(), + value-> { + interpolator = null; + if (callback != null) { + callback.accept(this); + } + }); + interpolator.start(); + } + + public void minimizeWidget(Consumer callback) { + this.scale = 1; + interpolator = new Interpolator(1, 0, 10, Eases.EaseLinear, + value-> scale = value.floatValue(), + value-> { + setVisible(false); + interpolator = null; + if (callback != null) { + callback.accept(this); + } + }); + interpolator.start(); + } + + protected void hookDrawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + super.drawInBackground(mouseX, mouseY, partialTicks, context); + } + + protected void hookDrawInForeground(int mouseX, int mouseY) { + super.drawInForeground(mouseX, mouseY); + } + + @Override + public final void drawInForeground(int mouseX, int mouseY) { + if (scale == 0) { + return; + } if (scale != 1) { + GlStateManager.pushMatrix(); + GlStateManager.translate((this.gui.getScreenWidth() - this.gui.getScreenWidth() * scale) / 2, + (this.gui.getScreenHeight() - this.gui.getScreenHeight() * scale) / 2, 0); + GlStateManager.scale(scale, scale, 1); + hookDrawInForeground(0, 0); + GlStateManager.popMatrix(); + } else { + hookDrawInForeground(mouseX, mouseY); + } + } + + @Override + public final void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + if (scale == 0) { + return; + }if (scale != 1) { + GlStateManager.pushMatrix(); + GlStateManager.translate((this.gui.getScreenWidth() - this.gui.getScreenWidth() * scale) / 2, + (this.gui.getScreenHeight() - this.gui.getScreenHeight() * scale) / 2, 0); + GlStateManager.scale(scale, scale, 1); + hookDrawInBackground(0, 0, partialTicks, context); + GlStateManager.popMatrix(); + } else { + hookDrawInBackground(mouseX, mouseY, partialTicks, context); + } + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java index 4b84b6707ab..fecc42d1dfe 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java @@ -23,6 +23,7 @@ public class CircleButtonWidget extends Widget { protected boolean isHover; protected String hoverText; protected IGuiTexture icon; + protected IGuiTexture hover; protected final int iconSize; protected Consumer onPressCallback; protected final int[] colors = { @@ -78,6 +79,11 @@ public CircleButtonWidget setClickListener(Consumer onPressed) { return this; } + public CircleButtonWidget setHoverIcon(IGuiTexture hover) { + this.hover = hover; + return this; + } + @Override public void updateScreen() { if (isHover) { @@ -104,6 +110,9 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender renderSector(x, y, r, colors[1], segments, 0, (int) (segments * ((hoverTick + partialTicks) / 8))); } renderCircle(x, y, r - border, colors[2], segments); + if (isHover && hover != null) { + hover.draw(x - iconSize / 2f, y - iconSize / 2f, iconSize, iconSize); + } if (icon != null) { icon.draw(x - iconSize / 2f, y - iconSize / 2f, iconSize, iconSize); } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/ColorWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/ColorWidget.java index 58b88ed577a..0dfc53e292f 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/ColorWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/ColorWidget.java @@ -40,8 +40,9 @@ public ColorWidget(int x, int y, int barWidth, int barHeight){ .setTextResponder((t) -> { setRed(t.isEmpty()? 0 : Integer.parseInt(t)); if (onColorChanged != null) { - onColorChanged.accept((alpha << 24) | (red << 16) | (green << 8) | (blue)); + onColorChanged.accept(getColor()); } + writeClientAction(2, buffer -> buffer.writeInt(getColor())); }, true) .setTextSupplier(() -> Integer.toString(red), true) .setValidator(this::checkValid); @@ -49,8 +50,9 @@ public ColorWidget(int x, int y, int barWidth, int barHeight){ .setTextResponder((t) -> { setGreen(t.isEmpty()? 0 : Integer.parseInt(t)); if (onColorChanged != null) { - onColorChanged.accept((alpha << 24) | (red << 16) | (green << 8) | (blue)); + onColorChanged.accept(getColor()); } + writeClientAction(2, buffer -> buffer.writeInt(getColor())); }, true) .setTextSupplier(() -> Integer.toString(green), true) .setValidator(this::checkValid); @@ -58,8 +60,9 @@ public ColorWidget(int x, int y, int barWidth, int barHeight){ .setTextResponder((t) -> { setBlue(t.isEmpty()? 0 : Integer.parseInt(t)); if (onColorChanged != null) { - onColorChanged.accept((alpha << 24) | (red << 16) | (green << 8) | (blue)); + onColorChanged.accept(getColor()); } + writeClientAction(2, buffer -> buffer.writeInt(getColor())); }, true) .setTextSupplier(() -> Integer.toString(blue), true) .setValidator(this::checkValid); @@ -67,8 +70,9 @@ public ColorWidget(int x, int y, int barWidth, int barHeight){ .setTextResponder((t) -> { setAlpha(t.isEmpty()? 0 : Integer.parseInt(t)); if (onColorChanged != null) { - onColorChanged.accept((alpha << 24) | (red << 16) | (green << 8) | (blue)); + onColorChanged.accept(getColor()); } + writeClientAction(2, buffer -> buffer.writeInt(getColor())); }, true) .setTextSupplier(() -> Integer.toString(alpha), true) .setValidator(this::checkValid); @@ -97,6 +101,10 @@ public ColorWidget setColorSupplier(Supplier colorSupplier, boolean isC return this; } + public int getColor() { + return (alpha << 24) | (red << 16) | (green << 8) | (blue); + } + @Override public void detectAndSendChanges() { super.detectAndSendChanges(); @@ -153,7 +161,7 @@ private void handleColor(int id, PacketBuffer buffer) { setBlue(b); setAlpha(a); if (onColorChanged != null) { - onColorChanged.accept((alpha << 24) | (red << 16) | (green << 8) | (blue)); + onColorChanged.accept(getColor()); } } } @@ -260,8 +268,9 @@ public boolean mouseDragged(int mouseX, int mouseY, int button, long timeDragged setAlpha(newX * 255 / barWidth); } if (onColorChanged != null) { - onColorChanged.accept((alpha << 24) | (red << 16) | (green << 8) | (blue)); + onColorChanged.accept(getColor()); } + writeClientAction(2, buffer -> buffer.writeInt(getColor())); dragged.setSelfPosition(new Position(newX - 4, dragged.getSelfPosition().y)); return true; } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/CustomPositionSizeWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/CustomPositionSizeWidget.java index 6bd708f2e5b..daf0a705b85 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/CustomPositionSizeWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/CustomPositionSizeWidget.java @@ -176,17 +176,17 @@ public boolean dragging(int mouseX, int mouseY, int deltaX, int deltaY) { if (!dragPos) { if (dragUp) { addY = deltaY; - height -= deltaY; + height = Math.max(1, height - deltaY); } if (dragDown) { - height += deltaY; + height = Math.max(1, height + deltaY); } if (dragLeft) { addX = deltaX; - width -= deltaX; + width = Math.max(1, width - deltaX); } if (dragRight) { - width += deltaX; + width = Math.max(1, width + deltaX); } controlled.addSelfPosition(addX, addY); controlled.setSize(new Size(width, height)); diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java b/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java index a00cfa35efe..f5dfe6121ed 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java @@ -8,8 +8,13 @@ import gregtech.api.util.Position; import gregtech.api.util.RenderUtil; import gregtech.api.util.Size; +import net.minecraft.client.renderer.GlStateManager; import net.minecraft.util.math.MathHelper; +import static gregtech.api.gui.impl.ModularUIGui.bColorForOverlay; +import static gregtech.api.gui.impl.ModularUIGui.gColorForOverlay; +import static gregtech.api.gui.impl.ModularUIGui.rColorForOverlay; + public class DraggableScrollableWidgetGroup extends WidgetGroup { protected int scrollXOffset; protected int scrollYOffset; @@ -84,6 +89,7 @@ public void addWidget(Widget widget) { maxHeight = Math.max(maxHeight, widget.getSize().height + widget.getSelfPosition().y); maxWidth = Math.max(maxWidth, widget.getSize().width + widget.getSelfPosition().x); widget.addSelfPosition(- scrollXOffset, - scrollYOffset); + widget.applyScissor(getPosition().x, getPosition().y, getSize().width - yBarWidth, getSize().height - xBarHeight); super.addWidget(widget); } @@ -108,6 +114,18 @@ public void setSize(Size size) { computeMax(); } + @Override + protected void onPositionUpdate() { + super.onPositionUpdate(); + this.applyScissor(getPosition().x, getPosition().y, getSize().width - yBarWidth, getSize().height - xBarHeight); + } + + @Override + protected void onSizeUpdate() { + super.onSizeUpdate(); + this.applyScissor(getPosition().x, getPosition().y, getSize().width - yBarWidth, getSize().height - xBarHeight); + } + protected void computeMax() { int mh = 0; int mw = 0; @@ -211,32 +229,34 @@ protected boolean hookDrawInBackground(int mouseX, int mouseY, float partialTick @Override public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { - Position position = getPosition(); - Size size = getSize(); + int x = getPosition().x; + int y = getPosition().y; + int width = getSize().width; + int height = getSize().height; if (background != null) { - background.draw(position.x, position.y, size.width, size.height); + background.draw(x, y, width, height); } - RenderUtil.useScissor(position.x, position.y, size.width - yBarWidth, size.height - xBarHeight, ()->{ + RenderUtil.useScissor(x, y, width - yBarWidth, height - xBarHeight, ()->{ if(!hookDrawInBackground(mouseX, mouseY, partialTicks, context)) { super.drawInBackground(mouseX, mouseY, partialTicks, context); } }); if (xBarHeight > 0) { if (xBarB != null) { - xBarB.draw(position.x, position.y - xBarHeight, size.width, xBarHeight); + xBarB.draw(x, y - xBarHeight, width, xBarHeight); } if (xBarF != null) { - int barWidth = size.width / getMaxWidth(); - xBarF.draw(position.x + scrollXOffset, position.y - xBarHeight, barWidth, xBarHeight); + int barWidth = width / getMaxWidth(); + xBarF.draw(x + scrollXOffset, y - xBarHeight, barWidth, xBarHeight); } } if (yBarWidth > 0) { if (yBarB != null) { - yBarB.draw(position.x + size.width - yBarWidth, position.y, yBarWidth, size.height); + yBarB.draw(x + width - yBarWidth, y, yBarWidth, height); } if (yBarF != null) { - int barHeight = (int) (size.height * 1.0f / getMaxHeight() * size.height); - yBarF.draw(position.x + size.width - yBarWidth, position.y + scrollYOffset * size.height * 1.0f / getMaxHeight(), yBarWidth, barHeight); + int barHeight = (int) (height * 1.0f / getMaxHeight() * height); + yBarF.draw(x + width - yBarWidth, y + scrollYOffset * height * 1.0f / getMaxHeight(), yBarWidth, barHeight); } } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/RectButtonWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/RectButtonWidget.java index a4060c2986e..6dde56eb33e 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/RectButtonWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/RectButtonWidget.java @@ -118,6 +118,9 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender drawSolidRect(x, (int) ((1 - per) * height) + y, border, (int) (height * per), colors[1]); } drawSolidRect(x + border, y + border, width - 2 * border, height - 2 * border, colors[2]); + if (isHover && hover != null) { + hover.draw(x + border, y + border, width - 2 * border, height - 2 * border); + } if (isPressed) { if (pressedIcon != null) { pressedIcon.draw(x + border, y + border, width - 2 * border, height - 2 * border); diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/TextEditorWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/TextEditorWidget.java index 98622a29dbe..d306e16dd94 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/TextEditorWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/TextEditorWidget.java @@ -25,9 +25,9 @@ public class TextEditorWidget extends WidgetGroup { private static final TextureArea STYLE = TextureArea.fullImage("textures/gui/widget/formatting.png"); private final TextPanelWidget textPanelWidget; - public TextEditorWidget(int x, int y, int width, int height, String initText,Consumer stringUpdate, boolean allowToolBox) { + public TextEditorWidget(int x, int y, int width, int height,Consumer stringUpdate, boolean allowToolBox) { super(new Position(x, y), new Size(Math.max(width, allowToolBox ? 80 : width), Math.max(height, allowToolBox ? 32 : height))); - textPanelWidget = new TextPanelWidget(0, 32, Math.max(width, allowToolBox ? 80 : width), Math.max(height, allowToolBox ? 32 : height) - 32, initText, stringUpdate); + textPanelWidget = new TextPanelWidget(0, 32, Math.max(width, allowToolBox ? 80 : width), Math.max(height, allowToolBox ? 32 : height) - 32, stringUpdate); this.addWidget(textPanelWidget); if (allowToolBox) { initToolBox(); @@ -39,6 +39,11 @@ public TextEditorWidget setBackground(IGuiTexture background) { return this; } + public TextEditorWidget setContent(String content) { + textPanelWidget.pageSetCurrent(content); + return this; + } + @Override public void setActive(boolean active) { super.setActive(active); @@ -103,10 +108,10 @@ private static class TextPanelWidget extends DraggableScrollableWidgetGroup { private static final Pattern COLOR_CODE_PATTERN = Pattern.compile("(?i)§[0-9A-F]"); - public TextPanelWidget(int x, int y, int width, int height, String text, Consumer stringUpdate) { + public TextPanelWidget(int x, int y, int width, int height, Consumer stringUpdate) { super(x, y, width, height); this.stringUpdate = stringUpdate; - this.content = text == null ? "" : text; + this.content = ""; if (isClientSide()) { fontRenderer = Minecraft.getMinecraft().fontRenderer; textHeight = fontRenderer.getWordWrappedHeight(content, width - yBarWidth); diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/TreeListWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/TreeListWidget.java new file mode 100644 index 00000000000..5c1939456ed --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/TreeListWidget.java @@ -0,0 +1,198 @@ +package gregtech.api.terminal.gui.widgets; + +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.terminal.util.TreeNode; +import gregtech.api.util.Position; +import gregtech.api.util.RenderUtil; +import gregtech.api.util.Size; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.resources.I18n; +import net.minecraft.util.math.MathHelper; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Function; + +public class TreeListWidget extends Widget { + private static final int ITEM_HEIGHT = 11; + protected int scrollOffset; + protected List> list; + protected TreeNode selected; + protected IGuiTexture background; + protected IGuiTexture nodeTexture; + protected IGuiTexture leafTexture; + protected Consumer> onSelected; + protected Function keyIconSupplier; + protected Function keyNameSupplier; + protected Function contentIconSupplier; + protected Function contentNameSupplier; + protected boolean canSelectNode; + private int tick; + + public TreeListWidget(int xPosition, int yPosition, int width, int height, + TreeNode root, + Consumer> onSelected) { + super(new Position(xPosition, yPosition), new Size(width, height)); + list = new ArrayList<>(); + if (root.getChildren() != null) { + list.addAll(root.getChildren()); + } + this.onSelected = onSelected; + } + + public TreeListWidget canSelectNode(boolean canSelectNode) { + this.canSelectNode = canSelectNode; + return this; + } + + public TreeListWidget setBackground(IGuiTexture background) { + this.background = background; + return this; + } + + public TreeListWidget setNodeTexture(IGuiTexture nodeTexture) { + this.nodeTexture = nodeTexture; + return this; + } + + public TreeListWidget setLeafTexture(IGuiTexture leafTexture) { + this.leafTexture = leafTexture; + return this; + } + + public TreeListWidget setContentIconSupplier(Function iconSupplier) { + contentIconSupplier = iconSupplier; + return this; + } + + public TreeListWidget setKeyIconSupplier(Function iconSupplier) { + keyIconSupplier = iconSupplier; + return this; + } + + public TreeListWidget setContentNameSupplier(Function nameSupplier) { + contentNameSupplier = nameSupplier; + return this; + } + + public TreeListWidget setKeyNameSupplier(Function nameSupplier) { + keyNameSupplier = nameSupplier; + return this; + } + + @Override + public void updateScreen() { + tick++; + } + + @Override + public boolean mouseWheelMove(int mouseX, int mouseY, int wheelDelta) { + if (this.isMouseOverElement(mouseX, mouseY, true)) { + int moveDelta = -MathHelper.clamp(wheelDelta, -1, 1) * 5; + this.scrollOffset = MathHelper.clamp(scrollOffset + moveDelta, 0, Math.max(list.size() * ITEM_HEIGHT - getSize().height, 0)); + return true; + } + return false; + } + + @Override + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + int x = getPosition().x; + int y = getPosition().y; + int width = getSize().width; + int height = getSize().height; + if (background != null) { + background.draw(x, y, width, height); + } else { + drawGradientRect(x, y, width, height, 0x8f000000, 0x8f000000); + } + RenderUtil.useScissor(x, y, width, height, ()->{ + FontRenderer fr = Minecraft.getMinecraft().fontRenderer; + int minToRender = scrollOffset / ITEM_HEIGHT; + int maxToRender = Math.min(list.size(), height / ITEM_HEIGHT + 2 + minToRender); + for (int i = minToRender; i < maxToRender; i++) { + GlStateManager.color(1,1,1,1); + TreeNode node = list.get(i); + int sX = x + 10 * node.dimension; + int sY = y - scrollOffset + i * ITEM_HEIGHT; + String name = node.toString(); + if (node.isLeaf()) { + if (leafTexture != null) { + leafTexture.draw(x, sY, width, ITEM_HEIGHT); + } else { + drawSolidRect(x, sY, width, ITEM_HEIGHT, 0xffff0000); + } + if (node.getContent() != null) { + String nameS = contentNameSupplier == null ? null : contentNameSupplier.apply(node.getContent()); + name = nameS == null ? name : nameS; + IGuiTexture icon = contentIconSupplier == null ? null : contentIconSupplier.apply(node.getContent()); + if (icon != null) { + icon.draw(sX - 9, sY + 1, 8, 8); + } + } + } else { + if (nodeTexture != null) { + nodeTexture.draw(x, sY, width, ITEM_HEIGHT); + } else { + drawSolidRect(x, sY, width, ITEM_HEIGHT, 0xffffff00); + } + String nameS = keyNameSupplier == null ? null : keyNameSupplier.apply(node.getKey()); + name = nameS == null ? name : nameS; + IGuiTexture icon = keyIconSupplier == null ? null : keyIconSupplier.apply(node.getKey()); + if (icon != null) { + icon.draw(sX - 9, sY + 1, 8, 8); + } + } + if (node == selected) { + drawSolidRect(x, sY, width, ITEM_HEIGHT, 0x7f000000); + } + int textW = Math.max(width - 10 * node.dimension, 10); + List list = fr.listFormattedStringToWidth(I18n.format(name), textW); + fr.drawString(list.get(Math.abs((tick / 20) % list.size())), sX, sY + 2, 0xff000000); + } + }); + GlStateManager.enableBlend(); + GlStateManager.color(1,1,1,1); + } + + @Override + public boolean mouseClicked(int mouseX, int mouseY, int button) { + if (this.isMouseOverElement(mouseX, mouseY)) { + int index = ((mouseY - getPosition().y) + scrollOffset) / ITEM_HEIGHT; + if (index < list.size()) { + TreeNode node = list.get(index); + if (node.isLeaf()) { + if (node != this.selected) { + this.selected = node; + if (onSelected != null){ + onSelected.accept(node); + } + } + } else { + if (canSelectNode && this.selected != node) { + this.selected = node; + if (onSelected != null){ + onSelected.accept(node); + } + } else if (node.getChildren().size() > 0 && list.contains(node.getChildren().get(0))){ + for (TreeNode child : node.getChildren()) { + list.remove(child); + } + } else { + for (int i = 0; i < node.getChildren().size(); i++) { + list.add(index + 1 + i, node.getChildren().get(i)); + } + } + } + playButtonClickSound(); + } + return true; + } + return false; + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/CardWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/CardWidget.java new file mode 100644 index 00000000000..07a108e97cc --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/CardWidget.java @@ -0,0 +1,108 @@ +package gregtech.api.terminal.gui.widgets.guide; + +import com.google.gson.JsonObject; +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.Widget; +import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; +import gregtech.api.terminal.gui.widgets.guide.configurator.BooleanConfigurator; +import gregtech.api.terminal.gui.widgets.guide.configurator.NumberConfigurator; +import gregtech.api.util.Position; +import gregtech.api.util.Size; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import org.lwjgl.opengl.GL11; + +import java.util.function.Consumer; + +public class CardWidget extends GuideWidget{ + public final static String NAME = "card"; + + //config + public int width; + public int height; + public boolean isShadow; + + @Override + public String getRegistryName() { + return NAME; + } + + @Override + public JsonObject getTemplate(boolean isFixed) { + JsonObject template = super.getTemplate(isFixed); + template.addProperty("fill", -3745585); + template.addProperty("width", 120); + template.addProperty("height", 60); + template.addProperty("isShadow", true); + return template; + } + + @Override + public void loadConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, boolean isFixed, Consumer needUpdate) { + super.loadConfigurator(group, config, isFixed, needUpdate); + if (!isFixed) { + group.addWidget(new NumberConfigurator(group, config, "width").setOnUpdated(needUpdate)); + group.addWidget(new NumberConfigurator(group, config, "height").setOnUpdated(needUpdate)); + } + group.addWidget(new BooleanConfigurator(group, config, "isShadow", true).setOnUpdated(needUpdate)); + } + + @Override + protected Widget initStream() { + int pageWidth = getSize().width; + int x = getSelfPosition().x; + int y = getSelfPosition().y; + if (page != null) { + x = page.getMargin(); + pageWidth = page.getPageWidth() - 2 * x; + } + this.setSelfPosition(new Position(x + (pageWidth - width) / 2, y)); + return initFixed(); + } + + @Override + protected Widget initFixed() { + this.setSize(new Size(width, height)); + return this; + } + + @Override + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + if (isShadow) { + int x = getPosition().x; + int y = getPosition().y; + int width = getSize().width; + int height = getSize().height; + drawGradientRect(x + 5, y + height, width - 5, 5, 0x4f000000, 0, false); + drawGradientRect(x + width, y + 5, 5, height - 5, 0x4f000000, 0, true); + + float startAlpha = (float) (0x4f) / 255.0F; + GlStateManager.disableTexture2D(); + GlStateManager.enableBlend(); + GlStateManager.disableAlpha(); + GlStateManager.tryBlendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO); + GlStateManager.shadeModel(GL11.GL_SMOOTH); + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder buffer = tessellator.getBuffer(); + buffer.begin(GL11.GL_TRIANGLES, DefaultVertexFormats.POSITION_COLOR); + x += width; + y += height; + width = 5; + height = 5; + buffer.pos(x, y, 0).color(0, 0, 0, startAlpha).endVertex(); + buffer.pos(x, y + height, 0).color(0, 0, 0, 0).endVertex(); + buffer.pos(x + width, y + height, 0).color(0, 0, 0, 0).endVertex(); + + buffer.pos(x, y, 0).color(0, 0, 0, startAlpha).endVertex(); + buffer.pos(x + width, y + height, 0).color(0, 0, 0, 0).endVertex(); + buffer.pos(x + width, y, 0).color(0, 0, 0, 0).endVertex(); + tessellator.draw(); + GlStateManager.shadeModel(GL11.GL_FLAT); + GlStateManager.enableAlpha(); + GlStateManager.enableTexture2D(); + } + super.drawInBackground(mouseX, mouseY, partialTicks, context); + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java index 10dfee6a877..191d3b8a7f0 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java @@ -1,22 +1,28 @@ package gregtech.api.terminal.gui.widgets.guide; import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.stream.JsonReader; import gregtech.api.gui.GuiTextures; import gregtech.api.gui.Widget; import gregtech.api.gui.resources.ColorRectTexture; import gregtech.api.gui.resources.TextTexture; import gregtech.api.gui.widgets.ImageWidget; -import gregtech.api.gui.widgets.LabelWidget; -import gregtech.api.gui.widgets.TabGroup; -import gregtech.api.gui.widgets.TextFieldWidget; +import gregtech.api.gui.widgets.*; import gregtech.api.gui.widgets.tab.IGuiTextureTabInfo; +import gregtech.api.terminal.app.GuideEditorApp; import gregtech.api.terminal.gui.CustomTabListRenderer; import gregtech.api.terminal.gui.widgets.CircleButtonWidget; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; import gregtech.api.terminal.gui.widgets.TextEditorWidget; +import gregtech.api.terminal.gui.widgets.os.TerminalDialogWidget; +import gregtech.api.util.Position; import gregtech.api.util.Size; import java.awt.*; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; import java.util.Map; public class GuideConfigEditor extends TabGroup { @@ -26,8 +32,9 @@ public class GuideConfigEditor extends TabGroup { private final DraggableScrollableWidgetGroup widgetSelector; private final DraggableScrollableWidgetGroup widgetConfigurator; private final CircleButtonWidget[] addButton; + private final GuideEditorApp app; - public GuideConfigEditor(int x, int y, int width, int height) { + public GuideConfigEditor(int x, int y, int width, int height, GuideEditorApp app) { super(x, y + 10, new CustomTabListRenderer( new ColorRectTexture(new Color(175, 0, 0, 131)), new ColorRectTexture(new Color(246, 120, 120, 190)), 30, 10)); @@ -60,7 +67,7 @@ public GuideConfigEditor(int x, int y, int width, int height) { new Color(146, 253, 118).getRGB()) .setIcon(GuiTextures.TERMINAL_ADD) .setHoverText("Export Config") - .setClickListener(this::getJson)); + .setClickListener(this::saveJson)); addButton[0] = new CircleButtonWidget(115, 15, 8, 1, 8) .setColors(new Color(255, 255, 255, 0).getRGB(), new Color(255, 255, 255).getRGB(), @@ -77,6 +84,7 @@ public GuideConfigEditor(int x, int y, int width, int height) { .setClickListener(this::addFixed); addButton[0].setVisible(false); addButton[1].setVisible(false); + this.app = app; this.addWidget(addButton[0]); this.addWidget(addButton[1]); } @@ -97,25 +105,16 @@ private DraggableScrollableWidgetGroup createPageConfig() { pageEditor.setSection(s); } }, true) + .setTextSupplier(pageEditor::getSection, true) .setMaxStringLength(Integer.MAX_VALUE) .setValidator(s->true)); group.addWidget(new ImageWidget(5, 48,116, 1, new ColorRectTexture(-1))); group.addWidget(new LabelWidget(5, 55, "title", -1).setShadow(true)); - group.addWidget(new TextEditorWidget(5, 65, 116, 70, "Template", s->{ + group.addWidget(new TextEditorWidget(5, 65, 116, 70, s->{ if (pageEditor != null) { pageEditor.setTitle(s); } - }, true).setBackground(new ColorRectTexture(0xA3FFFFFF))); -// group.addWidget(new ImageWidget(5, 148,116, 1, new ColorRectTexture(-1))); -// group.addWidget(new LabelWidget(5, 155, "translate key", -1).setShadow(true)); -// group.addWidget(new TextFieldWidget(5, 165, 116, 20, new ColorRectTexture(0x9f000000), null, null) -// .setTextResponder(s->{ -// if (pageEditor != null) { -// pageEditor.setTranslateKey(s); -// } -// }, true) -// .setMaxStringLength(Integer.MAX_VALUE) -// .setValidator(s->true)); + }, true).setContent(pageEditor.getTitle()).setBackground(new ColorRectTexture(0xA3FFFFFF))); return group; } @@ -128,11 +127,12 @@ private DraggableScrollableWidgetGroup createWidgetSelector() { for (Map.Entry entry : GuidePageWidget.REGISTER_WIDGETS.entrySet()) { IGuideWidget widgetTemplate = entry.getValue(); JsonObject template = widgetTemplate.getTemplate(false); - Widget guideWidget = widgetTemplate.createStreamWidget(5, y + 10, getSize().width - 14, template); + Widget guideWidget = widgetTemplate.updateOrCreateStreamWidget(5, y + 10, getSize().width - 14, template); group.addWidget(new LabelWidget(getSize().width / 2 - 1, y - 3, entry.getKey(), -1).setXCentered(true).setShadow(true)); y += guideWidget.getSize().height + 25; group.addWidget(guideWidget); } + group.addWidget(new WidgetGroup(new Position(5, group.getWidgetBottomHeight() + 5), Size.ZERO)); return group; } @@ -147,18 +147,41 @@ public void loadConfigurator(IGuideWidget widget) { widgetConfigurator.clearAllWidgets(); if (widget != null) { widget.loadConfigurator(widgetConfigurator, widget.getConfig(), widget.isFixed(), widget::updateValue); + widgetConfigurator.addWidget(new WidgetGroup(new Position(5, widgetConfigurator.getWidgetBottomHeight() + 5), Size.ZERO)); } } private void loadJson(ClickData data) { if(pageEditor != null) { - System.out.println(pageEditor.getJsonString()); + File file = new File("terminal\\guide_editor"); + TerminalDialogWidget.showFileDialog(app.getOs(), "Load Json", file, true, result->{ + if (result != null && result.isFile()) { + try { + FileReader reader = new FileReader(result); + pageEditor.loadJsonConfig(new JsonParser().parse(new JsonReader(reader)).getAsJsonObject()); + reader.close(); + } catch (Exception e) { + TerminalDialogWidget.showInfoDialog(app.getOs(), "ERROR", "An error occurred while loading the file.").setClientSide().open(); + } + } + }).setClientSide().open(); } } - private void getJson(ClickData data) { + private void saveJson(ClickData data) { if(pageEditor != null) { - System.out.println(pageEditor.getJsonString()); + File file = new File("terminal\\guide_editor"); + TerminalDialogWidget.showFileDialog(app.getOs(), "Save Json", file, false, result->{ + if (result != null) { + try { + FileWriter writer = new FileWriter(result); + writer.write(pageEditor.getJsonString()); + writer.close(); + } catch (Exception e) { + TerminalDialogWidget.showInfoDialog(app.getOs(), "ERROR", "An error occurred while saving the file.").setClientSide().open(); + } + } + }).setClientSide().open(); } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java index 15df7a65329..9283f11a7f7 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java @@ -14,6 +14,8 @@ import gregtech.api.util.Size; import gregtech.api.util.interpolate.Eases; import gregtech.api.util.interpolate.Interpolator; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.renderer.GlStateManager; import java.awt.*; @@ -26,7 +28,6 @@ public class GuidePageEditorWidget extends GuidePageWidget { private final CustomPositionSizeWidget customPositionSizeWidget; private GuideConfigEditor configEditor; private String section = "default"; -// private String translateKey = ""; public GuidePageEditorWidget(int xPosition, int yPosition, int width, int height, int margin) { super(xPosition, yPosition, width, height, margin); @@ -64,9 +65,9 @@ public void setSection(String section) { this.section = section; } -// public void setTranslateKey(String translateKey) { -// this.translateKey = translateKey; -// } + public String getSection() { + return section; + } private void onPosSizeChanged(Position pos, Size size) { Widget widget = customPositionSizeWidget.getControlled(); @@ -153,7 +154,7 @@ public JsonObject addGuideWidget(IGuideWidget widget, boolean isFixed) { int width = widgetConfig.get("width").getAsInt(); int height = widgetConfig.get("height").getAsInt(); - guideWidget = widget.createFixedWidget( + guideWidget = widget.updateOrCreateFixedWidget( (pageWidth - width) / 2 + 5, this.scrollYOffset + (this.getSize().height - height) / 2, width, @@ -163,7 +164,7 @@ public JsonObject addGuideWidget(IGuideWidget widget, boolean isFixed) { this.addWidget(guideWidget); } else { int y = getStreamBottom(); - guideWidget = widget.createStreamWidget(margin, y + 5, pageWidth - 2 * margin, widgetConfig); + guideWidget = widget.updateOrCreateStreamWidget(margin, y + 5, pageWidth - 2 * margin, widgetConfig); stream.add(guideWidget); this.addWidget(guideWidget); } @@ -194,6 +195,13 @@ public void moveUp(Widget widget) { stream.add(index - 1, widget); }).start(); } + } else { + int index2 = fixed.indexOf(widget); + if (index2 >= 0 && index2 < fixed.size() - 1) { + Widget target = fixed.get(index2 + 1); + fixed.remove(widget); + fixed.add(index2 + 1, widget); + } } } @@ -220,6 +228,13 @@ public void moveDown(Widget widget) { stream.add(index + 1, widget); }).start(); } + } else { + int index2 = fixed.indexOf(widget); + if (index2 > 0) { + Widget target = fixed.get(index2 - 1); + fixed.remove(widget); + fixed.add(index2 - 1, widget); + } } } @@ -259,7 +274,8 @@ public boolean mouseClicked(int mouseX, int mouseY, int button) { return true; } boolean flag = false; - for (Widget widget : fixed) { + for (int i = fixed.size() - 1; i >= 0; i--) { + Widget widget = fixed.get(i); if (widget.isMouseOverElement(mouseX, mouseY)) { if (widget instanceof IGuideWidget && widget != selected) { configEditor.loadConfigurator((IGuideWidget) widget); @@ -290,8 +306,10 @@ public boolean mouseClicked(int mouseX, int mouseY, int button) { @Override protected boolean hookDrawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { - Position position = getPosition(); - Size size = getSize(); + int x = getPosition().x; + int y = getPosition().y; + int width = getSize().width; + int height = getSize().height; if(title.isVisible()) { title.drawInBackground(mouseX, mouseY, partialTicks, context); } @@ -310,7 +328,7 @@ protected boolean hookDrawInBackground(int mouseX, int mouseY, float partialTick Position pos = widget.getPosition(); Size s = widget.getSize(); if (stream.contains(widget)) { - drawSolidRect(position.x, pos.y, size.width - yBarWidth, s.height, 0x6f000000); + drawSolidRect(x, pos.y, width - yBarWidth, s.height, 0x6f000000); } else { drawSolidRect(pos.x, pos.y, s.width, s.height, 0x6f000000); @@ -326,7 +344,7 @@ protected boolean hookDrawInBackground(int mouseX, int mouseY, float partialTick Position pos = widget.getPosition(); Size s = widget.getSize(); if (stream.contains(widget)) { - drawSolidRect(position.x, pos.y, size.width - yBarWidth, s.height, 0x6f000000); + drawSolidRect(x, pos.y, width - yBarWidth, s.height, 0x6f000000); } else { drawSolidRect(pos.x, pos.y, s.width, s.height, 0x6f000000); } @@ -335,13 +353,13 @@ protected boolean hookDrawInBackground(int mouseX, int mouseY, float partialTick } if (selected != null) { -// Position pos = selected.getPosition(); -// Size s = selected.getSize(); -// if (stream.contains(selected)) { -// drawSolidRect(position.x, pos.y, size.width - yBarWidth, s.height, 0x6f0000ff); -// } else { -// drawSolidRect(pos.x, pos.y, s.width, s.height, 0x6f0000ff); -// } + FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer; + int index = fixed.indexOf(selected); + String layer = "L: " + (index >= 0 ? index : stream.indexOf(selected)); + fontRenderer.drawString(layer, + selected.getPosition().x + (selected.getSize().width - fontRenderer.getStringWidth(layer)) / 2, + selected.getPosition().y - 20, + 0xffff0000, true); } if(toolButtons.isVisible()) { customPositionSizeWidget.drawInBackground(mouseX, mouseY, partialTicks, context); @@ -359,4 +377,16 @@ public boolean mouseDragged(int mouseX, int mouseY, int button, long timeDragged } return false; } + + @Override + public void clearAllWidgets() { + super.clearAllWidgets(); + selected = null; + configEditor.loadConfigurator(null); + toolButtons.setSelfPosition(new Position(-scrollYOffset, -scrollYOffset)); + customPositionSizeWidget.setControlled(null); + toolButtons.setVisible(false); + addWidget(customPositionSizeWidget); + addWidget(toolButtons); + } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java index 61669ee62d3..fa3ef7fe26a 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java @@ -21,6 +21,9 @@ public class GuidePageWidget extends DraggableScrollableWidgetGroup { static { //register guide widgets REGISTER_WIDGETS.put(TextBoxWidget.NAME, new TextBoxWidget()); REGISTER_WIDGETS.put(ImageWidget.NAME, new ImageWidget()); + REGISTER_WIDGETS.put(CardWidget.NAME, new CardWidget()); + REGISTER_WIDGETS.put(SlotListWidget.NAME, new SlotListWidget()); + REGISTER_WIDGETS.put(TankListWidget.NAME, new TankListWidget()); } protected TextBoxWidget title; protected List stream = new ArrayList<>(); @@ -72,6 +75,10 @@ public void setTitle(String config) { } } + public String getTitle() { + return title == null ? "" : String.join("\n", title.content); + } + public String loadJsonConfig(String config) { try { loadJsonConfig(new JsonParser().parse(config).getAsJsonObject()); @@ -83,6 +90,10 @@ public String loadJsonConfig(String config) { } public void loadJsonConfig(JsonObject config) { + this.stream.clear(); + this.fixed.clear(); + this.title = null; + this.clearAllWidgets(); int pageWidth = getPageWidth(); int margin = getMargin(); // add title @@ -94,7 +105,7 @@ public void loadJsonConfig(JsonObject config) { int y = title.getSize().height + 10; for (JsonElement element : config.getAsJsonArray("stream")) { JsonObject widgetConfig = element.getAsJsonObject(); - Widget widget = REGISTER_WIDGETS.get(widgetConfig.get("type").getAsString()).createStreamWidget(margin, y, pageWidth - 2 * margin, widgetConfig); + Widget widget = REGISTER_WIDGETS.get(widgetConfig.get("type").getAsString()).updateOrCreateStreamWidget(margin, y, pageWidth - 2 * margin, widgetConfig); y += widget.getSize().height + 5; stream.add(widget); this.addWidget(widget); @@ -105,7 +116,7 @@ public void loadJsonConfig(JsonObject config) { fixed = new ArrayList<>(); for (JsonElement element : config.getAsJsonArray("fixed")) { JsonObject widgetConfig = element.getAsJsonObject(); - Widget widget = REGISTER_WIDGETS.get(widgetConfig.get("type").getAsString()).createFixedWidget( + Widget widget = REGISTER_WIDGETS.get(widgetConfig.get("type").getAsString()).updateOrCreateFixedWidget( widgetConfig.get("x").getAsInt(), widgetConfig.get("y").getAsInt(), widgetConfig.get("width").getAsInt(), diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java index 4adc3648aa6..9cf86a39b6d 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java @@ -1,7 +1,6 @@ package gregtech.api.terminal.gui.widgets.guide; import com.google.gson.Gson; -import com.google.gson.JsonElement; import com.google.gson.JsonObject; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; @@ -14,10 +13,8 @@ import gregtech.api.util.Size; import net.minecraft.item.ItemStack; -import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; -import java.util.Map; import java.util.function.Consumer; public abstract class GuideWidget extends Widget implements IGuideWidget { @@ -29,7 +26,6 @@ public abstract class GuideWidget extends Widget implements IGuideWidget { public String link; public List hover_text; - private static final Gson GSON = new Gson(); private transient boolean isFixed; protected transient GuidePageWidget page; protected transient JsonObject config; @@ -44,26 +40,6 @@ public GuideWidget(){ public abstract String getRegistryName(); - public void updateValue(String field) { - if (config != null && config.has(field)) { - try { - Field f = this.getClass().getField(field); - JsonElement value = config.get(field); - if (value.isJsonNull()) { // default - f.set(this, f.get(GuidePageWidget.REGISTER_WIDGETS.get(getRegistryName()))); - } else { - f.set(this, new Gson().fromJson(value, f.getType())); - } - if (isFixed) { - initFixed(); - } else { - initStream(); - } - } catch (Exception e) { - } - } - } - @Override public JsonObject getConfig() { return config; @@ -74,9 +50,10 @@ public boolean isFixed() { return isFixed; } - @Override - public void onFixedPositionSizeChanged(Position position, Size size) { - this.initFixed(); + protected abstract Widget initFixed(); + + protected Widget initStream(){ + return initFixed(); } @Override @@ -102,11 +79,6 @@ protected void recomputePosition() { } } - @Override - public void setSelfPosition(Position selfPosition) { - super.setSelfPosition(selfPosition); - } - @Override public JsonObject getTemplate(boolean isFixed) { JsonObject template = new JsonObject(); @@ -128,12 +100,12 @@ public JsonObject getTemplate(boolean isFixed) { @Override public void loadConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, boolean isFixed, Consumer needUpdate) { - group.addWidget(new ColorConfigurator(5, group.getWidgetBottomHeight() + 5, config, "fill", 0).setOnUpdated(needUpdate)); - group.addWidget(new ColorConfigurator(5, group.getWidgetBottomHeight() + 5, config, "stroke", 0).setOnUpdated(needUpdate)); - group.addWidget(new NumberConfigurator(5, group.getWidgetBottomHeight() + 5, config, "stroke_width", 1).setOnUpdated(needUpdate)); - group.addWidget(new StringConfigurator(5, group.getWidgetBottomHeight() + 5, config, "ref", "").setOnUpdated(needUpdate)); - group.addWidget(new StringConfigurator(5, group.getWidgetBottomHeight() + 5, config, "link", "").setOnUpdated(needUpdate)); - group.addWidget(new TextListConfigurator(5, group.getWidgetBottomHeight() + 5, 40, config, "hover_text", true).setOnUpdated(needUpdate)); + group.addWidget(new ColorConfigurator(group, config, "fill", 0).setOnUpdated(needUpdate)); + group.addWidget(new ColorConfigurator(group, config, "stroke", 0).setOnUpdated(needUpdate)); + group.addWidget(new NumberConfigurator(group, config, "stroke_width", 1).setOnUpdated(needUpdate)); + group.addWidget(new StringConfigurator(group, config, "ref", "").setOnUpdated(needUpdate)); + group.addWidget(new StringConfigurator(group, config, "link", "").setOnUpdated(needUpdate)); + group.addWidget(new TextListConfigurator(group, 40, config, "hover_text", "").setOnUpdated(needUpdate)); } @Override @@ -142,8 +114,11 @@ public String getRef() { } @Override - public Widget createStreamWidget(int x, int y, int pageWidth, JsonObject config) { - GuideWidget widget = GSON.fromJson(config, this.getClass()); + public Widget updateOrCreateStreamWidget(int x, int y, int pageWidth, JsonObject config) { + if (config == null) { + return initStream(); + } + GuideWidget widget = new Gson().fromJson(config, this.getClass()); widget.isFixed = false; widget.setSelfPosition(new Position(x, y)); widget.setSize(new Size(pageWidth, 0)); @@ -152,8 +127,11 @@ public Widget createStreamWidget(int x, int y, int pageWidth, JsonObject config) } @Override - public Widget createFixedWidget(int x, int y, int width, int height, JsonObject config) { - GuideWidget widget = GSON.fromJson(config, this.getClass()); + public Widget updateOrCreateFixedWidget(int x, int y, int width, int height, JsonObject config) { + if (config == null) { + return initFixed(); + } + GuideWidget widget = new Gson().fromJson(config, this.getClass()); widget.isFixed = true; widget.setSelfPosition(new Position(x, y)); widget.setSize(new Size(width, height)); @@ -161,14 +139,6 @@ public Widget createFixedWidget(int x, int y, int width, int height, JsonObject return widget.initFixed(); } - protected Widget initStream() { - return initFixed(); - } - - protected Widget initFixed() { - return this; - } - @Override public void setPage(GuidePageWidget page) { this.page = page; @@ -198,7 +168,7 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender drawBorder(position.x, position.y, size.width, size.height, stroke, stroke_width); } if (fill != 0) { - drawGradientRect(position.x, position.y, size.width, size.height, fill, fill); + drawSolidRect(position.x, position.y, size.width, size.height, fill); } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidgetGroup.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidgetGroup.java new file mode 100644 index 00000000000..3dc31404fb2 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidgetGroup.java @@ -0,0 +1,195 @@ +package gregtech.api.terminal.gui.widgets.guide; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.Widget; +import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; +import gregtech.api.terminal.gui.widgets.guide.configurator.ColorConfigurator; +import gregtech.api.terminal.gui.widgets.guide.configurator.NumberConfigurator; +import gregtech.api.terminal.gui.widgets.guide.configurator.StringConfigurator; +import gregtech.api.terminal.gui.widgets.guide.configurator.TextListConfigurator; +import gregtech.api.util.Position; +import gregtech.api.util.Size; +import net.minecraft.item.ItemStack; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +public abstract class GuideWidgetGroup extends WidgetGroup implements IGuideWidget { + //config + public String ref; + public int fill; + public int stroke; + public int stroke_width = 1; + public String link; + public List hover_text; + + private transient boolean isFixed; + protected transient GuidePageWidget page; + protected transient JsonObject config; + + public GuideWidgetGroup(int x, int y, int width, int height) { + super(x, y, width, height); + } + + public GuideWidgetGroup(){ + super(Position.ORIGIN, Size.ZERO); + } + + public abstract String getRegistryName(); + + @Override + public JsonObject getConfig() { + return config; + } + + @Override + public boolean isFixed() { + return isFixed; + } + + @Override + public void setStroke(int color) { + this.stroke = color; + } + + @Override + public void setSize(Size size) { + Size oldSize = this.getSize(); + super.setSize(size); + if (page != null) { + page.onSizeUpdate(this, oldSize); + } + } + + @Override + protected void recomputePosition() { + Position oldPosition = getPosition(); + super.recomputePosition(); + if (page != null) { + page.onPositionUpdate(this, oldPosition); + } + } + + @Override + public JsonObject getTemplate(boolean isFixed) { + JsonObject template = new JsonObject(); + template.addProperty("type", getRegistryName()); + if (isFixed) { + template.addProperty("x", 0); + template.addProperty("y", 0); + template.addProperty("width", 100); + template.addProperty("height", 100); + } + template.addProperty("ref", (String) null); + template.addProperty("stroke", (String) null); + template.addProperty("stroke_width", (String) null); + template.addProperty("fill", (String) null); + template.addProperty("link", (String) null); + template.add("hover_text", new Gson().toJsonTree(hover_text)); + return template; + } + + @Override + public void loadConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, boolean isFixed, Consumer needUpdate) { + group.addWidget(new ColorConfigurator(group, config, "fill", 0).setOnUpdated(needUpdate)); + group.addWidget(new ColorConfigurator(group, config, "stroke", 0).setOnUpdated(needUpdate)); + group.addWidget(new NumberConfigurator(group, config, "stroke_width", 1).setOnUpdated(needUpdate)); + group.addWidget(new StringConfigurator(group, config, "ref", "").setOnUpdated(needUpdate)); + group.addWidget(new StringConfigurator(group, config, "link", "").setOnUpdated(needUpdate)); + group.addWidget(new TextListConfigurator(group, 40, config, "hover_text", "").setOnUpdated(needUpdate)); + } + + @Override + public String getRef() { + return ref; + } + + protected Widget initStream() { + return initFixed(); + } + + protected abstract Widget initFixed(); + + @Override + public Widget updateOrCreateStreamWidget(int x, int y, int pageWidth, JsonObject config) { + if (config == null) { + return initStream(); + } + GuideWidgetGroup widget = new Gson().fromJson(config, this.getClass()); + widget.isFixed = false; + widget.setSelfPosition(new Position(x, y)); + widget.setSize(new Size(pageWidth, 0)); + widget.config = config; + return widget.initStream(); + } + + @Override + public Widget updateOrCreateFixedWidget(int x, int y, int width, int height, JsonObject config) { + if (config == null) { + return initFixed(); + } + GuideWidgetGroup widget = new Gson().fromJson(config, this.getClass()); + widget.isFixed = true; + widget.setSelfPosition(new Position(x, y)); + widget.setSize(new Size(width, height)); + widget.config = config; + return widget.initFixed(); + } + + @Override + public void setPage(GuidePageWidget page) { + this.page = page; + } + + @Override + public void addWidget(Widget widget) { + super.addWidget(widget); + if (widget instanceof IGuideWidget) { + ((IGuideWidget) widget).setPage(page); + } + } + + @Override + public void drawInForeground(int mouseX, int mouseY) { + if (link != null && isMouseOverElement(mouseX, mouseY)) { + Position position = getPosition(); + Size size = getSize(); + drawBorder(position.x, position.y, size.width, size.height, 0xff0000ff, stroke_width); + } + if ((hover_text != null || link != null) && isMouseOverElement(mouseX, mouseY)) { + List tooltip = hover_text == null ? new ArrayList<>() : new ArrayList<>(hover_text); + if (link != null) { + tooltip.add("§9Ctrl+Click§r §e(" + link + ")§r"); + } + drawHoveringText(ItemStack.EMPTY, tooltip, 100, mouseX, mouseY); + } + super.drawInForeground(mouseX, mouseY); + } + + @Override + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + Position position = getPosition(); + Size size = getSize(); + if(stroke != 0) { + drawBorder(position.x, position.y, size.width, size.height, stroke, stroke_width); + } + if (fill != 0) { + drawSolidRect(position.x, position.y, size.width, size.height, fill); + } + super.drawInBackground(mouseX, mouseY, partialTicks, context); + } + + @Override + public boolean mouseClicked(int mouseX, int mouseY, int button) { + if (link != null && isMouseOverElement(mouseX, mouseY) && isCtrlDown()) { + page.jumpToRef(link); + return true; + } + return super.mouseClicked(mouseX, mouseY, button); + } + +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java index 99c387e7a83..5b55547f941 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java @@ -1,23 +1,48 @@ package gregtech.api.terminal.gui.widgets.guide; +import com.google.gson.Gson; +import com.google.gson.JsonElement; import com.google.gson.JsonObject; import gregtech.api.gui.Widget; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; import gregtech.api.util.Position; import gregtech.api.util.Size; +import java.lang.reflect.Field; import java.util.function.Consumer; public interface IGuideWidget { + String getRegistryName(); JsonObject getConfig(); boolean isFixed(); - Widget createStreamWidget(int x, int y, int pageWidth, JsonObject config); - Widget createFixedWidget(int x, int y, int width, int height, JsonObject config); + Widget updateOrCreateStreamWidget(int x, int y, int pageWidth, JsonObject config); + Widget updateOrCreateFixedWidget(int x, int y, int width, int height, JsonObject config); void setPage(GuidePageWidget page); - void updateValue(String field); + default void updateValue(String field){ + JsonObject config = getConfig(); + if (config != null && config.has(field)) { + try { + Field f = this.getClass().getField(field); + JsonElement value = config.get(field); + if (value.isJsonNull()) { // default + f.set(this, f.get(GuidePageWidget.REGISTER_WIDGETS.get(getRegistryName()))); + } else { + f.set(this, new Gson().fromJson(value, f.getGenericType())); + } + if (isFixed()) { + updateOrCreateFixedWidget(0,0,0,0,null); + } else { + updateOrCreateStreamWidget(0,0,0,null); + } + } catch (Exception e) { + } + } + } String getRef(); JsonObject getTemplate(boolean isFixed); void loadConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, boolean isFixed, Consumer needUpdate); void setStroke(int color); - void onFixedPositionSizeChanged(Position position, Size size); + default void onFixedPositionSizeChanged(Position position, Size size) { + updateOrCreateFixedWidget(0,0,0,0,null); + } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java index 2a45c6d6530..83900ef19bc 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java @@ -39,8 +39,8 @@ public String getRegistryName() { @Override public JsonObject getTemplate(boolean isFixed) { JsonObject template = super.getTemplate(isFixed); - template.addProperty("form", "item"); - template.addProperty("source", "minecraft:ender_pearl"); + template.addProperty("form", "resource"); + template.addProperty("source", "gregtech:textures/gui/icon/gregtech_logo.png"); template.addProperty("width", 50); template.addProperty("height", 50); return template; @@ -49,11 +49,11 @@ public JsonObject getTemplate(boolean isFixed) { @Override public void loadConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, boolean isFixed, Consumer needUpdate) { super.loadConfigurator(group, config, isFixed, needUpdate); - group.addWidget(new SelectorConfigurator(5, group.getWidgetBottomHeight() + 5, config, "form", Arrays.asList("url", "item", "resource")).setOnUpdated(needUpdate)); - group.addWidget(new StringConfigurator(5, group.getWidgetBottomHeight() + 5, config, "source").setOnUpdated(needUpdate)); + group.addWidget(new SelectorConfigurator(group, config, "form", Arrays.asList("url", "item", "resource")).setOnUpdated(needUpdate)); + group.addWidget(new StringConfigurator(group, config, "source").setOnUpdated(needUpdate)); if (!isFixed) { - group.addWidget(new NumberConfigurator(5, group.getWidgetBottomHeight() + 5, config, "width").setOnUpdated(needUpdate)); - group.addWidget(new NumberConfigurator(5, group.getWidgetBottomHeight() + 5, config, "height").setOnUpdated(needUpdate)); + group.addWidget(new NumberConfigurator(group, config, "width").setOnUpdated(needUpdate)); + group.addWidget(new NumberConfigurator(group, config, "height").setOnUpdated(needUpdate)); } } @@ -64,11 +64,6 @@ public void updateScreen() { } } - @Override - public void onFixedPositionSizeChanged(Position position, Size size) { - super.onFixedPositionSizeChanged(position, size); - } - @Override protected Widget initStream() { int pageWidth = getSize().width; @@ -78,12 +73,14 @@ protected Widget initStream() { x = page.getMargin(); pageWidth = page.getPageWidth() - 2 * x; } - this.setSelfPosition(new Position(x + (pageWidth - width) / 2, y)); + this.setSelfPosition(new Position(x + (pageWidth - Math.max(0, width)) / 2, y)); return initFixed(); } @Override protected Widget initFixed() { + width = Math.max(0, width); + height = Math.max(0, height); this.setSize(new Size(width, height)); switch (form) { case "url": diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/SlotListWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/SlotListWidget.java new file mode 100644 index 00000000000..502d8b7f29c --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/SlotListWidget.java @@ -0,0 +1,126 @@ +package gregtech.api.terminal.gui.widgets.guide; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.ColorRectTexture; +import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.widgets.SlotWidget; +import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; +import gregtech.api.terminal.gui.widgets.guide.configurator.ItemStackConfigurator; +import gregtech.api.util.Size; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.items.ItemStackHandler; + +import java.awt.*; +import java.util.Collections; +import java.util.List; +import java.util.function.Consumer; + +public class SlotListWidget extends GuideWidgetGroup { + public final static String NAME = "slots"; + + // config + public List item_list; + + protected transient Rectangle scissor; + + @Override + public Widget initFixed() { + this.clearAllWidgets(); + ItemStackHandler itemStackHandler = new ItemStackHandler(item_list.size()); + IGuiTexture background = new ColorRectTexture(0x4f000000); + int size = item_list.size(); + int maxXSize = getSize().width / 18; + int xPos; + if (maxXSize < 1) { + maxXSize = 1; + xPos = 0; + } else { + xPos = (getSize().width - (Math.min(size, maxXSize)) * 18) / 2; + } + int maxYSize = size / maxXSize + ((size % maxXSize) == 0 ? 0 : 1); + for (int y = 0; y <= size / maxXSize; y++) { + for (int x = 0; x < maxXSize; x++) { + int i = x + y * maxXSize; + if (i < size) { + itemStackHandler.setStackInSlot(i, item_list.get(i).getInstance()); + SlotWidget widget = new SlotWidget(itemStackHandler, i, xPos + x * 18, y * 18, false, false); + widget.setBackgroundTexture(background); + if (scissor != null) { + widget.applyScissor(scissor.x, scissor.y, scissor.width, scissor.height); + } + this.addWidget(widget); + } + } + } + setSize(new Size(getSize().width / 18 > 0 ? getSize().width : 18, maxYSize * 18)); + return this; + } + + @Override + public String getRegistryName() { + return NAME; + } + + @Override + public JsonObject getTemplate(boolean isFixed) { + JsonObject template = super.getTemplate(isFixed); + template.add("item_list", new Gson().toJsonTree(Collections.singletonList(new ItemStackInfo("gregtech:meta_item_2", 32581, 1)))); + return template; + } + + @Override + public void loadConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, boolean isFixed, Consumer needUpdate) { + super.loadConfigurator(group, config, isFixed, needUpdate); + group.addWidget(new ItemStackConfigurator(group, config, "item_list").setOnUpdated(needUpdate)); + } + + @Override + public void applyScissor(int parentX, int parentY, int parentWidth, int parentHeight) { + super.applyScissor(parentX, parentY, parentWidth, parentHeight); + scissor = new Rectangle(parentX, parentY, parentWidth, parentHeight); + } + + public static class ItemStackInfo { + // config + public String id; + public int damage; + public int count = 1; + + private transient ItemStack itemStack; + + public ItemStackInfo() { + + } + + public void update(ItemStack itemStack) { + ResourceLocation resourceLocation = itemStack.getItem().getRegistryName(); + id = resourceLocation == null ? "minecraft:air" : resourceLocation.toString(); + damage = itemStack.getItemDamage(); + count = itemStack.getCount(); + } + + public ItemStackInfo(String id, int damage, int count) { + this.id = id; + this.damage = damage; + this.count = count; + } + + public ItemStack getInstance() { + if (itemStack == null && id != null) { + Item item = Item.getByNameOrId(id); + if (item == null) { + itemStack = ItemStack.EMPTY; + return itemStack; + } + itemStack = item.getDefaultInstance(); + itemStack.setCount(count); + itemStack.setItemDamage(damage); + } + return itemStack == null ? ItemStack.EMPTY : itemStack; + } + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TankListWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TankListWidget.java new file mode 100644 index 00000000000..adac67ca2df --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TankListWidget.java @@ -0,0 +1,119 @@ +package gregtech.api.terminal.gui.widgets.guide; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.ColorRectTexture; +import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.widgets.TankWidget; +import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; +import gregtech.api.terminal.gui.widgets.guide.configurator.ItemStackConfigurator; +import gregtech.api.util.Size; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidRegistry; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.FluidTank; +import net.minecraftforge.items.ItemStackHandler; + +import java.awt.*; +import java.util.Collections; +import java.util.List; +import java.util.function.Consumer; + +public class TankListWidget extends GuideWidgetGroup { + public final static String NAME = "tanks"; + + // config + public List fluid_list; + + protected transient Rectangle scissor; + + @Override + public Widget initFixed() { + this.clearAllWidgets(); + IGuiTexture background = new ColorRectTexture(0x4f000000); + int size = fluid_list.size(); + int maxXSize = getSize().width / 18; + int xPos; + if (maxXSize < 1) { + maxXSize = 1; + xPos = 0; + } else { + xPos = (getSize().width - (Math.min(size, maxXSize)) * 18) / 2; + } + int maxYSize = size / maxXSize + ((size % maxXSize) == 0 ? 0 : 1); + for (int y = 0; y <= size / maxXSize; y++) { + for (int x = 0; x < maxXSize; x++) { + int i = x + y * maxXSize; + if (i < size) { + FluidStack fluidStack = fluid_list.get(i).getInstance(); + TankWidget widget = new TankWidget(new FluidTank(fluidStack, fluid_list.get(i).amount), xPos + x * 18, y * 18, 18, 18); + widget.setBackgroundTexture(background); + this.addWidget(widget); + } + } + } + setSize(new Size(getSize().width / 18 > 0 ? getSize().width : 18, maxYSize * 18)); + return this; + } + + @Override + public String getRegistryName() { + return NAME; + } + + @Override + public JsonObject getTemplate(boolean isFixed) { + JsonObject template = super.getTemplate(isFixed); + template.add("fluid_list", new Gson().toJsonTree(Collections.singletonList(new FluidStackInfo("distilled_water", 1)))); + return template; + } + + @Override + public void loadConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, boolean isFixed, Consumer needUpdate) { + super.loadConfigurator(group, config, isFixed, needUpdate); +// group.addWidget(new ItemStackConfigurator(group, config, "fluid_list").setOnUpdated(needUpdate)); + } + + @Override + public void applyScissor(int parentX, int parentY, int parentWidth, int parentHeight) { + super.applyScissor(parentX, parentY, parentWidth, parentHeight); + scissor = new Rectangle(parentX, parentY, parentWidth, parentHeight); + } + + public static class FluidStackInfo { + // config + public String id; + public int amount = 1; + + private transient FluidStack fluidStack; + + public FluidStackInfo() { + + } + + public void update(FluidStack itemStack) { + id = FluidRegistry.getFluidName(itemStack.getFluid()); + amount = itemStack.amount; + } + + public FluidStackInfo(String id, int amount) { + this.id = id; + this.amount = amount; + } + + public FluidStack getInstance() { + if (fluidStack == null && id != null) { + Fluid fluid = FluidRegistry.getFluid(id); + if (fluid != null) { + fluidStack = new FluidStack(fluid, amount); + } + id = null; + } + return fluidStack; + } + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java index 02eb98e8e9e..1d4fbcb06c7 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java @@ -70,12 +70,12 @@ public JsonObject getTemplate(boolean isFixed) { @Override public void loadConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, boolean isFixed, Consumer needUpdate) { super.loadConfigurator(group, config, isFixed, needUpdate); - group.addWidget(new NumberConfigurator(5, group.getWidgetBottomHeight() + 5, config, "space", 1).setOnUpdated(needUpdate)); - group.addWidget(new NumberConfigurator(5, group.getWidgetBottomHeight() + 5, config, "fontSize", 9).setOnUpdated(needUpdate)); - group.addWidget(new ColorConfigurator(5, group.getWidgetBottomHeight() + 5, config, "fontColor", 0xff000000).setOnUpdated(needUpdate)); - group.addWidget(new BooleanConfigurator(5, group.getWidgetBottomHeight() + 5, config, "isShadow", false).setOnUpdated(needUpdate)); - group.addWidget(new BooleanConfigurator(5, group.getWidgetBottomHeight() + 5, config, "isCenter", false).setOnUpdated(needUpdate)); - group.addWidget(new TextListConfigurator(5, group.getWidgetBottomHeight() + 5, 200, config, "content", false).setOnUpdated(needUpdate)); + group.addWidget(new NumberConfigurator(group, config, "space", 1).setOnUpdated(needUpdate)); + group.addWidget(new NumberConfigurator(group, config, "fontSize", 9).setOnUpdated(needUpdate)); + group.addWidget(new ColorConfigurator(group, config, "fontColor", 0xff000000).setOnUpdated(needUpdate)); + group.addWidget(new BooleanConfigurator(group, config, "isShadow", false).setOnUpdated(needUpdate)); + group.addWidget(new BooleanConfigurator(group, config, "isCenter", false).setOnUpdated(needUpdate)); + group.addWidget(new TextListConfigurator(group, 200, config, "content").setOnUpdated(needUpdate)); } @Override diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java deleted file mode 100644 index d7dca38ab5d..00000000000 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextTreeWidget.java +++ /dev/null @@ -1,150 +0,0 @@ -package gregtech.api.terminal.gui.widgets.guide; - -import com.google.gson.JsonObject; -import gregtech.api.gui.IRenderContext; -import gregtech.api.gui.Widget; -import gregtech.api.gui.resources.IGuiTexture; -import gregtech.api.terminal.util.TreeNode; -import gregtech.api.util.Position; -import gregtech.api.util.RenderUtil; -import gregtech.api.util.Size; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.FontRenderer; -import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.client.resources.I18n; -import net.minecraft.util.Tuple; -import net.minecraft.util.math.MathHelper; - -import java.util.ArrayList; -import java.util.List; -import java.util.function.Consumer; -import java.util.function.Function; - -public class TextTreeWidget extends Widget { - private static final int ITEM_HEIGHT = 11; - protected int scrollOffset; - protected List> list; - protected TreeNode selected; - protected IGuiTexture background; - protected IGuiTexture nodeTexture; - protected IGuiTexture leafTexture; - protected Consumer> onSelected; - protected Function iconSupplier; - protected Function nameSupplier; - - public TextTreeWidget(int xPosition, int yPosition, int width, int height, - TreeNode root, - Consumer> onSelected, - Function iconSupplier, - Function nameSupplier) { - super(new Position(xPosition, yPosition), new Size(width, height)); - list = new ArrayList<>(); - if (root.children != null) { - list.addAll(root.children); - } - this.onSelected = onSelected; - this.iconSupplier = iconSupplier; - this.nameSupplier = nameSupplier; - } - - public TextTreeWidget setBackground(IGuiTexture background) { - this.background = background; - return this; - } - - public TextTreeWidget setNodeTexture(IGuiTexture nodeTexture) { - this.nodeTexture = nodeTexture; - return this; - } - - public TextTreeWidget setLeafTexture(IGuiTexture leafTexture) { - this.leafTexture = leafTexture; - return this; - } - - @Override - public boolean mouseWheelMove(int mouseX, int mouseY, int wheelDelta) { - if (this.isMouseOverElement(mouseX, mouseY, true)) { - int moveDelta = -MathHelper.clamp(wheelDelta, -1, 1) * 5; - this.scrollOffset = MathHelper.clamp(scrollOffset + moveDelta, 0, Math.max(list.size() * ITEM_HEIGHT - getSize().height, 0)); - return true; - } - return false; - } - - @Override - public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { - Position position = getPosition(); - Size size = getSize(); - if (background != null) { - background.draw(position.x, position.y, size.width, size.height); - } else { - drawGradientRect(position.x, position.y, size.width, size.height, 0x8f000000, 0x8f000000); - } - RenderUtil.useScissor(position.x, position.y, size.width, size.height, ()->{ - FontRenderer fr = Minecraft.getMinecraft().fontRenderer; - int minToRender = scrollOffset / ITEM_HEIGHT; - int maxToRender = Math.min(list.size(), size.height / ITEM_HEIGHT + 2 + minToRender); - - for (int i = minToRender; i < maxToRender; i++) { - GlStateManager.color(1,1,1,1); - TreeNode node = list.get(i); - int x = position.x + 10 * node.dimension; - int y = position.y - scrollOffset + i * ITEM_HEIGHT; - String name = node.key; - if (node.isLeaf()) { - if (leafTexture != null) { - leafTexture.draw(position.x, y, size.width, ITEM_HEIGHT); - } else { - drawSolidRect(position.x, y, size.width, ITEM_HEIGHT, 0xffff0000); - } - if (node.content != null) { - String nameS = nameSupplier.apply(node.content); - name = nameS == null ? name : nameS; - IGuiTexture icon = iconSupplier.apply(node.content); - if (icon != null) { - icon.draw(x - 9, y + 1, 8, 8); - } - } - } else { - if (nodeTexture != null) { - nodeTexture.draw(position.x, y, size.width, ITEM_HEIGHT); - } else { - drawSolidRect(position.x, y, size.width, ITEM_HEIGHT, 0xffffff00); - } - } - if (node == selected) { - drawSolidRect(position.x, y, size.width, ITEM_HEIGHT, 0x7f000000); - } - fr.drawString(I18n.format(name), x, y + 2, 0xff000000); - } - }); - } - - @Override - public boolean mouseClicked(int mouseX, int mouseY, int button) { - if (this.isMouseOverElement(mouseX, mouseY)) { - int index = ((mouseY - getPosition().y) + scrollOffset) / ITEM_HEIGHT; - if (index < list.size()) { - TreeNode node = list.get(index); - if (node.isLeaf()) { - if (node != this.selected) { - this.selected = node; - onSelected.accept(node); - } - } else if (node.children.size() > 0 && list.contains(node.children.get(0))){ - for (TreeNode child : node.children) { - list.remove(child); - } - } else { - for (int i = 0; i < node.children.size(); i++) { - list.add(index + 1 + i, node.children.get(i)); - } - } - playButtonClickSound(); - } - return true; - } - return false; - } -} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/BooleanConfigurator.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/BooleanConfigurator.java index 2b4c4ae2ca8..8c3b3c567ea 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/BooleanConfigurator.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/BooleanConfigurator.java @@ -3,27 +3,24 @@ import com.google.gson.JsonObject; import gregtech.api.gui.GuiTextures; import gregtech.api.gui.resources.ColorRectTexture; +import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; import gregtech.api.terminal.gui.widgets.RectButtonWidget; import java.awt.*; -public class BooleanConfigurator extends ConfiguratorWidget{ - private boolean defaultValue; +public class BooleanConfigurator extends ConfiguratorWidget{ - public BooleanConfigurator(int x, int y, JsonObject config, String name) { - super(x, y, config, name, false); - init(); + public BooleanConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, String name) { + super(group, config, name); } - public BooleanConfigurator(int x, int y, JsonObject config, String name, boolean defaultValue) { - super(x, y, config, name, true); - this.defaultValue = defaultValue; - init(); + public BooleanConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, String name, boolean defaultValue) { + super(group, config, name, defaultValue); } - private void init(){ + protected void init(){ this.addWidget(new RectButtonWidget(0, 15, 10, 10, 2) - .setToggleButton(new ColorRectTexture(new Color(198, 198, 198).getRGB()), (c, p)-> update(p)) + .setToggleButton(new ColorRectTexture(new Color(198, 198, 198).getRGB()), (c, p)->updateValue(p)) .setValueSupplier(true, ()->{ if(config.get(name).isJsonNull()) { return defaultValue; @@ -35,9 +32,4 @@ private void init(){ new Color(255, 255, 255, 0).getRGB()) .setIcon(new ColorRectTexture(new Color(0, 0, 0, 74).getRGB()))); } - - private void update(boolean bool) { - config.addProperty(name, bool); - update(); - } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ColorConfigurator.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ColorConfigurator.java index f52019325ec..605593b0166 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ColorConfigurator.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ColorConfigurator.java @@ -2,33 +2,26 @@ import com.google.gson.JsonObject; import gregtech.api.terminal.gui.widgets.ColorWidget; +import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; -public class ColorConfigurator extends ConfiguratorWidget{ - private int defaultValue; +public class ColorConfigurator extends ConfiguratorWidget{ - public ColorConfigurator(int x, int y, JsonObject config, String name, int defaultValue) { - super(x, y, config, name, true); - this.defaultValue = defaultValue; - init(); + public ColorConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, String name, int defaultValue) { + super(group, config, name, defaultValue); } - public ColorConfigurator(int x, int y, JsonObject config, String name) { - super(x, y, config, name, false); - init(); + public ColorConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, String name) { + super(group, config, name); } - private void init(){ + protected void init(){ this.addWidget(new ColorWidget(0, 15, 85, 10).setColorSupplier(()->{ if(config.get(name).isJsonNull()) { return defaultValue; } return config.get(name).getAsInt(); - },true).setOnColorChanged(this::update)); + },true).setOnColorChanged(this::updateValue)); } - private void update(int color) { - config.addProperty(name, color); - update(); - } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ConfiguratorWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ConfiguratorWidget.java index 42b25898006..15c7fb5c561 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ConfiguratorWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ConfiguratorWidget.java @@ -1,9 +1,11 @@ package gregtech.api.terminal.gui.widgets.guide.configurator; +import com.google.gson.Gson; import com.google.gson.JsonObject; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.widgets.LabelWidget; import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; import gregtech.api.util.Position; import net.minecraft.client.Minecraft; import net.minecraft.item.ItemStack; @@ -11,20 +13,30 @@ import java.util.Collections; import java.util.function.Consumer; -public class ConfiguratorWidget extends WidgetGroup { +public class ConfiguratorWidget extends WidgetGroup { + protected T defaultValue; protected String name; protected boolean canDefault; protected boolean isDefault; protected JsonObject config; - + protected DraggableScrollableWidgetGroup group; private int nameWidth; private Consumer onUpdated; - public ConfiguratorWidget(int x, int y, JsonObject config, String name, boolean canDefault) { - super(new Position(x, y)); + public ConfiguratorWidget(DraggableScrollableWidgetGroup group, JsonObject config, String name) { + this(group, config, name, null); + } + + public ConfiguratorWidget(DraggableScrollableWidgetGroup group, JsonObject config, String name, T defaultValue) { + super(new Position(5, group.getWidgetBottomHeight() + 5)); + this.group = group; + this.defaultValue = defaultValue; this.name = name; - this.canDefault = canDefault; + this.canDefault = defaultValue != null; this.config = config; + if (config.get(name) == null) { + config.addProperty(name, (String)null); + } if (canDefault && config.get(name).isJsonNull()) { isDefault = true; } @@ -32,9 +44,20 @@ public ConfiguratorWidget(int x, int y, JsonObject config, String name, boolean if (isClientSide()) { nameWidth = Minecraft.getMinecraft().fontRenderer.getStringWidth(name); } + init(); + } + + protected void init() { + + } + + protected void updateValue(T value) { + if (canDefault && isDefault) return; + config.add(name, new Gson().toJsonTree(value)); + update(); } - public ConfiguratorWidget setOnUpdated(Consumer onUpdated) { + public ConfiguratorWidget setOnUpdated(Consumer onUpdated) { this.onUpdated = onUpdated; return this; } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/FluidStackConfigurator.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/FluidStackConfigurator.java new file mode 100644 index 00000000000..515003db110 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/FluidStackConfigurator.java @@ -0,0 +1,97 @@ +package gregtech.api.terminal.gui.widgets.guide.configurator; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import gregtech.api.gui.GuiTextures; +import gregtech.api.gui.resources.ColorRectTexture; +import gregtech.api.gui.resources.TextTexture; +import gregtech.api.gui.widgets.*; +import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; +import gregtech.api.terminal.gui.widgets.RectButtonWidget; +import gregtech.api.terminal.gui.widgets.guide.TankListWidget; + +import java.awt.*; +import java.util.ArrayList; +import java.util.List; + +public class FluidStackConfigurator extends ConfiguratorWidget>{ + DraggableScrollableWidgetGroup container; + List tanks; + + public FluidStackConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, String name) { + super(group, config, name); + } + + protected void init() { + container = new DraggableScrollableWidgetGroup(0, 27,116, 100); + this.addWidget(container); + this.addWidget(new RectButtonWidget(0, 15, 116, 10, 1) + .setIcon(new TextTexture("Add Slot", -1)) + .setClickListener(cd->{ + addSlot(container, new TankListWidget.FluidStackInfo(null, 0)); + updateValue(); + }) + .setColors(new Color(0, 0, 0, 74).getRGB(), + new Color(128, 255, 128).getRGB(), + new Color(255, 255, 255, 0).getRGB())); + tanks = new ArrayList<>(); + if (!config.get(name).isJsonNull()) { + Gson gson = new Gson(); + for (JsonElement o : config.get(name).getAsJsonArray()) { + addSlot(container, gson.fromJson(o, TankListWidget.FluidStackInfo.class)); + } + } + } + + private void addSlot(DraggableScrollableWidgetGroup container, TankListWidget.FluidStackInfo fluidStackInfo) { + WidgetGroup group = new WidgetGroup(0, tanks.size() * 20, 116, 20); + tanks.add(fluidStackInfo); + group.addWidget(new PhantomFluidWidget(1, 1, 18, 18, null, null) + .setBackgroundTexture(new ColorRectTexture(0x9f000000)) + .setFluidStackSupplier(fluidStackInfo::getInstance, true) + .setFluidStackUpdater(fluidStack->{ + fluidStackInfo.update(fluidStack); + updateValue(); + }, true)); + group.addWidget(new RectButtonWidget(20, 0, 20, 20) + .setColors(new Color(0, 0, 0, 74).getRGB(), + new Color(128, 255, 128).getRGB(), + new Color(255, 255, 255, 0).getRGB()) + .setClickListener(data -> { + fluidStackInfo.amount = Math.max(0, fluidStackInfo.amount - (data.isShiftClick ? 10 : 1)); + updateValue(); + }) + .setIcon(new TextTexture("-1", -1))); + group.addWidget(new RectButtonWidget(76, 0, 20, 20) + .setColors(new Color(0, 0, 0, 74).getRGB(), + new Color(128, 255, 128).getRGB(), + new Color(255, 255, 255, 0).getRGB()) + .setClickListener(data -> { + fluidStackInfo.amount = Math.max(0, fluidStackInfo.amount + (data.isShiftClick ? 10 : 1)); + updateValue(); + }) + .setIcon(new TextTexture("+1", -1))); + group.addWidget(new ImageWidget(40, 0, 36, 20, new ColorRectTexture(0x9f000000))); + group.addWidget(new SimpleTextWidget(58, 10, "", 0xFFFFFF, () -> Integer.toString(fluidStackInfo.amount), true)); + group.addWidget(new RectButtonWidget(96, 0, 20, 20) + .setColors(new Color(0, 0, 0, 74).getRGB(), + new Color(128, 255, 128).getRGB(), + new Color(255, 255, 255, 0).getRGB()) + .setClickListener(data -> { + container.waitToRemoved(group); + tanks.remove(fluidStackInfo); + int index = container.widgets.indexOf(group); + for (int i = container.widgets.size() - 1; i > index; i--) { + container.widgets.get(i).addSelfPosition(0, -20); + } + updateValue(); + }) + .setIcon(GuiTextures.TERMINAL_DELETE)); + container.addWidget(group); + } + + private void updateValue() { + updateValue(tanks); + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ItemStackConfigurator.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ItemStackConfigurator.java new file mode 100644 index 00000000000..1ddc765534e --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ItemStackConfigurator.java @@ -0,0 +1,101 @@ +package gregtech.api.terminal.gui.widgets.guide.configurator; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import gregtech.api.gui.GuiTextures; +import gregtech.api.gui.resources.ColorRectTexture; +import gregtech.api.gui.resources.TextTexture; +import gregtech.api.gui.widgets.ImageWidget; +import gregtech.api.gui.widgets.PhantomSlotWidget; +import gregtech.api.gui.widgets.SimpleTextWidget; +import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; +import gregtech.api.terminal.gui.widgets.RectButtonWidget; +import gregtech.api.terminal.gui.widgets.guide.SlotListWidget; +import net.minecraftforge.items.IItemHandlerModifiable; +import net.minecraftforge.items.ItemStackHandler; + +import java.awt.*; +import java.util.ArrayList; +import java.util.List; + +public class ItemStackConfigurator extends ConfiguratorWidget>{ + DraggableScrollableWidgetGroup container; + List slots; + + public ItemStackConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, String name) { + super(group, config, name); + } + + protected void init() { + container = new DraggableScrollableWidgetGroup(0, 27,116, 100); + this.addWidget(container); + this.addWidget(new RectButtonWidget(0, 15, 116, 10, 1) + .setIcon(new TextTexture("Add Slot", -1)) + .setClickListener(cd->{ + addSlot(container, new SlotListWidget.ItemStackInfo("minecraft:air", 0, 0)); + updateValue(); + }) + .setColors(new Color(0, 0, 0, 74).getRGB(), + new Color(128, 255, 128).getRGB(), + new Color(255, 255, 255, 0).getRGB())); + slots = new ArrayList<>(); + if (!config.get(name).isJsonNull()) { + Gson gson = new Gson(); + for (JsonElement o : config.get(name).getAsJsonArray()) { + addSlot(container, gson.fromJson(o, SlotListWidget.ItemStackInfo.class)); + } + } + } + + private void addSlot(DraggableScrollableWidgetGroup container, SlotListWidget.ItemStackInfo itemStackInfo) { + WidgetGroup group = new WidgetGroup(0,slots.size() * 20, 116, 20); + slots.add(itemStackInfo); + IItemHandlerModifiable handler = new ItemStackHandler(); + handler.setStackInSlot(0, itemStackInfo.getInstance()); + group.addWidget(new PhantomSlotWidget(handler, 0, 1, 1).setBackgroundTexture(new ColorRectTexture(0x9f000000)).setChangeListener(()->{ + itemStackInfo.update(handler.getStackInSlot(0)); + updateValue(); + })); + group.addWidget(new RectButtonWidget(20, 0, 20, 20) + .setColors(new Color(0, 0, 0, 74).getRGB(), + new Color(128, 255, 128).getRGB(), + new Color(255, 255, 255, 0).getRGB()) + .setClickListener(data -> { + itemStackInfo.count = Math.max(0, itemStackInfo.count - (data.isShiftClick ? 10 : 1)); + updateValue(); + }) + .setIcon(new TextTexture("-1", -1))); + group.addWidget(new RectButtonWidget(76, 0, 20, 20) + .setColors(new Color(0, 0, 0, 74).getRGB(), + new Color(128, 255, 128).getRGB(), + new Color(255, 255, 255, 0).getRGB()) + .setClickListener(data -> { + itemStackInfo.count = Math.max(0, itemStackInfo.count + (data.isShiftClick ? 10 : 1)); + updateValue(); + }) + .setIcon(new TextTexture("+1", -1))); + group.addWidget(new ImageWidget(40, 0, 36, 20, new ColorRectTexture(0x9f000000))); + group.addWidget(new SimpleTextWidget(58, 10, "", 0xFFFFFF, () -> Integer.toString(itemStackInfo.count), true)); + group.addWidget(new RectButtonWidget(96, 0, 20, 20) + .setColors(new Color(0, 0, 0, 74).getRGB(), + new Color(128, 255, 128).getRGB(), + new Color(255, 255, 255, 0).getRGB()) + .setClickListener(data -> { + container.waitToRemoved(group); + slots.remove(itemStackInfo); + int index = container.widgets.indexOf(group); + for (int i = container.widgets.size() - 1; i > index; i--) { + container.widgets.get(i).addSelfPosition(0, -20); + } + updateValue(); + }) + .setIcon(GuiTextures.TERMINAL_DELETE)); + container.addWidget(group); + } + + private void updateValue() { + updateValue(slots); + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/NumberConfigurator.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/NumberConfigurator.java index 58c4c8fb059..0779e0e661a 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/NumberConfigurator.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/NumberConfigurator.java @@ -7,25 +7,22 @@ import gregtech.api.gui.resources.TextTexture; import gregtech.api.gui.widgets.ImageWidget; import gregtech.api.gui.widgets.SimpleTextWidget; +import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; import gregtech.api.terminal.gui.widgets.RectButtonWidget; import java.awt.*; -public class NumberConfigurator extends ConfiguratorWidget{ - private int defaultValue; +public class NumberConfigurator extends ConfiguratorWidget{ - public NumberConfigurator(int x, int y, JsonObject config, String name) { - super(x, y, config, name, false); - init(0); + public NumberConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, String name) { + super(group, config, name); } - public NumberConfigurator(int x, int y, JsonObject config, String name, int defaultValue) { - super(x, y, config, name, true); - init(defaultValue); + public NumberConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, String name, int defaultValue) { + super(group, config, name, defaultValue); } - private void init(int defaultValue){ - this.defaultValue = defaultValue; + protected void init(){ int y = 15; this.addWidget(new RectButtonWidget(0, y, 20, 20) .setColors(new Color(0, 0, 0, 74).getRGB(), @@ -63,11 +60,12 @@ private void init(int defaultValue){ private void adjustTransferRate(int added) { JsonElement element = config.get(name); - int num = defaultValue; + int num = 0; if (!element.isJsonNull()) { num = element.getAsInt(); + } else { + num = defaultValue; } - config.addProperty(name, num + added); - update(); + updateValue(num + added); } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/SelectorConfigurator.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/SelectorConfigurator.java index eaeec766e7f..054f159ee57 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/SelectorConfigurator.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/SelectorConfigurator.java @@ -1,34 +1,24 @@ package gregtech.api.terminal.gui.widgets.guide.configurator; -import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import gregtech.api.gui.GuiTextures; -import gregtech.api.gui.resources.TextTexture; -import gregtech.api.gui.widgets.ImageWidget; -import gregtech.api.gui.widgets.SimpleTextWidget; -import gregtech.api.terminal.gui.widgets.RectButtonWidget; +import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; import gregtech.api.terminal.gui.widgets.SelectorWidget; import java.awt.*; import java.util.List; -public class SelectorConfigurator extends ConfiguratorWidget{ - private final List candidates; - private String defaultValue; - public SelectorConfigurator(int x, int y, JsonObject config, String name, List candidates, String defaultValue) { - super(x, y, config, name, true); - this.defaultValue = defaultValue; - this.candidates = candidates; - init(); +public class SelectorConfigurator extends ConfiguratorWidget{ + public SelectorConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, String name, List candidates, String defaultValue) { + super(group, config, name, defaultValue); + init(candidates); } - public SelectorConfigurator(int x, int y, JsonObject config, String name, List candidates) { - super(x, y, config, name, false); - this.candidates = candidates; - init(); + public SelectorConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, String name, List candidates) { + super(group, config, name); + init(candidates); } - private void init(){ + protected void init(List candidates){ this.addWidget(new SelectorWidget(0, 15, 80, 20, candidates, -1, ()->{ if(config.get(name).isJsonNull()) { return defaultValue; @@ -42,8 +32,4 @@ private void init(){ .setOnChanged(this::updateValue)); } - private void updateValue(String selected) { - config.addProperty(name, selected); - update(); - } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/StringConfigurator.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/StringConfigurator.java index 3ffba684148..fa5cc9616c2 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/StringConfigurator.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/StringConfigurator.java @@ -5,28 +5,23 @@ import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.resources.TextTexture; import gregtech.api.gui.widgets.TextFieldWidget; +import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; import gregtech.api.terminal.gui.widgets.RectButtonWidget; import java.awt.*; -public class StringConfigurator extends ConfiguratorWidget{ - private String defaultValue = ""; +public class StringConfigurator extends ConfiguratorWidget{ private TextFieldWidget textFieldWidget; - public StringConfigurator(int x, int y, JsonObject config, String name) { - super(x, y, config, name, false); - init(); - textFieldWidget.setCurrentString(config.get(name).isJsonNull() ? defaultValue : config.get(name).getAsString()); + public StringConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, String name) { + super(group, config, name); } - public StringConfigurator(int x, int y, JsonObject config, String name, String defaultValue) { - super(x, y, config, name, true); - this.defaultValue = defaultValue; - init(); - textFieldWidget.setCurrentString(config.get(name).isJsonNull() ? defaultValue : config.get(name).getAsString()); + public StringConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, String name, String defaultValue) { + super(group, config, name, defaultValue); } - private void init() { + protected void init() { this.addWidget(new RectButtonWidget(76, 15, 40, 20) .setColors(new Color(0, 0, 0, 74).getRGB(), new Color(128, 255, 128).getRGB(), @@ -40,8 +35,7 @@ private void init() { } private void updateString() { - config.addProperty(name, textFieldWidget.getCurrentString()); - update(); + updateValue(textFieldWidget.getCurrentString()); } @Override diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/TextListConfigurator.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/TextListConfigurator.java index 23a12ac1ead..1fae4a6711d 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/TextListConfigurator.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/TextListConfigurator.java @@ -2,39 +2,45 @@ import com.google.gson.*; import gregtech.api.gui.resources.ColorRectTexture; +import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; import gregtech.api.terminal.gui.widgets.TextEditorWidget; import net.minecraft.client.resources.I18n; +import java.util.Arrays; +import java.util.Collections; import java.util.List; -public class TextListConfigurator extends ConfiguratorWidget{ +public class TextListConfigurator extends ConfiguratorWidget>{ + private TextEditorWidget editor; - public TextListConfigurator(int x, int y, int height, JsonObject config, String name, boolean canDefault) { - super(x, y, config, name, canDefault); + public TextListConfigurator(DraggableScrollableWidgetGroup group, int height, JsonObject config, String name) { + super(group, config, name); + init(height); + } + + public TextListConfigurator(DraggableScrollableWidgetGroup group, int height, JsonObject config, String name, String defaultValue) { + super(group, config, name, Collections.singletonList(defaultValue)); + init(height); + } + + protected void init(int height) { JsonElement element = config.get(name); - if (element.isJsonNull()) { - init(height, ""); - } else { + String initValue = ""; + if (!element.isJsonNull()) { List init = new Gson().fromJson(element, List.class); - StringBuilder s = new StringBuilder(); - for (int i = 0; i < init.size(); i++) { - s.append(I18n.format(init.get(i).toString())); - if(i != init.size() - 1) { - s.append('\n'); - } - } - init(height, s.toString()); + initValue = String.join("\n", init); + } + editor = new TextEditorWidget(0, 15, 116, height, this::updateTextList, true).setContent(initValue).setBackground(new ColorRectTexture(0xA3FFFFFF)); + this.addWidget(editor); } - private void init(int height, String init) { - this.addWidget(new TextEditorWidget(0, 15, 116, height, init, this::updateTextList, true).setBackground(new ColorRectTexture(0xA3FFFFFF))); + private void updateTextList(String saved) { + updateValue(Collections.singletonList(saved)); } - private void updateTextList(String saved) { - JsonArray array = new JsonArray(); - array.add(saved); - config.add(name, array); - update(); + @Override + protected void onDefault() { + editor.setContent(defaultValue.get(0)); } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalDialogWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalDialogWidget.java new file mode 100644 index 00000000000..115420349cd --- /dev/null +++ b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalDialogWidget.java @@ -0,0 +1,270 @@ +package gregtech.api.terminal.gui.widgets.os; + +import gregtech.api.gui.GuiTextures; +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.ColorRectTexture; +import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.resources.TextureArea; +import gregtech.api.gui.widgets.*; +import gregtech.api.terminal.gui.widgets.AnimaWidgetGroup; +import gregtech.api.terminal.gui.widgets.CircleButtonWidget; +import gregtech.api.terminal.gui.widgets.ColorWidget; +import gregtech.api.terminal.gui.widgets.TreeListWidget; +import gregtech.api.terminal.util.FileTree; +import gregtech.api.util.Size; +import gregtech.api.util.interpolate.Interpolator; +import net.minecraft.inventory.IInventory; +import net.minecraft.network.PacketBuffer; + +import java.io.File; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; +import java.util.function.Predicate; + +public class TerminalDialogWidget extends AnimaWidgetGroup { + private static final IGuiTexture DIALOG_BACKGROUND = TextureArea.fullImage("textures/gui/terminal/terminal_dialog.png"); + private static final IGuiTexture OK_NORMAL = TextureArea.fullImage("textures/gui/terminal/ok_normal.png"); + private static final IGuiTexture OK_HOVER = TextureArea.fullImage("textures/gui/terminal/ok_hover.png"); + private static final IGuiTexture OK_DISABLE = TextureArea.fullImage("textures/gui/terminal/ok_disable.png"); + private static final IGuiTexture CANCEL_NORMAL = TextureArea.fullImage("textures/gui/terminal/cancel_normal.png"); + private static final IGuiTexture CANCEL_HOVER = TextureArea.fullImage("textures/gui/terminal/cancel_hover.png"); + private static final IGuiTexture CANCEL_DISABLE = TextureArea.fullImage("textures/gui/terminal/cancel_disable.png"); + private static final int HEIGHT = 128; + private static final int WIDTH = 184; + + protected Interpolator interpolator; + private final TerminalOSWidget os; + private IGuiTexture background; + private boolean isClient; + + private TerminalDialogWidget(TerminalOSWidget os, int x, int y, int width, int height) { + super(x, y, width, height); + this.os = os; + } + + public boolean isClient() { + return isClient; + } + + public void open(){ + os.openDialog(this); + } + + public TerminalDialogWidget setClientSide() { + this.isClient = true; + return this; + } + + public TerminalDialogWidget setBackground(IGuiTexture background) { + this.background = background; + return this; + } + + public TerminalDialogWidget addOkButton() { + addWidget(new CircleButtonWidget(WIDTH / 2, HEIGHT - 22, 12, 0, 24) + .setClickListener(cd -> os.closeDialog(this)) + .setColors(0, 0, 0) + .setIcon(OK_NORMAL) + .setHoverIcon(OK_HOVER)); + return this; + } + + public TerminalDialogWidget addConfirmButton(Consumer result) { + addWidget(new CircleButtonWidget(WIDTH / 2 - 30, HEIGHT - 22, 12, 0, 24) + .setClickListener(cd -> { + os.closeDialog(this); + if (result != null) + result.accept(true); + }) + .setColors(0, 0, 0) + .setIcon(OK_NORMAL) + .setHoverIcon(OK_HOVER)); + addWidget(new CircleButtonWidget(WIDTH / 2 + 30, HEIGHT - 22, 12, 0, 24) + .setClickListener(cd -> { + os.closeDialog(this); + if (result != null) + result.accept(false); + }) + .setColors(0, 0, 0) + .setIcon(CANCEL_NORMAL) + .setHoverIcon(CANCEL_HOVER)); + return this; + } + + public TerminalDialogWidget addTitle(String title) { + this.addWidget(new LabelWidget(WIDTH / 2, 11, title, -1).setXCentered(true)); + return this; + } + + public TerminalDialogWidget addInfo(String info) { + this.addWidget(new LabelWidget(WIDTH / 2, HEIGHT / 2 - 10, info, -1).setXCentered(true)); + return this; + } + + public TerminalDialogWidget addPlayerInventory() { + IInventory inventoryPlayer = os.getModularUI().entityPlayer.inventory; + int x = 20; + int y = 20; + for (int row = 0; row < 3; row++) { + for (int col = 0; col < 9; col++) { + this.addWidget(new SlotWidget(inventoryPlayer, col + (row + 1) * 9, x + col * 18, y + row * 18, true, true) + .setBackgroundTexture(GuiTextures.SLOT) + .setLocationInfo(true, false)); + } + } + y+=58; + for (int slot = 0; slot < 9; slot++) { + this.addWidget(new SlotWidget(inventoryPlayer, slot, x + slot * 18, y, true, true) + .setBackgroundTexture(GuiTextures.SLOT) + .setLocationInfo(true, true)); + } + return this; + } + + public static TerminalDialogWidget createEmptyTemplate(TerminalOSWidget os) { + Size size = os.getSize(); + return new TerminalDialogWidget(os, (size.width - WIDTH) / 2, (size.height - HEIGHT) / 2, WIDTH, HEIGHT).setBackground(DIALOG_BACKGROUND); + } + + public static TerminalDialogWidget showInfoDialog(TerminalOSWidget os, String title, String info) { + return createEmptyTemplate(os).addTitle(title).addInfo(info).addOkButton(); + } + + public static TerminalDialogWidget showConfirmDialog(TerminalOSWidget os, String info, Consumer result) { + TerminalDialogWidget dialog = createEmptyTemplate(os).addConfirmButton(result); + dialog.addWidget(new LabelWidget(WIDTH / 2, HEIGHT / 2 - 10, info, -1).setXCentered(true)); + return dialog; + } + + public static TerminalDialogWidget showTextFieldDialog(TerminalOSWidget os, String title, Predicate validator, Consumer result) { + TextFieldWidget textFieldWidget = new TextFieldWidget(WIDTH / 2 - 50, HEIGHT / 2 - 15, 100, 20, new ColorRectTexture(0x2fffffff), null, null).setValidator(validator); + TerminalDialogWidget dialog = createEmptyTemplate(os).addTitle(title).addConfirmButton(b -> { + if (b) { + if (result != null) + result.accept(textFieldWidget.getCurrentString()); + } else { + if (result != null) + result.accept(null); + } + }); + dialog.addWidget(textFieldWidget); + return dialog; + } + + public static TerminalDialogWidget showColorDialog(TerminalOSWidget os, String title, Consumer result) { + TerminalDialogWidget dialog = createEmptyTemplate(os).addTitle(title); + ColorWidget colorWidget = new ColorWidget(WIDTH / 2 - 60, HEIGHT / 2 - 35, 80, 10); + dialog.addWidget(colorWidget); + dialog.addConfirmButton(b -> { + if (b) { + if (result != null) + result.accept(colorWidget.getColor()); + } else { + if (result != null) + result.accept(null); + } + }); + return dialog; + } + + public static TerminalDialogWidget showFileDialog(TerminalOSWidget os, String title, File dir, boolean isSelector, Consumer result) { + Size size = os.getSize(); + TerminalDialogWidget dialog = new TerminalDialogWidget(os, 0, 0, size.width, size.height) + .setBackground(new ColorRectTexture(0x4f000000)); + if (!dir.isDirectory()) { + if (!dir.mkdirs()) { + return dialog.addInfo("error file path: " + dir.getPath()).addOkButton(); + } + } + AtomicReference selected = new AtomicReference<>(); + dialog.addWidget(new TreeListWidget<>(0, 0, 130, size.height, new FileTree(dir), node -> { + selected.set(node.getKey()); + System.out.println(node.toString()); + }).setNodeTexture(GuiTextures.BORDERED_BACKGROUND) + .canSelectNode(true) + .setLeafTexture(GuiTextures.SLOT_DARKENED)); + int x = 130 + (size.width - 133 - WIDTH) / 2; + int y = (size.height - HEIGHT) / 2; + dialog.addWidget(new ImageWidget(x, y, WIDTH, HEIGHT, DIALOG_BACKGROUND)); + dialog.addWidget(new CircleButtonWidget(x + WIDTH / 2 - 30, y + HEIGHT - 22, 12, 0, 24) + .setClickListener(cd -> { + os.closeDialog(dialog); + if (result != null) + result.accept(selected.get()); + }) + .setColors(0, 0, 0) + .setIcon(OK_NORMAL) + .setHoverIcon(OK_HOVER)); + dialog.addWidget(new CircleButtonWidget(x + WIDTH / 2 + 30, y + HEIGHT - 22, 12, 0, 24) + .setClickListener(cd -> { + os.closeDialog(dialog); + if (result != null) + result.accept(null); + }) + .setColors(0, 0, 0) + .setIcon(CANCEL_NORMAL) + .setHoverIcon(CANCEL_HOVER)); + if (isSelector) { + dialog.addWidget(new SimpleTextWidget(x + WIDTH / 2, y + HEIGHT / 2 - 5, "", -1, () -> { + if (selected.get() != null) { + return selected.get().toString(); + } + return "no file selected"; + }, true)); + } else { + dialog.addWidget(new TextFieldWidget(x + WIDTH / 2, y + HEIGHT / 2 - 5, 76, 20, new ColorRectTexture(0x4f000000), null, null) + .setTextResponder(res->{ + File file = selected.get(); + if (file == null) return; + if (file.isDirectory()) { + selected.set(new File(file, res)); + } else { + selected.set(new File(file.getParent(), res)); + } + },true) + .setTextSupplier(()->{ + File file = selected.get(); + if (file != null && !file.isDirectory()) { + return selected.get().getName(); + } + return ""; + }, true) + .setMaxStringLength(Integer.MAX_VALUE) + .setValidator(s->true)); + } + + dialog.addWidget(new LabelWidget(x + WIDTH / 2, y + 11, title, -1).setXCentered(true)); + os.menu.hideMenu(); + return dialog; + } + + @Override + public void hookDrawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + if (background != null) { + background.draw(getPosition().x, getPosition().y, getSize().width, getSize().height); + } + super.hookDrawInBackground(mouseX, mouseY, partialTicks, context); + } + + @Override + public boolean mouseClicked(int mouseX, int mouseY, int button) { + for (int i = widgets.size() - 1; i >= 0; i--) { + Widget widget = widgets.get(i); + if (widget.isVisible()) { + if (widget instanceof SlotWidget) { + return false; + } else if(widget.mouseClicked(mouseX, mouseY, button)){ + return true; + } + } + } + return true; + } + + @Override + protected void writeClientAction(int id, Consumer packetBufferWriter) { + if (isClient) return; + super.writeClientAction(id, packetBufferWriter); + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalMenuWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalMenuWidget.java index 935ce7f4948..0524137b242 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalMenuWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalMenuWidget.java @@ -12,6 +12,7 @@ import net.minecraft.client.renderer.GlStateManager; import java.awt.*; +import java.io.File; public class TerminalMenuWidget extends WidgetGroup { private Interpolator interpolator; @@ -64,11 +65,14 @@ public void minimize(ClickData clickData) { } public void maximize(ClickData clickData) { - + TerminalDialogWidget.showColorDialog(os, "test", System.out::println).addPlayerInventory().open(); } public void setting(ClickData clickData) { - +// TerminalDialogWidget.showInfoDialog(os, "test"); +// TerminalDialogWidget.showConfirmDialog(os, "test", null); +// TerminalDialogWidget.showTextFieldDialog(os, "test", s->true, System.out::println); +// TerminalDialogWidget.showFileDialog(os, "test", new File("./"), System.out::println).setClientSide().open(); } public void hideMenu() { diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalOSWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalOSWidget.java index 00589d4ca61..6668a0b09b9 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalOSWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalOSWidget.java @@ -2,36 +2,25 @@ import gregtech.api.gui.GuiTextures; import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.ModularUI; import gregtech.api.gui.Widget; import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.widgets.AbstractWidgetGroup; -import gregtech.api.gui.widgets.WidgetGroup; import gregtech.api.terminal.app.AbstractApplication; -import gregtech.api.terminal.gui.widgets.CircleButtonWidget; import gregtech.api.util.Position; import gregtech.api.util.RenderUtil; import gregtech.api.util.Size; -import gregtech.api.util.interpolate.Eases; -import gregtech.api.util.interpolate.Interpolator; -import javafx.application.Application; -import javafx.geometry.Pos; -import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import java.util.ArrayList; -import java.util.Collections; import java.util.List; -import static gregtech.api.gui.impl.ModularUIGui.*; - public class TerminalOSWidget extends AbstractWidgetGroup { private IGuiTexture background; public final List openedApps; public AbstractApplication focusApp; public final TerminalMenuWidget menu; public final TerminalDesktopWidget desktop; - public List waitToRemoved; private NBTTagCompound tabletNBT; public TerminalOSWidget(int xPosition, int yPosition, int width, int height, NBTTagCompound tabletNBT) { @@ -41,10 +30,13 @@ public TerminalOSWidget(int xPosition, int yPosition, int width, int height, NBT this.menu = new TerminalMenuWidget(Position.ORIGIN, new Size(31, 232), this).setBackground(GuiTextures.TERMINAL_MENU); this.addWidget(desktop); this.addWidget(menu); - this.waitToRemoved = new ArrayList<>(); this.tabletNBT = tabletNBT; } + public ModularUI getModularUI(){ + return this.gui; + } + public TerminalOSWidget setBackground(IGuiTexture background) { this.background = background; return this; @@ -69,7 +61,7 @@ public void openApplication(AbstractApplication application, boolean isClient) { if (!tabletNBT.hasKey(name)) { tabletNBT.setTag(name, new NBTTagCompound()); } - AbstractApplication app = application.createApp(isClient, tabletNBT.getCompoundTag(application.getName())); + AbstractApplication app = application.createApp(isClient, tabletNBT.getCompoundTag(application.getName())).setOs(this); if (app != null) { openedApps.add(app); desktop.addWidget(app); @@ -81,7 +73,7 @@ public void openApplication(AbstractApplication application, boolean isClient) { public void maximizeApplication(AbstractApplication application, boolean isClient) { application.setActive(true); if (isClient) { - application.maximizeApp(app->desktop.hideDesktop()); + application.maximizeWidget(app->desktop.hideDesktop()); if (!menu.isHide) { menu.hideMenu(); } @@ -95,7 +87,7 @@ public void minimizeApplication(AbstractApplication application, boolean isClien application.setActive(false); } if (isClient) { - application.minimizeApp(null); + application.minimizeWidget(null); } if(focusApp == application) { focusApp = null; @@ -112,9 +104,9 @@ public void closeApplication(AbstractApplication application, boolean isClient) } application.closeApp(isClient, tabletNBT.getCompoundTag(name)); if (isClient) { - application.minimizeApp(waitToRemoved::add); + application.minimizeWidget(desktop::waitToRemoved); } else { - waitToRemoved.add(application); + desktop.waitToRemoved(application); } openedApps.remove(application); if(focusApp == application) { @@ -134,6 +126,25 @@ public void homeTrigger(boolean isClient) { } } + protected TerminalDialogWidget openDialog(TerminalDialogWidget widget) { + if (isRemote()) { + widget.maximizeWidget(null); + } else if(widget.isClient()) { + return widget; + } + desktop.addWidget(widget); + return widget; + } + + protected TerminalDialogWidget closeDialog(TerminalDialogWidget widget) { + if (isRemote()) { + widget.minimizeWidget(desktop::waitToRemoved); + } else if(widget.isClient()) { + desktop.waitToRemoved(widget); + } + return widget; + } + @Override public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { Position position = getPosition(); @@ -148,21 +159,4 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender }); } - @Override - public void updateScreen() { - if (waitToRemoved.size() > 0) { - waitToRemoved.forEach(desktop::removeWidget); - } - waitToRemoved.clear(); - super.updateScreen(); - } - - @Override - public void detectAndSendChanges() { - if (waitToRemoved.size() > 0) { - waitToRemoved.forEach(desktop::removeWidget); - } - waitToRemoved.clear(); - super.detectAndSendChanges(); - } } diff --git a/src/main/java/gregtech/api/terminal/util/FileTree.java b/src/main/java/gregtech/api/terminal/util/FileTree.java new file mode 100644 index 00000000000..05be2dbacb6 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/util/FileTree.java @@ -0,0 +1,65 @@ +package gregtech.api.terminal.util; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class FileTree extends TreeNode { + + public FileTree(File dir){ + this(0, dir); + } + + private FileTree(int dimension, File key) { + super(dimension, key); + } + + @Override + public boolean isLeaf() { + return getKey().isFile(); + } + + @Override + public TreeNode getOrCreateChild(File childKey) { + return super.getOrCreateChild(childKey); + } + + @Override + public void addContent(File key, File content) { + super.addContent(key, content); + } + + @Override + public File getKey() { + return super.getKey(); + } + + @Override + public File getContent() { + return isLeaf() ? getKey() : null; + } + + @Override + public List> getChildren() { + if (children == null && !isLeaf()) { + children = new ArrayList<>(); + Arrays.stream(key.listFiles()).sorted((a, b)->{ + if (a.isFile() && b.isFile()) { + return a.compareTo(b); + } else if (a.isDirectory() && b.isDirectory()) { + return a.compareTo(b); + } else if(a.isDirectory()) { + return -1; + } + return 1; + }).forEach(file -> children.add(new FileTree(dimension + 1, file))); + } + return super.getChildren(); + } + + @Override + public String toString() { + return getKey().getName(); + } +} diff --git a/src/main/java/gregtech/api/terminal/util/IContent.java b/src/main/java/gregtech/api/terminal/util/IContent.java deleted file mode 100644 index 5e0652455e7..00000000000 --- a/src/main/java/gregtech/api/terminal/util/IContent.java +++ /dev/null @@ -1,4 +0,0 @@ -package gregtech.api.terminal.util; - -public class IContent { -} diff --git a/src/main/java/gregtech/api/terminal/util/TreeNode.java b/src/main/java/gregtech/api/terminal/util/TreeNode.java index e8d5c1aa7fb..93c1f2c3616 100644 --- a/src/main/java/gregtech/api/terminal/util/TreeNode.java +++ b/src/main/java/gregtech/api/terminal/util/TreeNode.java @@ -10,10 +10,11 @@ * @param leaf */ public class TreeNode { - public int dimension; - public List> children; - public final T key; - public K content; + public final int dimension; + protected final T key; + protected K content; + protected List> children; + public TreeNode(int dimension, T key) { this.dimension = dimension; @@ -44,6 +45,18 @@ public void addContent (T key, K content) { getOrCreateChild(key).content = content; } + public T getKey() { + return key; + } + + public K getContent() { + return content; + } + + public List> getChildren() { + return children; + } + @Override public String toString() { return key.toString(); diff --git a/src/main/java/gregtech/api/util/SlotUtil.java b/src/main/java/gregtech/api/util/SlotUtil.java index 77886e5e750..348daaa7e88 100644 --- a/src/main/java/gregtech/api/util/SlotUtil.java +++ b/src/main/java/gregtech/api/util/SlotUtil.java @@ -27,9 +27,8 @@ public static ItemStack slotClickPhantom(Slot slot, int mouseButton, ClickType c } else if (slot.isItemValid(stackHeld)) { if (areItemsEqual(stackSlot, stackHeld)) { adjustPhantomSlot(slot, mouseButton, clickTypeIn); - } else { - fillPhantomSlot(slot, stackHeld, mouseButton); } + fillPhantomSlot(slot, stackHeld, mouseButton); } } else if (mouseButton == 5) { if (!slot.getHasStack()) { diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/cancel_disable.png b/src/main/resources/assets/gregtech/textures/gui/terminal/cancel_disable.png new file mode 100644 index 0000000000000000000000000000000000000000..e0ec424c75e01da23e0f7f7daa335c952ac54d4d GIT binary patch literal 3159 zcmV-d45;&oP)78q>K_FC<2fLfQVuH;Az`)Cm-v- zaQo}%r{Bba$7;8hTSBfOqH+KR02@FGfK31xFaZP!umJd)G2&>y>!IE={l8Pdj=Gix zONi|N0vg=sYTa|&wr}np`Zzh?_rIuUwn~GcrHVwYAgU#RUDjv6(R2FZZx!(M>P;n! z4eQ$kL>$(g?bn7r`N!0Co%{W-f@O01k`lc~R-7;xuV;0^$Yd+y;~ zSI>=nZNQGYmbC#PANE+EZ@qH*WbXS{DmN@FHLM0xh$=}`CO~1Lj88Me*WjdP9&=dt zPqoNX?vdSa(l)?t9<5dTtm1Ua#7;sMNF$_{@C|^mHEm z%77>9@BfA(Y8p-_f3|n<<7pzoiMp27kdQkSQ5Zm)0Y9hbF8XuI1pxt{*-2{u{nti@ zj{Qq~*#D=c^~TnPrGKKq*B`jtdE}k}kJq(qu!P+Cd1~s%`-Uzi|6}>;!205ny#XPc z2}s=o*xg_SfRL^AmBIA%OZx{uj{j>}z1mb#`WGJaC#^l5r{?}i%pG{MW=okRk(Sm`@CR7`L_89+K)?KU@%<#Wd^XcWePaX2!%YS}VRDJczu3LqKGEDZx5 zk-WXSy8QO46-!78A|a>%5)4d-q-tre*-{MvDbG8hh&DdAqRF@eu%&Ey9RTm4-ZNJL zV4-2QN|1q!-{h26DzHSpZb5%$-DpN3NdzoPnwGaM9{J08J^Iedf;q;BfWkWu_1f45X0@ z2xb;UJY5tDFKOGedex@&B|*#5jR&5rNpEV7W*`+wLy@h0k>1oCUDNhtttq80S-RA$ zd*FSk>iFL*=XSUilgs3@MwRt4~_{^UfLd*vI`SM0Zz~ZFmUIBn&Wvr2)z#PAV zpHB0F%BZz!^TtKKo;x?m^ovdJRiW!*Kgb)H((jcG^rqR zzmnv@Y-CDz_{=VYbGdImIF^P%Y3)m=Wy7k*w!L*qDX`X@I|x~8R!X6n^c)us{vM$Ar)n2}03hjkU3zxi2M~dY$hdwp&Lg8S zNTDF5ASK24n;n-%4;~tj;gFQ!kQ_aDXkh%!j!UGZASsCfAwA!Yq@8Ks_cJb6u)RLu zP5E9I0E7**7Qp0Fpa0K{4+4O%^<^bQ6960@8R~OcU!zQ@&)hSVBzt%yJ^auA`EmN% za7|SJb>Gu{=LZ2m5;b~ScjdV9orTeK>eJ<+aLb$3n-~B4^hoSj?bdeH+9v(ub5JENkvD#{`6@egE{1o(~QIzDse`qvKY(QFHY3nm~^in4I?9$&d}5emsH+{|?$0~fSeU+bQlJPH6E zb=w*VD0+WvNGS%7=5T}<0r9}7$4yFXrjpLt;DVq(;>Uv!zLDU&=4)5G1s<^|1J zEjti&SdZVZQ!jr1dRO|j%8ikLkdLK&|LEV1_s=R)?zq)Gc;$4L&$@SY@uH^y;PJlm z*Ka!MpE;~!1cVE$@KuG8xzLAgt%pBPCx5!T|HIhdE~t=8tiaPQ^SOt6&kWqLy1QN6 z-)q?32Eg5M`Gc1M;Q8pfqN-r{aZAW`0`NI=6ct+YZcxaASsIL#*5}Sm#*X~;&CB-R zELc3sPwu#`It5>b)a z0WW)3o?D&?%CtTV2D^^tzPRt6e6;s$F95t;xuIx<6>MYh$d1dMzq-o;zr1<$ZvFOM zf>4*z-Wv~JIok&SWkmE`&6b*wP>qJ5r~oY_f<+*aF&q2LNNezftM%ZN_PQSHJvWfk zdAzQr*%IPmkNN!0p3Zl_X#RU@zjf5LG+IJD#K4V&=f1P+>bZQU>M@eyndsW$h*Cw0 z$Y21TW+&l0iG4$#+%D9AtZrL0C}b;uaMJgVKGJ)3@XO}D=LY7FmNlAdix=z=M5`GX z_nALSxK97${TJe2^uPA%EsKIm)e53U0zy9XN3B;*ci!u~U%3VR?20CfjnggYQP^l8MSb)Nq xIlCRroN!skh7yU`GdC|eU!v-F1NeU-{|m$vd^GfAGo}Cl002ovPDHLkV1lLP5Xb-k literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/cancel_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/cancel_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..b4187a19abdab8caa3363dd76700a13b11cc28c7 GIT binary patch literal 3070 zcmVau{rjC~5=ekTd9->#ESx~elRVHXg({eM`}m{R_SQNo)z-Gy zhY!HE&J+rkzD5)juN|${PVY>eDZvD_fVGlvLQ;%Gv?wK=lW`1k0{n=};{oQ*nVrKk1H}yd{dFo?zzS+TGp%NkpfVAP*U@CF;%9sBT z`)7UAg+!2u=%wXr>n#$WAfkl;3IH$wH)|rZzZf&0aG9TP?>+s(O(!~&|5CtThwA)G z3X5-)L=6CvnmMf597$>Y#@SS=?{}{siyun%V_WDl?-ZZE#3SX!lBiM;Ehk{A0q;MP zOg^--^SS;H9I(5#;aWxFRt8>6YW>i%!%rU>Z*xO%rVL1l9Yd$|_-`G{*DeZ3wN8L) z95#=KTALpDKmhkF{m+60!NQ#cOpj`JQ^n!t&fK?f)m7y|Wz{L7rGjX-00jVm!AZm1 z<1lw8wR`BH6UW6@c}(RN~8*cRY9If&p7Aul#623fJWQ(KASAWhg)eVZMOn?FeXk_xw&#-apF%&0C=Ug z@is;D#i;9EUmk8gcHV$(Rabtr*z)|=VY4IDy7y542v@JEDz@w&+9c`;NHGu}2bJG) zj)?$213rh%(TMBZU2(Yi_WZbZ$9EKy zd7JAG-mjVW=is_)8}BMo)(%OeF90rQOAJH>C{ZBQ=Hs=E+W=r`+tW=Bo5!cw-Uo>$ zx|{%btft{w0%nBT_I?ilUao1lDJa!F03r-Hxxv6-oLd4iHlucgOs@6?r22MuZNnV^ z5Nd7uIRnnIplnopPV`8vo?wPY|f2DPT2|(*Aecg zRu^1!-D?8>qz>AEynSsJ)>`}d2c+_tVL5%fvo5x^W|%p$RDalzCt z06^SzcN5VSElV!KtL*g(F73710p~wMG4oT!P>Gw>Besc{X(Los?09lw0?@7UMyiuezZYA+%M&I zyB3t&740pr0f@{F1XoM|w1im6%wYiduQ?YjRf5VGh+$;6GFWR^#Z$$?|Ne|uf}!IH zwuHpoJ8ms9tLps#kTiw{Ys&&lHr^KWDg~WNu}P)5q-=@hnO-8;$=xS1d<-NMiBLuH zjB)^A=CC4p`2;{By3}QE2Y{fm>IEp6KT{A93&HBIr<}o`?v7~31=%*4bea_j%)R}q zg~|E~|6pavU%Fv^&?6;uD#c{m1OUB1`1xS^Xm^@CHeswpF#*1SRP_Mhvgshg{4s!g zLMyxg3esA?0RR?>rP6uY%2>%nD@<_3rp|(M$jV_bSgap z*S~E?B)0EhlDwXLU!zk8Tty-T04c3c0w{R8^fKQF;D@~aA^>J6mFQm=oCzY##^}x+ z4+-J*QljNxqIdhQ2mltAMJDaA?Xh8dGEpVVB7nJn+x?Mf^ZtYg21X}2vAKdU>&D%g zx@CdV?|!GiiiiA8YAZ8n_zHEkuYVm=lB`09c|(x zfPYUWh5)FkK40-8(K9fN)0p_6VgQhq%7}1XSzyVAjFjYZjF7yukL-JAg&`2_NdMgq5s|oBC%(lPb7c;LbC72yCMu? zvTZV{4CLI6>x*P)p^cO?{&GPE9F4lpivXaAs+sxKk+skLagBbSh-v_!W1zRwWz$W7 zZ^Ri98GwCf`kmzOo{btJkk6aZxve`gQWEeJdA*cqK9K0!zH=y}lQzM&$?ZCxrgzS` zkOFxVX95DQ;iG%rd9y1!OjX*L{SyFB#iD;CU}{IznoGa(Mn^iX^bQ-4`==bK&5t992r zVwgJ@w>IsZ5J3PKOs94WqT2SVtLA_Hl|%7}<7_m5piGru^j1s+xGvncdvq3Vya;C^ zX<3v$`if%)B4!deOM}w`PI|+gZ+1DI)oaTMSlAPfJ(kZj2C%N<*_ z%?F~|*~~ym);1rK$Wr-H8{Y^3k;lfkWn}=;07b*DdslV1

c`K&h>cG54*0>A;wJ z&IB1l`0l90~`Ba^9&(1>4EQeg@ z8==;wtpISWw&6xWblF?+;jd3RyLWq-byTk{El}2zDWf+nY1_L806LeiT~(y4%@&De z1SGN#_xu;z1Sn*3*w26`&F0X6lipArZfOUA?%KwiETUWboYbf5+Mjv*ya02ML8Ttm z%ug(CZTcAiY+q3By=wZb>wH3fQ4y6A$eX=8I{8ol6a&(Lqb~E&xYoZYJN(RVG&=?W zj@LGB6+|og)2VCgj!X`BPCx*7zGC&vnI7Lm0GzX~v#~1N@;U&lE19QmnZLNoCsmyy z3JIcF1o8oZ0mlsUDVMn`>N^X{@=TUxZyj2nX z4+Cv6?f!4Y;pXGxZEl}BPsX&1oo9O{l;2*exw_gTGlvaxM^d{dqv_PZA5NT1c)T|1=6)m)u<&2q^DH4|x(R^e|z=pDU$bbi#d_2p{ucnPTuq@o% zdO_vp52DJyC$z#p%NHmVg8a-dnoa!ALjyzCy?!Kh?%w|ofd9(&4+uwZKT|7bX8-^I M07*qoM6N<$g0tPt>Hq)$ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/cancel_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/cancel_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..568c435b013efea20b9134c943729741968cb97a GIT binary patch literal 3082 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/ok_disable.png b/src/main/resources/assets/gregtech/textures/gui/terminal/ok_disable.png new file mode 100644 index 0000000000000000000000000000000000000000..a876388f3ca4321085643e1202a342d5cfe36a30 GIT binary patch literal 3322 zcmVSPY<^1uw zERs}i)vfB+@7;4gXSwGt#LW2r+>GlL5MTS-2w9P8A{haZ4S)c+&?=+-@nrAT6{FW9 zpT3L-Th||mlNp*1qBwy}04{^a0dfHV%od130BisXtS@ump6PkM^TPisVB5ySv&nG2 z0>EMBZYcMh$_{r&?~7mU1%Q^v zch}2k)9pgq^B`m;KpKPq3=Nco5kLZf1XzM~mX-T~%8nfB-MXR|0OC*VsgaS!hnZD( zV$-dA{%XLsr;dGfX_J{zKKTde#h0z5NMh-Iv&O>uIF`xA$*boo!t6N+{HJ+xN(I8(O*^#?EXOzr24jzG&@??ADHr)fJ6l8RDOd4_h9eV6<4B*9}{-d{0GT!+5yg# zDPrWoAccT!o3Jedra@#HM7CwXwoOPOidk6%&3lzOOVVyOtJ@#0e_)f<_sXgC<73Et(okas8d_@wDkv7V z#qp+)HKnDlY4NP#n%53r>^?PI)o(~sO@d^QBpHe=Bcg6*?rD4Gc-pL)F$X}`gbNCw?O+-}8;Q}PPB&``OPrlU#0MP0*q&a6oh#S|uV%UxI zYL%Pb4*Kg&eHuoI1V#jh~V$4e$HcAsMO!8CE+0zubF7fDT-`dtt1#z9wo1fnqP<;Kv7t-`jd% zxH~cAWxas47qGrG=w)9zFnsJf4hj(kI0XPQTo)x04#1_|3K;MM=Bc%II2yKWFk>VgWDlK9U#YO9EDKjD zr3pZVCFP;B>5r3{U>wY-3|rRJIy>wu=85YLGZ8t$sfre!Qy>v3n zWffxX06*g`nzSlq3rNsskC@boU@n0CW>W`#A-qKv z0_C?OsT_NnnKgrB6*3gF16vA-Lcq$^vSzRp5>>XcV->POGnkoqY@9v1YUx!SV8zP! zkQd|t@U8-~&H@w#0G%7l0PL0x1_3N3=)z!-&bZoRX4F-MLJOO@QENp~3My6TB_iYC#36Npd;NuCzR`{`bzWYv<)j~-B=Tg8qAt9 zuJ-nHr9LX4O-Kg-1}pzks%rc-u3_(;^gW2hgS6)EQ}n zI*_*%D3lFT5}oSFrCvWdcJ^CKV)KeD~gk?R^8umVuFU4gl(_BTh?w%!ZJx zl!7FpT_=-g&-CU}jwwXRGf75Rv|3_NM@DWJ>X?74SHGRQ)6;ii{1-sFa3warX{}wfVQVkJO&QV zC!Xtgr})u?yP06L=df8lZA0t&{nL70Sbi}W?%rkA&2A=X)l4cq1b~f#;*W;B@$(K`e#+n^odhl&z9TIunsU$y^T0;lf(D!khvj z1Qq|_2YOyy{viOgeD_yTqq6N0W_>xaY00lX#lX+MJZgLT z-LDhLS=!IM-t+t&-2gyD6kqrD46-A0NtjcJL@a-KS)8q`m^lYlBdq*O+D)D5ed%i# zOESOz&H^&*yI2J$63^Xs@U!%Pq3gHSjfdw7Bea6S{d#<4fA7}2N;g%`v<^{o$3In) z6^)WK@;f5sdpb9oy8P-Br~3bb{m@ zKo3I)r}cR9Lhs8f$3D}zb-%A6D>9RWoC{C|>)>S1=8mIZRPSGX1>CsiC$?38;{phI z1A(Fp_5ezObsC^teu{GiKoKH}aDLM<0v()5zVoB^Q-9i~K2OJW0hYI>hjutdRZATS zvlb-6$Zyjb%pO>$So=fX;JKkIzgXveSsm8}_CffOaK4? literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/ok_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/ok_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..bb85e273318897a7a2ef859555f633438939b40e GIT binary patch literal 3261 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/ok_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/ok_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..bb73df64b8f23facfdb250bf3567b314cc4e29b6 GIT binary patch literal 3278 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 M07*qoM6N<$f(*(#D*ylh literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_dialog.png b/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_dialog.png new file mode 100644 index 0000000000000000000000000000000000000000..d18efc6cbc13ee9bbc0bcfa3f1372fcfea7f9476 GIT binary patch literal 5193 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 Date: Sun, 8 Aug 2021 01:18:41 +0800 Subject: [PATCH 36/58] fix bad slotwidget in gtce --- src/main/java/gregtech/api/gui/Widget.java | 3 -- .../gregtech/api/gui/impl/ModularUIGui.java | 13 ------ .../api/gui/resources/ItemStackTexture.java | 7 ++-- .../api/gui/widgets/AbstractWidgetGroup.java | 6 --- .../api/gui/widgets/ScrollableListWidget.java | 1 - .../gregtech/api/gui/widgets/SlotWidget.java | 42 ++++++++----------- .../gregtech/api/gui/widgets/TankWidget.java | 2 + .../DraggableScrollableWidgetGroup.java | 13 ------ .../gui/widgets/guide/GuideConfigEditor.java | 21 ++++++++-- .../gui/widgets/guide/SlotListWidget.java | 12 ------ .../gui/widgets/guide/TankListWidget.java | 24 ++++++----- .../configurator/FluidStackConfigurator.java | 6 ++- .../gui/widgets/os/TerminalDialogWidget.java | 4 +- 13 files changed, 61 insertions(+), 93 deletions(-) diff --git a/src/main/java/gregtech/api/gui/Widget.java b/src/main/java/gregtech/api/gui/Widget.java index 14c15f2502d..e50b6172969 100644 --- a/src/main/java/gregtech/api/gui/Widget.java +++ b/src/main/java/gregtech/api/gui/Widget.java @@ -136,9 +136,6 @@ protected void recomputePosition() { onPositionUpdate(); } - public void applyScissor(final int parentX, final int parentY, final int parentWidth, final int parentHeight) { - } - protected void onPositionUpdate() { } diff --git a/src/main/java/gregtech/api/gui/impl/ModularUIGui.java b/src/main/java/gregtech/api/gui/impl/ModularUIGui.java index 575ef2aed9d..bfa14dd43e0 100644 --- a/src/main/java/gregtech/api/gui/impl/ModularUIGui.java +++ b/src/main/java/gregtech/api/gui/impl/ModularUIGui.java @@ -94,23 +94,10 @@ public void drawScreen(int mouseX, int mouseY, float partialTicks) { for (int i = 0; i < this.inventorySlots.inventorySlots.size(); ++i) { Slot slot = this.inventorySlots.inventorySlots.get(i); - Rectangle scissor = null; - if (slot instanceof IScissored) { - scissor = ((IScissored) slot).getScissor(); - if (scissor != null) { - RenderUtil.pushScissorFrame(scissor.x, scissor.y, scissor.width, scissor.height); - } - } - if (slot.isEnabled()) { - this.drawSlotContents(slot); - } if (isPointInRegion(slot.xPos, slot.yPos, 16, 16, mouseX, mouseY) && slot.isEnabled()) { renderSlotOverlay(slot); setHoveredSlot(slot); } - if (scissor != null) { - RenderUtil.popScissorFrame(); - } } RenderHelper.disableStandardItemLighting(); diff --git a/src/main/java/gregtech/api/gui/resources/ItemStackTexture.java b/src/main/java/gregtech/api/gui/resources/ItemStackTexture.java index bed8d58cccf..b339ff268ca 100644 --- a/src/main/java/gregtech/api/gui/resources/ItemStackTexture.java +++ b/src/main/java/gregtech/api/gui/resources/ItemStackTexture.java @@ -2,6 +2,7 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.client.renderer.RenderHelper; import net.minecraft.client.renderer.RenderItem; import net.minecraft.item.Item; @@ -20,12 +21,12 @@ public ItemStackTexture(Item item) { @Override public void draw(double x, double y, int width, int height) { - RenderHelper.enableStandardItemLighting(); + RenderHelper.enableGUIStandardItemLighting(); GlStateManager.pushMatrix(); GlStateManager.scale(width / 16f, height / 16f, 0.0001); GlStateManager.translate(x * 16 / width, y * 16 / height, 0); - RenderItem renderItem = Minecraft.getMinecraft().getRenderItem(); - renderItem.renderItemAndEffectIntoGUI(itemStack, 0, 0); + RenderItem itemRender = Minecraft.getMinecraft().getRenderItem(); + itemRender.renderItemAndEffectIntoGUI(itemStack, 0, 0); GlStateManager.enableAlpha(); GlStateManager.popMatrix(); RenderHelper.disableStandardItemLighting(); diff --git a/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java b/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java index 17cd3be18f2..86be3fec316 100644 --- a/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java +++ b/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java @@ -60,12 +60,6 @@ protected void onPositionUpdate() { recomputeSize(); } - public void applyScissor(final int parentX, final int parentY, final int parentWidth, final int parentHeight) { - for (Widget widget : getContainedWidgets(true)) { - widget.applyScissor(parentX, parentY, parentWidth, parentHeight); - } - } - protected boolean recomputeSize() { if (isDynamicSized) { Size currentSize = getSize(); diff --git a/src/main/java/gregtech/api/gui/widgets/ScrollableListWidget.java b/src/main/java/gregtech/api/gui/widgets/ScrollableListWidget.java index 8261ee648a8..47e27a66a89 100644 --- a/src/main/java/gregtech/api/gui/widgets/ScrollableListWidget.java +++ b/src/main/java/gregtech/api/gui/widgets/ScrollableListWidget.java @@ -66,7 +66,6 @@ private void updateElementPositions() { currentPosY += widget.getSize().getHeight(); totalListHeight += widget.getSize().getHeight(); final Size size = getSize(); - widget.applyScissor(position.x, position.y, size.width - scrollPaneWidth, size.height); } this.totalListHeight = totalListHeight; this.slotHeight = widgets.isEmpty() ? 0 : totalListHeight / widgets.size(); diff --git a/src/main/java/gregtech/api/gui/widgets/SlotWidget.java b/src/main/java/gregtech/api/gui/widgets/SlotWidget.java index c6a83527d48..35484c053e0 100644 --- a/src/main/java/gregtech/api/gui/widgets/SlotWidget.java +++ b/src/main/java/gregtech/api/gui/widgets/SlotWidget.java @@ -6,9 +6,15 @@ import gregtech.api.gui.*; import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.resources.ItemStackTexture; import gregtech.api.gui.resources.TextureArea; import gregtech.api.util.Position; import gregtech.api.util.Size; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.client.renderer.RenderItem; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.ClickType; import net.minecraft.inventory.IInventory; @@ -35,8 +41,6 @@ public class SlotWidget extends Widget implements INativeWidget { protected IGuiTexture[] backgroundTexture; protected Runnable changeListener; - protected Rectangle scissor; - public SlotWidget(IInventory inventory, int slotIndex, int xPosition, int yPosition, boolean canTakeItems, boolean canPutItems) { super(new Position(xPosition, yPosition), new Size(18, 18)); this.canTakeItems = canTakeItems; @@ -74,6 +78,15 @@ public void drawInBackground(int mouseX, int mouseY, IRenderContext context) { for (IGuiTexture backgroundTexture : this.backgroundTexture) { backgroundTexture.draw(pos.x, pos.y, size.width, size.height); } + + RenderHelper.enableGUIStandardItemLighting(); + GlStateManager.pushMatrix(); + RenderItem itemRender = Minecraft.getMinecraft().getRenderItem(); + itemRender.renderItemAndEffectIntoGUI(slotReference.getStack(), pos.x + 1, pos.y + 1); + itemRender.renderItemOverlayIntoGUI(Minecraft.getMinecraft().fontRenderer, slotReference.getStack(), pos.x + 1, pos.y + 1, null); + GlStateManager.enableAlpha(); + GlStateManager.popMatrix(); + RenderHelper.disableStandardItemLighting(); } } @@ -96,11 +109,6 @@ public void setEnabled(boolean enabled) { isEnabled = enabled; } - @Override - public void applyScissor(final int parentX, final int parentY, final int parentWidth, final int parentHeight) { - this.scissor = new Rectangle(parentX, parentY, parentWidth, parentHeight); - } - @Override public void detectAndSendChanges() { } @@ -141,13 +149,7 @@ public boolean canTakeStack(EntityPlayer player) { } public boolean isEnabled() { - if (!this.isEnabled) { - return false; - } - if (this.scissor == null) { - return true; - } - return scissor.intersects(toRectangleBox()); + return this.isEnabled; } @Override @@ -169,7 +171,7 @@ public final Slot getHandle() { return slotReference; } - protected class WidgetSlot extends Slot implements IScissored { + protected class WidgetSlot extends Slot { public WidgetSlot(IInventory inventory, int index, int xPosition, int yPosition) { super(inventory, index, xPosition, yPosition); } @@ -208,13 +210,9 @@ public boolean isEnabled() { return SlotWidget.this.isEnabled(); } - @Override - public Rectangle getScissor() { - return SlotWidget.this.scissor; - } } - protected class WidgetSlotItemHandler extends SlotItemHandler implements IScissored { + protected class WidgetSlotItemHandler extends SlotItemHandler { public WidgetSlotItemHandler(IItemHandler itemHandler, int index, int xPosition, int yPosition) { super(itemHandler, index, xPosition, yPosition); @@ -254,9 +252,5 @@ public boolean isEnabled() { return SlotWidget.this.isEnabled(); } - @Override - public Rectangle getScissor() { - return SlotWidget.this.scissor; - } } } diff --git a/src/main/java/gregtech/api/gui/widgets/TankWidget.java b/src/main/java/gregtech/api/gui/widgets/TankWidget.java index 1a1c17a0081..279599b6080 100644 --- a/src/main/java/gregtech/api/gui/widgets/TankWidget.java +++ b/src/main/java/gregtech/api/gui/widgets/TankWidget.java @@ -53,6 +53,8 @@ public class TankWidget extends Widget implements IIngredientSlot { public TankWidget(IFluidTank fluidTank, int x, int y, int width, int height) { super(new Position(x, y), new Size(width, height)); this.fluidTank = fluidTank; + this.lastFluidInTank = fluidTank != null ? fluidTank.getFluid() != null ? fluidTank.getFluid().copy() : null : null; + this.lastTankCapacity = fluidTank != null ? fluidTank.getCapacity() : 0; } public TankWidget setHideTooltip(boolean hideTooltip) { diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java b/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java index f5dfe6121ed..d5818e6eede 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java @@ -89,7 +89,6 @@ public void addWidget(Widget widget) { maxHeight = Math.max(maxHeight, widget.getSize().height + widget.getSelfPosition().y); maxWidth = Math.max(maxWidth, widget.getSize().width + widget.getSelfPosition().x); widget.addSelfPosition(- scrollXOffset, - scrollYOffset); - widget.applyScissor(getPosition().x, getPosition().y, getSize().width - yBarWidth, getSize().height - xBarHeight); super.addWidget(widget); } @@ -114,18 +113,6 @@ public void setSize(Size size) { computeMax(); } - @Override - protected void onPositionUpdate() { - super.onPositionUpdate(); - this.applyScissor(getPosition().x, getPosition().y, getSize().width - yBarWidth, getSize().height - xBarHeight); - } - - @Override - protected void onSizeUpdate() { - super.onSizeUpdate(); - this.applyScissor(getPosition().x, getPosition().y, getSize().width - yBarWidth, getSize().height - xBarHeight); - } - protected void computeMax() { int mh = 0; int mw = 0; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java index 191d3b8a7f0..a837b61a0e8 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java @@ -29,6 +29,7 @@ public class GuideConfigEditor extends TabGroup { public String json; private IGuideWidget selected; private GuidePageEditorWidget pageEditor; + private TextEditorWidget titleEditor; private final DraggableScrollableWidgetGroup widgetSelector; private final DraggableScrollableWidgetGroup widgetConfigurator; private final CircleButtonWidget[] addButton; @@ -93,6 +94,10 @@ public void setGuidePageEditorWidget(GuidePageEditorWidget pageEditor) { this.pageEditor = pageEditor; } + public GuidePageEditorWidget getPageEditor() { + return pageEditor; + } + private DraggableScrollableWidgetGroup createPageConfig() { DraggableScrollableWidgetGroup group = new DraggableScrollableWidgetGroup(0, 0, getSize().width, getSize().height - 10) .setBackground(new ColorRectTexture(new Color(246, 120, 120, 190))) @@ -105,19 +110,24 @@ private DraggableScrollableWidgetGroup createPageConfig() { pageEditor.setSection(s); } }, true) - .setTextSupplier(pageEditor::getSection, true) + .setTextSupplier(()-> getPageEditor().getSection(), true) .setMaxStringLength(Integer.MAX_VALUE) .setValidator(s->true)); group.addWidget(new ImageWidget(5, 48,116, 1, new ColorRectTexture(-1))); group.addWidget(new LabelWidget(5, 55, "title", -1).setShadow(true)); - group.addWidget(new TextEditorWidget(5, 65, 116, 70, s->{ + titleEditor = new TextEditorWidget(5, 65, 116, 70, s->{ if (pageEditor != null) { pageEditor.setTitle(s); } - }, true).setContent(pageEditor.getTitle()).setBackground(new ColorRectTexture(0xA3FFFFFF))); + }, true).setContent("Template").setBackground(new ColorRectTexture(0xA3FFFFFF)); + group.addWidget(titleEditor); return group; } + public void updateTitle(String title) { + titleEditor.setContent(title); + } + private DraggableScrollableWidgetGroup createWidgetSelector() { DraggableScrollableWidgetGroup group = new DraggableScrollableWidgetGroup(0, 0, getSize().width, getSize().height - 10) .setBackground(new ColorRectTexture(new Color(246, 120, 120, 190))) @@ -158,8 +168,11 @@ private void loadJson(ClickData data) { if (result != null && result.isFile()) { try { FileReader reader = new FileReader(result); - pageEditor.loadJsonConfig(new JsonParser().parse(new JsonReader(reader)).getAsJsonObject()); + JsonObject config = new JsonParser().parse(new JsonReader(reader)).getAsJsonObject(); + pageEditor.loadJsonConfig(config); reader.close(); + getPageEditor().setSection(config.get("section").getAsString()); + updateTitle(config.get("title").getAsString()); } catch (Exception e) { TerminalDialogWidget.showInfoDialog(app.getOs(), "ERROR", "An error occurred while loading the file.").setClientSide().open(); } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/SlotListWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/SlotListWidget.java index 502d8b7f29c..84b927691da 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/SlotListWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/SlotListWidget.java @@ -14,7 +14,6 @@ import net.minecraft.util.ResourceLocation; import net.minecraftforge.items.ItemStackHandler; -import java.awt.*; import java.util.Collections; import java.util.List; import java.util.function.Consumer; @@ -25,8 +24,6 @@ public class SlotListWidget extends GuideWidgetGroup { // config public List item_list; - protected transient Rectangle scissor; - @Override public Widget initFixed() { this.clearAllWidgets(); @@ -49,9 +46,6 @@ public Widget initFixed() { itemStackHandler.setStackInSlot(i, item_list.get(i).getInstance()); SlotWidget widget = new SlotWidget(itemStackHandler, i, xPos + x * 18, y * 18, false, false); widget.setBackgroundTexture(background); - if (scissor != null) { - widget.applyScissor(scissor.x, scissor.y, scissor.width, scissor.height); - } this.addWidget(widget); } } @@ -78,12 +72,6 @@ public void loadConfigurator(DraggableScrollableWidgetGroup group, JsonObject co group.addWidget(new ItemStackConfigurator(group, config, "item_list").setOnUpdated(needUpdate)); } - @Override - public void applyScissor(int parentX, int parentY, int parentWidth, int parentHeight) { - super.applyScissor(parentX, parentY, parentWidth, parentHeight); - scissor = new Rectangle(parentX, parentY, parentWidth, parentHeight); - } - public static class ItemStackInfo { // config public String id; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TankListWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TankListWidget.java index adac67ca2df..c42c7cc4f2c 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TankListWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/TankListWidget.java @@ -7,6 +7,7 @@ import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.widgets.TankWidget; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; +import gregtech.api.terminal.gui.widgets.guide.configurator.FluidStackConfigurator; import gregtech.api.terminal.gui.widgets.guide.configurator.ItemStackConfigurator; import gregtech.api.util.Size; import net.minecraft.item.Item; @@ -51,7 +52,7 @@ public Widget initFixed() { if (i < size) { FluidStack fluidStack = fluid_list.get(i).getInstance(); TankWidget widget = new TankWidget(new FluidTank(fluidStack, fluid_list.get(i).amount), xPos + x * 18, y * 18, 18, 18); - widget.setBackgroundTexture(background); + widget.setBackgroundTexture(background).setAlwaysShowFull(true); this.addWidget(widget); } } @@ -75,13 +76,7 @@ public JsonObject getTemplate(boolean isFixed) { @Override public void loadConfigurator(DraggableScrollableWidgetGroup group, JsonObject config, boolean isFixed, Consumer needUpdate) { super.loadConfigurator(group, config, isFixed, needUpdate); -// group.addWidget(new ItemStackConfigurator(group, config, "fluid_list").setOnUpdated(needUpdate)); - } - - @Override - public void applyScissor(int parentX, int parentY, int parentWidth, int parentHeight) { - super.applyScissor(parentX, parentY, parentWidth, parentHeight); - scissor = new Rectangle(parentX, parentY, parentWidth, parentHeight); + group.addWidget(new FluidStackConfigurator(group, config, "fluid_list").setOnUpdated(needUpdate)); } public static class FluidStackInfo { @@ -96,8 +91,14 @@ public FluidStackInfo() { } public void update(FluidStack itemStack) { - id = FluidRegistry.getFluidName(itemStack.getFluid()); - amount = itemStack.amount; + if (itemStack != null) { + id = FluidRegistry.getFluidName(itemStack.getFluid()); + amount = itemStack.amount; + } else { + id = null; + fluidStack = null; + amount = 0; + } } public FluidStackInfo(String id, int amount) { @@ -110,8 +111,9 @@ public FluidStack getInstance() { Fluid fluid = FluidRegistry.getFluid(id); if (fluid != null) { fluidStack = new FluidStack(fluid, amount); + } else { + id = null; } - id = null; } return fluidStack; } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/FluidStackConfigurator.java b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/FluidStackConfigurator.java index 515003db110..e62171cd33f 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/FluidStackConfigurator.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/FluidStackConfigurator.java @@ -59,18 +59,20 @@ private void addSlot(DraggableScrollableWidgetGroup container, TankListWidget.Fl new Color(128, 255, 128).getRGB(), new Color(255, 255, 255, 0).getRGB()) .setClickListener(data -> { - fluidStackInfo.amount = Math.max(0, fluidStackInfo.amount - (data.isShiftClick ? 10 : 1)); + fluidStackInfo.amount = Math.max(0, fluidStackInfo.amount - (data.isShiftClick ? data.isCtrlClick ? 1000 : 10 : data.isCtrlClick? 100: 1)); updateValue(); }) + .setHoverText("Shift -10|Ctrl -100|Shift+Ctrl -1000") .setIcon(new TextTexture("-1", -1))); group.addWidget(new RectButtonWidget(76, 0, 20, 20) .setColors(new Color(0, 0, 0, 74).getRGB(), new Color(128, 255, 128).getRGB(), new Color(255, 255, 255, 0).getRGB()) .setClickListener(data -> { - fluidStackInfo.amount = Math.max(0, fluidStackInfo.amount + (data.isShiftClick ? 10 : 1)); + fluidStackInfo.amount = Math.max(0, fluidStackInfo.amount + (data.isShiftClick ? data.isCtrlClick ? 1000 : 10 : data.isCtrlClick? 100: 1)); updateValue(); }) + .setHoverText("Shift +10|Ctrl +100|Shift+Ctrl +1000") .setIcon(new TextTexture("+1", -1))); group.addWidget(new ImageWidget(40, 0, 36, 20, new ColorRectTexture(0x9f000000))); group.addWidget(new SimpleTextWidget(58, 10, "", 0xFFFFFF, () -> Integer.toString(fluidStackInfo.amount), true)); diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalDialogWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalDialogWidget.java index 115420349cd..401d1fa51ff 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalDialogWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalDialogWidget.java @@ -17,6 +17,7 @@ import net.minecraft.inventory.IInventory; import net.minecraft.network.PacketBuffer; +import java.awt.*; import java.io.File; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; @@ -178,6 +179,7 @@ public static TerminalDialogWidget showFileDialog(TerminalOSWidget os, String ti } } AtomicReference selected = new AtomicReference<>(); + selected.set(dir); dialog.addWidget(new TreeListWidget<>(0, 0, 130, size.height, new FileTree(dir), node -> { selected.set(node.getKey()); System.out.println(node.toString()); @@ -213,7 +215,7 @@ public static TerminalDialogWidget showFileDialog(TerminalOSWidget os, String ti return "no file selected"; }, true)); } else { - dialog.addWidget(new TextFieldWidget(x + WIDTH / 2, y + HEIGHT / 2 - 5, 76, 20, new ColorRectTexture(0x4f000000), null, null) + dialog.addWidget(new TextFieldWidget(x + WIDTH / 2 - 38, y + HEIGHT / 2 - 10, 76, 20, new ColorRectTexture(0x4f000000), null, null) .setTextResponder(res->{ File file = selected.get(); if (file == null) return; From 896a564914d8b7dd4bf82ad28690e8208a0b6273 Mon Sep 17 00:00:00 2001 From: Yefancy Date: Sun, 8 Aug 2021 13:50:28 +0800 Subject: [PATCH 37/58] adjust package structure --- .../api/terminal/app/AbstractApplication.java | 2 +- .../api/terminal/app/GuideEditorApp.java | 4 +-- .../api/terminal/app/guide/GuideApp.java | 2 +- .../guide/widget}/CardWidget.java | 6 ++-- .../guide/widget}/GuideConfigEditor.java | 33 ++++++++++++++----- .../guide/widget}/GuidePageEditorWidget.java | 2 +- .../guide/widget}/GuidePageWidget.java | 2 +- .../guide/widget}/GuideWidget.java | 10 +++--- .../guide/widget}/GuideWidgetGroup.java | 10 +++--- .../guide/widget}/IGuideWidget.java | 2 +- .../guide/widget}/ImageWidget.java | 9 +++-- .../guide/widget}/SlotListWidget.java | 4 +-- .../guide/widget}/TankListWidget.java | 9 ++--- .../guide/widget}/TextBoxWidget.java | 11 +++---- .../configurator/BooleanConfigurator.java | 3 +- .../configurator/ColorConfigurator.java | 2 +- .../configurator/ConfiguratorWidget.java | 2 +- .../configurator/FluidStackConfigurator.java | 4 +-- .../configurator/ItemStackConfigurator.java | 4 +-- .../configurator/NumberConfigurator.java | 3 +- .../configurator/SelectorConfigurator.java | 2 +- .../configurator/StringConfigurator.java | 3 +- .../configurator/TextListConfigurator.java | 4 +-- .../os/TerminalDesktopWidget.java | 2 +- .../widgets => }/os/TerminalDialogWidget.java | 9 ++--- .../widgets => }/os/TerminalMenuWidget.java | 3 +- .../widgets => }/os/TerminalOSWidget.java | 3 +- .../behaviors/GuideTerminalBehaviour.java | 2 +- 28 files changed, 76 insertions(+), 76 deletions(-) rename src/main/java/gregtech/api/terminal/{gui/widgets/guide => app/guide/widget}/CardWidget.java (95%) rename src/main/java/gregtech/api/terminal/{gui/widgets/guide => app/guide/widget}/GuideConfigEditor.java (89%) rename src/main/java/gregtech/api/terminal/{gui/widgets/guide => app/guide/widget}/GuidePageEditorWidget.java (99%) rename src/main/java/gregtech/api/terminal/{gui/widgets/guide => app/guide/widget}/GuidePageWidget.java (99%) rename src/main/java/gregtech/api/terminal/{gui/widgets/guide => app/guide/widget}/GuideWidget.java (94%) rename src/main/java/gregtech/api/terminal/{gui/widgets/guide => app/guide/widget}/GuideWidgetGroup.java (94%) rename src/main/java/gregtech/api/terminal/{gui/widgets/guide => app/guide/widget}/IGuideWidget.java (97%) rename src/main/java/gregtech/api/terminal/{gui/widgets/guide => app/guide/widget}/ImageWidget.java (91%) rename src/main/java/gregtech/api/terminal/{gui/widgets/guide => app/guide/widget}/SlotListWidget.java (96%) rename src/main/java/gregtech/api/terminal/{gui/widgets/guide => app/guide/widget}/TankListWidget.java (91%) rename src/main/java/gregtech/api/terminal/{gui/widgets/guide => app/guide/widget}/TextBoxWidget.java (92%) rename src/main/java/gregtech/api/terminal/{gui/widgets/guide => app/guide/widget}/configurator/BooleanConfigurator.java (93%) rename src/main/java/gregtech/api/terminal/{gui/widgets/guide => app/guide/widget}/configurator/ColorConfigurator.java (93%) rename src/main/java/gregtech/api/terminal/{gui/widgets/guide => app/guide/widget}/configurator/ConfiguratorWidget.java (98%) rename src/main/java/gregtech/api/terminal/{gui/widgets/guide => app/guide/widget}/configurator/FluidStackConfigurator.java (97%) rename src/main/java/gregtech/api/terminal/{gui/widgets/guide => app/guide/widget}/configurator/ItemStackConfigurator.java (97%) rename src/main/java/gregtech/api/terminal/{gui/widgets/guide => app/guide/widget}/configurator/NumberConfigurator.java (96%) rename src/main/java/gregtech/api/terminal/{gui/widgets/guide => app/guide/widget}/configurator/SelectorConfigurator.java (95%) rename src/main/java/gregtech/api/terminal/{gui/widgets/guide => app/guide/widget}/configurator/StringConfigurator.java (93%) rename src/main/java/gregtech/api/terminal/{gui/widgets/guide => app/guide/widget}/configurator/TextListConfigurator.java (91%) rename src/main/java/gregtech/api/terminal/{gui/widgets => }/os/TerminalDesktopWidget.java (97%) rename src/main/java/gregtech/api/terminal/{gui/widgets => }/os/TerminalDialogWidget.java (97%) rename src/main/java/gregtech/api/terminal/{gui/widgets => }/os/TerminalMenuWidget.java (98%) rename src/main/java/gregtech/api/terminal/{gui/widgets => }/os/TerminalOSWidget.java (98%) diff --git a/src/main/java/gregtech/api/terminal/app/AbstractApplication.java b/src/main/java/gregtech/api/terminal/app/AbstractApplication.java index 3a93dc51108..671538d2090 100644 --- a/src/main/java/gregtech/api/terminal/app/AbstractApplication.java +++ b/src/main/java/gregtech/api/terminal/app/AbstractApplication.java @@ -2,7 +2,7 @@ import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.terminal.gui.widgets.AnimaWidgetGroup; -import gregtech.api.terminal.gui.widgets.os.TerminalOSWidget; +import gregtech.api.terminal.os.TerminalOSWidget; import gregtech.api.util.Position; import gregtech.api.util.Size; import net.minecraft.nbt.NBTTagCompound; diff --git a/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java b/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java index 3dd11f4b5cc..dbe72974447 100644 --- a/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java +++ b/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java @@ -1,8 +1,8 @@ package gregtech.api.terminal.app; import gregtech.api.gui.resources.TextureArea; -import gregtech.api.terminal.gui.widgets.guide.GuideConfigEditor; -import gregtech.api.terminal.gui.widgets.guide.GuidePageEditorWidget; +import gregtech.api.terminal.app.guide.widget.GuideConfigEditor; +import gregtech.api.terminal.app.guide.widget.GuidePageEditorWidget; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.PacketBuffer; diff --git a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java index 6c394c2c530..a7d19ccb608 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java @@ -8,7 +8,7 @@ import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.terminal.app.AbstractApplication; import gregtech.api.terminal.gui.widgets.TreeListWidget; -import gregtech.api.terminal.gui.widgets.guide.*; +import gregtech.api.terminal.app.guide.widget.*; import gregtech.api.terminal.util.TreeNode; import net.minecraft.client.Minecraft; import net.minecraft.nbt.NBTTagCompound; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/CardWidget.java b/src/main/java/gregtech/api/terminal/app/guide/widget/CardWidget.java similarity index 95% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/CardWidget.java rename to src/main/java/gregtech/api/terminal/app/guide/widget/CardWidget.java index 07a108e97cc..77b8f0ae588 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/CardWidget.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/CardWidget.java @@ -1,11 +1,11 @@ -package gregtech.api.terminal.gui.widgets.guide; +package gregtech.api.terminal.app.guide.widget; import com.google.gson.JsonObject; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; -import gregtech.api.terminal.gui.widgets.guide.configurator.BooleanConfigurator; -import gregtech.api.terminal.gui.widgets.guide.configurator.NumberConfigurator; +import gregtech.api.terminal.app.guide.widget.configurator.BooleanConfigurator; +import gregtech.api.terminal.app.guide.widget.configurator.NumberConfigurator; import gregtech.api.util.Position; import gregtech.api.util.Size; import net.minecraft.client.renderer.BufferBuilder; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java b/src/main/java/gregtech/api/terminal/app/guide/widget/GuideConfigEditor.java similarity index 89% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java rename to src/main/java/gregtech/api/terminal/app/guide/widget/GuideConfigEditor.java index a837b61a0e8..f455d61ebba 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideConfigEditor.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/GuideConfigEditor.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.gui.widgets.guide; +package gregtech.api.terminal.app.guide.widget; import com.google.gson.JsonObject; import com.google.gson.JsonParser; @@ -15,7 +15,7 @@ import gregtech.api.terminal.gui.widgets.CircleButtonWidget; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; import gregtech.api.terminal.gui.widgets.TextEditorWidget; -import gregtech.api.terminal.gui.widgets.os.TerminalDialogWidget; +import gregtech.api.terminal.os.TerminalDialogWidget; import gregtech.api.util.Position; import gregtech.api.util.Size; @@ -55,19 +55,26 @@ public GuideConfigEditor(int x, int y, int width, int height, GuideEditorApp app addButton[1].setVisible(false); } }); - this.addWidget(new CircleButtonWidget(100, -5, 5, 1, 3) + this.addWidget(new CircleButtonWidget(97, -5, 5, 1, 3) + .setColors(new Color(255, 255, 255, 0).getRGB(), + new Color(255, 255, 255).getRGB(), + new Color(144, 243, 116).getRGB()) + .setIcon(GuiTextures.TERMINAL_ADD) + .setHoverText("New Page") + .setClickListener(this::newPage)); + this.addWidget(new CircleButtonWidget(112, -5, 5, 1, 3) .setColors(new Color(255, 255, 255, 0).getRGB(), new Color(255, 255, 255).getRGB(), new Color(243, 208, 116).getRGB()) .setIcon(GuiTextures.TERMINAL_ADD) - .setHoverText("Import Guide") + .setHoverText("Import Page") .setClickListener(this::loadJson)); - this.addWidget(new CircleButtonWidget(120, -5, 5, 1, 3) + this.addWidget(new CircleButtonWidget(127, -5, 5, 1, 3) .setColors(new Color(255, 255, 255, 0).getRGB(), new Color(255, 255, 255).getRGB(), - new Color(146, 253, 118).getRGB()) + new Color(231, 95, 95).getRGB()) .setIcon(GuiTextures.TERMINAL_ADD) - .setHoverText("Export Config") + .setHoverText("Export Page") .setClickListener(this::saveJson)); addButton[0] = new CircleButtonWidget(115, 15, 8, 1, 8) .setColors(new Color(255, 255, 255, 0).getRGB(), @@ -161,8 +168,18 @@ public void loadConfigurator(IGuideWidget widget) { } } + private void newPage(ClickData data) { + TerminalDialogWidget.showConfirmDialog(app.getOs(), "New Page", "New page", res->{ + if (res) { + pageEditor.loadJsonConfig("{\"section\":\"default\",\"title\":\"Template\",\"stream\":[],\"fixed\":[]}"); + getPageEditor().setSection("default"); + updateTitle("Template"); + } + }).setClientSide().open(); + } + private void loadJson(ClickData data) { - if(pageEditor != null) { + if (pageEditor != null) { File file = new File("terminal\\guide_editor"); TerminalDialogWidget.showFileDialog(app.getOs(), "Load Json", file, true, result->{ if (result != null && result.isFile()) { diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java b/src/main/java/gregtech/api/terminal/app/guide/widget/GuidePageEditorWidget.java similarity index 99% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java rename to src/main/java/gregtech/api/terminal/app/guide/widget/GuidePageEditorWidget.java index 9283f11a7f7..95470e3a3fb 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageEditorWidget.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/GuidePageEditorWidget.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.gui.widgets.guide; +package gregtech.api.terminal.app.guide.widget; import com.google.gson.Gson; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java b/src/main/java/gregtech/api/terminal/app/guide/widget/GuidePageWidget.java similarity index 99% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java rename to src/main/java/gregtech/api/terminal/app/guide/widget/GuidePageWidget.java index fa3ef7fe26a..fb3c7c29b4d 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuidePageWidget.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/GuidePageWidget.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.gui.widgets.guide; +package gregtech.api.terminal.app.guide.widget; import com.google.gson.JsonElement; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java b/src/main/java/gregtech/api/terminal/app/guide/widget/GuideWidget.java similarity index 94% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java rename to src/main/java/gregtech/api/terminal/app/guide/widget/GuideWidget.java index 9cf86a39b6d..2ee618f80c6 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidget.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/GuideWidget.java @@ -1,14 +1,14 @@ -package gregtech.api.terminal.gui.widgets.guide; +package gregtech.api.terminal.app.guide.widget; import com.google.gson.Gson; import com.google.gson.JsonObject; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; -import gregtech.api.terminal.gui.widgets.guide.configurator.ColorConfigurator; -import gregtech.api.terminal.gui.widgets.guide.configurator.NumberConfigurator; -import gregtech.api.terminal.gui.widgets.guide.configurator.StringConfigurator; -import gregtech.api.terminal.gui.widgets.guide.configurator.TextListConfigurator; +import gregtech.api.terminal.app.guide.widget.configurator.ColorConfigurator; +import gregtech.api.terminal.app.guide.widget.configurator.NumberConfigurator; +import gregtech.api.terminal.app.guide.widget.configurator.StringConfigurator; +import gregtech.api.terminal.app.guide.widget.configurator.TextListConfigurator; import gregtech.api.util.Position; import gregtech.api.util.Size; import net.minecraft.item.ItemStack; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidgetGroup.java b/src/main/java/gregtech/api/terminal/app/guide/widget/GuideWidgetGroup.java similarity index 94% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidgetGroup.java rename to src/main/java/gregtech/api/terminal/app/guide/widget/GuideWidgetGroup.java index 3dc31404fb2..8ade843e2c5 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/GuideWidgetGroup.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/GuideWidgetGroup.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.gui.widgets.guide; +package gregtech.api.terminal.app.guide.widget; import com.google.gson.Gson; import com.google.gson.JsonObject; @@ -6,10 +6,10 @@ import gregtech.api.gui.Widget; import gregtech.api.gui.widgets.WidgetGroup; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; -import gregtech.api.terminal.gui.widgets.guide.configurator.ColorConfigurator; -import gregtech.api.terminal.gui.widgets.guide.configurator.NumberConfigurator; -import gregtech.api.terminal.gui.widgets.guide.configurator.StringConfigurator; -import gregtech.api.terminal.gui.widgets.guide.configurator.TextListConfigurator; +import gregtech.api.terminal.app.guide.widget.configurator.ColorConfigurator; +import gregtech.api.terminal.app.guide.widget.configurator.NumberConfigurator; +import gregtech.api.terminal.app.guide.widget.configurator.StringConfigurator; +import gregtech.api.terminal.app.guide.widget.configurator.TextListConfigurator; import gregtech.api.util.Position; import gregtech.api.util.Size; import net.minecraft.item.ItemStack; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java b/src/main/java/gregtech/api/terminal/app/guide/widget/IGuideWidget.java similarity index 97% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java rename to src/main/java/gregtech/api/terminal/app/guide/widget/IGuideWidget.java index 5b55547f941..cd6f91be62b 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/IGuideWidget.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/IGuideWidget.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.gui.widgets.guide; +package gregtech.api.terminal.app.guide.widget; import com.google.gson.Gson; import com.google.gson.JsonElement; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java b/src/main/java/gregtech/api/terminal/app/guide/widget/ImageWidget.java similarity index 91% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java rename to src/main/java/gregtech/api/terminal/app/guide/widget/ImageWidget.java index 83900ef19bc..2001be50038 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/ImageWidget.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/ImageWidget.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.gui.widgets.guide; +package gregtech.api.terminal.app.guide.widget; import com.google.gson.JsonObject; import gregtech.api.gui.IRenderContext; @@ -8,13 +8,12 @@ import gregtech.api.gui.resources.TextureArea; import gregtech.api.gui.resources.URLTexture; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; -import gregtech.api.terminal.gui.widgets.guide.configurator.NumberConfigurator; -import gregtech.api.terminal.gui.widgets.guide.configurator.SelectorConfigurator; -import gregtech.api.terminal.gui.widgets.guide.configurator.StringConfigurator; +import gregtech.api.terminal.app.guide.widget.configurator.NumberConfigurator; +import gregtech.api.terminal.app.guide.widget.configurator.SelectorConfigurator; +import gregtech.api.terminal.app.guide.widget.configurator.StringConfigurator; import gregtech.api.util.Position; import gregtech.api.util.Size; import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.client.resources.I18n; import net.minecraft.item.Item; import net.minecraft.util.ResourceLocation; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/SlotListWidget.java b/src/main/java/gregtech/api/terminal/app/guide/widget/SlotListWidget.java similarity index 96% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/SlotListWidget.java rename to src/main/java/gregtech/api/terminal/app/guide/widget/SlotListWidget.java index 84b927691da..e944d34f0cb 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/SlotListWidget.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/SlotListWidget.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.gui.widgets.guide; +package gregtech.api.terminal.app.guide.widget; import com.google.gson.Gson; import com.google.gson.JsonObject; @@ -7,7 +7,7 @@ import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.widgets.SlotWidget; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; -import gregtech.api.terminal.gui.widgets.guide.configurator.ItemStackConfigurator; +import gregtech.api.terminal.app.guide.widget.configurator.ItemStackConfigurator; import gregtech.api.util.Size; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TankListWidget.java b/src/main/java/gregtech/api/terminal/app/guide/widget/TankListWidget.java similarity index 91% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/TankListWidget.java rename to src/main/java/gregtech/api/terminal/app/guide/widget/TankListWidget.java index c42c7cc4f2c..587c3cd5f8f 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TankListWidget.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/TankListWidget.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.gui.widgets.guide; +package gregtech.api.terminal.app.guide.widget; import com.google.gson.Gson; import com.google.gson.JsonObject; @@ -7,17 +7,12 @@ import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.widgets.TankWidget; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; -import gregtech.api.terminal.gui.widgets.guide.configurator.FluidStackConfigurator; -import gregtech.api.terminal.gui.widgets.guide.configurator.ItemStackConfigurator; +import gregtech.api.terminal.app.guide.widget.configurator.FluidStackConfigurator; import gregtech.api.util.Size; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.util.ResourceLocation; import net.minecraftforge.fluids.Fluid; import net.minecraftforge.fluids.FluidRegistry; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.FluidTank; -import net.minecraftforge.items.ItemStackHandler; import java.awt.*; import java.util.Collections; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java b/src/main/java/gregtech/api/terminal/app/guide/widget/TextBoxWidget.java similarity index 92% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java rename to src/main/java/gregtech/api/terminal/app/guide/widget/TextBoxWidget.java index 1d4fbcb06c7..98c8259f10f 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/TextBoxWidget.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/TextBoxWidget.java @@ -1,15 +1,14 @@ -package gregtech.api.terminal.gui.widgets.guide; +package gregtech.api.terminal.app.guide.widget; import com.google.gson.Gson; -import com.google.gson.JsonElement; import com.google.gson.JsonObject; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; -import gregtech.api.terminal.gui.widgets.guide.configurator.BooleanConfigurator; -import gregtech.api.terminal.gui.widgets.guide.configurator.ColorConfigurator; -import gregtech.api.terminal.gui.widgets.guide.configurator.NumberConfigurator; -import gregtech.api.terminal.gui.widgets.guide.configurator.TextListConfigurator; +import gregtech.api.terminal.app.guide.widget.configurator.BooleanConfigurator; +import gregtech.api.terminal.app.guide.widget.configurator.ColorConfigurator; +import gregtech.api.terminal.app.guide.widget.configurator.NumberConfigurator; +import gregtech.api.terminal.app.guide.widget.configurator.TextListConfigurator; import gregtech.api.util.Position; import gregtech.api.util.Size; import net.minecraft.client.Minecraft; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/BooleanConfigurator.java b/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/BooleanConfigurator.java similarity index 93% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/BooleanConfigurator.java rename to src/main/java/gregtech/api/terminal/app/guide/widget/configurator/BooleanConfigurator.java index 8c3b3c567ea..18605fa62e9 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/BooleanConfigurator.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/BooleanConfigurator.java @@ -1,7 +1,6 @@ -package gregtech.api.terminal.gui.widgets.guide.configurator; +package gregtech.api.terminal.app.guide.widget.configurator; import com.google.gson.JsonObject; -import gregtech.api.gui.GuiTextures; import gregtech.api.gui.resources.ColorRectTexture; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; import gregtech.api.terminal.gui.widgets.RectButtonWidget; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ColorConfigurator.java b/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/ColorConfigurator.java similarity index 93% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ColorConfigurator.java rename to src/main/java/gregtech/api/terminal/app/guide/widget/configurator/ColorConfigurator.java index 605593b0166..031c5206d55 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ColorConfigurator.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/ColorConfigurator.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.gui.widgets.guide.configurator; +package gregtech.api.terminal.app.guide.widget.configurator; import com.google.gson.JsonObject; import gregtech.api.terminal.gui.widgets.ColorWidget; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ConfiguratorWidget.java b/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/ConfiguratorWidget.java similarity index 98% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ConfiguratorWidget.java rename to src/main/java/gregtech/api/terminal/app/guide/widget/configurator/ConfiguratorWidget.java index 15c7fb5c561..522dd9abc32 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ConfiguratorWidget.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/ConfiguratorWidget.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.gui.widgets.guide.configurator; +package gregtech.api.terminal.app.guide.widget.configurator; import com.google.gson.Gson; import com.google.gson.JsonObject; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/FluidStackConfigurator.java b/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/FluidStackConfigurator.java similarity index 97% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/FluidStackConfigurator.java rename to src/main/java/gregtech/api/terminal/app/guide/widget/configurator/FluidStackConfigurator.java index e62171cd33f..7833d42569d 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/FluidStackConfigurator.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/FluidStackConfigurator.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.gui.widgets.guide.configurator; +package gregtech.api.terminal.app.guide.widget.configurator; import com.google.gson.Gson; import com.google.gson.JsonElement; @@ -9,7 +9,7 @@ import gregtech.api.gui.widgets.*; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; import gregtech.api.terminal.gui.widgets.RectButtonWidget; -import gregtech.api.terminal.gui.widgets.guide.TankListWidget; +import gregtech.api.terminal.app.guide.widget.TankListWidget; import java.awt.*; import java.util.ArrayList; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ItemStackConfigurator.java b/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/ItemStackConfigurator.java similarity index 97% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ItemStackConfigurator.java rename to src/main/java/gregtech/api/terminal/app/guide/widget/configurator/ItemStackConfigurator.java index 1ddc765534e..c9b81e4ffda 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/ItemStackConfigurator.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/ItemStackConfigurator.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.gui.widgets.guide.configurator; +package gregtech.api.terminal.app.guide.widget.configurator; import com.google.gson.Gson; import com.google.gson.JsonElement; @@ -12,7 +12,7 @@ import gregtech.api.gui.widgets.WidgetGroup; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; import gregtech.api.terminal.gui.widgets.RectButtonWidget; -import gregtech.api.terminal.gui.widgets.guide.SlotListWidget; +import gregtech.api.terminal.app.guide.widget.SlotListWidget; import net.minecraftforge.items.IItemHandlerModifiable; import net.minecraftforge.items.ItemStackHandler; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/NumberConfigurator.java b/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/NumberConfigurator.java similarity index 96% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/NumberConfigurator.java rename to src/main/java/gregtech/api/terminal/app/guide/widget/configurator/NumberConfigurator.java index 0779e0e661a..54ce1be916b 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/NumberConfigurator.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/NumberConfigurator.java @@ -1,8 +1,7 @@ -package gregtech.api.terminal.gui.widgets.guide.configurator; +package gregtech.api.terminal.app.guide.widget.configurator; import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import gregtech.api.gui.GuiTextures; import gregtech.api.gui.resources.ColorRectTexture; import gregtech.api.gui.resources.TextTexture; import gregtech.api.gui.widgets.ImageWidget; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/SelectorConfigurator.java b/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/SelectorConfigurator.java similarity index 95% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/SelectorConfigurator.java rename to src/main/java/gregtech/api/terminal/app/guide/widget/configurator/SelectorConfigurator.java index 054f159ee57..a6e46f27eb9 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/SelectorConfigurator.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/SelectorConfigurator.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.gui.widgets.guide.configurator; +package gregtech.api.terminal.app.guide.widget.configurator; import com.google.gson.JsonObject; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/StringConfigurator.java b/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/StringConfigurator.java similarity index 93% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/StringConfigurator.java rename to src/main/java/gregtech/api/terminal/app/guide/widget/configurator/StringConfigurator.java index fa5cc9616c2..dbcb7d300f0 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/StringConfigurator.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/StringConfigurator.java @@ -1,8 +1,7 @@ -package gregtech.api.terminal.gui.widgets.guide.configurator; +package gregtech.api.terminal.app.guide.widget.configurator; import com.google.gson.JsonObject; import gregtech.api.gui.resources.ColorRectTexture; -import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.resources.TextTexture; import gregtech.api.gui.widgets.TextFieldWidget; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/TextListConfigurator.java b/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/TextListConfigurator.java similarity index 91% rename from src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/TextListConfigurator.java rename to src/main/java/gregtech/api/terminal/app/guide/widget/configurator/TextListConfigurator.java index 1fae4a6711d..c5f37b36f2e 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/guide/configurator/TextListConfigurator.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/TextListConfigurator.java @@ -1,12 +1,10 @@ -package gregtech.api.terminal.gui.widgets.guide.configurator; +package gregtech.api.terminal.app.guide.widget.configurator; import com.google.gson.*; import gregtech.api.gui.resources.ColorRectTexture; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; import gregtech.api.terminal.gui.widgets.TextEditorWidget; -import net.minecraft.client.resources.I18n; -import java.util.Arrays; import java.util.Collections; import java.util.List; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalDesktopWidget.java b/src/main/java/gregtech/api/terminal/os/TerminalDesktopWidget.java similarity index 97% rename from src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalDesktopWidget.java rename to src/main/java/gregtech/api/terminal/os/TerminalDesktopWidget.java index ccff0af79b3..41118ea9127 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalDesktopWidget.java +++ b/src/main/java/gregtech/api/terminal/os/TerminalDesktopWidget.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.gui.widgets.os; +package gregtech.api.terminal.os; import gregtech.api.gui.widgets.WidgetGroup; import gregtech.api.terminal.app.AbstractApplication; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalDialogWidget.java b/src/main/java/gregtech/api/terminal/os/TerminalDialogWidget.java similarity index 97% rename from src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalDialogWidget.java rename to src/main/java/gregtech/api/terminal/os/TerminalDialogWidget.java index 401d1fa51ff..41b278c9638 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalDialogWidget.java +++ b/src/main/java/gregtech/api/terminal/os/TerminalDialogWidget.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.gui.widgets.os; +package gregtech.api.terminal.os; import gregtech.api.gui.GuiTextures; import gregtech.api.gui.IRenderContext; @@ -17,7 +17,6 @@ import net.minecraft.inventory.IInventory; import net.minecraft.network.PacketBuffer; -import java.awt.*; import java.io.File; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; @@ -132,10 +131,8 @@ public static TerminalDialogWidget showInfoDialog(TerminalOSWidget os, String ti return createEmptyTemplate(os).addTitle(title).addInfo(info).addOkButton(); } - public static TerminalDialogWidget showConfirmDialog(TerminalOSWidget os, String info, Consumer result) { - TerminalDialogWidget dialog = createEmptyTemplate(os).addConfirmButton(result); - dialog.addWidget(new LabelWidget(WIDTH / 2, HEIGHT / 2 - 10, info, -1).setXCentered(true)); - return dialog; + public static TerminalDialogWidget showConfirmDialog(TerminalOSWidget os, String title, String info, Consumer result) { + return createEmptyTemplate(os).addConfirmButton(result).addTitle(title).addInfo(info); } public static TerminalDialogWidget showTextFieldDialog(TerminalOSWidget os, String title, Predicate validator, Consumer result) { diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalMenuWidget.java b/src/main/java/gregtech/api/terminal/os/TerminalMenuWidget.java similarity index 98% rename from src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalMenuWidget.java rename to src/main/java/gregtech/api/terminal/os/TerminalMenuWidget.java index 0524137b242..8bf7bcbb199 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalMenuWidget.java +++ b/src/main/java/gregtech/api/terminal/os/TerminalMenuWidget.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.gui.widgets.os; +package gregtech.api.terminal.os; import gregtech.api.gui.GuiTextures; import gregtech.api.gui.IRenderContext; @@ -12,7 +12,6 @@ import net.minecraft.client.renderer.GlStateManager; import java.awt.*; -import java.io.File; public class TerminalMenuWidget extends WidgetGroup { private Interpolator interpolator; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalOSWidget.java b/src/main/java/gregtech/api/terminal/os/TerminalOSWidget.java similarity index 98% rename from src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalOSWidget.java rename to src/main/java/gregtech/api/terminal/os/TerminalOSWidget.java index 6668a0b09b9..b94cc7575ec 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/os/TerminalOSWidget.java +++ b/src/main/java/gregtech/api/terminal/os/TerminalOSWidget.java @@ -1,9 +1,8 @@ -package gregtech.api.terminal.gui.widgets.os; +package gregtech.api.terminal.os; import gregtech.api.gui.GuiTextures; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.ModularUI; -import gregtech.api.gui.Widget; import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.widgets.AbstractWidgetGroup; import gregtech.api.terminal.app.AbstractApplication; diff --git a/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java b/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java index a451c053d23..ebb61dd949f 100644 --- a/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java +++ b/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java @@ -8,7 +8,7 @@ import gregtech.api.items.metaitem.stats.IItemBehaviour; import gregtech.api.terminal.TerminalBuilder; import gregtech.api.terminal.gui.widgets.CircleButtonWidget; -import gregtech.api.terminal.gui.widgets.os.TerminalOSWidget; +import gregtech.api.terminal.os.TerminalOSWidget; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.util.ActionResult; From 8a49f053fe9a1da28eaa34de2ecf2ff2c5a6d2c8 Mon Sep 17 00:00:00 2001 From: Yefancy Date: Sun, 8 Aug 2021 13:56:37 +0800 Subject: [PATCH 38/58] adjust package structure --- src/main/java/gregtech/api/terminal/TerminalBuilder.java | 1 + .../api/terminal/app/guide/widget/CardWidget.java | 4 ++-- .../api/terminal/app/guide/widget/GuideWidget.java | 8 ++++---- .../api/terminal/app/guide/widget/GuideWidgetGroup.java | 8 ++++---- .../api/terminal/app/guide/widget/ImageWidget.java | 6 +++--- .../api/terminal/app/guide/widget/SlotListWidget.java | 2 +- .../api/terminal/app/guide/widget/TankListWidget.java | 2 +- .../api/terminal/app/guide/widget/TextBoxWidget.java | 8 ++++---- .../terminal/app/{ => guideeditor}/GuideEditorApp.java | 9 +++++---- .../{guide => guideeditor}/widget/GuideConfigEditor.java | 6 ++++-- .../widget/GuidePageEditorWidget.java | 4 +++- .../widget/configurator/BooleanConfigurator.java | 2 +- .../widget/configurator/ColorConfigurator.java | 2 +- .../widget/configurator/ConfiguratorWidget.java | 2 +- .../widget/configurator/FluidStackConfigurator.java | 2 +- .../widget/configurator/ItemStackConfigurator.java | 2 +- .../widget/configurator/NumberConfigurator.java | 2 +- .../widget/configurator/SelectorConfigurator.java | 2 +- .../widget/configurator/StringConfigurator.java | 2 +- .../widget/configurator/TextListConfigurator.java | 2 +- 20 files changed, 41 insertions(+), 35 deletions(-) rename src/main/java/gregtech/api/terminal/app/{ => guideeditor}/GuideEditorApp.java (77%) rename src/main/java/gregtech/api/terminal/app/{guide => guideeditor}/widget/GuideConfigEditor.java (98%) rename src/main/java/gregtech/api/terminal/app/{guide => guideeditor}/widget/GuidePageEditorWidget.java (98%) rename src/main/java/gregtech/api/terminal/app/{guide => guideeditor}/widget/configurator/BooleanConfigurator.java (95%) rename src/main/java/gregtech/api/terminal/app/{guide => guideeditor}/widget/configurator/ColorConfigurator.java (92%) rename src/main/java/gregtech/api/terminal/app/{guide => guideeditor}/widget/configurator/ConfiguratorWidget.java (98%) rename src/main/java/gregtech/api/terminal/app/{guide => guideeditor}/widget/configurator/FluidStackConfigurator.java (98%) rename src/main/java/gregtech/api/terminal/app/{guide => guideeditor}/widget/configurator/ItemStackConfigurator.java (98%) rename src/main/java/gregtech/api/terminal/app/{guide => guideeditor}/widget/configurator/NumberConfigurator.java (97%) rename src/main/java/gregtech/api/terminal/app/{guide => guideeditor}/widget/configurator/SelectorConfigurator.java (95%) rename src/main/java/gregtech/api/terminal/app/{guide => guideeditor}/widget/configurator/StringConfigurator.java (96%) rename src/main/java/gregtech/api/terminal/app/{guide => guideeditor}/widget/configurator/TextListConfigurator.java (95%) diff --git a/src/main/java/gregtech/api/terminal/TerminalBuilder.java b/src/main/java/gregtech/api/terminal/TerminalBuilder.java index 38b4f0a0cb2..4b45d754825 100644 --- a/src/main/java/gregtech/api/terminal/TerminalBuilder.java +++ b/src/main/java/gregtech/api/terminal/TerminalBuilder.java @@ -5,6 +5,7 @@ import gregtech.api.terminal.app.guide.MultiBlockGuideApp; import gregtech.api.terminal.app.guide.SimpleMachineGuideApp; import gregtech.api.terminal.app.guide.TutorialGuideApp; +import gregtech.api.terminal.app.guideeditor.GuideEditorApp; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/CardWidget.java b/src/main/java/gregtech/api/terminal/app/guide/widget/CardWidget.java index 77b8f0ae588..a3e8f6a1f76 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/CardWidget.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/CardWidget.java @@ -4,8 +4,8 @@ import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; -import gregtech.api.terminal.app.guide.widget.configurator.BooleanConfigurator; -import gregtech.api.terminal.app.guide.widget.configurator.NumberConfigurator; +import gregtech.api.terminal.app.guideeditor.widget.configurator.BooleanConfigurator; +import gregtech.api.terminal.app.guideeditor.widget.configurator.NumberConfigurator; import gregtech.api.util.Position; import gregtech.api.util.Size; import net.minecraft.client.renderer.BufferBuilder; diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/GuideWidget.java b/src/main/java/gregtech/api/terminal/app/guide/widget/GuideWidget.java index 2ee618f80c6..fda63019391 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/GuideWidget.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/GuideWidget.java @@ -5,10 +5,10 @@ import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; -import gregtech.api.terminal.app.guide.widget.configurator.ColorConfigurator; -import gregtech.api.terminal.app.guide.widget.configurator.NumberConfigurator; -import gregtech.api.terminal.app.guide.widget.configurator.StringConfigurator; -import gregtech.api.terminal.app.guide.widget.configurator.TextListConfigurator; +import gregtech.api.terminal.app.guideeditor.widget.configurator.ColorConfigurator; +import gregtech.api.terminal.app.guideeditor.widget.configurator.NumberConfigurator; +import gregtech.api.terminal.app.guideeditor.widget.configurator.StringConfigurator; +import gregtech.api.terminal.app.guideeditor.widget.configurator.TextListConfigurator; import gregtech.api.util.Position; import gregtech.api.util.Size; import net.minecraft.item.ItemStack; diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/GuideWidgetGroup.java b/src/main/java/gregtech/api/terminal/app/guide/widget/GuideWidgetGroup.java index 8ade843e2c5..0ac2f9c3542 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/GuideWidgetGroup.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/GuideWidgetGroup.java @@ -6,10 +6,10 @@ import gregtech.api.gui.Widget; import gregtech.api.gui.widgets.WidgetGroup; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; -import gregtech.api.terminal.app.guide.widget.configurator.ColorConfigurator; -import gregtech.api.terminal.app.guide.widget.configurator.NumberConfigurator; -import gregtech.api.terminal.app.guide.widget.configurator.StringConfigurator; -import gregtech.api.terminal.app.guide.widget.configurator.TextListConfigurator; +import gregtech.api.terminal.app.guideeditor.widget.configurator.ColorConfigurator; +import gregtech.api.terminal.app.guideeditor.widget.configurator.NumberConfigurator; +import gregtech.api.terminal.app.guideeditor.widget.configurator.StringConfigurator; +import gregtech.api.terminal.app.guideeditor.widget.configurator.TextListConfigurator; import gregtech.api.util.Position; import gregtech.api.util.Size; import net.minecraft.item.ItemStack; diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/ImageWidget.java b/src/main/java/gregtech/api/terminal/app/guide/widget/ImageWidget.java index 2001be50038..8749aa572be 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/ImageWidget.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/ImageWidget.java @@ -8,9 +8,9 @@ import gregtech.api.gui.resources.TextureArea; import gregtech.api.gui.resources.URLTexture; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; -import gregtech.api.terminal.app.guide.widget.configurator.NumberConfigurator; -import gregtech.api.terminal.app.guide.widget.configurator.SelectorConfigurator; -import gregtech.api.terminal.app.guide.widget.configurator.StringConfigurator; +import gregtech.api.terminal.app.guideeditor.widget.configurator.NumberConfigurator; +import gregtech.api.terminal.app.guideeditor.widget.configurator.SelectorConfigurator; +import gregtech.api.terminal.app.guideeditor.widget.configurator.StringConfigurator; import gregtech.api.util.Position; import gregtech.api.util.Size; import net.minecraft.client.renderer.GlStateManager; diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/SlotListWidget.java b/src/main/java/gregtech/api/terminal/app/guide/widget/SlotListWidget.java index e944d34f0cb..8cc14e1fad4 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/SlotListWidget.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/SlotListWidget.java @@ -7,7 +7,7 @@ import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.widgets.SlotWidget; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; -import gregtech.api.terminal.app.guide.widget.configurator.ItemStackConfigurator; +import gregtech.api.terminal.app.guideeditor.widget.configurator.ItemStackConfigurator; import gregtech.api.util.Size; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/TankListWidget.java b/src/main/java/gregtech/api/terminal/app/guide/widget/TankListWidget.java index 587c3cd5f8f..8b67b853137 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/TankListWidget.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/TankListWidget.java @@ -7,7 +7,7 @@ import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.widgets.TankWidget; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; -import gregtech.api.terminal.app.guide.widget.configurator.FluidStackConfigurator; +import gregtech.api.terminal.app.guideeditor.widget.configurator.FluidStackConfigurator; import gregtech.api.util.Size; import net.minecraftforge.fluids.Fluid; import net.minecraftforge.fluids.FluidRegistry; diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/TextBoxWidget.java b/src/main/java/gregtech/api/terminal/app/guide/widget/TextBoxWidget.java index 98c8259f10f..2594280a3b5 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/TextBoxWidget.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/TextBoxWidget.java @@ -5,10 +5,10 @@ import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; -import gregtech.api.terminal.app.guide.widget.configurator.BooleanConfigurator; -import gregtech.api.terminal.app.guide.widget.configurator.ColorConfigurator; -import gregtech.api.terminal.app.guide.widget.configurator.NumberConfigurator; -import gregtech.api.terminal.app.guide.widget.configurator.TextListConfigurator; +import gregtech.api.terminal.app.guideeditor.widget.configurator.BooleanConfigurator; +import gregtech.api.terminal.app.guideeditor.widget.configurator.ColorConfigurator; +import gregtech.api.terminal.app.guideeditor.widget.configurator.NumberConfigurator; +import gregtech.api.terminal.app.guideeditor.widget.configurator.TextListConfigurator; import gregtech.api.util.Position; import gregtech.api.util.Size; import net.minecraft.client.Minecraft; diff --git a/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java b/src/main/java/gregtech/api/terminal/app/guideeditor/GuideEditorApp.java similarity index 77% rename from src/main/java/gregtech/api/terminal/app/GuideEditorApp.java rename to src/main/java/gregtech/api/terminal/app/guideeditor/GuideEditorApp.java index dbe72974447..7bd1c2c2a1c 100644 --- a/src/main/java/gregtech/api/terminal/app/GuideEditorApp.java +++ b/src/main/java/gregtech/api/terminal/app/guideeditor/GuideEditorApp.java @@ -1,14 +1,15 @@ -package gregtech.api.terminal.app; +package gregtech.api.terminal.app.guideeditor; import gregtech.api.gui.resources.TextureArea; -import gregtech.api.terminal.app.guide.widget.GuideConfigEditor; -import gregtech.api.terminal.app.guide.widget.GuidePageEditorWidget; +import gregtech.api.terminal.app.AbstractApplication; +import gregtech.api.terminal.app.guideeditor.widget.GuideConfigEditor; +import gregtech.api.terminal.app.guideeditor.widget.GuidePageEditorWidget; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.PacketBuffer; import java.util.function.Consumer; -public class GuideEditorApp extends AbstractApplication{ +public class GuideEditorApp extends AbstractApplication { public static final TextureArea ICON = TextureArea.fullImage("textures/gui/terminal/guide_editor/icon.png"); public GuideEditorApp() { diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/GuideConfigEditor.java b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/GuideConfigEditor.java similarity index 98% rename from src/main/java/gregtech/api/terminal/app/guide/widget/GuideConfigEditor.java rename to src/main/java/gregtech/api/terminal/app/guideeditor/widget/GuideConfigEditor.java index f455d61ebba..8d6aa85fcfe 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/GuideConfigEditor.java +++ b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/GuideConfigEditor.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.guide.widget; +package gregtech.api.terminal.app.guideeditor.widget; import com.google.gson.JsonObject; import com.google.gson.JsonParser; @@ -10,7 +10,9 @@ import gregtech.api.gui.widgets.ImageWidget; import gregtech.api.gui.widgets.*; import gregtech.api.gui.widgets.tab.IGuiTextureTabInfo; -import gregtech.api.terminal.app.GuideEditorApp; +import gregtech.api.terminal.app.guide.widget.GuidePageWidget; +import gregtech.api.terminal.app.guide.widget.IGuideWidget; +import gregtech.api.terminal.app.guideeditor.GuideEditorApp; import gregtech.api.terminal.gui.CustomTabListRenderer; import gregtech.api.terminal.gui.widgets.CircleButtonWidget; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/GuidePageEditorWidget.java b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/GuidePageEditorWidget.java similarity index 98% rename from src/main/java/gregtech/api/terminal/app/guide/widget/GuidePageEditorWidget.java rename to src/main/java/gregtech/api/terminal/app/guideeditor/widget/GuidePageEditorWidget.java index 95470e3a3fb..6995f88cc6a 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/GuidePageEditorWidget.java +++ b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/GuidePageEditorWidget.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.guide.widget; +package gregtech.api.terminal.app.guideeditor.widget; import com.google.gson.Gson; @@ -8,6 +8,8 @@ import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.terminal.app.guide.widget.GuidePageWidget; +import gregtech.api.terminal.app.guide.widget.IGuideWidget; import gregtech.api.terminal.gui.widgets.CircleButtonWidget; import gregtech.api.terminal.gui.widgets.CustomPositionSizeWidget; import gregtech.api.util.Position; diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/BooleanConfigurator.java b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/BooleanConfigurator.java similarity index 95% rename from src/main/java/gregtech/api/terminal/app/guide/widget/configurator/BooleanConfigurator.java rename to src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/BooleanConfigurator.java index 18605fa62e9..cfb4ff12802 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/BooleanConfigurator.java +++ b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/BooleanConfigurator.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.guide.widget.configurator; +package gregtech.api.terminal.app.guideeditor.widget.configurator; import com.google.gson.JsonObject; import gregtech.api.gui.resources.ColorRectTexture; diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/ColorConfigurator.java b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/ColorConfigurator.java similarity index 92% rename from src/main/java/gregtech/api/terminal/app/guide/widget/configurator/ColorConfigurator.java rename to src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/ColorConfigurator.java index 031c5206d55..c561275cc46 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/ColorConfigurator.java +++ b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/ColorConfigurator.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.guide.widget.configurator; +package gregtech.api.terminal.app.guideeditor.widget.configurator; import com.google.gson.JsonObject; import gregtech.api.terminal.gui.widgets.ColorWidget; diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/ConfiguratorWidget.java b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/ConfiguratorWidget.java similarity index 98% rename from src/main/java/gregtech/api/terminal/app/guide/widget/configurator/ConfiguratorWidget.java rename to src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/ConfiguratorWidget.java index 522dd9abc32..26300ca40ba 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/ConfiguratorWidget.java +++ b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/ConfiguratorWidget.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.guide.widget.configurator; +package gregtech.api.terminal.app.guideeditor.widget.configurator; import com.google.gson.Gson; import com.google.gson.JsonObject; diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/FluidStackConfigurator.java b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/FluidStackConfigurator.java similarity index 98% rename from src/main/java/gregtech/api/terminal/app/guide/widget/configurator/FluidStackConfigurator.java rename to src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/FluidStackConfigurator.java index 7833d42569d..a79ed58485e 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/FluidStackConfigurator.java +++ b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/FluidStackConfigurator.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.guide.widget.configurator; +package gregtech.api.terminal.app.guideeditor.widget.configurator; import com.google.gson.Gson; import com.google.gson.JsonElement; diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/ItemStackConfigurator.java b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/ItemStackConfigurator.java similarity index 98% rename from src/main/java/gregtech/api/terminal/app/guide/widget/configurator/ItemStackConfigurator.java rename to src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/ItemStackConfigurator.java index c9b81e4ffda..c361b889772 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/ItemStackConfigurator.java +++ b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/ItemStackConfigurator.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.guide.widget.configurator; +package gregtech.api.terminal.app.guideeditor.widget.configurator; import com.google.gson.Gson; import com.google.gson.JsonElement; diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/NumberConfigurator.java b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/NumberConfigurator.java similarity index 97% rename from src/main/java/gregtech/api/terminal/app/guide/widget/configurator/NumberConfigurator.java rename to src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/NumberConfigurator.java index 54ce1be916b..ece9cc52422 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/NumberConfigurator.java +++ b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/NumberConfigurator.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.guide.widget.configurator; +package gregtech.api.terminal.app.guideeditor.widget.configurator; import com.google.gson.JsonElement; import com.google.gson.JsonObject; diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/SelectorConfigurator.java b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/SelectorConfigurator.java similarity index 95% rename from src/main/java/gregtech/api/terminal/app/guide/widget/configurator/SelectorConfigurator.java rename to src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/SelectorConfigurator.java index a6e46f27eb9..23511f0a03d 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/SelectorConfigurator.java +++ b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/SelectorConfigurator.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.guide.widget.configurator; +package gregtech.api.terminal.app.guideeditor.widget.configurator; import com.google.gson.JsonObject; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/StringConfigurator.java b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/StringConfigurator.java similarity index 96% rename from src/main/java/gregtech/api/terminal/app/guide/widget/configurator/StringConfigurator.java rename to src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/StringConfigurator.java index dbcb7d300f0..8329ec1365d 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/StringConfigurator.java +++ b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/StringConfigurator.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.guide.widget.configurator; +package gregtech.api.terminal.app.guideeditor.widget.configurator; import com.google.gson.JsonObject; import gregtech.api.gui.resources.ColorRectTexture; diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/TextListConfigurator.java b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/TextListConfigurator.java similarity index 95% rename from src/main/java/gregtech/api/terminal/app/guide/widget/configurator/TextListConfigurator.java rename to src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/TextListConfigurator.java index c5f37b36f2e..ccc30ac3152 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/configurator/TextListConfigurator.java +++ b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/TextListConfigurator.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.guide.widget.configurator; +package gregtech.api.terminal.app.guideeditor.widget.configurator; import com.google.gson.*; import gregtech.api.gui.resources.ColorRectTexture; From e3bf33cdfa726619fd53dfa03843fd6ed7d33abe Mon Sep 17 00:00:00 2001 From: DStrand1 Date: Sun, 8 Aug 2021 18:22:19 -0500 Subject: [PATCH 39/58] fix rebase issues --- .../api/gui/widgets/PhantomFluidWidget.java | 4 ++-- .../terminal/gui/widgets/TextEditorWidget.java | 10 ++++++---- src/main/java/gregtech/common/CommonProxy.java | 15 --------------- .../java/gregtech/common/items/MetaItem1.java | 1 + 4 files changed, 9 insertions(+), 21 deletions(-) diff --git a/src/main/java/gregtech/api/gui/widgets/PhantomFluidWidget.java b/src/main/java/gregtech/api/gui/widgets/PhantomFluidWidget.java index b4fbc668b9f..6fa9bf5dbf0 100644 --- a/src/main/java/gregtech/api/gui/widgets/PhantomFluidWidget.java +++ b/src/main/java/gregtech/api/gui/widgets/PhantomFluidWidget.java @@ -34,8 +34,8 @@ public class PhantomFluidWidget extends Widget implements IIngredientSlot, IGhos protected IGuiTexture backgroundTexture = GuiTextures.FLUID_SLOT; - private final Supplier fluidStackSupplier; - private final Consumer fluidStackUpdater; + private Supplier fluidStackSupplier; + private Consumer fluidStackUpdater; private boolean isClient; protected FluidStack lastFluidStack; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/TextEditorWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/TextEditorWidget.java index d306e16dd94..d2db1989d4f 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/TextEditorWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/TextEditorWidget.java @@ -100,12 +100,14 @@ private static class TextPanelWidget extends DraggableScrollableWidgetGroup { public TextFormatting frontColor; public List frontStyle; + private static final char SECTION_SIGN = '\u00A7'; + @SideOnly(Side.CLIENT) public FontRenderer fontRenderer; @SideOnly(Side.CLIENT) - private static final Pattern R_CODE_PATTERN = Pattern.compile("(?i)§[R]"); + private static final Pattern R_CODE_PATTERN = Pattern.compile("(?i)" + SECTION_SIGN + "[R]"); @SideOnly(Side.CLIENT) - private static final Pattern COLOR_CODE_PATTERN = Pattern.compile("(?i)§[0-9A-F]"); + private static final Pattern COLOR_CODE_PATTERN = Pattern.compile("(?i)" + SECTION_SIGN + "[0-9A-F]"); public TextPanelWidget(int x, int y, int width, int height, Consumer stringUpdate) { @@ -162,7 +164,7 @@ public boolean keyTyped(char typedChar, int keyCode) { } private static TextFormatting lookAheadChars(final String content, int index) { - if (index > 1 && content.charAt(index - 2) == '§') { + if (index > 1 && content.charAt(index - 2) == SECTION_SIGN) { int t = content.charAt(index - 1); if ('0' <= t && t <= '9'){ return TextFormatting.values()[t - '0']; @@ -220,7 +222,7 @@ public static String cleanUpFormatting(final String content) { } private void findFrontFormatting() { - int lastReset = content.lastIndexOf("§r"); + int lastReset = content.lastIndexOf(SECTION_SIGN + "r"); int lastColor = -1; frontColor = null; frontStyle.clear(); diff --git a/src/main/java/gregtech/common/CommonProxy.java b/src/main/java/gregtech/common/CommonProxy.java index 08e32ac1fc2..e39810e833d 100644 --- a/src/main/java/gregtech/common/CommonProxy.java +++ b/src/main/java/gregtech/common/CommonProxy.java @@ -1,9 +1,5 @@ package gregtech.common; -import com.google.gson.Gson; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import forestry.core.config.Constants; import gregtech.api.GTValues; import gregtech.api.block.machines.MachineItemBlock; import gregtech.api.enchants.EnchantmentEnderDamage; @@ -15,8 +11,6 @@ import gregtech.api.unification.material.properties.DustProperty; import gregtech.api.unification.material.properties.PropertyKey; import gregtech.api.terminal.TerminalBuilder; -import gregtech.api.unification.material.type.DustMaterial; -import gregtech.api.unification.material.type.Material; import gregtech.api.unification.ore.OrePrefix; import gregtech.api.util.GTLog; import gregtech.common.blocks.*; @@ -38,14 +32,12 @@ import gregtech.loaders.recipe.*; import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; -import net.minecraft.client.Minecraft; import net.minecraft.enchantment.Enchantment; import net.minecraft.item.Item; import net.minecraft.item.ItemBlock; import net.minecraft.item.ItemMultiTexture; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.IRecipe; -import net.minecraft.util.ResourceLocation; import net.minecraftforge.common.config.Config.Type; import net.minecraftforge.common.config.ConfigManager; import net.minecraftforge.event.RegistryEvent; @@ -56,14 +48,7 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.registries.IForgeRegistry; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.URL; -import java.util.Enumeration; import java.util.function.Function; -import java.util.stream.Collectors; import static gregtech.common.blocks.MetaBlocks.*; diff --git a/src/main/java/gregtech/common/items/MetaItem1.java b/src/main/java/gregtech/common/items/MetaItem1.java index 972fa117247..c91e9d94116 100644 --- a/src/main/java/gregtech/common/items/MetaItem1.java +++ b/src/main/java/gregtech/common/items/MetaItem1.java @@ -374,6 +374,7 @@ public void registerSubItems() { ENERGY_FIELD_PROJECTOR = addItem(464, "energy_field_projector").addComponents(ElectricStats.createElectricItem(16000000L, GTValues.EV)).setMaxStackSize(1); SCANNER = addItem(465, "scanner").addComponents(ElectricStats.createElectricItem(200_000L, GTValues.LV), new ScannerBehavior(50)); /* CLIPBOARD GOES HERE - ID 466 */ + GUIDE_TERMINAL = addItem(467, "guide_terminal").addComponents(new GuideTerminalBehaviour()); // Misc Crafting Items: ID 491-515 ENERGIUM_DUST = addItem(491, "energium_dust"); From 812c6c7b7d865e7d9b1f3c74ae5cd0d9a5390f01 Mon Sep 17 00:00:00 2001 From: Yefancy Date: Mon, 9 Aug 2021 11:30:43 +0800 Subject: [PATCH 40/58] searching --- .../api/gui/widgets/TextFieldWidget.java | 3 +- .../api/terminal/app/AbstractApplication.java | 11 ++ .../api/terminal/app/guide/GuideApp.java | 117 +++++++++++++++--- .../terminal/gui/widgets/SelectorWidget.java | 7 +- .../terminal/gui/widgets/TreeListWidget.java | 35 ++++++ .../api/terminal/os/TerminalOSWidget.java | 7 +- .../os/{ => menu}/TerminalMenuWidget.java | 80 +++++++++--- .../os/menu/component/IMenuComponent.java | 15 +++ .../os/menu/component/SearchComponent.java | 112 +++++++++++++++++ .../gregtech/api/terminal/util/FileTree.java | 15 --- .../gregtech/api/terminal/util/ISearch.java | 8 ++ .../api/terminal/util/SearchEngine.java | 37 ++++++ .../gregtech/api/terminal/util/TreeNode.java | 21 +++- 13 files changed, 407 insertions(+), 61 deletions(-) rename src/main/java/gregtech/api/terminal/os/{ => menu}/TerminalMenuWidget.java (61%) create mode 100644 src/main/java/gregtech/api/terminal/os/menu/component/IMenuComponent.java create mode 100644 src/main/java/gregtech/api/terminal/os/menu/component/SearchComponent.java create mode 100644 src/main/java/gregtech/api/terminal/util/ISearch.java create mode 100644 src/main/java/gregtech/api/terminal/util/SearchEngine.java diff --git a/src/main/java/gregtech/api/gui/widgets/TextFieldWidget.java b/src/main/java/gregtech/api/gui/widgets/TextFieldWidget.java index 2f89b089fb3..d6c2d5437bf 100644 --- a/src/main/java/gregtech/api/gui/widgets/TextFieldWidget.java +++ b/src/main/java/gregtech/api/gui/widgets/TextFieldWidget.java @@ -170,9 +170,8 @@ protected void onTextChanged(String newTextString) { if (textValidator.test(newTextString)) { if (isClient && textResponder != null) { textResponder.accept(newTextString); - } else { - writeClientAction(1, buffer -> buffer.writeString(newTextString)); } + writeClientAction(1, buffer -> buffer.writeString(newTextString)); } } diff --git a/src/main/java/gregtech/api/terminal/app/AbstractApplication.java b/src/main/java/gregtech/api/terminal/app/AbstractApplication.java index 671538d2090..c1dab7aa5d1 100644 --- a/src/main/java/gregtech/api/terminal/app/AbstractApplication.java +++ b/src/main/java/gregtech/api/terminal/app/AbstractApplication.java @@ -3,9 +3,16 @@ import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.terminal.gui.widgets.AnimaWidgetGroup; import gregtech.api.terminal.os.TerminalOSWidget; +import gregtech.api.terminal.os.menu.component.IMenuComponent; import gregtech.api.util.Position; import gregtech.api.util.Size; import net.minecraft.nbt.NBTTagCompound; +import sun.security.util.ArrayUtil; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; public abstract class AbstractApplication extends AnimaWidgetGroup { protected final String name; @@ -43,4 +50,8 @@ public boolean isBackgroundApp() { public TerminalOSWidget getOs() { return os; } + + public List getMenuComponents() { + return Collections.emptyList(); + } } diff --git a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java index a7d19ccb608..da907f2dd40 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java @@ -7,10 +7,13 @@ import gregtech.api.gui.GuiTextures; import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.terminal.app.AbstractApplication; +import gregtech.api.terminal.app.guide.widget.GuidePageWidget; import gregtech.api.terminal.gui.widgets.TreeListWidget; -import gregtech.api.terminal.app.guide.widget.*; +import gregtech.api.terminal.os.menu.component.IMenuComponent; +import gregtech.api.terminal.os.menu.component.SearchComponent; import gregtech.api.terminal.util.TreeNode; import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.I18n; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.PacketBuffer; import net.minecraft.util.ResourceLocation; @@ -19,10 +22,15 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.util.Arrays; +import java.util.List; +import java.util.Stack; import java.util.function.Consumer; +import java.util.stream.Collectors; -public abstract class GuideApp extends AbstractApplication { +public abstract class GuideApp extends AbstractApplication implements SearchComponent.IMenuSearch>> { private GuidePageWidget pageWidget; + private TreeListWidget tree; public GuideApp(String name, IGuiTexture icon) { super(name, icon); } @@ -32,24 +40,11 @@ public AbstractApplication createApp(boolean isClient, NBTTagCompound nbt) { try { GuideApp app = this.getClass().newInstance(); if (isClient && getTree() != null) { - app.addWidget( - new TreeListWidget<>(0, 0, 133, 232, getTree(), leaf -> { - if (app.pageWidget != null) { - app.removeWidget(app.pageWidget); - } - app.pageWidget = new GuidePageWidget(133, 0, 200, 232, 5); - if (leaf.isLeaf() && leaf.getContent() != null) { - JsonObject page = getPage(leaf.getContent()); - if (page != null) { - app.pageWidget.loadJsonConfig(page); - } - } - app.addWidget(app.pageWidget); - }).setContentIconSupplier(this::itemIcon) - .setContentNameSupplier(this::itemName) - .setNodeTexture(GuiTextures.BORDERED_BACKGROUND) - .setLeafTexture(GuiTextures.SLOT_DARKENED) - ); + app.tree = new TreeListWidget<>(0, 0, 133, 232, getTree(), app::loadPage).setContentIconSupplier(this::itemIcon) + .setContentNameSupplier(this::itemName) + .setNodeTexture(GuiTextures.BORDERED_BACKGROUND) + .setLeafTexture(GuiTextures.SLOT_DARKENED); + app.addWidget(app.tree); } return app; } catch (Exception e) { @@ -58,6 +53,23 @@ public AbstractApplication createApp(boolean isClient, NBTTagCompound nbt) { return null; } + protected void loadPage(TreeNode leaf) { + if (leaf == null) { + return; + } + if (this.pageWidget != null) { + this.removeWidget(this.pageWidget); + } + this.pageWidget = new GuidePageWidget(133, 0, 200, 232, 5); + if (leaf.isLeaf() && leaf.getContent() != null) { + JsonObject page = getPage(leaf.getContent()); + if (page != null) { + this.pageWidget.loadJsonConfig(page); + } + } + this.addWidget(this.pageWidget); + } + @Override protected void writeClientAction(int id, Consumer packetBufferWriter) { } @@ -86,4 +98,69 @@ public static JsonObject getConfig(String fileName) { return null; } } + + // ISearch + @Override + public boolean isManualInterrupt() { + return true; + } + + @Override + public void search(String word, Consumer>> find) { + Stack> stack = new Stack<>(); + stack.push(getTree()); + dfsSearch(Thread.currentThread(), stack, word.toLowerCase(), find); + } + + private boolean dfsSearch(Thread thread, Stack> stack, String regex, Consumer>> find) { + if (thread.isInterrupted()) { + return true; + } else { + TreeNode node = stack.peek(); + if (!node.isLeaf() && I18n.format(node.getKey()).toLowerCase().contains(regex)) { + find.accept((Stack>) stack.clone()); + } else if (node.isLeaf()) { + String name = itemName(node.getContent()); + if (name == null) { + name = node.getKey(); + } + if (I18n.format(name).toLowerCase().contains(regex)) { + find.accept((Stack>) stack.clone()); + } + } + if (node.getChildren() != null) { + for (TreeNode child : node.getChildren()) { + stack.push(child); + if (dfsSearch(thread, stack, regex, find)) return true; + stack.pop(); + } + } + } + return false; + } + + @Override + public void selectResult(Stack> result) { + if (result.size() > 0 && tree != null) { + List path = result.stream().map(TreeNode::getKey).collect(Collectors.toList()); + path.remove(0); + loadPage(tree.jumpTo(path)); + } + } + + @Override + public String resultDisplay(Stack> result) { + return result.stream().map(node->{ + String name = node.getContent() != null ? itemName(node.getContent()) : null; + if (name == null) { + name = node.getKey(); + } + return I18n.format(name); + }).collect(Collectors.joining("->")); + } + + @Override + public List getMenuComponents() { + return Arrays.asList(new SearchComponent<>(this)); + } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/SelectorWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/SelectorWidget.java index 6f8b0efbef2..fcfa2898fb2 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/SelectorWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/SelectorWidget.java @@ -64,7 +64,7 @@ public void drawInForeground(int mouseX, int mouseY) { int x = getPosition().x; int width = getSize().width; int height = getSize().height; - int y = (isUp ? -candidates.size(): (candidates.size() + 1)) * height + getPosition().y; + int y = (isUp ? -candidates.size() : 1) * height + getPosition().y; for (String candidate : candidates) { if (background != null) { background.draw(x, y, width, height); @@ -75,7 +75,7 @@ public void drawInForeground(int mouseX, int mouseY) { fontRenderer.drawString(candidate, x + 4, y + (height - fontRenderer.FONT_HEIGHT) / 2 + 1, fontColor); y += height; } - y = (isUp ? -candidates.size(): (candidates.size() + 1)) * height + getPosition().y; + y = (isUp ? -candidates.size() : 1) * height + getPosition().y; for (String ignored : candidates) { if (isMouseOver(x, y, width, height, mouseX, mouseY)) { drawBorder(x, y, width, height, -1, 1); @@ -91,13 +91,14 @@ public boolean mouseClicked(int mouseX, int mouseY, int button) { int x = getPosition().x; int width = getSize().width; int height = getSize().height; - int y = (isUp ? -candidates.size(): (candidates.size() + 1)) * height + getPosition().y; + int y = (isUp ? -candidates.size() : 1) * height + getPosition().y; for (String candidate : candidates) { if (isMouseOver(x, y, width, height, mouseX, mouseY)) { if (onChanged != null) { onChanged.accept(candidate); } writeClientAction(2, buffer -> buffer.writeString(candidate)); + return true; } y += height; } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/TreeListWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/TreeListWidget.java index 5c1939456ed..4cae842735d 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/TreeListWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/TreeListWidget.java @@ -160,6 +160,41 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender GlStateManager.color(1,1,1,1); } + public TreeNode jumpTo(List path) { + list.removeIf(node->node.dimension != 1); + this.selected = null; + int dim = 1; + int index = 0; + boolean flag = false; + TreeNode node = null; + for (K key : path) { + flag = false; + for (int i = index; i < list.size(); i++) { + node = list.get(i); + if (node.dimension != dim) { + return null; + } else if (node.getKey().equals(key)) { //expand + if(!node.isLeaf() && path.size() > dim) { + for (int j = 0; j < node.getChildren().size(); j++) { + list.add(index + 1 + j, node.getChildren().get(j)); + } + } + index = i + 1; + dim++; + flag = true; + break; + } + } + if (!flag) return null; + } + if (flag) { + this.selected = node; + this.scrollOffset = MathHelper.clamp(ITEM_HEIGHT * (index - 1), 0, Math.max(list.size() * ITEM_HEIGHT - getSize().height, 0)); + return this.selected; + } + return null; + } + @Override public boolean mouseClicked(int mouseX, int mouseY, int button) { if (this.isMouseOverElement(mouseX, mouseY)) { diff --git a/src/main/java/gregtech/api/terminal/os/TerminalOSWidget.java b/src/main/java/gregtech/api/terminal/os/TerminalOSWidget.java index b94cc7575ec..5ff4851446f 100644 --- a/src/main/java/gregtech/api/terminal/os/TerminalOSWidget.java +++ b/src/main/java/gregtech/api/terminal/os/TerminalOSWidget.java @@ -6,6 +6,7 @@ import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.widgets.AbstractWidgetGroup; import gregtech.api.terminal.app.AbstractApplication; +import gregtech.api.terminal.os.menu.TerminalMenuWidget; import gregtech.api.util.Position; import gregtech.api.util.RenderUtil; import gregtech.api.util.Size; @@ -51,7 +52,6 @@ public void openApplication(AbstractApplication application, boolean isClient) { } for (AbstractApplication app : openedApps) { if (app.getClass() == application.getClass()) { - focusApp = app; maximizeApplication(app, isClient); return; } @@ -64,7 +64,6 @@ public void openApplication(AbstractApplication application, boolean isClient) { if (app != null) { openedApps.add(app); desktop.addWidget(app); - focusApp = app; maximizeApplication(app, isClient); } } @@ -77,6 +76,8 @@ public void maximizeApplication(AbstractApplication application, boolean isClien menu.hideMenu(); } } + focusApp = application; + menu.loadComponents(focusApp); desktop.hideDesktop(); } @@ -91,6 +92,7 @@ public void minimizeApplication(AbstractApplication application, boolean isClien if(focusApp == application) { focusApp = null; } + menu.removeComponents(); desktop.showDesktop(); } } @@ -111,6 +113,7 @@ public void closeApplication(AbstractApplication application, boolean isClient) if(focusApp == application) { focusApp = null; } + menu.removeComponents(); desktop.showDesktop(); } } diff --git a/src/main/java/gregtech/api/terminal/os/TerminalMenuWidget.java b/src/main/java/gregtech/api/terminal/os/menu/TerminalMenuWidget.java similarity index 61% rename from src/main/java/gregtech/api/terminal/os/TerminalMenuWidget.java rename to src/main/java/gregtech/api/terminal/os/menu/TerminalMenuWidget.java index 8bf7bcbb199..39c7f2c5fe7 100644 --- a/src/main/java/gregtech/api/terminal/os/TerminalMenuWidget.java +++ b/src/main/java/gregtech/api/terminal/os/menu/TerminalMenuWidget.java @@ -1,28 +1,38 @@ -package gregtech.api.terminal.os; +package gregtech.api.terminal.os.menu; -import gregtech.api.gui.GuiTextures; import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.Widget; import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.terminal.app.AbstractApplication; import gregtech.api.terminal.gui.widgets.CircleButtonWidget; +import gregtech.api.terminal.os.TerminalDialogWidget; +import gregtech.api.terminal.os.TerminalOSWidget; +import gregtech.api.terminal.os.menu.component.IMenuComponent; import gregtech.api.util.Position; import gregtech.api.util.Size; import gregtech.api.util.interpolate.Eases; import gregtech.api.util.interpolate.Interpolator; import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.util.Tuple; import java.awt.*; +import java.util.ArrayList; +import java.util.List; + public class TerminalMenuWidget extends WidgetGroup { private Interpolator interpolator; private IGuiTexture background; private final TerminalOSWidget os; + private final List> components; public boolean isHide; public TerminalMenuWidget(Position position, Size size, TerminalOSWidget os) { super(position, size); this.os = os; + components = new ArrayList<>(); this.addWidget(new CircleButtonWidget(5, 10, 4, 1, 0) .setColors(new Color(255, 255, 255, 0).getRGB(), new Color(255, 255, 255).getRGB(), @@ -41,13 +51,6 @@ public TerminalMenuWidget(Position position, Size size, TerminalOSWidget os) { new Color(154, 243, 122).getRGB()) .setHoverText("maximize") .setClickListener(this::maximize)); - this.addWidget(new CircleButtonWidget(15, 40, 10, 1, 14) - .setColors(new Color(255, 255, 255, 0).getRGB(), - new Color(255, 255, 255).getRGB(), - new Color(80, 80, 80).getRGB()) - .setHoverText("setting") - .setIcon(GuiTextures.TERMINAL_SETTING) - .setClickListener(this::setting)); } public TerminalMenuWidget setBackground(IGuiTexture background) { @@ -67,11 +70,49 @@ public void maximize(ClickData clickData) { TerminalDialogWidget.showColorDialog(os, "test", System.out::println).addPlayerInventory().open(); } - public void setting(ClickData clickData) { -// TerminalDialogWidget.showInfoDialog(os, "test"); -// TerminalDialogWidget.showConfirmDialog(os, "test", null); -// TerminalDialogWidget.showTextFieldDialog(os, "test", s->true, System.out::println); -// TerminalDialogWidget.showFileDialog(os, "test", new File("./"), System.out::println).setClientSide().open(); + public void addComponent(IMenuComponent component) { + WidgetGroup group = new WidgetGroup(); + int x = 15; + int y = 40 + components.size() * 25; + group.addWidget(new CircleButtonWidget(x, y, 10, 1, 14) + .setColors(0x00FFFFFF, 0xFFFFFFFF, 0xFF505050) + .setHoverText(component.hoverText()) + .setIcon(component.buttonIcon()) + .setClickListener(c->{ + components.forEach(tuple -> { + if (tuple.getFirst() instanceof Widget && tuple.getFirst() != component){ + ((Widget) tuple.getFirst()).setActive(false); + ((Widget) tuple.getFirst()).setVisible(false); + } + }); + if (component instanceof Widget) { + Widget widget = (Widget)component; + widget.setVisible(!widget.isVisible()); + widget.setActive(!widget.isActive()); + } + component.click(c); + })); + if (component instanceof Widget) { + Widget widget = (Widget)component; + widget.setSelfPosition(new Position(x + 20, y - 10)); + widget.setVisible(false); + widget.setActive(false); + group.addWidget(widget); + } + this.addWidget(group); + components.add(new Tuple<>(component, group)); + } + + public void loadComponents(AbstractApplication app) { + removeComponents(); + if (app != null) { + app.getMenuComponents().forEach(this::addComponent); + } + } + + public void removeComponents() { + components.forEach(component->this.removeWidget(component.getSecond())); + components.clear(); } public void hideMenu() { @@ -119,4 +160,15 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender GlStateManager.color(1,1,1,1); super.drawInBackground(mouseX, mouseY, partialTicks, context); } + + @Override + public boolean mouseClicked(int mouseX, int mouseY, int button) { + if (!super.mouseClicked(mouseX, mouseY, button)) { + if (!isMouseOverElement(mouseX, mouseY) && !isHide) { + hideMenu(); + } + return false; + } + return true; + } } diff --git a/src/main/java/gregtech/api/terminal/os/menu/component/IMenuComponent.java b/src/main/java/gregtech/api/terminal/os/menu/component/IMenuComponent.java new file mode 100644 index 00000000000..46a7f63fbb8 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/os/menu/component/IMenuComponent.java @@ -0,0 +1,15 @@ +package gregtech.api.terminal.os.menu.component; + +import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.ColorRectTexture; +import gregtech.api.gui.resources.IGuiTexture; + +public interface IMenuComponent { + default IGuiTexture buttonIcon() { + return new ColorRectTexture(0); + } + default String hoverText() { + return null; + } + default void click(Widget.ClickData clickData){} +} diff --git a/src/main/java/gregtech/api/terminal/os/menu/component/SearchComponent.java b/src/main/java/gregtech/api/terminal/os/menu/component/SearchComponent.java new file mode 100644 index 00000000000..4339596b354 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/os/menu/component/SearchComponent.java @@ -0,0 +1,112 @@ +package gregtech.api.terminal.os.menu.component; + +import gregtech.api.gui.GuiTextures; +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.ColorRectTexture; +import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.widgets.TextFieldWidget; +import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.terminal.util.ISearch; +import gregtech.api.terminal.util.SearchEngine; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.util.Tuple; +import net.minecraft.util.math.MathHelper; + +import java.util.ArrayList; +import java.util.List; + +public class SearchComponent extends WidgetGroup implements IMenuComponent{ + private final static int SIZE = 6; + private final SearchEngine engine; + private final List> results; + private final IMenuSearch search; + private boolean isUp; + private int offset; + + public SearchComponent(IMenuSearch search){ + this.search = search; + results = new ArrayList<>(); + engine = new SearchEngine<>(search, r -> results.add(new Tuple<>(r, search.resultDisplay(r)))); + this.addWidget(new TextFieldWidget(0, 0, 260, 20, new ColorRectTexture(0xcf000000), null, null) + .setValidator(s->true) + .setTextResponder(s->{ + results.clear(); + engine.searchWord(s); + offset = 0; + }, true)); + } + + @Override + public IGuiTexture buttonIcon() { + return GuiTextures.TERMINAL_SETTING; + } + + @Override + public String hoverText() { + return "searching"; + } + + public void setUp(boolean up) { + isUp = up; + } + + @Override + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + super.drawInBackground(mouseX, mouseY, partialTicks, context); + int x = getPosition().x; + int width = getSize().width; + int height = getSize().height; + int y = (isUp ? -results.size() : 1) * height + getPosition().y; + int max = Math.min(offset + SIZE, results.size()); + for (int i = offset; i < max; i++) { + Tuple result = results.get(i); + drawSolidRect(x, y, width, height, 0xAA000000); + FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer; + fontRenderer.drawString(result.getSecond(), x + 4, y + (height - fontRenderer.FONT_HEIGHT) / 2 + 1, -1); + if (isMouseOver(x, y, width, height, mouseX, mouseY)) { + drawBorder(x + 1, y + 1, width - 2, height - 2, -1, 1); + } + y += height; + } + } + + @Override + public boolean mouseClicked(int mouseX, int mouseY, int button) { + int x = getPosition().x; + int width = getSize().width; + int height = getSize().height; + int y = (isUp ? -results.size() : 1) * height + getPosition().y; + int max = Math.min(offset + SIZE, results.size()); + for (int i = offset; i < max; i++) { + Tuple result = results.get(i); + if (isMouseOver(x, y, width, height, mouseX, mouseY)) { + search.selectResult(result.getFirst()); + engine.dispose(); + return true; + } + y += height; + } + return super.mouseClicked(mouseX, mouseY, button); + } + + @Override + public boolean mouseWheelMove(int mouseX, int mouseY, int wheelDelta) { + int x = getPosition().x; + int width = getSize().width; + int height = getSize().height; + int y = (isUp ? -results.size() : 1) * height + getPosition().y; + int max = Math.min(offset + SIZE, results.size()); + if (isMouseOver(x, y, width, height * (max - offset), mouseX, mouseY)) { + offset = MathHelper.clamp(offset + (wheelDelta > 0 ? -1 : +1), 0, Math.max(0, results.size() - SIZE)); + return true; + } + return super.mouseWheelMove(mouseX, mouseY, wheelDelta); + } + + public interface IMenuSearch extends ISearch{ + String resultDisplay(T result); + void selectResult(T result); + } +} diff --git a/src/main/java/gregtech/api/terminal/util/FileTree.java b/src/main/java/gregtech/api/terminal/util/FileTree.java index 05be2dbacb6..192b6495a7e 100644 --- a/src/main/java/gregtech/api/terminal/util/FileTree.java +++ b/src/main/java/gregtech/api/terminal/util/FileTree.java @@ -20,21 +20,6 @@ public boolean isLeaf() { return getKey().isFile(); } - @Override - public TreeNode getOrCreateChild(File childKey) { - return super.getOrCreateChild(childKey); - } - - @Override - public void addContent(File key, File content) { - super.addContent(key, content); - } - - @Override - public File getKey() { - return super.getKey(); - } - @Override public File getContent() { return isLeaf() ? getKey() : null; diff --git a/src/main/java/gregtech/api/terminal/util/ISearch.java b/src/main/java/gregtech/api/terminal/util/ISearch.java new file mode 100644 index 00000000000..eaa8e0abd85 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/util/ISearch.java @@ -0,0 +1,8 @@ +package gregtech.api.terminal.util; + +import java.util.function.Consumer; + +public interface ISearch { + default boolean isManualInterrupt() {return false;} + void search(String word, Consumer find); +} diff --git a/src/main/java/gregtech/api/terminal/util/SearchEngine.java b/src/main/java/gregtech/api/terminal/util/SearchEngine.java new file mode 100644 index 00000000000..1cfe7a28bb1 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/util/SearchEngine.java @@ -0,0 +1,37 @@ +package gregtech.api.terminal.util; + +import javax.annotation.Nonnull; +import java.util.function.Consumer; + +public class SearchEngine { + private final ISearch search; + private final Consumer result; + private Thread thread; + + public SearchEngine(@Nonnull ISearch search, @Nonnull Consumer result){ + this.search = search; + this.result = result; + } + + public void searchWord(String word) { + dispose(); + thread = new Thread(()-> search.search(word, result)); + thread.start(); + } + + public boolean isSearching() { + return thread != null && thread.isAlive(); + } + + public void dispose() { + if (isSearching()) { + if (search.isManualInterrupt()) { + thread.interrupt(); + } else { + thread.stop(); + } + } + thread = null; + } + +} diff --git a/src/main/java/gregtech/api/terminal/util/TreeNode.java b/src/main/java/gregtech/api/terminal/util/TreeNode.java index 93c1f2c3616..d54b56d9925 100644 --- a/src/main/java/gregtech/api/terminal/util/TreeNode.java +++ b/src/main/java/gregtech/api/terminal/util/TreeNode.java @@ -22,25 +22,36 @@ public TreeNode(int dimension, T key) { } public boolean isLeaf(){ - return children == null || children.isEmpty(); + return getChildren() == null || getChildren().isEmpty(); } public TreeNode getOrCreateChild (T childKey) { TreeNode result; - if (children != null) { - result = children.stream().filter(child->child.key.equals(childKey)).findFirst().orElseGet(()->{ + if (getChildren() != null) { + result = getChildren().stream().filter(child->child.key.equals(childKey)).findFirst().orElseGet(()->{ TreeNode newNode = new TreeNode<>(dimension + 1, childKey); - children.add(newNode); + getChildren().add(newNode); return newNode; }); } else { children = new ArrayList<>(); result = new TreeNode<>(dimension + 1, childKey); - children.add(result); + getChildren().add(result); } return result; } + public TreeNode getChild(T key) { + if (getChildren() != null) { + for (TreeNode child : getChildren()) { + if (child.key.equals(key)) { + return child; + } + } + } + return null; + } + public void addContent (T key, K content) { getOrCreateChild(key).content = content; } From 0e306b8685c2d984a67e5e4e1ec5b58412818b05 Mon Sep 17 00:00:00 2001 From: Yefancy Date: Tue, 10 Aug 2021 00:12:19 +0800 Subject: [PATCH 41/58] themeAPP --- .../java/gregtech/api/gui/GuiTextures.java | 1 - .../gregtech/api/gui/impl/ModularUIGui.java | 62 ++++++++++--- .../api/gui/resources/ColorRectTexture.java | 10 ++- .../api/gui/resources/FileTexture.java | 87 +++++++++++++++++++ .../api/gui/resources/ModifyGuiTexture.java | 79 +++++++++++++++++ .../api/gui/resources/TextTexture.java | 4 +- .../api/gui/resources/TextureArea.java | 1 + .../api/gui/resources/URLTexture.java | 6 +- .../AnimatedPictureTexture.java | 4 +- .../OrdinaryTexture.java | 4 +- .../PictureTexture.java | 2 +- .../VideoTexture.java | 2 +- .../{onlinepic => utils}/DownloadThread.java | 47 ++-------- .../{onlinepic => utils}/GifDecoder.java | 2 +- .../api/gui/resources/utils/ImageUtils.java | 54 ++++++++++++ .../ProcessedImageData.java | 2 +- .../{onlinepic => utils}/TextureCache.java | 2 +- .../api/terminal/TerminalBuilder.java | 1 + .../api/terminal/app/ThemeSettingApp.java | 61 +++++++++++++ .../api/terminal/app/guide/GuideApp.java | 3 +- .../app/guide/widget/SlotListWidget.java | 2 +- .../guideeditor/widget/GuideConfigEditor.java | 54 +++++------- .../widget/GuidePageEditorWidget.java | 17 ++-- .../configurator/BooleanConfigurator.java | 5 +- .../configurator/FluidStackConfigurator.java | 21 ++--- .../configurator/ItemStackConfigurator.java | 21 ++--- .../configurator/NumberConfigurator.java | 19 ++-- .../configurator/SelectorConfigurator.java | 5 +- .../configurator/StringConfigurator.java | 7 +- .../api/terminal/os/TerminalTheme.java | 71 +++++++++++++++ .../terminal/os/menu/TerminalMenuWidget.java | 25 +++--- .../os/menu/component/SearchComponent.java | 12 +-- .../component/setting/GuiTextureSetter.java | 32 +++++++ .../os/menu/component/setting/ISetting.java | 10 +++ .../component/setting/IWidgetSettings.java | 7 ++ .../component/setting/SettingComponent.java | 29 +++++++ .../gregtech/api/terminal/util/FileUtils.java | 39 +++++++++ .../behaviors/GuideTerminalBehaviour.java | 3 +- 38 files changed, 646 insertions(+), 167 deletions(-) create mode 100644 src/main/java/gregtech/api/gui/resources/FileTexture.java create mode 100644 src/main/java/gregtech/api/gui/resources/ModifyGuiTexture.java rename src/main/java/gregtech/api/gui/resources/{onlinepictexture => picturetexture}/AnimatedPictureTexture.java (94%) rename src/main/java/gregtech/api/gui/resources/{onlinepictexture => picturetexture}/OrdinaryTexture.java (76%) rename src/main/java/gregtech/api/gui/resources/{onlinepictexture => picturetexture}/PictureTexture.java (97%) rename src/main/java/gregtech/api/gui/resources/{onlinepictexture => picturetexture}/VideoTexture.java (85%) rename src/main/java/gregtech/api/gui/resources/{onlinepic => utils}/DownloadThread.java (84%) rename src/main/java/gregtech/api/gui/resources/{onlinepic => utils}/GifDecoder.java (99%) create mode 100644 src/main/java/gregtech/api/gui/resources/utils/ImageUtils.java rename src/main/java/gregtech/api/gui/resources/{onlinepic => utils}/ProcessedImageData.java (98%) rename src/main/java/gregtech/api/gui/resources/{onlinepic => utils}/TextureCache.java (99%) create mode 100644 src/main/java/gregtech/api/terminal/app/ThemeSettingApp.java create mode 100644 src/main/java/gregtech/api/terminal/os/TerminalTheme.java create mode 100644 src/main/java/gregtech/api/terminal/os/menu/component/setting/GuiTextureSetter.java create mode 100644 src/main/java/gregtech/api/terminal/os/menu/component/setting/ISetting.java create mode 100644 src/main/java/gregtech/api/terminal/os/menu/component/setting/IWidgetSettings.java create mode 100644 src/main/java/gregtech/api/terminal/os/menu/component/setting/SettingComponent.java create mode 100644 src/main/java/gregtech/api/terminal/util/FileUtils.java diff --git a/src/main/java/gregtech/api/gui/GuiTextures.java b/src/main/java/gregtech/api/gui/GuiTextures.java index 463718feade..7643b2fa457 100644 --- a/src/main/java/gregtech/api/gui/GuiTextures.java +++ b/src/main/java/gregtech/api/gui/GuiTextures.java @@ -169,7 +169,6 @@ public class GuiTextures { //Terminal public static final TextureArea TERMINAL_FRAME = TextureArea.fullImage("textures/gui/terminal/terminal_frame.png"); - public static final TextureArea TERMINAL_BACKGROUND = TextureArea.fullImage("textures/gui/terminal/terminal_background.png"); public static final TextureArea TERMINAL_MENU = TextureArea.fullImage("textures/gui/terminal/terminal_menu.png"); public static final TextureArea TERMINAL_HOME = TextureArea.fullImage("textures/gui/terminal/terminal_home.png"); public static final TextureArea TERMINAL_SETTING = TextureArea.fullImage("textures/gui/terminal/terminal_setting.png"); diff --git a/src/main/java/gregtech/api/gui/impl/ModularUIGui.java b/src/main/java/gregtech/api/gui/impl/ModularUIGui.java index bfa14dd43e0..3e969f3dc41 100644 --- a/src/main/java/gregtech/api/gui/impl/ModularUIGui.java +++ b/src/main/java/gregtech/api/gui/impl/ModularUIGui.java @@ -224,40 +224,74 @@ public void handleMouseInput() throws IOException { protected void mouseWheelMove(int mouseX, int mouseY, int wheelDelta) { //noinspection ResultOfMethodCallIgnored - modularUI.guiWidgets.values().stream().anyMatch(widget -> widget.mouseWheelMove(mouseX, mouseY, wheelDelta)); +// modularUI.guiWidgets.values().stream().anyMatch(widget -> widget.mouseWheelMove(mouseX, mouseY, wheelDelta)); + for (int i = modularUI.guiWidgets.size() - 1; i >= 0; i--) { + Widget widget = modularUI.guiWidgets.get(i); + if(widget.isVisible() && widget.isActive() && widget.mouseWheelMove(mouseX, mouseY, wheelDelta)) { + return; + } + } } @Override protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException { - boolean result = modularUI.guiWidgets.values().stream().anyMatch(widget -> widget.mouseClicked(mouseX, mouseY, mouseButton)); - if (!result) { - super.mouseClicked(mouseX, mouseY, mouseButton); +// boolean result = modularUI.guiWidgets.values().stream().anyMatch(widget -> widget.mouseClicked(mouseX, mouseY, mouseButton)); +// if (!result) { +// super.mouseClicked(mouseX, mouseY, mouseButton); +// } + for (int i = modularUI.guiWidgets.size() - 1; i >= 0; i--) { + Widget widget = modularUI.guiWidgets.get(i); + if(widget.isVisible() && widget.isActive() && widget.mouseClicked(mouseX, mouseY, mouseButton)) { + return; + } } + super.mouseClicked(mouseX, mouseY, mouseButton); } @Override protected void mouseClickMove(int mouseX, int mouseY, int clickedMouseButton, long timeSinceLastClick) { - boolean result = modularUI.guiWidgets.values().stream().anyMatch(widget -> - widget.mouseDragged(mouseX, mouseY, clickedMouseButton, timeSinceLastClick)); - if (!result) { - super.mouseClickMove(mouseX, mouseY, clickedMouseButton, timeSinceLastClick); +// boolean result = modularUI.guiWidgets.values().stream().anyMatch(widget -> +// widget.mouseDragged(mouseX, mouseY, clickedMouseButton, timeSinceLastClick)); +// if (!result) { +// super.mouseClickMove(mouseX, mouseY, clickedMouseButton, timeSinceLastClick); +// } + for (int i = modularUI.guiWidgets.size() - 1; i >= 0; i--) { + Widget widget = modularUI.guiWidgets.get(i); + if(widget.isVisible() && widget.isActive() && widget.mouseDragged(mouseX, mouseY, clickedMouseButton, timeSinceLastClick)) { + return; + } } + super.mouseClickMove(mouseX, mouseY, clickedMouseButton, timeSinceLastClick); } @Override protected void mouseReleased(int mouseX, int mouseY, int state) { - boolean result = modularUI.guiWidgets.values().stream().anyMatch(widget -> widget.mouseReleased(mouseX, mouseY, state)); - if (!result) { - super.mouseReleased(mouseX, mouseY, state); +// boolean result = modularUI.guiWidgets.values().stream().anyMatch(widget -> widget.mouseReleased(mouseX, mouseY, state)); +// if (!result) { +// super.mouseReleased(mouseX, mouseY, state); +// } + for (int i = modularUI.guiWidgets.size() - 1; i >= 0; i--) { + Widget widget = modularUI.guiWidgets.get(i); + if(widget.isVisible() && widget.isActive() && widget.mouseReleased(mouseX, mouseY, state)) { + return; + } } + super.mouseReleased(mouseX, mouseY, state); } @Override protected void keyTyped(char typedChar, int keyCode) throws IOException { - boolean result = modularUI.guiWidgets.values().stream().anyMatch(widget -> widget.keyTyped(typedChar, keyCode)); - if (!result) { - super.keyTyped(typedChar, keyCode); +// boolean result = modularUI.guiWidgets.values().stream().anyMatch(widget -> widget.keyTyped(typedChar, keyCode)); +// if (!result) { +// super.keyTyped(typedChar, keyCode); +// } + for (int i = modularUI.guiWidgets.size() - 1; i >= 0; i--) { + Widget widget = modularUI.guiWidgets.get(i); + if(widget.isVisible() && widget.isActive() && widget.keyTyped(typedChar, keyCode)) { + return; + } } + super.keyTyped(typedChar, keyCode); } } diff --git a/src/main/java/gregtech/api/gui/resources/ColorRectTexture.java b/src/main/java/gregtech/api/gui/resources/ColorRectTexture.java index 8c1683cd0c7..0a1edaca220 100644 --- a/src/main/java/gregtech/api/gui/resources/ColorRectTexture.java +++ b/src/main/java/gregtech/api/gui/resources/ColorRectTexture.java @@ -8,7 +8,7 @@ import java.awt.*; public class ColorRectTexture implements IGuiTexture{ - private final int color; + public int color; public ColorRectTexture(int color) { this.color = color; @@ -18,6 +18,14 @@ public ColorRectTexture(Color color) { this.color = color.getRGB(); } + public void setColor(int color) { + this.color = color; + } + + public int getColor() { + return color; + } + @Override public void draw(double x, double y, int width, int height) { double j; diff --git a/src/main/java/gregtech/api/gui/resources/FileTexture.java b/src/main/java/gregtech/api/gui/resources/FileTexture.java new file mode 100644 index 00000000000..3b261001e78 --- /dev/null +++ b/src/main/java/gregtech/api/gui/resources/FileTexture.java @@ -0,0 +1,87 @@ +package gregtech.api.gui.resources; + +import gregtech.api.gui.resources.picturetexture.AnimatedPictureTexture; +import gregtech.api.gui.resources.picturetexture.OrdinaryTexture; +import gregtech.api.gui.resources.picturetexture.PictureTexture; +import gregtech.api.gui.resources.utils.DownloadThread; +import gregtech.api.gui.resources.utils.GifDecoder; +import gregtech.api.gui.resources.utils.ImageUtils; +import gregtech.api.gui.resources.utils.ProcessedImageData; +import net.minecraftforge.fml.common.FMLCommonHandler; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import org.apache.commons.compress.utils.IOUtils; + +import javax.imageio.ImageIO; +import javax.imageio.ImageReader; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.Iterator; + +public class FileTexture implements IGuiTexture{ + public final File file; + @SideOnly(Side.CLIENT) + private PictureTexture texture; + boolean init; + + public FileTexture(File file) { + this.file = file; + } + + @SideOnly(Side.CLIENT) + public boolean loadFile(){ + init = true; + FileInputStream inputStream = null; + try { + inputStream = new FileInputStream(file); + String type = ImageUtils.readType(inputStream); + if (type.equalsIgnoreCase("gif")) { + GifDecoder gif = new GifDecoder(); + inputStream.close(); + inputStream = new FileInputStream(file); + int status = gif.read(inputStream); + if (status == GifDecoder.STATUS_OK) { + texture = new AnimatedPictureTexture(new ProcessedImageData(gif)); + return true; + } else { + return false; + } + } else { + inputStream.close(); + inputStream = new FileInputStream(file); + BufferedImage image = ImageIO.read(inputStream); + if (image != null) { + texture = new OrdinaryTexture(new ProcessedImageData(image)); + return true; + } else { + return false; + } + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + IOUtils.closeQuietly(inputStream); + } + return false; + } + + @SideOnly(Side.CLIENT) + @Override + public void updateTick() { + if(this.texture != null) { + texture.tick(); // gif\video update + } + } + + @Override + public void draw(double x, double y, int width, int height) { + if(this.texture != null) { + texture.draw(x, y, width, height); // gif\video update + } else if (!init){ + loadFile(); + } + } + +} diff --git a/src/main/java/gregtech/api/gui/resources/ModifyGuiTexture.java b/src/main/java/gregtech/api/gui/resources/ModifyGuiTexture.java new file mode 100644 index 00000000000..a3d14ed4f76 --- /dev/null +++ b/src/main/java/gregtech/api/gui/resources/ModifyGuiTexture.java @@ -0,0 +1,79 @@ +package gregtech.api.gui.resources; + +import com.google.gson.JsonObject; +import net.minecraft.util.ResourceLocation; + +import java.io.File; + +public class ModifyGuiTexture implements IGuiTexture{ + private IGuiTexture texture; + + public ModifyGuiTexture(IGuiTexture texture) { + this.texture = texture; + if (texture == null) { + this.texture = new TextTexture("Missing Texture"); + } + } + + public IGuiTexture getTexture() { + return texture; + } + + public void setTexture(IGuiTexture texture) { + if (texture != null) { + this.texture = texture; + } + } + + @Override + public void draw(double x, double y, int width, int height) { + texture.draw(x, y, width, height); + } + + @Override + public void updateTick() { + texture.updateTick(); + } + + public JsonObject saveConfig() { + JsonObject config = new JsonObject(); + if (texture instanceof TextureArea) { + config.addProperty("type", "resource"); + config.addProperty("resource", ((TextureArea) texture).imageLocation.toString()); + } else if (texture instanceof URLTexture) { + config.addProperty("type", "url"); + config.addProperty("url", ((URLTexture) texture).url); + } else if (texture instanceof TextTexture) { + config.addProperty("type", "text"); + config.addProperty("text", ((TextTexture) texture).text); + config.addProperty("color", ((TextTexture) texture).color); + } else if (texture instanceof ColorRectTexture) { + config.addProperty("type", "color"); + config.addProperty("color", ((ColorRectTexture) texture).color); + } else if (texture instanceof FileTexture) { + config.addProperty("type", "file"); + config.addProperty("file", ((FileTexture) texture).file.getPath()); + } else { + return null; + } + return config; + } + + public void loadConfig(JsonObject config) { + try { + switch (config.get("type").getAsString()) { + case "resource": + setTexture(new TextureArea(new ResourceLocation(config.get("resource").getAsString()), 0.0, 0.0, 1.0, 1.0)); + case "url": + setTexture(new URLTexture(config.get("url").getAsString())); + case "text": + setTexture(new TextTexture(config.get("text").getAsString(), config.get("color").getAsInt())); + case "color": + setTexture(new ColorRectTexture(config.get("color").getAsInt())); + case "file": + setTexture(new FileTexture(new File(config.get("file").getAsString()))); + } + } catch (Exception ignored) { + } + } +} diff --git a/src/main/java/gregtech/api/gui/resources/TextTexture.java b/src/main/java/gregtech/api/gui/resources/TextTexture.java index 04f20a4e37f..f7d503740b7 100644 --- a/src/main/java/gregtech/api/gui/resources/TextTexture.java +++ b/src/main/java/gregtech/api/gui/resources/TextTexture.java @@ -6,8 +6,8 @@ import net.minecraftforge.fml.common.FMLCommonHandler; public class TextTexture implements IGuiTexture{ - private final String text; - private final int color; + public final String text; + public final int color; private final int textWidth; public TextTexture(String text) { diff --git a/src/main/java/gregtech/api/gui/resources/TextureArea.java b/src/main/java/gregtech/api/gui/resources/TextureArea.java index 4fb6db081af..0fc6278276e 100644 --- a/src/main/java/gregtech/api/gui/resources/TextureArea.java +++ b/src/main/java/gregtech/api/gui/resources/TextureArea.java @@ -4,6 +4,7 @@ import codechicken.lib.vec.Transformation; import codechicken.lib.vec.Translation; import codechicken.lib.vec.Vector3; +import com.google.gson.JsonObject; import gregtech.api.GTValues; import gregtech.api.util.Position; import gregtech.api.util.PositionedRect; diff --git a/src/main/java/gregtech/api/gui/resources/URLTexture.java b/src/main/java/gregtech/api/gui/resources/URLTexture.java index 7f2fd4679d1..1cb42186db9 100644 --- a/src/main/java/gregtech/api/gui/resources/URLTexture.java +++ b/src/main/java/gregtech/api/gui/resources/URLTexture.java @@ -1,12 +1,12 @@ package gregtech.api.gui.resources; -import gregtech.api.gui.resources.onlinepic.DownloadThread; -import gregtech.api.gui.resources.onlinepictexture.PictureTexture; +import gregtech.api.gui.resources.picturetexture.PictureTexture; +import gregtech.api.gui.resources.utils.DownloadThread; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; public class URLTexture implements IGuiTexture{ - private final String url; + public final String url; @SideOnly(Side.CLIENT) private DownloadThread downloader; @SideOnly(Side.CLIENT) diff --git a/src/main/java/gregtech/api/gui/resources/onlinepictexture/AnimatedPictureTexture.java b/src/main/java/gregtech/api/gui/resources/picturetexture/AnimatedPictureTexture.java similarity index 94% rename from src/main/java/gregtech/api/gui/resources/onlinepictexture/AnimatedPictureTexture.java rename to src/main/java/gregtech/api/gui/resources/picturetexture/AnimatedPictureTexture.java index bee61ca36b3..a8b4526edef 100644 --- a/src/main/java/gregtech/api/gui/resources/onlinepictexture/AnimatedPictureTexture.java +++ b/src/main/java/gregtech/api/gui/resources/picturetexture/AnimatedPictureTexture.java @@ -1,7 +1,7 @@ -package gregtech.api.gui.resources.onlinepictexture; +package gregtech.api.gui.resources.picturetexture; -import gregtech.api.gui.resources.onlinepic.ProcessedImageData; +import gregtech.api.gui.resources.utils.ProcessedImageData; import net.minecraft.client.renderer.GlStateManager; import java.util.Arrays; diff --git a/src/main/java/gregtech/api/gui/resources/onlinepictexture/OrdinaryTexture.java b/src/main/java/gregtech/api/gui/resources/picturetexture/OrdinaryTexture.java similarity index 76% rename from src/main/java/gregtech/api/gui/resources/onlinepictexture/OrdinaryTexture.java rename to src/main/java/gregtech/api/gui/resources/picturetexture/OrdinaryTexture.java index 2eea82b9ea8..31d2e2a3983 100644 --- a/src/main/java/gregtech/api/gui/resources/onlinepictexture/OrdinaryTexture.java +++ b/src/main/java/gregtech/api/gui/resources/picturetexture/OrdinaryTexture.java @@ -1,6 +1,6 @@ -package gregtech.api.gui.resources.onlinepictexture; +package gregtech.api.gui.resources.picturetexture; -import gregtech.api.gui.resources.onlinepic.ProcessedImageData; +import gregtech.api.gui.resources.utils.ProcessedImageData; public class OrdinaryTexture extends PictureTexture { diff --git a/src/main/java/gregtech/api/gui/resources/onlinepictexture/PictureTexture.java b/src/main/java/gregtech/api/gui/resources/picturetexture/PictureTexture.java similarity index 97% rename from src/main/java/gregtech/api/gui/resources/onlinepictexture/PictureTexture.java rename to src/main/java/gregtech/api/gui/resources/picturetexture/PictureTexture.java index 82efb803fae..8d614fbecac 100644 --- a/src/main/java/gregtech/api/gui/resources/onlinepictexture/PictureTexture.java +++ b/src/main/java/gregtech/api/gui/resources/picturetexture/PictureTexture.java @@ -1,4 +1,4 @@ -package gregtech.api.gui.resources.onlinepictexture; +package gregtech.api.gui.resources.picturetexture; import gregtech.api.gui.resources.IGuiTexture; import net.minecraft.client.renderer.GlStateManager; diff --git a/src/main/java/gregtech/api/gui/resources/onlinepictexture/VideoTexture.java b/src/main/java/gregtech/api/gui/resources/picturetexture/VideoTexture.java similarity index 85% rename from src/main/java/gregtech/api/gui/resources/onlinepictexture/VideoTexture.java rename to src/main/java/gregtech/api/gui/resources/picturetexture/VideoTexture.java index af5ea14b8fe..70f1dc7aebf 100644 --- a/src/main/java/gregtech/api/gui/resources/onlinepictexture/VideoTexture.java +++ b/src/main/java/gregtech/api/gui/resources/picturetexture/VideoTexture.java @@ -1,4 +1,4 @@ -package gregtech.api.gui.resources.onlinepictexture; +package gregtech.api.gui.resources.picturetexture; public class VideoTexture extends PictureTexture { //TODO implementations of it in the future diff --git a/src/main/java/gregtech/api/gui/resources/onlinepic/DownloadThread.java b/src/main/java/gregtech/api/gui/resources/utils/DownloadThread.java similarity index 84% rename from src/main/java/gregtech/api/gui/resources/onlinepic/DownloadThread.java rename to src/main/java/gregtech/api/gui/resources/utils/DownloadThread.java index fb344586ed2..e2fdb63be5f 100644 --- a/src/main/java/gregtech/api/gui/resources/onlinepic/DownloadThread.java +++ b/src/main/java/gregtech/api/gui/resources/utils/DownloadThread.java @@ -1,10 +1,10 @@ -package gregtech.api.gui.resources.onlinepic; +package gregtech.api.gui.resources.utils; import gregtech.GregTechMod; -import gregtech.api.gui.resources.onlinepictexture.AnimatedPictureTexture; -import gregtech.api.gui.resources.onlinepictexture.OrdinaryTexture; -import gregtech.api.gui.resources.onlinepictexture.PictureTexture; -import gregtech.api.gui.resources.onlinepictexture.VideoTexture; +import gregtech.api.gui.resources.picturetexture.AnimatedPictureTexture; +import gregtech.api.gui.resources.picturetexture.OrdinaryTexture; +import gregtech.api.gui.resources.picturetexture.PictureTexture; +import gregtech.api.gui.resources.picturetexture.VideoTexture; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import org.apache.commons.compress.utils.IOUtils; @@ -78,7 +78,7 @@ public void run() { Exception exception = null; try { byte[] data = load(url); - String type = readType(data); + String type = ImageUtils.readType(data); ByteArrayInputStream in = null; try { in = new ByteArrayInputStream(data); @@ -201,41 +201,6 @@ public static byte[] load(String url) throws IOException, FoundVideoException { } } - private static String readType(byte[] input) throws IOException { - InputStream in = null; - try { - in = new ByteArrayInputStream(input); - return readType(in); - } finally { - IOUtils.closeQuietly(in); - } - } - - private static String readType(InputStream input) throws IOException { - ImageInputStream stream = ImageIO.createImageInputStream(input); - Iterator iter = ImageIO.getImageReaders(stream); - if (!iter.hasNext()) { - return ""; - } - ImageReader reader = iter.next(); - - if (reader.getFormatName().equalsIgnoreCase("gif")) - return "gif"; - - ImageReadParam param = reader.getDefaultReadParam(); - reader.setInput(stream, true, true); - try { - reader.read(0, param); - } catch (IOException e) { - LOGGER.error("Failed to parse input format", e); - } finally { - reader.dispose(); - IOUtils.closeQuietly(stream); - } - input.reset(); - return reader.getFormatName(); - } - public static PictureTexture loadImage(DownloadThread thread) { PictureTexture texture = null; diff --git a/src/main/java/gregtech/api/gui/resources/onlinepic/GifDecoder.java b/src/main/java/gregtech/api/gui/resources/utils/GifDecoder.java similarity index 99% rename from src/main/java/gregtech/api/gui/resources/onlinepic/GifDecoder.java rename to src/main/java/gregtech/api/gui/resources/utils/GifDecoder.java index 425953dab42..69a25f3e217 100644 --- a/src/main/java/gregtech/api/gui/resources/onlinepic/GifDecoder.java +++ b/src/main/java/gregtech/api/gui/resources/utils/GifDecoder.java @@ -1,4 +1,4 @@ -package gregtech.api.gui.resources.onlinepic; +package gregtech.api.gui.resources.utils; import java.awt.*; import java.awt.image.BufferedImage; diff --git a/src/main/java/gregtech/api/gui/resources/utils/ImageUtils.java b/src/main/java/gregtech/api/gui/resources/utils/ImageUtils.java new file mode 100644 index 00000000000..838dc3592b4 --- /dev/null +++ b/src/main/java/gregtech/api/gui/resources/utils/ImageUtils.java @@ -0,0 +1,54 @@ +package gregtech.api.gui.resources.utils; + +import gregtech.GregTechMod; +import org.apache.commons.compress.utils.IOUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import javax.imageio.ImageIO; +import javax.imageio.ImageReadParam; +import javax.imageio.ImageReader; +import javax.imageio.stream.ImageInputStream; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Iterator; + +public class ImageUtils { + public static final Logger LOGGER = LogManager.getLogger(GregTechMod.class); + + public static String readType(byte[] input) throws IOException { + InputStream in = null; + try { + in = new ByteArrayInputStream(input); + return readType(in); + } finally { + IOUtils.closeQuietly(in); + } + } + + public static String readType(InputStream input) throws IOException { + ImageInputStream stream = ImageIO.createImageInputStream(input); + Iterator iter = ImageIO.getImageReaders(stream); + if (!iter.hasNext()) { + return ""; + } + ImageReader reader = iter.next(); + + if (reader.getFormatName().equalsIgnoreCase("gif")) + return "gif"; + + ImageReadParam param = reader.getDefaultReadParam(); + reader.setInput(stream, true, true); + try { + reader.read(0, param); + } catch (IOException e) { + LOGGER.error("Failed to parse input format", e); + } finally { + reader.dispose(); + IOUtils.closeQuietly(stream); + } + input.reset(); + return reader.getFormatName(); + } +} diff --git a/src/main/java/gregtech/api/gui/resources/onlinepic/ProcessedImageData.java b/src/main/java/gregtech/api/gui/resources/utils/ProcessedImageData.java similarity index 98% rename from src/main/java/gregtech/api/gui/resources/onlinepic/ProcessedImageData.java rename to src/main/java/gregtech/api/gui/resources/utils/ProcessedImageData.java index 794c2f28afe..81a354d91a2 100644 --- a/src/main/java/gregtech/api/gui/resources/onlinepic/ProcessedImageData.java +++ b/src/main/java/gregtech/api/gui/resources/utils/ProcessedImageData.java @@ -1,4 +1,4 @@ -package gregtech.api.gui.resources.onlinepic; +package gregtech.api.gui.resources.utils; import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL11; diff --git a/src/main/java/gregtech/api/gui/resources/onlinepic/TextureCache.java b/src/main/java/gregtech/api/gui/resources/utils/TextureCache.java similarity index 99% rename from src/main/java/gregtech/api/gui/resources/onlinepic/TextureCache.java rename to src/main/java/gregtech/api/gui/resources/utils/TextureCache.java index d48678e5153..3bdc29701a1 100644 --- a/src/main/java/gregtech/api/gui/resources/onlinepic/TextureCache.java +++ b/src/main/java/gregtech/api/gui/resources/utils/TextureCache.java @@ -1,4 +1,4 @@ -package gregtech.api.gui.resources.onlinepic; +package gregtech.api.gui.resources.utils; import net.minecraft.client.Minecraft; import org.apache.commons.codec.binary.Base64; diff --git a/src/main/java/gregtech/api/terminal/TerminalBuilder.java b/src/main/java/gregtech/api/terminal/TerminalBuilder.java index 4b45d754825..06c6845f426 100644 --- a/src/main/java/gregtech/api/terminal/TerminalBuilder.java +++ b/src/main/java/gregtech/api/terminal/TerminalBuilder.java @@ -19,6 +19,7 @@ public static void init() { appRegister.add(new ItemGuideApp()); appRegister.add(new TutorialGuideApp()); appRegister.add(new GuideEditorApp()); + appRegister.add(new ThemeSettingApp()); } public static List getApplications() { diff --git a/src/main/java/gregtech/api/terminal/app/ThemeSettingApp.java b/src/main/java/gregtech/api/terminal/app/ThemeSettingApp.java new file mode 100644 index 00000000000..5c17921a7a6 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/app/ThemeSettingApp.java @@ -0,0 +1,61 @@ +package gregtech.api.terminal.app; + +import gregtech.api.gui.GuiTextures; +import gregtech.api.gui.resources.ColorRectTexture; +import gregtech.api.gui.widgets.ImageWidget; +import gregtech.api.terminal.gui.widgets.CircleButtonWidget; +import gregtech.api.terminal.os.TerminalDialogWidget; +import gregtech.api.terminal.os.TerminalTheme; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.PacketBuffer; + +import java.util.function.Consumer; + +public class ThemeSettingApp extends AbstractApplication { + public ThemeSettingApp() { + super("Theme Setting", GuiTextures.GREGTECH_LOGO); + } + + @Override + public AbstractApplication createApp(boolean isClient, NBTTagCompound nbt) { + ThemeSettingApp app = new ThemeSettingApp(); + if (isClient) { //333 232 + float x = 333 * 1.0f / 13; + app.addWidget(new ImageWidget(5, 5, 333 - 10, 232 - 10, TerminalTheme.COLOR_B_2)); + app.addColorButton(TerminalTheme.COLOR_1, "COLOR_1", (int) x, 30); + app.addColorButton(TerminalTheme.COLOR_2, "COLOR_2", (int) (x * 2), 30); + app.addColorButton(TerminalTheme.COLOR_3, "COLOR_3", (int) (x * 3), 30); + app.addColorButton(TerminalTheme.COLOR_4, "COLOR_4", (int) (x * 4), 30); + app.addColorButton(TerminalTheme.COLOR_5, "COLOR_5", (int) (x * 5), 30); + app.addColorButton(TerminalTheme.COLOR_6, "COLOR_6", (int) (x * 6), 30); + app.addColorButton(TerminalTheme.COLOR_7, "COLOR_7", (int) (x * 7), 30); + app.addColorButton(TerminalTheme.COLOR_F_1, "COLOR_F_1", (int) (x * 8), 30); + app.addColorButton(TerminalTheme.COLOR_F_2, "COLOR_F_2", (int) (x * 9), 30); + app.addColorButton(TerminalTheme.COLOR_B_1, "COLOR_B_1", (int) (x * 10), 30); + app.addColorButton(TerminalTheme.COLOR_B_2, "COLOR_B_2", (int) (x * 11), 30); + app.addColorButton(TerminalTheme.COLOR_B_3, "COLOR_B_3", (int) (x * 12), 30); + app.addWidget(new ImageWidget((int) x, 80, 333 / 2, 232 / 2, TerminalTheme.WALL_PAPER)); + } + return app; + } + + private void addColorButton(ColorRectTexture texture, String name, int x, int y) { + CircleButtonWidget buttonWidget = new CircleButtonWidget(x, y).setFill(texture.getColor()).setStrokeAnima(-1).setHoverText(name); + buttonWidget.setClickListener(cd -> { + TerminalDialogWidget.showColorDialog(getOs(), name, color -> { + if (color != null) { + buttonWidget.setFill(color); + texture.setColor(color); + if (!TerminalTheme.saveConfig()) { + TerminalDialogWidget.showInfoDialog(getOs(), "ERROR", "error while saving config").setClientSide().open(); + } + } + }).setClientSide().open(); + }); + addWidget(buttonWidget); + } + + @Override + protected void writeClientAction(int id, Consumer packetBufferWriter) { + } +} diff --git a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java index da907f2dd40..18f921b79a3 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java @@ -28,7 +28,8 @@ import java.util.function.Consumer; import java.util.stream.Collectors; -public abstract class GuideApp extends AbstractApplication implements SearchComponent.IMenuSearch>> { +public abstract class GuideApp extends AbstractApplication implements + SearchComponent.IWidgetSearch>> { private GuidePageWidget pageWidget; private TreeListWidget tree; public GuideApp(String name, IGuiTexture icon) { diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/SlotListWidget.java b/src/main/java/gregtech/api/terminal/app/guide/widget/SlotListWidget.java index 8cc14e1fad4..4b0378ca2e3 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/SlotListWidget.java +++ b/src/main/java/gregtech/api/terminal/app/guide/widget/SlotListWidget.java @@ -62,7 +62,7 @@ public String getRegistryName() { @Override public JsonObject getTemplate(boolean isFixed) { JsonObject template = super.getTemplate(isFixed); - template.add("item_list", new Gson().toJsonTree(Collections.singletonList(new ItemStackInfo("gregtech:meta_item_2", 32581, 1)))); + template.add("item_list", new Gson().toJsonTree(Collections.singletonList(new ItemStackInfo("minecraft:ender_pearl", 0, 1)))); return template; } diff --git a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/GuideConfigEditor.java b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/GuideConfigEditor.java index 8d6aa85fcfe..c0d0888bf21 100644 --- a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/GuideConfigEditor.java +++ b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/GuideConfigEditor.java @@ -1,13 +1,10 @@ package gregtech.api.terminal.app.guideeditor.widget; import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.google.gson.stream.JsonReader; import gregtech.api.gui.GuiTextures; import gregtech.api.gui.Widget; import gregtech.api.gui.resources.ColorRectTexture; import gregtech.api.gui.resources.TextTexture; -import gregtech.api.gui.widgets.ImageWidget; import gregtech.api.gui.widgets.*; import gregtech.api.gui.widgets.tab.IGuiTextureTabInfo; import gregtech.api.terminal.app.guide.widget.GuidePageWidget; @@ -18,14 +15,15 @@ import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; import gregtech.api.terminal.gui.widgets.TextEditorWidget; import gregtech.api.terminal.os.TerminalDialogWidget; +import gregtech.api.terminal.os.TerminalTheme; +import gregtech.api.terminal.util.FileUtils; import gregtech.api.util.Position; import gregtech.api.util.Size; import java.awt.*; import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; import java.util.Map; +import java.util.Objects; public class GuideConfigEditor extends TabGroup { public String json; @@ -38,9 +36,7 @@ public class GuideConfigEditor extends TabGroup { private final GuideEditorApp app; public GuideConfigEditor(int x, int y, int width, int height, GuideEditorApp app) { - super(x, y + 10, new CustomTabListRenderer( - new ColorRectTexture(new Color(175, 0, 0, 131)), - new ColorRectTexture(new Color(246, 120, 120, 190)), 30, 10)); + super(x, y + 10, new CustomTabListRenderer(TerminalTheme.COLOR_F_2, TerminalTheme.COLOR_B_3, 30, 10)); setSize(new Size(width, height)); addButton = new CircleButtonWidget[2]; widgetSelector = createWidgetSelector(); @@ -59,36 +55,36 @@ public GuideConfigEditor(int x, int y, int width, int height, GuideEditorApp app }); this.addWidget(new CircleButtonWidget(97, -5, 5, 1, 3) .setColors(new Color(255, 255, 255, 0).getRGB(), - new Color(255, 255, 255).getRGB(), - new Color(144, 243, 116).getRGB()) + TerminalTheme.COLOR_7.getColor(), + TerminalTheme.COLOR_1.getColor()) .setIcon(GuiTextures.TERMINAL_ADD) .setHoverText("New Page") .setClickListener(this::newPage)); this.addWidget(new CircleButtonWidget(112, -5, 5, 1, 3) .setColors(new Color(255, 255, 255, 0).getRGB(), - new Color(255, 255, 255).getRGB(), - new Color(243, 208, 116).getRGB()) + TerminalTheme.COLOR_7.getColor(), + TerminalTheme.COLOR_2.getColor()) .setIcon(GuiTextures.TERMINAL_ADD) .setHoverText("Import Page") .setClickListener(this::loadJson)); this.addWidget(new CircleButtonWidget(127, -5, 5, 1, 3) .setColors(new Color(255, 255, 255, 0).getRGB(), - new Color(255, 255, 255).getRGB(), - new Color(231, 95, 95).getRGB()) + TerminalTheme.COLOR_7.getColor(), + TerminalTheme.COLOR_3.getColor()) .setIcon(GuiTextures.TERMINAL_ADD) .setHoverText("Export Page") .setClickListener(this::saveJson)); addButton[0] = new CircleButtonWidget(115, 15, 8, 1, 8) .setColors(new Color(255, 255, 255, 0).getRGB(), - new Color(255, 255, 255).getRGB(), - new Color(0, 115, 255).getRGB()) + TerminalTheme.COLOR_7.getColor(), + TerminalTheme.COLOR_4.getColor()) .setIcon(GuiTextures.TERMINAL_ADD) .setHoverText("add stream") .setClickListener(this::addStream); addButton[1] = new CircleButtonWidget(115, 35, 8, 1, 8) .setColors(new Color(255, 255, 255, 0).getRGB(), - new Color(255, 255, 255).getRGB(), - new Color(113, 27, 217).getRGB()) + TerminalTheme.COLOR_7.getColor(), + TerminalTheme.COLOR_5.getColor()) .setIcon(GuiTextures.TERMINAL_ADD) .setHoverText("add fixed") .setClickListener(this::addFixed); @@ -109,9 +105,9 @@ public GuidePageEditorWidget getPageEditor() { private DraggableScrollableWidgetGroup createPageConfig() { DraggableScrollableWidgetGroup group = new DraggableScrollableWidgetGroup(0, 0, getSize().width, getSize().height - 10) - .setBackground(new ColorRectTexture(new Color(246, 120, 120, 190))) + .setBackground(TerminalTheme.COLOR_B_3) .setYScrollBarWidth(4) - .setYBarStyle(null, new ColorRectTexture(new Color(148, 226, 193))); + .setYBarStyle(null, TerminalTheme.COLOR_F_1); group.addWidget(new LabelWidget(5, 5, "section", -1).setShadow(true)); group.addWidget(new TextFieldWidget(5, 15, 116, 20, new ColorRectTexture(0x9f000000), null, null) .setTextResponder(s->{ @@ -139,9 +135,9 @@ public void updateTitle(String title) { private DraggableScrollableWidgetGroup createWidgetSelector() { DraggableScrollableWidgetGroup group = new DraggableScrollableWidgetGroup(0, 0, getSize().width, getSize().height - 10) - .setBackground(new ColorRectTexture(new Color(246, 120, 120, 190))) + .setBackground(TerminalTheme.COLOR_B_3) .setYScrollBarWidth(4) - .setYBarStyle(null, new ColorRectTexture(new Color(148, 226, 193))); + .setYBarStyle(null, TerminalTheme.COLOR_F_1); int y = 10; //133 for (Map.Entry entry : GuidePageWidget.REGISTER_WIDGETS.entrySet()) { IGuideWidget widgetTemplate = entry.getValue(); @@ -157,9 +153,9 @@ private DraggableScrollableWidgetGroup createWidgetSelector() { private DraggableScrollableWidgetGroup createConfigurator() { return new DraggableScrollableWidgetGroup(0, 0, getSize().width, getSize().height - 10) - .setBackground(new ColorRectTexture(new Color(246, 120, 120, 190))) + .setBackground(TerminalTheme.COLOR_B_3) .setYScrollBarWidth(4) - .setYBarStyle(null, new ColorRectTexture(new Color(148, 226, 193))); + .setYBarStyle(null, TerminalTheme.COLOR_F_1); } public void loadConfigurator(IGuideWidget widget) { @@ -186,10 +182,8 @@ private void loadJson(ClickData data) { TerminalDialogWidget.showFileDialog(app.getOs(), "Load Json", file, true, result->{ if (result != null && result.isFile()) { try { - FileReader reader = new FileReader(result); - JsonObject config = new JsonParser().parse(new JsonReader(reader)).getAsJsonObject(); + JsonObject config = Objects.requireNonNull(FileUtils.loadJson(result)).getAsJsonObject(); pageEditor.loadJsonConfig(config); - reader.close(); getPageEditor().setSection(config.get("section").getAsString()); updateTitle(config.get("title").getAsString()); } catch (Exception e) { @@ -205,11 +199,7 @@ private void saveJson(ClickData data) { File file = new File("terminal\\guide_editor"); TerminalDialogWidget.showFileDialog(app.getOs(), "Save Json", file, false, result->{ if (result != null) { - try { - FileWriter writer = new FileWriter(result); - writer.write(pageEditor.getJsonString()); - writer.close(); - } catch (Exception e) { + if(!FileUtils.saveJson(result, pageEditor.getJsonConfig())) { TerminalDialogWidget.showInfoDialog(app.getOs(), "ERROR", "An error occurred while saving the file.").setClientSide().open(); } } diff --git a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/GuidePageEditorWidget.java b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/GuidePageEditorWidget.java index 6995f88cc6a..398b21ec0d9 100644 --- a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/GuidePageEditorWidget.java +++ b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/GuidePageEditorWidget.java @@ -12,6 +12,7 @@ import gregtech.api.terminal.app.guide.widget.IGuideWidget; import gregtech.api.terminal.gui.widgets.CircleButtonWidget; import gregtech.api.terminal.gui.widgets.CustomPositionSizeWidget; +import gregtech.api.terminal.os.TerminalTheme; import gregtech.api.util.Position; import gregtech.api.util.Size; import gregtech.api.util.interpolate.Eases; @@ -40,22 +41,22 @@ public GuidePageEditorWidget(int xPosition, int yPosition, int width, int height toolButtons.setVisible(false); toolButtons.addWidget(new CircleButtonWidget(-20, -4, 8, 1, 12) .setColors(new Color(255, 255, 255, 0).getRGB(), - new Color(88, 198, 88).getRGB(), - new Color(158, 238, 124).getRGB()) + TerminalTheme.COLOR_B_2.getColor(), + TerminalTheme.COLOR_1.getColor()) .setIcon(GuiTextures.TERMINAL_UP) .setHoverText("up") .setClickListener(this::moveUp)); toolButtons.addWidget(new CircleButtonWidget(0, -4, 8, 1, 12) .setColors(new Color(255, 255, 255, 0).getRGB(), - new Color(255, 217, 0).getRGB(), - new Color(243, 217, 117).getRGB()) + TerminalTheme.COLOR_B_2.getColor(), + TerminalTheme.COLOR_2.getColor()) .setIcon(GuiTextures.TERMINAL_DOWN) .setHoverText("down") .setClickListener(this::moveDown)); toolButtons.addWidget(new CircleButtonWidget(20, -4, 8, 1, 12) .setColors(new Color(255, 255, 255, 0).getRGB(), - new Color(238, 46, 46).getRGB(), - new Color(238, 116, 116).getRGB()) + TerminalTheme.COLOR_B_2.getColor(), + TerminalTheme.COLOR_3.getColor()) .setIcon(GuiTextures.TERMINAL_DELETE) .setHoverText("delete") .setClickListener(this::delete)); @@ -124,7 +125,7 @@ private void moveDown(ClickData clickData) { moveDown(selected); } - public String getJsonString() { + public JsonObject getJsonConfig() { JsonObject json = new JsonObject(); json.addProperty("section", section); json.addProperty("title", title.content.get(0)); @@ -144,7 +145,7 @@ public String getJsonString() { } }); - return new Gson().toJson(json); + return json; } public JsonObject addGuideWidget(IGuideWidget widget, boolean isFixed) { diff --git a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/BooleanConfigurator.java b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/BooleanConfigurator.java index cfb4ff12802..250f0e978eb 100644 --- a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/BooleanConfigurator.java +++ b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/BooleanConfigurator.java @@ -4,6 +4,7 @@ import gregtech.api.gui.resources.ColorRectTexture; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; import gregtech.api.terminal.gui.widgets.RectButtonWidget; +import gregtech.api.terminal.os.TerminalTheme; import java.awt.*; @@ -26,8 +27,8 @@ protected void init(){ } return config.get(name).getAsBoolean(); }) - .setColors(new Color(0, 0, 0, 74).getRGB(), - new Color(128, 255, 128).getRGB(), + .setColors(TerminalTheme.COLOR_B_1.getColor(), + TerminalTheme.COLOR_1.getColor(), new Color(255, 255, 255, 0).getRGB()) .setIcon(new ColorRectTexture(new Color(0, 0, 0, 74).getRGB()))); } diff --git a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/FluidStackConfigurator.java b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/FluidStackConfigurator.java index a79ed58485e..789cf68ced8 100644 --- a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/FluidStackConfigurator.java +++ b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/FluidStackConfigurator.java @@ -10,6 +10,7 @@ import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; import gregtech.api.terminal.gui.widgets.RectButtonWidget; import gregtech.api.terminal.app.guide.widget.TankListWidget; +import gregtech.api.terminal.os.TerminalTheme; import java.awt.*; import java.util.ArrayList; @@ -32,8 +33,8 @@ protected void init() { addSlot(container, new TankListWidget.FluidStackInfo(null, 0)); updateValue(); }) - .setColors(new Color(0, 0, 0, 74).getRGB(), - new Color(128, 255, 128).getRGB(), + .setColors(TerminalTheme.COLOR_B_1.getColor(), + TerminalTheme.COLOR_1.getColor(), new Color(255, 255, 255, 0).getRGB())); tanks = new ArrayList<>(); if (!config.get(name).isJsonNull()) { @@ -48,15 +49,15 @@ private void addSlot(DraggableScrollableWidgetGroup container, TankListWidget.Fl WidgetGroup group = new WidgetGroup(0, tanks.size() * 20, 116, 20); tanks.add(fluidStackInfo); group.addWidget(new PhantomFluidWidget(1, 1, 18, 18, null, null) - .setBackgroundTexture(new ColorRectTexture(0x9f000000)) + .setBackgroundTexture(TerminalTheme.COLOR_B_2) .setFluidStackSupplier(fluidStackInfo::getInstance, true) .setFluidStackUpdater(fluidStack->{ fluidStackInfo.update(fluidStack); updateValue(); }, true)); group.addWidget(new RectButtonWidget(20, 0, 20, 20) - .setColors(new Color(0, 0, 0, 74).getRGB(), - new Color(128, 255, 128).getRGB(), + .setColors(TerminalTheme.COLOR_B_1.getColor(), + TerminalTheme.COLOR_1.getColor(), new Color(255, 255, 255, 0).getRGB()) .setClickListener(data -> { fluidStackInfo.amount = Math.max(0, fluidStackInfo.amount - (data.isShiftClick ? data.isCtrlClick ? 1000 : 10 : data.isCtrlClick? 100: 1)); @@ -65,8 +66,8 @@ private void addSlot(DraggableScrollableWidgetGroup container, TankListWidget.Fl .setHoverText("Shift -10|Ctrl -100|Shift+Ctrl -1000") .setIcon(new TextTexture("-1", -1))); group.addWidget(new RectButtonWidget(76, 0, 20, 20) - .setColors(new Color(0, 0, 0, 74).getRGB(), - new Color(128, 255, 128).getRGB(), + .setColors(TerminalTheme.COLOR_B_1.getColor(), + TerminalTheme.COLOR_1.getColor(), new Color(255, 255, 255, 0).getRGB()) .setClickListener(data -> { fluidStackInfo.amount = Math.max(0, fluidStackInfo.amount + (data.isShiftClick ? data.isCtrlClick ? 1000 : 10 : data.isCtrlClick? 100: 1)); @@ -74,11 +75,11 @@ private void addSlot(DraggableScrollableWidgetGroup container, TankListWidget.Fl }) .setHoverText("Shift +10|Ctrl +100|Shift+Ctrl +1000") .setIcon(new TextTexture("+1", -1))); - group.addWidget(new ImageWidget(40, 0, 36, 20, new ColorRectTexture(0x9f000000))); + group.addWidget(new ImageWidget(40, 0, 36, 20, TerminalTheme.COLOR_B_2)); group.addWidget(new SimpleTextWidget(58, 10, "", 0xFFFFFF, () -> Integer.toString(fluidStackInfo.amount), true)); group.addWidget(new RectButtonWidget(96, 0, 20, 20) - .setColors(new Color(0, 0, 0, 74).getRGB(), - new Color(128, 255, 128).getRGB(), + .setColors(TerminalTheme.COLOR_B_1.getColor(), + TerminalTheme.COLOR_1.getColor(), new Color(255, 255, 255, 0).getRGB()) .setClickListener(data -> { container.waitToRemoved(group); diff --git a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/ItemStackConfigurator.java b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/ItemStackConfigurator.java index c361b889772..3e57b49e634 100644 --- a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/ItemStackConfigurator.java +++ b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/ItemStackConfigurator.java @@ -13,6 +13,7 @@ import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; import gregtech.api.terminal.gui.widgets.RectButtonWidget; import gregtech.api.terminal.app.guide.widget.SlotListWidget; +import gregtech.api.terminal.os.TerminalTheme; import net.minecraftforge.items.IItemHandlerModifiable; import net.minecraftforge.items.ItemStackHandler; @@ -37,8 +38,8 @@ protected void init() { addSlot(container, new SlotListWidget.ItemStackInfo("minecraft:air", 0, 0)); updateValue(); }) - .setColors(new Color(0, 0, 0, 74).getRGB(), - new Color(128, 255, 128).getRGB(), + .setColors(TerminalTheme.COLOR_B_1.getColor(), + TerminalTheme.COLOR_1.getColor(), new Color(255, 255, 255, 0).getRGB())); slots = new ArrayList<>(); if (!config.get(name).isJsonNull()) { @@ -54,13 +55,13 @@ private void addSlot(DraggableScrollableWidgetGroup container, SlotListWidget.It slots.add(itemStackInfo); IItemHandlerModifiable handler = new ItemStackHandler(); handler.setStackInSlot(0, itemStackInfo.getInstance()); - group.addWidget(new PhantomSlotWidget(handler, 0, 1, 1).setBackgroundTexture(new ColorRectTexture(0x9f000000)).setChangeListener(()->{ + group.addWidget(new PhantomSlotWidget(handler, 0, 1, 1).setBackgroundTexture(TerminalTheme.COLOR_B_2).setChangeListener(()->{ itemStackInfo.update(handler.getStackInSlot(0)); updateValue(); })); group.addWidget(new RectButtonWidget(20, 0, 20, 20) - .setColors(new Color(0, 0, 0, 74).getRGB(), - new Color(128, 255, 128).getRGB(), + .setColors(TerminalTheme.COLOR_B_1.getColor(), + TerminalTheme.COLOR_1.getColor(), new Color(255, 255, 255, 0).getRGB()) .setClickListener(data -> { itemStackInfo.count = Math.max(0, itemStackInfo.count - (data.isShiftClick ? 10 : 1)); @@ -68,19 +69,19 @@ private void addSlot(DraggableScrollableWidgetGroup container, SlotListWidget.It }) .setIcon(new TextTexture("-1", -1))); group.addWidget(new RectButtonWidget(76, 0, 20, 20) - .setColors(new Color(0, 0, 0, 74).getRGB(), - new Color(128, 255, 128).getRGB(), + .setColors(TerminalTheme.COLOR_B_1.getColor(), + TerminalTheme.COLOR_1.getColor(), new Color(255, 255, 255, 0).getRGB()) .setClickListener(data -> { itemStackInfo.count = Math.max(0, itemStackInfo.count + (data.isShiftClick ? 10 : 1)); updateValue(); }) .setIcon(new TextTexture("+1", -1))); - group.addWidget(new ImageWidget(40, 0, 36, 20, new ColorRectTexture(0x9f000000))); + group.addWidget(new ImageWidget(40, 0, 36, 20, TerminalTheme.COLOR_B_2)); group.addWidget(new SimpleTextWidget(58, 10, "", 0xFFFFFF, () -> Integer.toString(itemStackInfo.count), true)); group.addWidget(new RectButtonWidget(96, 0, 20, 20) - .setColors(new Color(0, 0, 0, 74).getRGB(), - new Color(128, 255, 128).getRGB(), + .setColors(TerminalTheme.COLOR_B_1.getColor(), + TerminalTheme.COLOR_1.getColor(), new Color(255, 255, 255, 0).getRGB()) .setClickListener(data -> { container.waitToRemoved(group); diff --git a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/NumberConfigurator.java b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/NumberConfigurator.java index ece9cc52422..2bcb2a0f4eb 100644 --- a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/NumberConfigurator.java +++ b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/NumberConfigurator.java @@ -8,6 +8,7 @@ import gregtech.api.gui.widgets.SimpleTextWidget; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; import gregtech.api.terminal.gui.widgets.RectButtonWidget; +import gregtech.api.terminal.os.TerminalTheme; import java.awt.*; @@ -24,30 +25,30 @@ public NumberConfigurator(DraggableScrollableWidgetGroup group, JsonObject confi protected void init(){ int y = 15; this.addWidget(new RectButtonWidget(0, y, 20, 20) - .setColors(new Color(0, 0, 0, 74).getRGB(), - new Color(128, 255, 128).getRGB(), + .setColors(TerminalTheme.COLOR_B_1.getColor(), + TerminalTheme.COLOR_1.getColor(), new Color(255, 255, 255, 0).getRGB()) .setClickListener(data -> adjustTransferRate(data.isShiftClick ? -100 : -10)) .setIcon(new TextTexture("-10", -1))); this.addWidget(new RectButtonWidget(96, y, 20, 20) - .setColors(new Color(0, 0, 0, 74).getRGB(), - new Color(128, 255, 128).getRGB(), + .setColors(TerminalTheme.COLOR_B_1.getColor(), + TerminalTheme.COLOR_1.getColor(), new Color(255, 255, 255, 0).getRGB()) .setClickListener(data -> adjustTransferRate(data.isShiftClick ? +100 : +10)) .setIcon(new TextTexture("+10", -1))); this.addWidget(new RectButtonWidget(20, y, 20, 20) - .setColors(new Color(0, 0, 0, 74).getRGB(), - new Color(128, 255, 128).getRGB(), + .setColors(TerminalTheme.COLOR_B_1.getColor(), + TerminalTheme.COLOR_1.getColor(), new Color(255, 255, 255, 0).getRGB()) .setClickListener(data -> adjustTransferRate(data.isShiftClick ? -5 : -1)) .setIcon(new TextTexture("-1", -1))); this.addWidget(new RectButtonWidget(76, y, 20, 20) - .setColors(new Color(0, 0, 0, 74).getRGB(), - new Color(128, 255, 128).getRGB(), + .setColors(TerminalTheme.COLOR_B_1.getColor(), + TerminalTheme.COLOR_1.getColor(), new Color(255, 255, 255, 0).getRGB()) .setClickListener(data -> adjustTransferRate(data.isShiftClick ? +5 : +1)) .setIcon(new TextTexture("+1", -1))); - this.addWidget(new ImageWidget(40, y, 36, 20, new ColorRectTexture(0x9f000000))); + this.addWidget(new ImageWidget(40, y, 36, 20, TerminalTheme.COLOR_B_2)); this.addWidget(new SimpleTextWidget(58, 25, "", 0xFFFFFF, () -> { JsonElement element = config.get(name); if (element.isJsonNull()) { diff --git a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/SelectorConfigurator.java b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/SelectorConfigurator.java index 23511f0a03d..8a55bf68b78 100644 --- a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/SelectorConfigurator.java +++ b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/SelectorConfigurator.java @@ -3,6 +3,7 @@ import com.google.gson.JsonObject; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; import gregtech.api.terminal.gui.widgets.SelectorWidget; +import gregtech.api.terminal.os.TerminalTheme; import java.awt.*; import java.util.List; @@ -25,8 +26,8 @@ protected void init(List candidates){ } return config.get(name).getAsString(); }, true) - .setColors(new Color(0, 0, 0, 74).getRGB(), - new Color(128, 255, 128).getRGB(), + .setColors(TerminalTheme.COLOR_B_1.getColor(), + TerminalTheme.COLOR_1.getColor(), new Color(255, 255, 255, 0).getRGB()) .setIsUp(true) .setOnChanged(this::updateValue)); diff --git a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/StringConfigurator.java b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/StringConfigurator.java index 8329ec1365d..29724fb1a38 100644 --- a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/StringConfigurator.java +++ b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/StringConfigurator.java @@ -6,6 +6,7 @@ import gregtech.api.gui.widgets.TextFieldWidget; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; import gregtech.api.terminal.gui.widgets.RectButtonWidget; +import gregtech.api.terminal.os.TerminalTheme; import java.awt.*; @@ -22,12 +23,12 @@ public StringConfigurator(DraggableScrollableWidgetGroup group, JsonObject confi protected void init() { this.addWidget(new RectButtonWidget(76, 15, 40, 20) - .setColors(new Color(0, 0, 0, 74).getRGB(), - new Color(128, 255, 128).getRGB(), + .setColors(TerminalTheme.COLOR_B_1.getColor(), + TerminalTheme.COLOR_1.getColor(), new Color(255, 255, 255, 0).getRGB()) .setClickListener(data -> updateString()) .setIcon(new TextTexture("Update", -1))); - textFieldWidget = new TextFieldWidget(0, 15, 76, 20, new ColorRectTexture(0x9f000000), null, null) + textFieldWidget = new TextFieldWidget(0, 15, 76, 20, TerminalTheme.COLOR_B_2, null, null) .setMaxStringLength(Integer.MAX_VALUE) .setValidator(s->true); this.addWidget(textFieldWidget); diff --git a/src/main/java/gregtech/api/terminal/os/TerminalTheme.java b/src/main/java/gregtech/api/terminal/os/TerminalTheme.java new file mode 100644 index 00000000000..edd952b696c --- /dev/null +++ b/src/main/java/gregtech/api/terminal/os/TerminalTheme.java @@ -0,0 +1,71 @@ +package gregtech.api.terminal.os; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import gregtech.api.gui.resources.ColorRectTexture; +import gregtech.api.gui.resources.ModifyGuiTexture; +import gregtech.api.gui.resources.TextureArea; +import gregtech.api.terminal.util.FileUtils; + +import java.awt.*; +import java.io.File; + +public class TerminalTheme { + private static final String FILE_PATH = "terminal\\config\\theme.json"; + public static final ColorRectTexture COLOR_1 = new ColorRectTexture(new Color(144, 243, 116)); + public static final ColorRectTexture COLOR_2 = new ColorRectTexture(new Color(243, 208, 116)); + public static final ColorRectTexture COLOR_3 = new ColorRectTexture(new Color(231, 95, 95)); + public static final ColorRectTexture COLOR_4 = new ColorRectTexture(new Color(0, 115, 255)); + public static final ColorRectTexture COLOR_5 = new ColorRectTexture(new Color(113, 27, 217)); + public static final ColorRectTexture COLOR_6 = new ColorRectTexture(new Color(0, 0, 0, 255)); + public static final ColorRectTexture COLOR_7 = new ColorRectTexture(new Color(255, 255, 255, 255)); + + public static final ColorRectTexture COLOR_F_1 = new ColorRectTexture(new Color(148, 226, 193)); + public static final ColorRectTexture COLOR_F_2 = new ColorRectTexture(new Color(175, 0, 0, 131)); + + public static final ColorRectTexture COLOR_B_1 = new ColorRectTexture(new Color(0, 0, 0, 79)); + public static final ColorRectTexture COLOR_B_2 = new ColorRectTexture(new Color(0, 0, 0, 159)); + public static final ColorRectTexture COLOR_B_3 = new ColorRectTexture(new Color(246, 120, 120, 190)); + + public static final ModifyGuiTexture WALL_PAPER = new ModifyGuiTexture(TextureArea.fullImage("textures/gui/terminal/terminal_background.png")); + + static { + JsonElement element = FileUtils.loadJson(new File(FILE_PATH)); + if (element == null || element.isJsonObject()) { + saveConfig(); + } else { + JsonObject config = element.getAsJsonObject(); + if (config.has("COLOR_1")) { COLOR_1.setColor(config.get("COLOR_1").getAsInt()); } + if (config.has("COLOR_2")) { COLOR_2.setColor(config.get("COLOR_2").getAsInt()); } + if (config.has("COLOR_3")) { COLOR_3.setColor(config.get("COLOR_3").getAsInt()); } + if (config.has("COLOR_4")) { COLOR_4.setColor(config.get("COLOR_4").getAsInt()); } + if (config.has("COLOR_5")) { COLOR_5.setColor(config.get("COLOR_5").getAsInt()); } + if (config.has("COLOR_6")) { COLOR_6.setColor(config.get("COLOR_6").getAsInt()); } + if (config.has("COLOR_7")) { COLOR_7.setColor(config.get("COLOR_7").getAsInt()); } + if (config.has("COLOR_F_1")) { COLOR_F_1.setColor(config.get("COLOR_F_1").getAsInt()); } + if (config.has("COLOR_F_2")) { COLOR_F_2.setColor(config.get("COLOR_F_2").getAsInt()); } + if (config.has("COLOR_B_1")) { COLOR_B_1.setColor(config.get("COLOR_B_1").getAsInt()); } + if (config.has("COLOR_B_2")) { COLOR_B_2.setColor(config.get("COLOR_B_2").getAsInt()); } + if (config.has("COLOR_B_3")) { COLOR_B_3.setColor(config.get("COLOR_B_3").getAsInt()); } + if (config.has("WALL_PAPER")) { WALL_PAPER.loadConfig(config.get("WALL_PAPER").getAsJsonObject()); } + } + } + + public static boolean saveConfig() { + JsonObject config = new JsonObject(); + config.addProperty("COLOR_1", COLOR_1.getColor()); + config.addProperty("COLOR_2", COLOR_2.getColor()); + config.addProperty("COLOR_3", COLOR_3.getColor()); + config.addProperty("COLOR_4", COLOR_4.getColor()); + config.addProperty("COLOR_5", COLOR_5.getColor()); + config.addProperty("COLOR_6", COLOR_6.getColor()); + config.addProperty("COLOR_7", COLOR_7.getColor()); + config.addProperty("COLOR_F_1", COLOR_F_1.getColor()); + config.addProperty("COLOR_F_2", COLOR_F_2.getColor()); + config.addProperty("COLOR_B_1", COLOR_B_1.getColor()); + config.addProperty("COLOR_B_2", COLOR_B_2.getColor()); + config.addProperty("COLOR_B_3", COLOR_B_3.getColor()); + config.add("WALL_PAPER", WALL_PAPER.saveConfig()); + return FileUtils.saveJson(new File(FILE_PATH), config); + } +} diff --git a/src/main/java/gregtech/api/terminal/os/menu/TerminalMenuWidget.java b/src/main/java/gregtech/api/terminal/os/menu/TerminalMenuWidget.java index 39c7f2c5fe7..78605b9533e 100644 --- a/src/main/java/gregtech/api/terminal/os/menu/TerminalMenuWidget.java +++ b/src/main/java/gregtech/api/terminal/os/menu/TerminalMenuWidget.java @@ -8,6 +8,7 @@ import gregtech.api.terminal.gui.widgets.CircleButtonWidget; import gregtech.api.terminal.os.TerminalDialogWidget; import gregtech.api.terminal.os.TerminalOSWidget; +import gregtech.api.terminal.os.TerminalTheme; import gregtech.api.terminal.os.menu.component.IMenuComponent; import gregtech.api.util.Position; import gregtech.api.util.Size; @@ -35,20 +36,20 @@ public TerminalMenuWidget(Position position, Size size, TerminalOSWidget os) { components = new ArrayList<>(); this.addWidget(new CircleButtonWidget(5, 10, 4, 1, 0) .setColors(new Color(255, 255, 255, 0).getRGB(), - new Color(255, 255, 255).getRGB(), - new Color(239, 105, 105).getRGB()) + TerminalTheme.COLOR_7.getColor(), + TerminalTheme.COLOR_3.getColor()) .setHoverText("close") .setClickListener(this::close)); this.addWidget(new CircleButtonWidget(15, 10, 4, 1, 0) .setColors(new Color(255, 255, 255, 0).getRGB(), - new Color(255, 255, 255).getRGB(), - new Color(243, 217, 117).getRGB()) + TerminalTheme.COLOR_7.getColor(), + TerminalTheme.COLOR_2.getColor()) .setHoverText("minimize") .setClickListener(this::minimize)); this.addWidget(new CircleButtonWidget(25, 10, 4, 1, 0) .setColors(new Color(255, 255, 255, 0).getRGB(), - new Color(255, 255, 255).getRGB(), - new Color(154, 243, 122).getRGB()) + TerminalTheme.COLOR_7.getColor(), + TerminalTheme.COLOR_1.getColor()) .setHoverText("maximize") .setClickListener(this::maximize)); } @@ -74,11 +75,11 @@ public void addComponent(IMenuComponent component) { WidgetGroup group = new WidgetGroup(); int x = 15; int y = 40 + components.size() * 25; - group.addWidget(new CircleButtonWidget(x, y, 10, 1, 14) + CircleButtonWidget button = new CircleButtonWidget(x, y, 10, 1, 14) .setColors(0x00FFFFFF, 0xFFFFFFFF, 0xFF505050) .setHoverText(component.hoverText()) - .setIcon(component.buttonIcon()) - .setClickListener(c->{ + .setIcon(component.buttonIcon()); + button.setClickListener(c->{ components.forEach(tuple -> { if (tuple.getFirst() instanceof Widget && tuple.getFirst() != component){ ((Widget) tuple.getFirst()).setActive(false); @@ -89,12 +90,14 @@ public void addComponent(IMenuComponent component) { Widget widget = (Widget)component; widget.setVisible(!widget.isVisible()); widget.setActive(!widget.isActive()); + button.setFill(widget.isVisible() ? 0xFF94E2C1 : 0xFF505050); } component.click(c); - })); + }); + group.addWidget(button); if (component instanceof Widget) { Widget widget = (Widget)component; - widget.setSelfPosition(new Position(x + 20, y - 10)); + widget.setSelfPosition(new Position(x + 20, 0)); widget.setVisible(false); widget.setActive(false); group.addWidget(widget); diff --git a/src/main/java/gregtech/api/terminal/os/menu/component/SearchComponent.java b/src/main/java/gregtech/api/terminal/os/menu/component/SearchComponent.java index 4339596b354..db2b8d53b5f 100644 --- a/src/main/java/gregtech/api/terminal/os/menu/component/SearchComponent.java +++ b/src/main/java/gregtech/api/terminal/os/menu/component/SearchComponent.java @@ -2,7 +2,6 @@ import gregtech.api.gui.GuiTextures; import gregtech.api.gui.IRenderContext; -import gregtech.api.gui.Widget; import gregtech.api.gui.resources.ColorRectTexture; import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.widgets.TextFieldWidget; @@ -18,18 +17,19 @@ import java.util.List; public class SearchComponent extends WidgetGroup implements IMenuComponent{ - private final static int SIZE = 6; + private final static int SIZE = 10; private final SearchEngine engine; private final List> results; - private final IMenuSearch search; + private final IWidgetSearch search; private boolean isUp; private int offset; - public SearchComponent(IMenuSearch search){ + public SearchComponent(IWidgetSearch search){ + super(0,0,280,20); this.search = search; results = new ArrayList<>(); engine = new SearchEngine<>(search, r -> results.add(new Tuple<>(r, search.resultDisplay(r)))); - this.addWidget(new TextFieldWidget(0, 0, 260, 20, new ColorRectTexture(0xcf000000), null, null) + this.addWidget(new TextFieldWidget(0, 5, 280, 20, new ColorRectTexture(0xcf000000), null, null) .setValidator(s->true) .setTextResponder(s->{ results.clear(); @@ -105,7 +105,7 @@ public boolean mouseWheelMove(int mouseX, int mouseY, int wheelDelta) { return super.mouseWheelMove(mouseX, mouseY, wheelDelta); } - public interface IMenuSearch extends ISearch{ + public interface IWidgetSearch extends ISearch{ String resultDisplay(T result); void selectResult(T result); } diff --git a/src/main/java/gregtech/api/terminal/os/menu/component/setting/GuiTextureSetter.java b/src/main/java/gregtech/api/terminal/os/menu/component/setting/GuiTextureSetter.java new file mode 100644 index 00000000000..ad9ca8370db --- /dev/null +++ b/src/main/java/gregtech/api/terminal/os/menu/component/setting/GuiTextureSetter.java @@ -0,0 +1,32 @@ +package gregtech.api.terminal.os.menu.component.setting; + +import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.widgets.WidgetGroup; + +import java.util.function.Consumer; + +public class GuiTextureSetter extends WidgetGroup implements ISetting{ + private final String name; + private Consumer updated; + + public GuiTextureSetter(String name, Consumer updated) { + this.name = name; + this.updated = updated; + } + + @Override + public String getName() { + return name; + } + + @Override + public IGuiTexture getIcon() { + return null; + } + + @Override + public Widget getWidget() { + return null; + } +} diff --git a/src/main/java/gregtech/api/terminal/os/menu/component/setting/ISetting.java b/src/main/java/gregtech/api/terminal/os/menu/component/setting/ISetting.java new file mode 100644 index 00000000000..df3878fc96a --- /dev/null +++ b/src/main/java/gregtech/api/terminal/os/menu/component/setting/ISetting.java @@ -0,0 +1,10 @@ +package gregtech.api.terminal.os.menu.component.setting; + +import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.IGuiTexture; + +public interface ISetting { + String getName(); + IGuiTexture getIcon(); + Widget getWidget(); +} diff --git a/src/main/java/gregtech/api/terminal/os/menu/component/setting/IWidgetSettings.java b/src/main/java/gregtech/api/terminal/os/menu/component/setting/IWidgetSettings.java new file mode 100644 index 00000000000..3b534a5f8b1 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/os/menu/component/setting/IWidgetSettings.java @@ -0,0 +1,7 @@ +package gregtech.api.terminal.os.menu.component.setting; + +import gregtech.api.terminal.util.TreeNode; + +public interface IWidgetSettings { + TreeNode getSettings(); +} diff --git a/src/main/java/gregtech/api/terminal/os/menu/component/setting/SettingComponent.java b/src/main/java/gregtech/api/terminal/os/menu/component/setting/SettingComponent.java new file mode 100644 index 00000000000..e5cfcfdeded --- /dev/null +++ b/src/main/java/gregtech/api/terminal/os/menu/component/setting/SettingComponent.java @@ -0,0 +1,29 @@ +package gregtech.api.terminal.os.menu.component.setting; + +import gregtech.api.gui.GuiTextures; +import gregtech.api.gui.Widget; +import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.terminal.gui.widgets.TreeListWidget; +import gregtech.api.terminal.os.menu.component.IMenuComponent; + +public class SettingComponent extends WidgetGroup implements IMenuComponent { + private Widget settingWidget; + + public SettingComponent(IWidgetSettings settings) { + this.addWidget(new TreeListWidget<>(0, 0, 130, 232, settings.getSettings(), (selected) -> { + if (selected.getContent() != null) { + if (settingWidget != null) { + removeWidget(settingWidget); + } + settingWidget = selected.getContent().getWidget(); + if (settingWidget != null) { + addWidget(settingWidget); + } + } + }).setContentIconSupplier(ISetting::getIcon) + .setContentNameSupplier(ISetting::getName) + .setNodeTexture(GuiTextures.BORDERED_BACKGROUND) + .setLeafTexture(GuiTextures.SLOT_DARKENED)); + } + +} diff --git a/src/main/java/gregtech/api/terminal/util/FileUtils.java b/src/main/java/gregtech/api/terminal/util/FileUtils.java new file mode 100644 index 00000000000..245cd7c0587 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/util/FileUtils.java @@ -0,0 +1,39 @@ +package gregtech.api.terminal.util; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; +import com.google.gson.stream.JsonReader; + +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; + +public class FileUtils { + public static JsonElement loadJson(File file) { + try { + FileReader reader = new FileReader(file); + JsonElement json = new JsonParser().parse(new JsonReader(reader)); + reader.close(); + return json; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public static boolean saveJson(File file, JsonElement element) { + try { + if (!file.getParentFile().isDirectory()) { + file.getParentFile().mkdirs(); + } + FileWriter writer = new FileWriter(file); + writer.write(new Gson().toJson(element)); + writer.close(); + return true; + } catch (Exception e) { + e.printStackTrace(); + } + return false; + } +} diff --git a/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java b/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java index ebb61dd949f..9610675e9cf 100644 --- a/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java +++ b/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java @@ -9,6 +9,7 @@ import gregtech.api.terminal.TerminalBuilder; import gregtech.api.terminal.gui.widgets.CircleButtonWidget; import gregtech.api.terminal.os.TerminalOSWidget; +import gregtech.api.terminal.os.TerminalTheme; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.util.ActionResult; @@ -38,7 +39,7 @@ public void addInformation(ItemStack itemStack, List lines) { @Override public ModularUI createUI(PlayerInventoryHolder holder, EntityPlayer entityPlayer) { TerminalOSWidget os = new TerminalOSWidget(12, 11, 333, 232, holder.getCurrentItem().getOrCreateSubCompound("terminal")) - .setBackground(GuiTextures.TERMINAL_BACKGROUND); + .setBackground(TerminalTheme.WALL_PAPER); CircleButtonWidget home = new CircleButtonWidget(362, 126).setIcon(GuiTextures.TERMINAL_HOME) .setColors(new Color(82, 97, 93, 255).getRGB(), new Color(39, 232, 141).getRGB(), From 787cca0edead0eba5a31f3ff94ff4942fc179e0a Mon Sep 17 00:00:00 2001 From: Yefancy Date: Wed, 11 Aug 2021 21:20:23 +0800 Subject: [PATCH 42/58] ThemeApp WALLPAPER setting --- .../api/gui/resources/FileTexture.java | 5 +- .../api/gui/resources/ModifyGuiTexture.java | 19 +++ .../api/gui/resources/utils/ImageUtils.java | 5 +- .../gregtech/api/gui/widgets/ImageWidget.java | 18 +++ .../api/gui/widgets/TextFieldWidget.java | 3 +- .../api/terminal/TerminalBuilder.java | 32 +++-- .../api/terminal/app/AbstractApplication.java | 3 +- .../api/terminal/app/ThemeSettingApp.java | 123 +++++++++++++++--- .../gui/widgets/AnimaWidgetGroup.java | 1 - .../terminal/gui/widgets/SelectorWidget.java | 3 +- .../api/terminal/os/TerminalOSWidget.java | 25 ++-- .../terminal/os/menu/TerminalMenuWidget.java | 4 +- .../behaviors/GuideTerminalBehaviour.java | 1 - 13 files changed, 200 insertions(+), 42 deletions(-) diff --git a/src/main/java/gregtech/api/gui/resources/FileTexture.java b/src/main/java/gregtech/api/gui/resources/FileTexture.java index 3b261001e78..a178c791ad5 100644 --- a/src/main/java/gregtech/api/gui/resources/FileTexture.java +++ b/src/main/java/gregtech/api/gui/resources/FileTexture.java @@ -28,6 +28,9 @@ public class FileTexture implements IGuiTexture{ public FileTexture(File file) { this.file = file; + if (file == null) { + init = true; + } } @SideOnly(Side.CLIENT) @@ -78,7 +81,7 @@ public void updateTick() { @Override public void draw(double x, double y, int width, int height) { if(this.texture != null) { - texture.draw(x, y, width, height); // gif\video update + texture.render((float)x, (float)y, width, height, 0, 1, 1, false, false); } else if (!init){ loadFile(); } diff --git a/src/main/java/gregtech/api/gui/resources/ModifyGuiTexture.java b/src/main/java/gregtech/api/gui/resources/ModifyGuiTexture.java index a3d14ed4f76..c0f3029f8a3 100644 --- a/src/main/java/gregtech/api/gui/resources/ModifyGuiTexture.java +++ b/src/main/java/gregtech/api/gui/resources/ModifyGuiTexture.java @@ -4,8 +4,11 @@ import net.minecraft.util.ResourceLocation; import java.io.File; +import java.util.Arrays; +import java.util.List; public class ModifyGuiTexture implements IGuiTexture{ + public static List TYPES = Arrays.asList("resource", "url", "text", "color", "file"); private IGuiTexture texture; public ModifyGuiTexture(IGuiTexture texture) { @@ -25,6 +28,22 @@ public void setTexture(IGuiTexture texture) { } } + public String getTypeName() { + if (texture instanceof TextureArea) { + return "resource"; + } else if (texture instanceof URLTexture) { + return "url"; + } else if (texture instanceof TextTexture) { + return "text"; + } else if (texture instanceof ColorRectTexture) { + return "color"; + } else if (texture instanceof FileTexture) { + return "file"; + } else { + return null; + } + } + @Override public void draw(double x, double y, int width, int height) { texture.draw(x, y, width, height); diff --git a/src/main/java/gregtech/api/gui/resources/utils/ImageUtils.java b/src/main/java/gregtech/api/gui/resources/utils/ImageUtils.java index 838dc3592b4..af980ff8eaf 100644 --- a/src/main/java/gregtech/api/gui/resources/utils/ImageUtils.java +++ b/src/main/java/gregtech/api/gui/resources/utils/ImageUtils.java @@ -10,6 +10,7 @@ import javax.imageio.ImageReader; import javax.imageio.stream.ImageInputStream; import java.io.ByteArrayInputStream; +import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.Iterator; @@ -48,7 +49,9 @@ public static String readType(InputStream input) throws IOException { reader.dispose(); IOUtils.closeQuietly(stream); } - input.reset(); + if (!(input instanceof FileInputStream)) { + input.reset(); + } return reader.getFormatName(); } } diff --git a/src/main/java/gregtech/api/gui/widgets/ImageWidget.java b/src/main/java/gregtech/api/gui/widgets/ImageWidget.java index c6f5af688b9..a4c98417aef 100644 --- a/src/main/java/gregtech/api/gui/widgets/ImageWidget.java +++ b/src/main/java/gregtech/api/gui/widgets/ImageWidget.java @@ -21,6 +21,8 @@ public class ImageWidget extends Widget { private BooleanSupplier predicate; private boolean isVisible = true; + private int border; + private int borderColor; public ImageWidget(int xPosition, int yPosition, int width, int height) { super(new Position(xPosition, yPosition), new Size(width, height)); @@ -36,12 +38,25 @@ public ImageWidget setImage(TextureArea area) { return this; } + public ImageWidget setBorder(int border, int color) { + this.border = border; + this.borderColor = color; + return this; + } + public ImageWidget setPredicate(BooleanSupplier predicate) { this.predicate = predicate; this.isVisible = false; return this; } + @Override + public void updateScreen() { + if (area != null) { + area.updateTick(); + } + } + @Override public void detectAndSendChanges() { super.detectAndSendChanges(); @@ -66,6 +81,9 @@ public void drawInBackground(int mouseX, int mouseY, IRenderContext context) { Position position = getPosition(); Size size = getSize(); area.draw(position.x, position.y, size.width, size.height); + if (border > 0) { + drawBorder(position.x, position.y, size.width, size.height, borderColor, border); + } GlStateManager.color(rColorForOverlay, gColorForOverlay, bColorForOverlay, 1.0F); } diff --git a/src/main/java/gregtech/api/gui/widgets/TextFieldWidget.java b/src/main/java/gregtech/api/gui/widgets/TextFieldWidget.java index d6c2d5437bf..26995fbce86 100644 --- a/src/main/java/gregtech/api/gui/widgets/TextFieldWidget.java +++ b/src/main/java/gregtech/api/gui/widgets/TextFieldWidget.java @@ -79,9 +79,10 @@ public TextFieldWidget setTextResponder(Consumer textResponder, boolean return this; } - public void setCurrentString(String currentString) { + public TextFieldWidget setCurrentString(String currentString) { this.currentString = currentString; this.textField.setText(currentString); + return this; } public String getCurrentString() { diff --git a/src/main/java/gregtech/api/terminal/TerminalBuilder.java b/src/main/java/gregtech/api/terminal/TerminalBuilder.java index 06c6845f426..94660e13bdf 100644 --- a/src/main/java/gregtech/api/terminal/TerminalBuilder.java +++ b/src/main/java/gregtech/api/terminal/TerminalBuilder.java @@ -8,21 +8,35 @@ import gregtech.api.terminal.app.guideeditor.GuideEditorApp; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; public class TerminalBuilder { - private static final List appRegister = new ArrayList<>(); + private static final Map appRegister = new HashMap<>(); + private static final List defaultApps = new ArrayList<>(); public static void init() { - appRegister.add(new SimpleMachineGuideApp()); - appRegister.add(new MultiBlockGuideApp()); - appRegister.add(new ItemGuideApp()); - appRegister.add(new TutorialGuideApp()); - appRegister.add(new GuideEditorApp()); - appRegister.add(new ThemeSettingApp()); + registerApp(new SimpleMachineGuideApp(), true); + registerApp(new MultiBlockGuideApp(), true); + registerApp(new ItemGuideApp(), true); + registerApp(new TutorialGuideApp(), true); + registerApp(new GuideEditorApp(), true); + registerApp(new ThemeSettingApp(), true); } - public static List getApplications() { - return appRegister; + public static void registerApp(AbstractApplication application, boolean isDefaultApp) { + appRegister.put(application.getName(), application); + if (isDefaultApp) { + defaultApps.add(application.getName()); + } + } + + public static List getDefaultApps() { + return defaultApps; + } + + public static AbstractApplication getApplication(String name) { + return appRegister.get(name); } } diff --git a/src/main/java/gregtech/api/terminal/app/AbstractApplication.java b/src/main/java/gregtech/api/terminal/app/AbstractApplication.java index c1dab7aa5d1..4a28e05c8a0 100644 --- a/src/main/java/gregtech/api/terminal/app/AbstractApplication.java +++ b/src/main/java/gregtech/api/terminal/app/AbstractApplication.java @@ -40,7 +40,8 @@ public IGuiTexture getIcon() { public abstract AbstractApplication createApp(boolean isClient, NBTTagCompound nbt); - public void closeApp(boolean isClient, NBTTagCompound nbt) { + public NBTTagCompound closeApp(boolean isClient, NBTTagCompound nbt) { + return null; } public boolean isBackgroundApp() { diff --git a/src/main/java/gregtech/api/terminal/app/ThemeSettingApp.java b/src/main/java/gregtech/api/terminal/app/ThemeSettingApp.java index 5c17921a7a6..87bc263bb81 100644 --- a/src/main/java/gregtech/api/terminal/app/ThemeSettingApp.java +++ b/src/main/java/gregtech/api/terminal/app/ThemeSettingApp.java @@ -1,14 +1,24 @@ package gregtech.api.terminal.app; import gregtech.api.gui.GuiTextures; -import gregtech.api.gui.resources.ColorRectTexture; +import gregtech.api.gui.resources.*; import gregtech.api.gui.widgets.ImageWidget; +import gregtech.api.gui.widgets.LabelWidget; +import gregtech.api.gui.widgets.TextFieldWidget; +import gregtech.api.gui.widgets.WidgetGroup; import gregtech.api.terminal.gui.widgets.CircleButtonWidget; +import gregtech.api.terminal.gui.widgets.ColorWidget; +import gregtech.api.terminal.gui.widgets.RectButtonWidget; +import gregtech.api.terminal.gui.widgets.SelectorWidget; import gregtech.api.terminal.os.TerminalDialogWidget; import gregtech.api.terminal.os.TerminalTheme; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.PacketBuffer; +import net.minecraft.util.ResourceLocation; +import java.awt.*; +import java.io.File; +import java.util.Arrays; import java.util.function.Consumer; public class ThemeSettingApp extends AbstractApplication { @@ -16,31 +26,43 @@ public ThemeSettingApp() { super("Theme Setting", GuiTextures.GREGTECH_LOGO); } + private WidgetGroup textureGroup; + @Override public AbstractApplication createApp(boolean isClient, NBTTagCompound nbt) { ThemeSettingApp app = new ThemeSettingApp(); if (isClient) { //333 232 float x = 333 * 1.0f / 13; + int y = 50; app.addWidget(new ImageWidget(5, 5, 333 - 10, 232 - 10, TerminalTheme.COLOR_B_2)); - app.addColorButton(TerminalTheme.COLOR_1, "COLOR_1", (int) x, 30); - app.addColorButton(TerminalTheme.COLOR_2, "COLOR_2", (int) (x * 2), 30); - app.addColorButton(TerminalTheme.COLOR_3, "COLOR_3", (int) (x * 3), 30); - app.addColorButton(TerminalTheme.COLOR_4, "COLOR_4", (int) (x * 4), 30); - app.addColorButton(TerminalTheme.COLOR_5, "COLOR_5", (int) (x * 5), 30); - app.addColorButton(TerminalTheme.COLOR_6, "COLOR_6", (int) (x * 6), 30); - app.addColorButton(TerminalTheme.COLOR_7, "COLOR_7", (int) (x * 7), 30); - app.addColorButton(TerminalTheme.COLOR_F_1, "COLOR_F_1", (int) (x * 8), 30); - app.addColorButton(TerminalTheme.COLOR_F_2, "COLOR_F_2", (int) (x * 9), 30); - app.addColorButton(TerminalTheme.COLOR_B_1, "COLOR_B_1", (int) (x * 10), 30); - app.addColorButton(TerminalTheme.COLOR_B_2, "COLOR_B_2", (int) (x * 11), 30); - app.addColorButton(TerminalTheme.COLOR_B_3, "COLOR_B_3", (int) (x * 12), 30); - app.addWidget(new ImageWidget((int) x, 80, 333 / 2, 232 / 2, TerminalTheme.WALL_PAPER)); + app.addWidget(new LabelWidget(333 / 2, 20, "Theme Color Settings", -1).setXCentered(true)); + app.addColorButton(TerminalTheme.COLOR_1, "COLOR_1", (int) x, y); + app.addColorButton(TerminalTheme.COLOR_2, "COLOR_2", (int) (x * 2), y); + app.addColorButton(TerminalTheme.COLOR_3, "COLOR_3", (int) (x * 3), y); + app.addColorButton(TerminalTheme.COLOR_4, "COLOR_4", (int) (x * 4), y); + app.addColorButton(TerminalTheme.COLOR_5, "COLOR_5", (int) (x * 5), y); + app.addColorButton(TerminalTheme.COLOR_6, "COLOR_6", (int) (x * 6), y); + app.addColorButton(TerminalTheme.COLOR_7, "COLOR_7", (int) (x * 7), y); + app.addColorButton(TerminalTheme.COLOR_F_1, "COLOR_F_1", (int) (x * 8), y); + app.addColorButton(TerminalTheme.COLOR_F_2, "COLOR_F_2", (int) (x * 9), y); + app.addColorButton(TerminalTheme.COLOR_B_1, "COLOR_B_1", (int) (x * 10), y); + app.addColorButton(TerminalTheme.COLOR_B_2, "COLOR_B_2", (int) (x * 11), y); + app.addColorButton(TerminalTheme.COLOR_B_3, "COLOR_B_3", (int) (x * 12), y); + app.addWidget(new LabelWidget(333 / 2, 85, "Wallpaper Settings", -1).setXCentered(true)); + app.addWidget(new ImageWidget((int) x, 105, 150, 105, TerminalTheme.WALL_PAPER).setBorder(2, -1)); + app.addWidget(new SelectorWidget((int) (x + 170), 105, 116, 20, Arrays.asList("resource", "url", "color", "file"), -1, TerminalTheme.WALL_PAPER::getTypeName, true) + .setIsUp(true) + .setOnChanged(type->onModifyTextureChanged(type, app)) + .setColors(TerminalTheme.COLOR_B_2.getColor(), TerminalTheme.COLOR_F_1.getColor(), 0) + .setBackground(TerminalTheme.COLOR_B_1)); + textureGroup = new WidgetGroup((int) (x + 170), 132, (int) (x * 11 - 170), 65); + app.addWidget(textureGroup); } return app; } private void addColorButton(ColorRectTexture texture, String name, int x, int y) { - CircleButtonWidget buttonWidget = new CircleButtonWidget(x, y).setFill(texture.getColor()).setStrokeAnima(-1).setHoverText(name); + CircleButtonWidget buttonWidget = new CircleButtonWidget(x, y, 8, 1, 0).setFill(texture.getColor()).setStrokeAnima(-1).setHoverText(name); buttonWidget.setClickListener(cd -> { TerminalDialogWidget.showColorDialog(getOs(), name, color -> { if (color != null) { @@ -55,6 +77,77 @@ private void addColorButton(ColorRectTexture texture, String name, int x, int y) addWidget(buttonWidget); } + private void onModifyTextureChanged(String type, AbstractApplication app) { + textureGroup.clearAllWidgets(); + switch (type) { + case "resource": + if (!(TerminalTheme.WALL_PAPER.getTexture() instanceof TextureArea)) { + TerminalTheme.WALL_PAPER.setTexture(new TextureArea(new ResourceLocation("gregtech:textures/gui/icon/gregtech_logo.png"), 0.0, 0.0, 1.0, 1.0)); + TerminalTheme.saveConfig(); + } + addStringSetting(((TextureArea)TerminalTheme.WALL_PAPER.getTexture()).imageLocation.toString(), + s -> { + TerminalTheme.WALL_PAPER.setTexture(new TextureArea(new ResourceLocation(s), 0.0, 0.0, 1.0, 1.0)); + TerminalTheme.saveConfig(); + }); + break; + case "url": + if (!(TerminalTheme.WALL_PAPER.getTexture() instanceof URLTexture)) { + TerminalTheme.WALL_PAPER.setTexture(new URLTexture(null)); + TerminalTheme.saveConfig(); + } + addStringSetting(((URLTexture)TerminalTheme.WALL_PAPER.getTexture()).url, s -> { + TerminalTheme.WALL_PAPER.setTexture(new URLTexture(s)); + TerminalTheme.saveConfig(); + }); + break; + case "color": + ColorRectTexture texture; + if (!(TerminalTheme.WALL_PAPER.getTexture() instanceof ColorRectTexture)) { + texture = new ColorRectTexture(-1); + TerminalTheme.WALL_PAPER.setTexture(texture); + TerminalTheme.saveConfig(); + } else { + texture = (ColorRectTexture) TerminalTheme.WALL_PAPER.getTexture(); + } + textureGroup.addWidget(new ColorWidget(0, 0, 80, 10) + .setColorSupplier(texture::getColor, true) + .setOnColorChanged(texture::setColor)); + break; + case "file": + if (!(TerminalTheme.WALL_PAPER.getTexture() instanceof FileTexture)) { + TerminalTheme.WALL_PAPER.setTexture(new FileTexture(null)); + TerminalTheme.saveConfig(); + } + textureGroup.addWidget(new RectButtonWidget(0, 0, 116, 20) + .setColors(TerminalTheme.COLOR_B_1.getColor(), + TerminalTheme.COLOR_1.getColor(), + new Color(255, 255, 255, 0).getRGB()) + .setClickListener(cd-> TerminalDialogWidget.showFileDialog(app.getOs(), "Image File", new File("terminal"), true, file->{ + if (file != null && file.isFile()) { + TerminalTheme.WALL_PAPER.setTexture(new FileTexture(file)); + TerminalTheme.saveConfig(); + } + }).setClientSide().open()) + .setIcon(new TextTexture("Select", -1))); + break; + } + } + + private void addStringSetting(String init, Consumer callback) { + TextFieldWidget textFieldWidget = new TextFieldWidget(0, 0, 76, 20, TerminalTheme.COLOR_B_2, null, null) + .setMaxStringLength(Integer.MAX_VALUE) + .setValidator(s -> true) + .setCurrentString(init == null ? "" : init); + textureGroup.addWidget(textFieldWidget); + textureGroup.addWidget(new RectButtonWidget(76, 0, 40, 20) + .setColors(TerminalTheme.COLOR_B_1.getColor(), + TerminalTheme.COLOR_1.getColor(), + new Color(255, 255, 255, 0).getRGB()) + .setClickListener(cd->callback.accept(textFieldWidget.getCurrentString())) + .setIcon(new TextTexture("Update", -1))); + } + @Override protected void writeClientAction(int id, Consumer packetBufferWriter) { } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/AnimaWidgetGroup.java b/src/main/java/gregtech/api/terminal/gui/widgets/AnimaWidgetGroup.java index cc040f489a2..bdf943daf6e 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/AnimaWidgetGroup.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/AnimaWidgetGroup.java @@ -1,6 +1,5 @@ package gregtech.api.terminal.gui.widgets; -import gregtech.api.gui.INativeWidget; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.widgets.WidgetGroup; import gregtech.api.util.Position; diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/SelectorWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/SelectorWidget.java index fcfa2898fb2..3b22e532f8e 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/SelectorWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/SelectorWidget.java @@ -65,13 +65,13 @@ public void drawInForeground(int mouseX, int mouseY) { int width = getSize().width; int height = getSize().height; int y = (isUp ? -candidates.size() : 1) * height + getPosition().y; + FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer; for (String candidate : candidates) { if (background != null) { background.draw(x, y, width, height); } else { drawSolidRect(x, y, width, height, 0xAA000000); } - FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer; fontRenderer.drawString(candidate, x + 4, y + (height - fontRenderer.FONT_HEIGHT) / 2 + 1, fontColor); y += height; } @@ -98,6 +98,7 @@ public boolean mouseClicked(int mouseX, int mouseY, int button) { onChanged.accept(candidate); } writeClientAction(2, buffer -> buffer.writeString(candidate)); + isShow = false; return true; } y += height; diff --git a/src/main/java/gregtech/api/terminal/os/TerminalOSWidget.java b/src/main/java/gregtech/api/terminal/os/TerminalOSWidget.java index 5ff4851446f..b995d247bb7 100644 --- a/src/main/java/gregtech/api/terminal/os/TerminalOSWidget.java +++ b/src/main/java/gregtech/api/terminal/os/TerminalOSWidget.java @@ -5,12 +5,16 @@ import gregtech.api.gui.ModularUI; import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.widgets.AbstractWidgetGroup; +import gregtech.api.terminal.TerminalBuilder; import gregtech.api.terminal.app.AbstractApplication; import gregtech.api.terminal.os.menu.TerminalMenuWidget; import gregtech.api.util.Position; import gregtech.api.util.RenderUtil; import gregtech.api.util.Size; +import net.minecraft.nbt.NBTBase; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.nbt.NBTTagString; import java.util.ArrayList; import java.util.List; @@ -31,6 +35,16 @@ public TerminalOSWidget(int xPosition, int yPosition, int width, int height, NBT this.addWidget(desktop); this.addWidget(menu); this.tabletNBT = tabletNBT; + TerminalBuilder.getDefaultApps().forEach(name-> installApplication(TerminalBuilder.getApplication(name))); + NBTTagList installed = tabletNBT.getTagList("installed", 8); + for (NBTBase nbtBase : installed) { + if (nbtBase instanceof NBTTagString) { + AbstractApplication app = TerminalBuilder.getApplication(((NBTTagString) nbtBase).getString()); + if (app != null) { + installApplication(app); + } + } + } } public ModularUI getModularUI(){ @@ -56,10 +70,6 @@ public void openApplication(AbstractApplication application, boolean isClient) { return; } } - String name = application.getName(); - if (!tabletNBT.hasKey(name)) { - tabletNBT.setTag(name, new NBTTagCompound()); - } AbstractApplication app = application.createApp(isClient, tabletNBT.getCompoundTag(application.getName())).setOs(this); if (app != null) { openedApps.add(app); @@ -99,11 +109,10 @@ public void minimizeApplication(AbstractApplication application, boolean isClien public void closeApplication(AbstractApplication application, boolean isClient) { if (application != null) { - String name = application.getName(); - if (!tabletNBT.hasKey(name)) { - tabletNBT.setTag(name, new NBTTagCompound()); + NBTTagCompound nbt = application.closeApp(isClient, tabletNBT.getCompoundTag(application.getName())); + if (nbt != null) { + tabletNBT.setTag(application.getName(), nbt); } - application.closeApp(isClient, tabletNBT.getCompoundTag(name)); if (isClient) { application.minimizeWidget(desktop::waitToRemoved); } else { diff --git a/src/main/java/gregtech/api/terminal/os/menu/TerminalMenuWidget.java b/src/main/java/gregtech/api/terminal/os/menu/TerminalMenuWidget.java index 78605b9533e..371232acded 100644 --- a/src/main/java/gregtech/api/terminal/os/menu/TerminalMenuWidget.java +++ b/src/main/java/gregtech/api/terminal/os/menu/TerminalMenuWidget.java @@ -67,9 +67,7 @@ public void minimize(ClickData clickData) { os.minimizeApplication(os.focusApp, clickData.isClient); } - public void maximize(ClickData clickData) { - TerminalDialogWidget.showColorDialog(os, "test", System.out::println).addPlayerInventory().open(); - } + public void maximize(ClickData clickData) { } public void addComponent(IMenuComponent component) { WidgetGroup group = new WidgetGroup(); diff --git a/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java b/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java index 9610675e9cf..7b3e0b49e39 100644 --- a/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java +++ b/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java @@ -45,7 +45,6 @@ public ModularUI createUI(PlayerInventoryHolder holder, EntityPlayer entityPlaye new Color(39, 232, 141).getRGB(), 0xff9197A5) .setClickListener(clickData -> os.homeTrigger(clickData.isClient)); - TerminalBuilder.getApplications().forEach(os::installApplication); return ModularUI.builder(GuiTextures.TERMINAL_FRAME, 380, 256) .widget(os) .widget(new ImageWidget(0, 0, 380, 256, GuiTextures.TERMINAL_FRAME)) From 385ae171aaafadbfc330d4fbab23674936d25ecf Mon Sep 17 00:00:00 2001 From: Yefancy Date: Wed, 11 Aug 2021 21:30:44 +0800 Subject: [PATCH 43/58] fix crash and set default resource wallpaper --- .../java/gregtech/api/gui/resources/ModifyGuiTexture.java | 6 +++++- .../java/gregtech/api/terminal/app/ThemeSettingApp.java | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/gregtech/api/gui/resources/ModifyGuiTexture.java b/src/main/java/gregtech/api/gui/resources/ModifyGuiTexture.java index c0f3029f8a3..46628884df3 100644 --- a/src/main/java/gregtech/api/gui/resources/ModifyGuiTexture.java +++ b/src/main/java/gregtech/api/gui/resources/ModifyGuiTexture.java @@ -71,7 +71,11 @@ public JsonObject saveConfig() { config.addProperty("color", ((ColorRectTexture) texture).color); } else if (texture instanceof FileTexture) { config.addProperty("type", "file"); - config.addProperty("file", ((FileTexture) texture).file.getPath()); + if (((FileTexture) texture).file != null) { + config.addProperty("file", ((FileTexture) texture).file.getPath()); + } else { + config.addProperty("file", (String)null); + } } else { return null; } diff --git a/src/main/java/gregtech/api/terminal/app/ThemeSettingApp.java b/src/main/java/gregtech/api/terminal/app/ThemeSettingApp.java index 87bc263bb81..ac7daceb6fc 100644 --- a/src/main/java/gregtech/api/terminal/app/ThemeSettingApp.java +++ b/src/main/java/gregtech/api/terminal/app/ThemeSettingApp.java @@ -82,7 +82,7 @@ private void onModifyTextureChanged(String type, AbstractApplication app) { switch (type) { case "resource": if (!(TerminalTheme.WALL_PAPER.getTexture() instanceof TextureArea)) { - TerminalTheme.WALL_PAPER.setTexture(new TextureArea(new ResourceLocation("gregtech:textures/gui/icon/gregtech_logo.png"), 0.0, 0.0, 1.0, 1.0)); + TerminalTheme.WALL_PAPER.setTexture(new TextureArea(new ResourceLocation("gregtech:textures/gui/terminal/terminal_background.png"), 0.0, 0.0, 1.0, 1.0)); TerminalTheme.saveConfig(); } addStringSetting(((TextureArea)TerminalTheme.WALL_PAPER.getTexture()).imageLocation.toString(), From 664860519edb31ffd80969a09d20b5398e271a0e Mon Sep 17 00:00:00 2001 From: Yefancy Date: Thu, 12 Aug 2021 00:05:02 +0800 Subject: [PATCH 44/58] new Menu component -- ClickComponent --- .../java/gregtech/api/gui/GuiTextures.java | 1 - .../app/guideeditor/GuideEditorApp.java | 38 +++++++++++++-- .../guideeditor/widget/GuideConfigEditor.java | 27 ++--------- .../gui/widgets/CustomPositionSizeWidget.java | 1 - .../os/menu/component/ClickComponent.java | 44 ++++++++++++++++++ .../os/menu/component/SearchComponent.java | 5 +- .../textures/gui/terminal/terminal_export.png | Bin 0 -> 1934 bytes .../textures/gui/terminal/terminal_import.png | Bin 0 -> 1929 bytes .../gui/terminal/terminal_new_page.png | Bin 0 -> 1902 bytes .../gui/terminal/terminal_searching.png | Bin 0 -> 1939 bytes 10 files changed, 84 insertions(+), 32 deletions(-) create mode 100644 src/main/java/gregtech/api/terminal/os/menu/component/ClickComponent.java create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/terminal_export.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/terminal_import.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/terminal_new_page.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/terminal_searching.png diff --git a/src/main/java/gregtech/api/gui/GuiTextures.java b/src/main/java/gregtech/api/gui/GuiTextures.java index 7643b2fa457..f1281d43ed9 100644 --- a/src/main/java/gregtech/api/gui/GuiTextures.java +++ b/src/main/java/gregtech/api/gui/GuiTextures.java @@ -171,7 +171,6 @@ public class GuiTextures { public static final TextureArea TERMINAL_FRAME = TextureArea.fullImage("textures/gui/terminal/terminal_frame.png"); public static final TextureArea TERMINAL_MENU = TextureArea.fullImage("textures/gui/terminal/terminal_menu.png"); public static final TextureArea TERMINAL_HOME = TextureArea.fullImage("textures/gui/terminal/terminal_home.png"); - public static final TextureArea TERMINAL_SETTING = TextureArea.fullImage("textures/gui/terminal/terminal_setting.png"); public static final TextureArea TERMINAL_DELETE = TextureArea.fullImage("textures/gui/terminal/terminal_delete.png"); public static final TextureArea TERMINAL_UP = TextureArea.fullImage("textures/gui/terminal/terminal_up.png"); public static final TextureArea TERMINAL_DOWN = TextureArea.fullImage("textures/gui/terminal/terminal_down.png"); diff --git a/src/main/java/gregtech/api/terminal/app/guideeditor/GuideEditorApp.java b/src/main/java/gregtech/api/terminal/app/guideeditor/GuideEditorApp.java index 7bd1c2c2a1c..04d78eecd43 100644 --- a/src/main/java/gregtech/api/terminal/app/guideeditor/GuideEditorApp.java +++ b/src/main/java/gregtech/api/terminal/app/guideeditor/GuideEditorApp.java @@ -4,13 +4,23 @@ import gregtech.api.terminal.app.AbstractApplication; import gregtech.api.terminal.app.guideeditor.widget.GuideConfigEditor; import gregtech.api.terminal.app.guideeditor.widget.GuidePageEditorWidget; +import gregtech.api.terminal.os.menu.component.ClickComponent; +import gregtech.api.terminal.os.menu.component.IMenuComponent; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.PacketBuffer; +import java.util.Arrays; +import java.util.List; import java.util.function.Consumer; public class GuideEditorApp extends AbstractApplication { public static final TextureArea ICON = TextureArea.fullImage("textures/gui/terminal/guide_editor/icon.png"); + private final static TextureArea NEW_PAGE = TextureArea.fullImage("textures/gui/terminal/terminal_new_page.png"); + private final static TextureArea IMPORT_PAGE = TextureArea.fullImage("textures/gui/terminal/terminal_import.png"); + private final static TextureArea EXPORT_PAGE = TextureArea.fullImage("textures/gui/terminal/terminal_export.png"); + + private GuideConfigEditor configEditor; + public GuideEditorApp() { super("Guide Editor", ICON); @@ -20,16 +30,36 @@ public GuideEditorApp() { public AbstractApplication createApp(boolean isClient, NBTTagCompound nbt) { GuideEditorApp app = new GuideEditorApp(); if (isClient) { - GuideConfigEditor configEditor = new GuideConfigEditor(0, 0, 133, 232, app); + app.configEditor = new GuideConfigEditor(0, 0, 133, 232, app); GuidePageEditorWidget pageEditor = new GuidePageEditorWidget(133, 0, 200, 232, 5); - configEditor.setGuidePageEditorWidget(pageEditor); - pageEditor.setGuideConfigEditor(configEditor); + app.configEditor.setGuidePageEditorWidget(pageEditor); + pageEditor.setGuideConfigEditor(app.configEditor); app.addWidget(pageEditor); - app.addWidget(configEditor); + app.addWidget(app.configEditor); } return app; } + @Override + public List getMenuComponents() { + ClickComponent newPage = new ClickComponent().setIcon(NEW_PAGE).setHoverText("New Page").setClickConsumer(cd->{ + if (configEditor != null) { + configEditor.newPage(cd); + } + }); + ClickComponent importPage = new ClickComponent().setIcon(IMPORT_PAGE).setHoverText("Import Page").setClickConsumer(cd->{ + if (configEditor != null) { + configEditor.loadJson(cd); + } + }); + ClickComponent exportPage = new ClickComponent().setIcon(EXPORT_PAGE).setHoverText("Export Page").setClickConsumer(cd->{ + if (configEditor != null) { + configEditor.saveJson(cd); + } + }); + return Arrays.asList(newPage, importPage, exportPage); + } + @Override protected void writeClientAction(int id, Consumer packetBufferWriter) { } diff --git a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/GuideConfigEditor.java b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/GuideConfigEditor.java index c0d0888bf21..df797f5d4ff 100644 --- a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/GuideConfigEditor.java +++ b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/GuideConfigEditor.java @@ -53,27 +53,6 @@ public GuideConfigEditor(int x, int y, int width, int height, GuideEditorApp app addButton[1].setVisible(false); } }); - this.addWidget(new CircleButtonWidget(97, -5, 5, 1, 3) - .setColors(new Color(255, 255, 255, 0).getRGB(), - TerminalTheme.COLOR_7.getColor(), - TerminalTheme.COLOR_1.getColor()) - .setIcon(GuiTextures.TERMINAL_ADD) - .setHoverText("New Page") - .setClickListener(this::newPage)); - this.addWidget(new CircleButtonWidget(112, -5, 5, 1, 3) - .setColors(new Color(255, 255, 255, 0).getRGB(), - TerminalTheme.COLOR_7.getColor(), - TerminalTheme.COLOR_2.getColor()) - .setIcon(GuiTextures.TERMINAL_ADD) - .setHoverText("Import Page") - .setClickListener(this::loadJson)); - this.addWidget(new CircleButtonWidget(127, -5, 5, 1, 3) - .setColors(new Color(255, 255, 255, 0).getRGB(), - TerminalTheme.COLOR_7.getColor(), - TerminalTheme.COLOR_3.getColor()) - .setIcon(GuiTextures.TERMINAL_ADD) - .setHoverText("Export Page") - .setClickListener(this::saveJson)); addButton[0] = new CircleButtonWidget(115, 15, 8, 1, 8) .setColors(new Color(255, 255, 255, 0).getRGB(), TerminalTheme.COLOR_7.getColor(), @@ -166,7 +145,7 @@ public void loadConfigurator(IGuideWidget widget) { } } - private void newPage(ClickData data) { + public void newPage(ClickData data) { TerminalDialogWidget.showConfirmDialog(app.getOs(), "New Page", "New page", res->{ if (res) { pageEditor.loadJsonConfig("{\"section\":\"default\",\"title\":\"Template\",\"stream\":[],\"fixed\":[]}"); @@ -176,7 +155,7 @@ private void newPage(ClickData data) { }).setClientSide().open(); } - private void loadJson(ClickData data) { + public void loadJson(ClickData data) { if (pageEditor != null) { File file = new File("terminal\\guide_editor"); TerminalDialogWidget.showFileDialog(app.getOs(), "Load Json", file, true, result->{ @@ -194,7 +173,7 @@ private void loadJson(ClickData data) { } } - private void saveJson(ClickData data) { + public void saveJson(ClickData data) { if(pageEditor != null) { File file = new File("terminal\\guide_editor"); TerminalDialogWidget.showFileDialog(app.getOs(), "Save Json", file, false, result->{ diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/CustomPositionSizeWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/CustomPositionSizeWidget.java index daf0a705b85..8de8f36477e 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/CustomPositionSizeWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/CustomPositionSizeWidget.java @@ -5,7 +5,6 @@ import gregtech.api.terminal.gui.IDraggable; import gregtech.api.util.Position; import gregtech.api.util.Size; -import javafx.geometry.Pos; import java.util.function.BiConsumer; diff --git a/src/main/java/gregtech/api/terminal/os/menu/component/ClickComponent.java b/src/main/java/gregtech/api/terminal/os/menu/component/ClickComponent.java new file mode 100644 index 00000000000..ae60d32a351 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/os/menu/component/ClickComponent.java @@ -0,0 +1,44 @@ +package gregtech.api.terminal.os.menu.component; + +import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.IGuiTexture; + +import java.util.function.Consumer; + +public class ClickComponent implements IMenuComponent{ + private IGuiTexture icon; + private String hoverText; + private Consumer consumer; + + public ClickComponent setIcon(IGuiTexture icon) { + this.icon = icon; + return this; + } + + public ClickComponent setHoverText(String hoverText) { + this.hoverText = hoverText; + return this; + } + + public ClickComponent setClickConsumer(Consumer consumer) { + this.consumer = consumer; + return this; + } + + @Override + public IGuiTexture buttonIcon() { + return icon; + } + + @Override + public String hoverText() { + return hoverText; + } + + @Override + public void click(Widget.ClickData clickData) { + if (consumer != null) { + consumer.accept(clickData); + } + } +} diff --git a/src/main/java/gregtech/api/terminal/os/menu/component/SearchComponent.java b/src/main/java/gregtech/api/terminal/os/menu/component/SearchComponent.java index db2b8d53b5f..2965779861f 100644 --- a/src/main/java/gregtech/api/terminal/os/menu/component/SearchComponent.java +++ b/src/main/java/gregtech/api/terminal/os/menu/component/SearchComponent.java @@ -1,9 +1,9 @@ package gregtech.api.terminal.os.menu.component; -import gregtech.api.gui.GuiTextures; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.resources.ColorRectTexture; import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.gui.resources.TextureArea; import gregtech.api.gui.widgets.TextFieldWidget; import gregtech.api.gui.widgets.WidgetGroup; import gregtech.api.terminal.util.ISearch; @@ -17,6 +17,7 @@ import java.util.List; public class SearchComponent extends WidgetGroup implements IMenuComponent{ + private final static TextureArea SEARCHING = TextureArea.fullImage("textures/gui/terminal/terminal_searching.png"); private final static int SIZE = 10; private final SearchEngine engine; private final List> results; @@ -40,7 +41,7 @@ public SearchComponent(IWidgetSearch search){ @Override public IGuiTexture buttonIcon() { - return GuiTextures.TERMINAL_SETTING; + return SEARCHING; } @Override diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_export.png b/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_export.png new file mode 100644 index 0000000000000000000000000000000000000000..9d7c511d2c87e3a2dd82bdf013b83ef42c734685 GIT binary patch literal 1934 zcmb_dO>Epm6n2WJ+Mq%O7uriL2O%Pu^^E`4Hd)eSH#7@uh_)*dqzV|%jCW0TJ;wHC zH$fo&4pgWpq8tEms1OKIK@SL!C@L+Ss=^U*;Kl`sQ!9bE!g&AK()0&}C6C85-@Ny| zH{Y8%y1aB~&*c6|Ns{)I7fV&~-J89;c8d1EZ+~L(*&QuDo=DOycVzE`^v=6?O480R zg4$}jT6x4Jyp_Y0do0&&MFK5JGqc?YlQovg9;*joLAm(VSw#+LL0K^?uo4wnBUs#w z+2PHl8rfVU4pn9!kY~ECFwkNtmb4t$Bfg3?IS$W_%& zr<3dGIUd(l4$<)w7i6tZsqBP*4oLR&kZ>I%CFztuXibiI` zWRND2Ftv*#73E+SQV&SU2p6^EX3se#Dr>S93)4hk(Fhwgc*>Iozl!P6^koi2YAcnI zk8QcMS|b-py09+77$js{bW+=hm|A5CZ^wi!tP7e`Su~Mbj2TXOT;ses+^FRtWw}_C z?^y{#$~(#Q7@U=G$_k1GH3VQD=&**MYuYZf?}eg;eQ1T#z~2~$+5n-Nrn`pen&xFt zAsC8Nd|faluFvBZ7U2dhTxV(&))je_M7PMBJQj`xJAHh-Tr4if+z*;!BB>slm&*%9 z3pthrv>fWutyJ7{n4~x)tXwK6A~m@npswX$+p=v4eABQ1@9RtVm48X9#fM=QnXcSS~vvr)ewV|~~<3N-nZjM{c zSW#ioU>d~+#-fZI3K%mq;1SOPG;dkH&LGwZ%S7MPk-HcqVuv>dWptQ5Gw3w~xhEYL zldL2P3dyv`R}3J zm?p0bW!v)mzd}*71GTR$^`Elq&5a$tViS8q;zZB7qpL*xj4mSh&jop7=$dy6yMX6E9{rW_e+$bZY*o Gm;M6umTA`j literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_import.png b/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_import.png new file mode 100644 index 0000000000000000000000000000000000000000..8cf830a620070de2c84a7ef559f223ff00f3611d GIT binary patch literal 1929 zcmb_dONbmr81A5kO~RU>NF*ROy(kH$rmG**)7@l@o9WH&NM;>&M|Ojkt*NS>X?CWo z?e5)~T^9_|g9$`MJ!uYJRqzrL0(($$5IsuJvmoSPh%R{Z5dC{zZp`MPI848)zWV;} ze^s5U&Q6c-J+xPnr1A2MHwVuH*)_Hs?$7@ICxOSFXy$YxN&BA6u3gf{7oV1--B*Iz zV!Bv4VeVIB;IsT%2tm^_no2NwXwp(H1c8f}n*M;|NSXJa6Bwa2llbJzzu~L;wBIa^F zXCbPYx?FH_nuQ(RJSyv0E2y}jY6ilZi!Il1s&+b^ zT*t_XxS?u} zCJ30?C6TJ-aOP4E$mj?ct;DUKaYj|%;%y$L31GDmHfoAgBu#M->e2Ka1|YPR%E-o! zTH5WAi6os`1vdr(*%6)8)*`OX@kFe|luxaK%!$mK$SuX3q#~{f(HbVII+QGzO7h`_ zAY`JG9N7lv9!Yso(Xp-}TtEh{Y1qx%F1BC5aL0XUMX{o7kF(^Ay-@hJ0??h#1U9wqX`*2iK`(g6v-Q-B;oO+L5%jvu3Io zFq&Lv#3TgT$YF?cQ%7}Lw-75>mTz!Objq`$?=#H=31oO}&_?t8^}$;!kb9-$5}LI{ zQK4BaaHb4~gB{}WP?iVlJ53Ix_oY zk}q&nw@n`r2NDTMq!4^x^L?n>zM{K@=Ur^L1|F98zZX7WrcDwyIP9&e^50!~xSG7% zl^xsf|8hmmHq?G?ssAjy-rTm$7n0Z;f*n139UUd`F*=NR2vLgRsJZq17cv}EYh`b; zW?#7c;pX_)c+7k6@IL*>#0Sq`8M`t6>D9M?-t+jW&(D9idGZJ8SNX@w-ZMWPcy%j$ z^p<<*jjjDJc^fzX_~zv^Prd)nqP&$~UA}~le*1*~+PUea8{?myH>6$FM^0BSEV0{X t4|cC_ynE*QTfa1~U3~1LOTO5c*?;ZkbIzL!pQPDgS)Q8pzC5vX_AkO)X!rmC literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_new_page.png b/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_new_page.png new file mode 100644 index 0000000000000000000000000000000000000000..6e35218d5bbd9b0e441dd2da11f11c1725394bbf GIT binary patch literal 1902 zcmb_dONbmr7;Xuy$;x8Di+V6^M>4)$#Wp&2v zTXcJqx`A@|8Trrv3xb#xL>|Q5B*%lQGUCPJyKL4Jc?2motIBd2P~K>+$sW&`Y^gS& zx{2h9tLip%k@>WYpkC2nMbixcbqsB6xboyuM6@gj@p|pqNi6YKRXRnHVomG!`)c1% zdDhl+*L5|BG=zXafP9z~WB`(U|CFJ|a+*bH5%EMW8Hvw(MO6_>$0@|=j5f(9WfBF` z1|-#V6_zQDfB~K1(q7gb1rMmkx-4c%kqfLo!=@cx@VvusLp|%hDS#+#vpI{gqn0?H zg~*HgmPlh#kR8!^YnU=^o#nijQC8m)GWVC+q}an&tp!@;I;6I2)`AO*QA zIG{M>SxiK_QB2xQOOv)D&x(jW-sPDHEYunE?G4Xc%Xk=dMMu7V^oZQ3d$#V{HbAOA zlG|+JMv@mKp{!A>Dxx%M6a`pEHlw;>0|!D1T-!8&OQ{c-Zm}S&7|`{}bbO7|UTJ`G z{CF({oC=P=<>|g{I<9X4%b*ZIWLAK0IuuwsvwRyt8&P-4_CgkkqzqFl`IaI%b!vDYSF-AEo;2NPN@iK;?N zFR(zFG)FtskQ<%T-;miABEjr!&`UonZJCb6TJpR=Px{LBs`mWV24;;4D`Gq@^_sh1nI<(6~i z>igd;O7d>c`t8Om7r(!J`PB8#KYk*9ec{s&zpZT+FV(g_xpd(C(jRBfzSBGY?pu$2 zu;*v_ZSbpl<;sN@cRl&T@VmWVUwC8RxoZc{U3=uG$CrO^*H0fu=AUQoKYjH<{3U#D QS9u~f>Z`Rcj+}b)FDtrSZU6uP literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_searching.png b/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_searching.png new file mode 100644 index 0000000000000000000000000000000000000000..7e0b19abdd2037b4c22ff2a270f503de4de6baab GIT binary patch literal 1939 zcmb_dONbmr7@mlUd5~SULJlsN(G z|L_0n`>W1X=1(5n|M31)Ds`|lS6CG7;pE-BM|>Z3o2A>$K%i5pH89YIk_Ik z0alb&tCenL(mbpws%2RUL<&McAVAddW6}nGbZlUuz#>T zC`%3$8$TQP!p(X6=g6o zuxi`{6@qa{OzsMHD0X?+BqCg|Noq_9{F*EclZf-Y!9(F#u*-~&m-6{a$X%}?CZffY zvr?&;*Huf`0ZOY~y5%x1`B6-K%1VWtEK-y9JO^u<5T=Q;fSAw%Sy!XLq_zr>sadv7 zvYMvbgY^YY*Af9F>wC4}a4Ky4O;59sVLJ{2gb@fFqPf7%Y8l{Y%+M?gy0%LP))qof zlp|@3T1{9v2`h%gVnRe2Sq@-KL%^oC4je<*-3)^SQI?3lt0O$;MPi3L{W4l&FZX*5 zPwGks6PlDnPNs<#m?QUxy`A!LFP{7BTXiOk-a#cj?-6(7775u*P2}z_8dPpaJtFIO zCQguMSQdhSWDN#vQ>30)$P_zaQOz)2)pdn#dyH-+p2aYOGjO2Ue^0z`nbwJ4W8!R8 zkt^Bu@0CJG@H7&+sy0zQ|H2u9|Ok z`>MF6UM&@7s^(jty;B Date: Thu, 12 Aug 2021 15:17:42 +0800 Subject: [PATCH 45/58] add loading anima and faild tip for url/filetexture fix theme loading bugs --- .../api/gui/resources/FileTexture.java | 100 ++++++++++-------- .../api/gui/resources/URLTexture.java | 19 ++-- .../api/terminal/app/AbstractApplication.java | 3 - .../api/terminal/os/TerminalOSWidget.java | 8 ++ .../api/terminal/os/TerminalTheme.java | 2 +- 5 files changed, 77 insertions(+), 55 deletions(-) diff --git a/src/main/java/gregtech/api/gui/resources/FileTexture.java b/src/main/java/gregtech/api/gui/resources/FileTexture.java index a178c791ad5..d45ad7e372b 100644 --- a/src/main/java/gregtech/api/gui/resources/FileTexture.java +++ b/src/main/java/gregtech/api/gui/resources/FileTexture.java @@ -1,73 +1,82 @@ package gregtech.api.gui.resources; +import gregtech.api.gui.Widget; import gregtech.api.gui.resources.picturetexture.AnimatedPictureTexture; import gregtech.api.gui.resources.picturetexture.OrdinaryTexture; import gregtech.api.gui.resources.picturetexture.PictureTexture; -import gregtech.api.gui.resources.utils.DownloadThread; import gregtech.api.gui.resources.utils.GifDecoder; import gregtech.api.gui.resources.utils.ImageUtils; import gregtech.api.gui.resources.utils.ProcessedImageData; -import net.minecraftforge.fml.common.FMLCommonHandler; +import net.minecraft.client.Minecraft; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import org.apache.commons.compress.utils.IOUtils; import javax.imageio.ImageIO; -import javax.imageio.ImageReader; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileInputStream; import java.io.IOException; -import java.util.Iterator; public class FileTexture implements IGuiTexture{ public final File file; @SideOnly(Side.CLIENT) private PictureTexture texture; - boolean init; + @SideOnly(Side.CLIENT) + private ProcessedImageData imageData; + private Thread downloadThread; + private boolean failed; public FileTexture(File file) { this.file = file; - if (file == null) { - init = true; - } } @SideOnly(Side.CLIENT) - public boolean loadFile(){ - init = true; - FileInputStream inputStream = null; - try { - inputStream = new FileInputStream(file); - String type = ImageUtils.readType(inputStream); - if (type.equalsIgnoreCase("gif")) { - GifDecoder gif = new GifDecoder(); - inputStream.close(); - inputStream = new FileInputStream(file); - int status = gif.read(inputStream); - if (status == GifDecoder.STATUS_OK) { - texture = new AnimatedPictureTexture(new ProcessedImageData(gif)); - return true; - } else { - return false; - } + public void loadFile(){ + if (imageData != null) { + if (imageData.isAnimated()) { + texture = new AnimatedPictureTexture(imageData); + texture.tick(); } else { - inputStream.close(); - inputStream = new FileInputStream(file); - BufferedImage image = ImageIO.read(inputStream); - if (image != null) { - texture = new OrdinaryTexture(new ProcessedImageData(image)); - return true; - } else { - return false; - } + texture = new OrdinaryTexture(imageData); } - } catch (IOException e) { - e.printStackTrace(); - } finally { - IOUtils.closeQuietly(inputStream); + imageData = null; + downloadThread = null; + } else if (downloadThread == null) { + downloadThread = new Thread(() -> { + FileInputStream inputStream = null; + try { + inputStream = new FileInputStream(file); + String type = ImageUtils.readType(inputStream); + if (type.equalsIgnoreCase("gif")) { + GifDecoder gif = new GifDecoder(); + inputStream.close(); + inputStream = new FileInputStream(file); + int status = gif.read(inputStream); + if (status == GifDecoder.STATUS_OK) { + imageData = new ProcessedImageData(gif); + } else { + failed = true; + } + } else { + inputStream.close(); + inputStream = new FileInputStream(file); + BufferedImage image = ImageIO.read(inputStream); + if (image != null) { + imageData = new ProcessedImageData(image); + } else { + failed = true; + } + } + } catch (IOException e) { + failed = true; + texture = null; + } finally { + IOUtils.closeQuietly(inputStream); + } + }); + downloadThread.start(); } - return false; } @SideOnly(Side.CLIENT) @@ -80,10 +89,17 @@ public void updateTick() { @Override public void draw(double x, double y, int width, int height) { - if(this.texture != null) { + if (texture != null && texture.hasTexture()) { texture.render((float)x, (float)y, width, height, 0, 1, 1, false, false); - } else if (!init){ - loadFile(); + } else { + if (failed || file == null) { + Minecraft.getMinecraft().fontRenderer.drawString(" Load Failed", (int)x, (int)(y + height / 2.0 - 4), 0xffff0000); + } else { + this.loadFile(); + int s = (int) Math.floorMod(System.currentTimeMillis() / 200, 24); + Widget.renderSector((float)(x + width / 2.0), (float)(y + height / 2.0), (float)(Math.min(width, height) / 4.0), + 0xFF94E2C1, 24, s, s + 5); + } } } diff --git a/src/main/java/gregtech/api/gui/resources/URLTexture.java b/src/main/java/gregtech/api/gui/resources/URLTexture.java index 1cb42186db9..94cc92eaa4c 100644 --- a/src/main/java/gregtech/api/gui/resources/URLTexture.java +++ b/src/main/java/gregtech/api/gui/resources/URLTexture.java @@ -1,7 +1,9 @@ package gregtech.api.gui.resources; +import gregtech.api.gui.Widget; import gregtech.api.gui.resources.picturetexture.PictureTexture; import gregtech.api.gui.resources.utils.DownloadThread; +import net.minecraft.client.Minecraft; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; @@ -31,16 +33,16 @@ public void updateTick() { @Override public void draw(double x, double y, int width, int height) { - if (url != null &&!this.url.equals("")) { - if (texture != null && texture.hasTexture()) { - texture.render((float)x, (float)y, width, height, 0, 1, 1, false, false); + if (texture != null && texture.hasTexture()) { + texture.render((float)x, (float)y, width, height, 0, 1, 1, false, false); + } else { + if (failed || url == null || this.url.equals("")) { + Minecraft.getMinecraft().fontRenderer.drawString(" Load Failed", (int)x, (int)(y + height / 2.0 - 4), 0xffff0000); } else { this.loadTexture(); - if (failed) { - - } else { - - } + int s = (int) Math.floorMod(System.currentTimeMillis() / 200, 24); + Widget.renderSector((float)(x + width / 2.0), (float)(y + height / 2.0), (float)(Math.min(width, height) / 4.0), + 0xFF94E2C1, 24, s, s + 5); } } } @@ -50,7 +52,6 @@ public void loadTexture() { if (texture == null && !failed) { if (downloader == null && DownloadThread.activeDownloads < DownloadThread.MAXIMUM_ACTIVE_DOWNLOADS) { PictureTexture loadedTexture = DownloadThread.loadedImages.get(url); - if (loadedTexture == null) { synchronized (DownloadThread.LOCK) { if (!DownloadThread.loadingImages.contains(url)) { diff --git a/src/main/java/gregtech/api/terminal/app/AbstractApplication.java b/src/main/java/gregtech/api/terminal/app/AbstractApplication.java index 4a28e05c8a0..83d5b898dd0 100644 --- a/src/main/java/gregtech/api/terminal/app/AbstractApplication.java +++ b/src/main/java/gregtech/api/terminal/app/AbstractApplication.java @@ -7,10 +7,7 @@ import gregtech.api.util.Position; import gregtech.api.util.Size; import net.minecraft.nbt.NBTTagCompound; -import sun.security.util.ArrayUtil; -import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.List; diff --git a/src/main/java/gregtech/api/terminal/os/TerminalOSWidget.java b/src/main/java/gregtech/api/terminal/os/TerminalOSWidget.java index b995d247bb7..4ecee188593 100644 --- a/src/main/java/gregtech/api/terminal/os/TerminalOSWidget.java +++ b/src/main/java/gregtech/api/terminal/os/TerminalOSWidget.java @@ -156,6 +156,14 @@ protected TerminalDialogWidget closeDialog(TerminalDialogWidget widget) { return widget; } + @Override + public void updateScreen() { + super.updateScreen(); + if( background != null) { + background.updateTick(); + } + } + @Override public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { Position position = getPosition(); diff --git a/src/main/java/gregtech/api/terminal/os/TerminalTheme.java b/src/main/java/gregtech/api/terminal/os/TerminalTheme.java index edd952b696c..fdebd8a4b1c 100644 --- a/src/main/java/gregtech/api/terminal/os/TerminalTheme.java +++ b/src/main/java/gregtech/api/terminal/os/TerminalTheme.java @@ -31,7 +31,7 @@ public class TerminalTheme { static { JsonElement element = FileUtils.loadJson(new File(FILE_PATH)); - if (element == null || element.isJsonObject()) { + if (element == null || !element.isJsonObject()) { saveConfig(); } else { JsonObject config = element.getAsJsonObject(); From 73ffdbbc0874f752e50ac9d5a64fe353a5bd6198 Mon Sep 17 00:00:00 2001 From: Yefancy Date: Thu, 12 Aug 2021 23:45:13 +0800 Subject: [PATCH 46/58] fix SlotWidget --- src/main/java/gregtech/api/GTValues.java | 3 +- .../gregtech/api/gui/impl/ModularUIGui.java | 31 +++------ .../api/gui/widgets/AbstractWidgetGroup.java | 1 - .../gregtech/api/gui/widgets/SlotWidget.java | 62 ++++++++++++++---- .../api/terminal/TerminalBuilder.java | 5 ++ .../widget/GuidePageEditorWidget.java | 1 + .../configurator/ItemStackConfigurator.java | 3 +- .../app/recipegraph/RecipeGraphApp.java | 36 ++++++++++ .../app/recipegraph/widget/RGContainer.java | 27 ++++++++ .../app/recipegraph/widget/RGNode.java | 40 +++++++++++ .../DraggableScrollableWidgetGroup.java | 17 +++-- .../gui/terminal/recipe_graph/icon.png | Bin 0 -> 27259 bytes 12 files changed, 182 insertions(+), 44 deletions(-) create mode 100644 src/main/java/gregtech/api/terminal/app/recipegraph/RecipeGraphApp.java create mode 100644 src/main/java/gregtech/api/terminal/app/recipegraph/widget/RGContainer.java create mode 100644 src/main/java/gregtech/api/terminal/app/recipegraph/widget/RGNode.java create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/recipe_graph/icon.png diff --git a/src/main/java/gregtech/api/GTValues.java b/src/main/java/gregtech/api/GTValues.java index 03749fca777..a45f5fd32df 100644 --- a/src/main/java/gregtech/api/GTValues.java +++ b/src/main/java/gregtech/api/GTValues.java @@ -91,7 +91,8 @@ public class GTValues { MODID_EIO = "enderio", MODID_BC = "buildcraftcore", MODID_COFH = "cofhcore", - MODID_APPENG = "appliedenergistics2"; + MODID_APPENG = "appliedenergistics2", + MODID_JEI = "jei"; //because forge is too fucking retarded to cache results or at least do not create fucking //immutable collections every time you retrieve indexed mod list diff --git a/src/main/java/gregtech/api/gui/impl/ModularUIGui.java b/src/main/java/gregtech/api/gui/impl/ModularUIGui.java index 3e969f3dc41..ed3f213925b 100644 --- a/src/main/java/gregtech/api/gui/impl/ModularUIGui.java +++ b/src/main/java/gregtech/api/gui/impl/ModularUIGui.java @@ -1,11 +1,10 @@ package gregtech.api.gui.impl; import gregtech.api.gui.IRenderContext; -import gregtech.api.gui.IScissored; import gregtech.api.gui.ModularUI; import gregtech.api.gui.Widget; +import gregtech.api.gui.widgets.SlotWidget; import gregtech.api.net.PacketUIWidgetUpdate; -import gregtech.api.util.RenderUtil; import gregtech.common.ConfigHolder; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.inventory.GuiContainer; @@ -21,7 +20,6 @@ import org.lwjgl.input.Keyboard; import org.lwjgl.input.Mouse; -import java.awt.*; import java.io.IOException; public class ModularUIGui extends GuiContainer implements IRenderContext { @@ -94,7 +92,11 @@ public void drawScreen(int mouseX, int mouseY, float partialTicks) { for (int i = 0; i < this.inventorySlots.inventorySlots.size(); ++i) { Slot slot = this.inventorySlots.inventorySlots.get(i); - if (isPointInRegion(slot.xPos, slot.yPos, 16, 16, mouseX, mouseY) && slot.isEnabled()) { + if (slot instanceof SlotWidget.ISlotWidget) { + if (((SlotWidget.ISlotWidget) slot).isHover()) { + setHoveredSlot(slot); + } + } else if (isPointInRegion(slot.xPos, slot.yPos, 16, 16, mouseX, mouseY) && slot.isEnabled()) { renderSlotOverlay(slot); setHoveredSlot(slot); } @@ -127,6 +129,7 @@ public void setHoveredSlot(Slot hoveredSlot) { this.hoveredSlot = hoveredSlot; } + @Deprecated public void drawSlotContents(Slot slot) { GlStateManager.enableDepth(); RenderHelper.enableGUIStandardItemLighting(); @@ -138,6 +141,7 @@ public void drawSlotContents(Slot slot) { GlStateManager.disableLighting(); } + @Deprecated public void renderSlotOverlay(Slot slot) { GlStateManager.disableDepth(); int slotX = slot.xPos; @@ -223,8 +227,6 @@ public void handleMouseInput() throws IOException { } protected void mouseWheelMove(int mouseX, int mouseY, int wheelDelta) { - //noinspection ResultOfMethodCallIgnored -// modularUI.guiWidgets.values().stream().anyMatch(widget -> widget.mouseWheelMove(mouseX, mouseY, wheelDelta)); for (int i = modularUI.guiWidgets.size() - 1; i >= 0; i--) { Widget widget = modularUI.guiWidgets.get(i); if(widget.isVisible() && widget.isActive() && widget.mouseWheelMove(mouseX, mouseY, wheelDelta)) { @@ -235,10 +237,6 @@ protected void mouseWheelMove(int mouseX, int mouseY, int wheelDelta) { @Override protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException { -// boolean result = modularUI.guiWidgets.values().stream().anyMatch(widget -> widget.mouseClicked(mouseX, mouseY, mouseButton)); -// if (!result) { -// super.mouseClicked(mouseX, mouseY, mouseButton); -// } for (int i = modularUI.guiWidgets.size() - 1; i >= 0; i--) { Widget widget = modularUI.guiWidgets.get(i); if(widget.isVisible() && widget.isActive() && widget.mouseClicked(mouseX, mouseY, mouseButton)) { @@ -250,11 +248,6 @@ protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOEx @Override protected void mouseClickMove(int mouseX, int mouseY, int clickedMouseButton, long timeSinceLastClick) { -// boolean result = modularUI.guiWidgets.values().stream().anyMatch(widget -> -// widget.mouseDragged(mouseX, mouseY, clickedMouseButton, timeSinceLastClick)); -// if (!result) { -// super.mouseClickMove(mouseX, mouseY, clickedMouseButton, timeSinceLastClick); -// } for (int i = modularUI.guiWidgets.size() - 1; i >= 0; i--) { Widget widget = modularUI.guiWidgets.get(i); if(widget.isVisible() && widget.isActive() && widget.mouseDragged(mouseX, mouseY, clickedMouseButton, timeSinceLastClick)) { @@ -266,10 +259,6 @@ protected void mouseClickMove(int mouseX, int mouseY, int clickedMouseButton, lo @Override protected void mouseReleased(int mouseX, int mouseY, int state) { -// boolean result = modularUI.guiWidgets.values().stream().anyMatch(widget -> widget.mouseReleased(mouseX, mouseY, state)); -// if (!result) { -// super.mouseReleased(mouseX, mouseY, state); -// } for (int i = modularUI.guiWidgets.size() - 1; i >= 0; i--) { Widget widget = modularUI.guiWidgets.get(i); if(widget.isVisible() && widget.isActive() && widget.mouseReleased(mouseX, mouseY, state)) { @@ -281,10 +270,6 @@ protected void mouseReleased(int mouseX, int mouseY, int state) { @Override protected void keyTyped(char typedChar, int keyCode) throws IOException { -// boolean result = modularUI.guiWidgets.values().stream().anyMatch(widget -> widget.keyTyped(typedChar, keyCode)); -// if (!result) { -// super.keyTyped(typedChar, keyCode); -// } for (int i = modularUI.guiWidgets.size() - 1; i >= 0; i--) { Widget widget = modularUI.guiWidgets.get(i); if(widget.isVisible() && widget.isActive() && widget.keyTyped(typedChar, keyCode)) { diff --git a/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java b/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java index 86be3fec316..269666d0a90 100644 --- a/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java +++ b/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java @@ -94,7 +94,6 @@ public void setVisible(boolean visible) { return; } super.setVisible(visible); - widgets.stream().flatMap(it -> it.getNativeWidgets().stream()).forEach(it -> it.setEnabled(visible)); } protected void addWidget(Widget widget) { diff --git a/src/main/java/gregtech/api/gui/widgets/SlotWidget.java b/src/main/java/gregtech/api/gui/widgets/SlotWidget.java index 35484c053e0..1d72ce11d5a 100644 --- a/src/main/java/gregtech/api/gui/widgets/SlotWidget.java +++ b/src/main/java/gregtech/api/gui/widgets/SlotWidget.java @@ -1,18 +1,14 @@ package gregtech.api.gui.widgets; -import java.awt.Rectangle; - -import javax.annotation.Nonnull; - -import gregtech.api.gui.*; +import gregtech.api.gui.INativeWidget; +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.ISizeProvider; +import gregtech.api.gui.Widget; import gregtech.api.gui.resources.IGuiTexture; -import gregtech.api.gui.resources.ItemStackTexture; -import gregtech.api.gui.resources.TextureArea; import gregtech.api.util.Position; import gregtech.api.util.Size; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.client.renderer.RenderHelper; import net.minecraft.client.renderer.RenderItem; import net.minecraft.entity.player.EntityPlayer; @@ -27,7 +23,6 @@ import net.minecraftforge.items.SlotItemHandler; import javax.annotation.Nonnull; -import java.awt.*; public class SlotWidget extends Widget implements INativeWidget { @@ -90,6 +85,23 @@ public void drawInBackground(int mouseX, int mouseY, IRenderContext context) { } } + @Override + public void drawInForeground(int mouseX, int mouseY) { + if (slotReference instanceof ISlotWidget) { + if (isMouseOverElement(mouseX, mouseY)) { + ((ISlotWidget) slotReference).setHover(true); + GlStateManager.disableDepth(); + GlStateManager.colorMask(true, true, true, false); + drawSolidRect(getPosition().x + 1, getPosition().y + 1, 16, 16, -2130706433); + GlStateManager.colorMask(true, true, true, true); + GlStateManager.enableDepth(); + GlStateManager.enableBlend(); + } else { + ((ISlotWidget) slotReference).setHover(false); + } + } + } + @Override protected void onPositionUpdate() { if (slotReference != null && sizes != null) { @@ -171,11 +183,28 @@ public final Slot getHandle() { return slotReference; } - protected class WidgetSlot extends Slot { + public interface ISlotWidget { + void setHover(boolean isHover); + boolean isHover(); + } + + protected class WidgetSlot extends Slot implements ISlotWidget { + boolean isHover; + public WidgetSlot(IInventory inventory, int index, int xPosition, int yPosition) { super(inventory, index, xPosition, yPosition); } + @Override + public void setHover(boolean isHover) { + this.isHover = isHover; + } + + @Override + public boolean isHover() { + return isHover; + } + @Override public boolean isItemValid(@Nonnull ItemStack stack) { return SlotWidget.this.canPutStack(stack) && super.isItemValid(stack); @@ -212,12 +241,23 @@ public boolean isEnabled() { } - protected class WidgetSlotItemHandler extends SlotItemHandler { + protected class WidgetSlotItemHandler extends SlotItemHandler implements ISlotWidget { + boolean isHover; public WidgetSlotItemHandler(IItemHandler itemHandler, int index, int xPosition, int yPosition) { super(itemHandler, index, xPosition, yPosition); } + @Override + public void setHover(boolean isHover) { + this.isHover = isHover; + } + + @Override + public boolean isHover() { + return isHover; + } + @Override public boolean isItemValid(@Nonnull ItemStack stack) { return SlotWidget.this.canPutStack(stack) && super.isItemValid(stack); diff --git a/src/main/java/gregtech/api/terminal/TerminalBuilder.java b/src/main/java/gregtech/api/terminal/TerminalBuilder.java index 94660e13bdf..42b25dbb232 100644 --- a/src/main/java/gregtech/api/terminal/TerminalBuilder.java +++ b/src/main/java/gregtech/api/terminal/TerminalBuilder.java @@ -1,11 +1,13 @@ package gregtech.api.terminal; +import gregtech.api.GTValues; import gregtech.api.terminal.app.*; import gregtech.api.terminal.app.guide.ItemGuideApp; import gregtech.api.terminal.app.guide.MultiBlockGuideApp; import gregtech.api.terminal.app.guide.SimpleMachineGuideApp; import gregtech.api.terminal.app.guide.TutorialGuideApp; import gregtech.api.terminal.app.guideeditor.GuideEditorApp; +import gregtech.api.terminal.app.recipegraph.RecipeGraphApp; import java.util.ArrayList; import java.util.HashMap; @@ -23,6 +25,9 @@ public static void init() { registerApp(new TutorialGuideApp(), true); registerApp(new GuideEditorApp(), true); registerApp(new ThemeSettingApp(), true); + if (GTValues.isModLoaded(GTValues.MODID_JEI)) { + registerApp(new RecipeGraphApp(), true); + } } public static void registerApp(AbstractApplication application, boolean isDefaultApp) { diff --git a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/GuidePageEditorWidget.java b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/GuidePageEditorWidget.java index 398b21ec0d9..a2c078becb2 100644 --- a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/GuidePageEditorWidget.java +++ b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/GuidePageEditorWidget.java @@ -103,6 +103,7 @@ public void setGuideConfigEditor(GuideConfigEditor configEditor) { private void setToolButton(Widget widget) { customPositionSizeWidget.setControlled(widget); + customPositionSizeWidget.setVisible(true); customPositionSizeWidget.setActive(!(widget instanceof IGuideWidget) || ((IGuideWidget) widget).isFixed()); toolButtons.setVisible(true); toolButtons.setSelfPosition(new Position(widget.getSelfPosition().x + widget.getSize().width / 2, widget.getSelfPosition().y)); diff --git a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/ItemStackConfigurator.java b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/ItemStackConfigurator.java index 3e57b49e634..e20b218cbab 100644 --- a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/ItemStackConfigurator.java +++ b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/ItemStackConfigurator.java @@ -14,6 +14,7 @@ import gregtech.api.terminal.gui.widgets.RectButtonWidget; import gregtech.api.terminal.app.guide.widget.SlotListWidget; import gregtech.api.terminal.os.TerminalTheme; +import gregtech.common.inventory.handlers.SingleItemStackHandler; import net.minecraftforge.items.IItemHandlerModifiable; import net.minecraftforge.items.ItemStackHandler; @@ -53,7 +54,7 @@ protected void init() { private void addSlot(DraggableScrollableWidgetGroup container, SlotListWidget.ItemStackInfo itemStackInfo) { WidgetGroup group = new WidgetGroup(0,slots.size() * 20, 116, 20); slots.add(itemStackInfo); - IItemHandlerModifiable handler = new ItemStackHandler(); + IItemHandlerModifiable handler = new SingleItemStackHandler(1); handler.setStackInSlot(0, itemStackInfo.getInstance()); group.addWidget(new PhantomSlotWidget(handler, 0, 1, 1).setBackgroundTexture(TerminalTheme.COLOR_B_2).setChangeListener(()->{ itemStackInfo.update(handler.getStackInSlot(0)); diff --git a/src/main/java/gregtech/api/terminal/app/recipegraph/RecipeGraphApp.java b/src/main/java/gregtech/api/terminal/app/recipegraph/RecipeGraphApp.java new file mode 100644 index 00000000000..c5d480e4fc8 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/app/recipegraph/RecipeGraphApp.java @@ -0,0 +1,36 @@ +package gregtech.api.terminal.app.recipegraph; + +import gregtech.api.gui.resources.TextureArea; +import gregtech.api.terminal.app.AbstractApplication; +import gregtech.api.terminal.app.recipegraph.widget.RGContainer; +import gregtech.api.terminal.app.recipegraph.widget.RGNode; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.PacketBuffer; + +import java.util.function.Consumer; + +public class RecipeGraphApp extends AbstractApplication { + public static final TextureArea ICON = TextureArea.fullImage("textures/gui/terminal/recipe_graph/icon.png"); + + private RGContainer container; + + public RecipeGraphApp() { + super("Recipe Graph", ICON); + } + + @Override + public AbstractApplication createApp(boolean isClient, NBTTagCompound nbt) { + RecipeGraphApp app = new RecipeGraphApp(); + if (isClient) { + app.container = new RGContainer(0,0,333, 232); + app.addWidget(app.container); + app.container.addWidget(new RGNode(10,10)); + } + return app; + } + + @Override + protected void writeClientAction(int id, Consumer packetBufferWriter) { + + } +} diff --git a/src/main/java/gregtech/api/terminal/app/recipegraph/widget/RGContainer.java b/src/main/java/gregtech/api/terminal/app/recipegraph/widget/RGContainer.java new file mode 100644 index 00000000000..0626c57334a --- /dev/null +++ b/src/main/java/gregtech/api/terminal/app/recipegraph/widget/RGContainer.java @@ -0,0 +1,27 @@ +package gregtech.api.terminal.app.recipegraph.widget; + +import gregtech.api.gui.Widget; +import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; +import gregtech.api.terminal.os.TerminalTheme; + +public class RGContainer extends DraggableScrollableWidgetGroup { + public RGContainer(int x, int y, int width, int height) { + super(x, y, width, height); + this.setDraggable(true); + this.setXScrollBarHeight(4); + this.setYScrollBarWidth(4); + this.setXBarStyle(null, TerminalTheme.COLOR_F_1); + this.setYBarStyle(null, TerminalTheme.COLOR_F_1); + } + + @Override + public boolean mouseWheelMove(int mouseX, int mouseY, int wheelDelta) { + for (int i = widgets.size() - 1; i >= 0; i--) { + Widget widget = widgets.get(i); + if(widget.isVisible() && widget.isActive() && widget.mouseWheelMove(mouseX, mouseY, wheelDelta)) { + return true; + } + } + return false; + } +} diff --git a/src/main/java/gregtech/api/terminal/app/recipegraph/widget/RGNode.java b/src/main/java/gregtech/api/terminal/app/recipegraph/widget/RGNode.java new file mode 100644 index 00000000000..34ccbc08d54 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/app/recipegraph/widget/RGNode.java @@ -0,0 +1,40 @@ +package gregtech.api.terminal.app.recipegraph.widget; + +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.widgets.PhantomSlotWidget; +import gregtech.api.gui.widgets.SimpleTextWidget; +import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.terminal.gui.IDraggable; +import gregtech.api.terminal.os.TerminalTheme; +import gregtech.common.inventory.handlers.SingleItemStackHandler; +import net.minecraftforge.items.IItemHandlerModifiable; + +public class RGNode extends WidgetGroup implements IDraggable { + IItemHandlerModifiable itemHandler = new SingleItemStackHandler(1); + + public RGNode(int x, int y) { + super(x, y, 50, 40); + this.addWidget(new SimpleTextWidget(25, 5, "", -1, () -> itemHandler.getStackInSlot(0).getDisplayName(), true)); + this.addWidget(new PhantomSlotWidget(itemHandler, 0, 0, 20) + .setChangeListener(this::onItemChanged) + .setBackgroundTexture(TerminalTheme.COLOR_B_2)); + } + + private void onItemChanged() { + } + + @Override + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + int x = getPosition().x; + int y = getPosition().y; + int width = getSize().width; + int height = getSize().height; + drawSolidRect(x, y, width, height, TerminalTheme.COLOR_B_1.color); + super.drawInBackground(mouseX, mouseY, partialTicks, context); + } + + @Override + public boolean allowDrag(int mouseX, int mouseY, int button) { + return isMouseOverElement(mouseX, mouseY); + } +} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java b/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java index d5818e6eede..ca45a5e71fe 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java @@ -122,7 +122,7 @@ protected void computeMax() { } int offsetY = 0; int offsetX = 0; - if (mh > getSize().height && mh < maxHeight) { + if (mh > getSize().height) { offsetY = maxHeight - mh; maxHeight = mh; if (scrollYOffset - offsetY < 0) { @@ -137,7 +137,7 @@ protected void computeMax() { } scrollYOffset -= offsetY; } - if (mw > getSize().width && mw < maxWidth) { + if (mw > getSize().width) { offsetX = maxWidth - mw; maxWidth = mw; if (scrollXOffset - offsetX < 0) { @@ -201,7 +201,7 @@ protected void setScrollYOffset(int scrollYOffset) { private boolean isOnXScrollPane(int mouseX, int mouseY) { Position pos = getPosition(); Size size = getSize(); - return isMouseOver(pos.x, pos.y - xBarHeight, size.width, xBarHeight, mouseX, mouseY); + return isMouseOver(pos.x, pos.y + size.height - xBarHeight, size.width, xBarHeight, mouseX, mouseY); } private boolean isOnYScrollPane(int mouseX, int mouseY) { @@ -233,8 +233,8 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender xBarB.draw(x, y - xBarHeight, width, xBarHeight); } if (xBarF != null) { - int barWidth = width / getMaxWidth(); - xBarF.draw(x + scrollXOffset, y - xBarHeight, barWidth, xBarHeight); + int barWidth = (int) (width * 1.0f / getMaxWidth() * width); + xBarF.draw(x + scrollXOffset * width * 1.0f / getMaxWidth(), y + height - xBarHeight, barWidth, xBarHeight); } } if (yBarWidth > 0) { @@ -323,8 +323,11 @@ public boolean mouseDragged(int mouseX, int mouseY, int button, long timeDragged } else if (draggedOnYScrollBar && (getMaxHeight() - getSize().height > 0 || scrollYOffset > getMaxHeight() - getSize().height)) { setScrollYOffset(MathHelper.clamp(scrollYOffset + deltaY * getMaxHeight() / getSize().height, 0, getMaxHeight() - getSize().height)); return true; - } else if (draggedWidget != null && ((IDraggable)draggedWidget).dragging(mouseX, mouseY, deltaX, deltaY)) { - draggedWidget.addSelfPosition(deltaX, deltaY); + } else if (draggedWidget != null) { + if (((IDraggable)draggedWidget).dragging(mouseX, mouseY, deltaX, deltaY)) { + draggedWidget.addSelfPosition(deltaX, deltaY); + } + computeMax(); return true; } else if (draggedPanel) { setScrollXOffset(MathHelper.clamp(scrollXOffset - deltaX, 0, Math.max(getMaxWidth() - yBarWidth - getSize().width, 0))); diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/recipe_graph/icon.png b/src/main/resources/assets/gregtech/textures/gui/terminal/recipe_graph/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..c319617e70986d7469baa7cc05d9587a6ad4bbeb GIT binary patch literal 27259 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 LG(@UG!YJ^60Pb`k literal 0 HcmV?d00001 From c284ae3f5fdd32ac3c490246cab2060907f06031 Mon Sep 17 00:00:00 2001 From: brachy84 Date: Thu, 12 Aug 2021 18:49:31 +0200 Subject: [PATCH 47/58] lots of improvements content is now registered from json --- src/main/java/gregtech/GregTechMod.java | 4 + src/main/java/gregtech/api/GregTechAPI.java | 16 --- .../api/gui/resources/ItemStackTexture.java | 28 +++-- .../gregtech/api/items/metaitem/MetaItem.java | 15 --- .../api/terminal/TerminalBuilder.java | 9 +- .../api/terminal/app/AbstractApplication.java | 14 ++- .../api/terminal/app/guide/GuideApp.java | 74 ++++++++--- .../api/terminal/app/guide/ItemGuideApp.java | 118 +++++++++++------- .../app/guide/MultiBlockGuideApp.java | 65 +++------- .../app/guide/SimpleMachineGuideApp.java | 66 +++------- .../terminal/app/guide/TutorialGuideApp.java | 67 ++-------- .../terminal/gui/widgets/TreeListWidget.java | 12 +- .../terminal/os/TerminalDesktopWidget.java | 2 +- .../api/terminal/os/TerminalOSWidget.java | 6 +- .../api/terminal/util/GuideJsonLoader.java | 37 ++++++ .../java/gregtech/common/CommonProxy.java | 17 +-- .../resources/assets/gregtech/lang/en_us.lang | 8 ++ .../{simplemachines => machines}/default.json | 0 .../tutorials/en_us/api_0_guidepage.json | 2 +- .../guide/tutorials/en_us/api_1_widget.json | 2 +- .../guide/tutorials/en_us/api_2_textbox.json | 2 +- .../guide/tutorials/en_us/api_3_image.json | 2 +- 22 files changed, 287 insertions(+), 279 deletions(-) create mode 100644 src/main/java/gregtech/api/terminal/util/GuideJsonLoader.java rename src/main/resources/assets/gregtech/terminal/guide/{simplemachines => machines}/default.json (100%) diff --git a/src/main/java/gregtech/GregTechMod.java b/src/main/java/gregtech/GregTechMod.java index 93c20d87cfc..893befe55cb 100644 --- a/src/main/java/gregtech/GregTechMod.java +++ b/src/main/java/gregtech/GregTechMod.java @@ -10,6 +10,7 @@ import gregtech.api.model.ResourcePackHook; import gregtech.api.net.NetworkHandler; import gregtech.api.recipes.RecipeMap; +import gregtech.api.terminal.util.GuideJsonLoader; import gregtech.api.unification.OreDictUnifier; import gregtech.api.unification.material.IMaterialHandler; import gregtech.api.unification.material.MaterialRegistry; @@ -36,6 +37,8 @@ import gregtech.common.worldgen.WorldGenRubberTree; import gregtech.integration.theoneprobe.TheOneProbeCompatibility; import gregtech.loaders.dungeon.DungeonLootLoader; +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.SimpleReloadableResourceManager; import net.minecraftforge.classloading.FMLForgePlugin; import net.minecraftforge.fluids.FluidRegistry; import net.minecraftforge.fml.common.FMLCommonHandler; @@ -62,6 +65,7 @@ public class GregTechMod { BlockOreFactory.init(); BlockCompressedFactory.init(); BlockFrameFactory.init(); + ((SimpleReloadableResourceManager)Minecraft.getMinecraft().getResourceManager()).registerReloadListener(new GuideJsonLoader()); } } diff --git a/src/main/java/gregtech/api/GregTechAPI.java b/src/main/java/gregtech/api/GregTechAPI.java index a3031b46495..b79496a2fd1 100644 --- a/src/main/java/gregtech/api/GregTechAPI.java +++ b/src/main/java/gregtech/api/GregTechAPI.java @@ -38,22 +38,6 @@ public class GregTechAPI { public static T registerMetaTileEntity(int id, T sampleMetaTileEntity) { META_TILE_ENTITY_REGISTRY.register(id, sampleMetaTileEntity.metaTileEntityId, sampleMetaTileEntity); - if (sampleMetaTileEntity instanceof MultiblockControllerBase || sampleMetaTileEntity instanceof MetaTileEntityMultiblockPart) { - MultiBlockGuideApp.registerMultiBlock(sampleMetaTileEntity, "default"); - } else { - SimpleMachineGuideApp.registerSimpleMachine(sampleMetaTileEntity, "default"); - } return sampleMetaTileEntity; } - - public static T registerMetaTileEntity(int id, T sampleMetaTileEntity, String section) { - META_TILE_ENTITY_REGISTRY.register(id, sampleMetaTileEntity.metaTileEntityId, sampleMetaTileEntity); - if (sampleMetaTileEntity instanceof MultiblockControllerBase || sampleMetaTileEntity instanceof MetaTileEntityMultiblockPart) { - MultiBlockGuideApp.registerMultiBlock(sampleMetaTileEntity, section); - } else { - SimpleMachineGuideApp.registerSimpleMachine(sampleMetaTileEntity, section); - } - return sampleMetaTileEntity; - } - } diff --git a/src/main/java/gregtech/api/gui/resources/ItemStackTexture.java b/src/main/java/gregtech/api/gui/resources/ItemStackTexture.java index b339ff268ca..429676a3b1d 100644 --- a/src/main/java/gregtech/api/gui/resources/ItemStackTexture.java +++ b/src/main/java/gregtech/api/gui/resources/ItemStackTexture.java @@ -2,21 +2,35 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.client.renderer.RenderHelper; import net.minecraft.client.renderer.RenderItem; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; public class ItemStackTexture implements IGuiTexture{ - private ItemStack itemStack; + private final ItemStack[] itemStack; + private int index = 0; + private int ticks = 0; - public ItemStackTexture(ItemStack itemStack) { - this.itemStack = itemStack; + public ItemStackTexture(ItemStack stack, ItemStack... itemStack) { + this.itemStack = new ItemStack[itemStack.length + 1]; + this.itemStack[0] = stack; + System.arraycopy(itemStack, 0, this.itemStack, 1, itemStack.length); } - public ItemStackTexture(Item item) { - this.itemStack = new ItemStack(item); + public ItemStackTexture(Item item, Item... items) { + this.itemStack = new ItemStack[items.length + 1]; + this.itemStack[0] = new ItemStack(item); + for(int i = 0; i < items.length; i++) { + itemStack[i+1] = new ItemStack(items[i]); + } + } + + @Override + public void updateTick() { + if(itemStack.length > 1 && ++ticks % 20 == 0) + if(++index == itemStack.length) + index = 0; } @Override @@ -26,7 +40,7 @@ public void draw(double x, double y, int width, int height) { GlStateManager.scale(width / 16f, height / 16f, 0.0001); GlStateManager.translate(x * 16 / width, y * 16 / height, 0); RenderItem itemRender = Minecraft.getMinecraft().getRenderItem(); - itemRender.renderItemAndEffectIntoGUI(itemStack, 0, 0); + itemRender.renderItemAndEffectIntoGUI(itemStack[index], 0, 0); GlStateManager.enableAlpha(); GlStateManager.popMatrix(); RenderHelper.disableStandardItemLighting(); diff --git a/src/main/java/gregtech/api/items/metaitem/MetaItem.java b/src/main/java/gregtech/api/items/metaitem/MetaItem.java index cfbd293d99d..24f989f3058 100644 --- a/src/main/java/gregtech/api/items/metaitem/MetaItem.java +++ b/src/main/java/gregtech/api/items/metaitem/MetaItem.java @@ -18,7 +18,6 @@ import gregtech.api.items.gui.PlayerInventoryHolder; import gregtech.api.items.metaitem.stats.*; import gregtech.api.recipes.ingredients.IntCircuitIngredient; -import gregtech.api.terminal.app.guide.ItemGuideApp; import gregtech.api.unification.OreDictUnifier; import gregtech.api.unification.material.Material; import gregtech.api.unification.ore.OrePrefix; @@ -221,20 +220,6 @@ public final T addItem(int metaValue, String unlocalizedName) { } metaItems.put((short) metaValue, metaValueItem); names.put(unlocalizedName, metaValueItem); - ItemGuideApp.registerItem(metaValueItem, "default"); - return metaValueItem; - } - - public final T addItem(int metaValue, String unlocalizedName, String section) { - Validate.inclusiveBetween(0, Short.MAX_VALUE - 1, metaValue + metaItemOffset, "MetaItem ID should be in range from 0 to Short.MAX_VALUE-1"); - T metaValueItem = constructMetaValueItem((short) metaValue, unlocalizedName); - if (metaItems.containsKey((short) metaValue)) { - T registeredItem = metaItems.get((short) metaValue); - throw new IllegalArgumentException(String.format("MetaId %d is already occupied by item %s (requested by item %s)", metaValue, registeredItem.unlocalizedName, unlocalizedName)); - } - metaItems.put((short) metaValue, metaValueItem); - names.put(unlocalizedName, metaValueItem); - ItemGuideApp.registerItem(metaValueItem, section); return metaValueItem; } diff --git a/src/main/java/gregtech/api/terminal/TerminalBuilder.java b/src/main/java/gregtech/api/terminal/TerminalBuilder.java index 42b25dbb232..8ebd79385b8 100644 --- a/src/main/java/gregtech/api/terminal/TerminalBuilder.java +++ b/src/main/java/gregtech/api/terminal/TerminalBuilder.java @@ -9,10 +9,7 @@ import gregtech.api.terminal.app.guideeditor.GuideEditorApp; import gregtech.api.terminal.app.recipegraph.RecipeGraphApp; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; public class TerminalBuilder { private static final Map appRegister = new HashMap<>(); @@ -31,9 +28,9 @@ public static void init() { } public static void registerApp(AbstractApplication application, boolean isDefaultApp) { - appRegister.put(application.getName(), application); + appRegister.put(application.getRegistryName(), application); if (isDefaultApp) { - defaultApps.add(application.getName()); + defaultApps.add(application.getRegistryName()); } } diff --git a/src/main/java/gregtech/api/terminal/app/AbstractApplication.java b/src/main/java/gregtech/api/terminal/app/AbstractApplication.java index 83d5b898dd0..60f67a71684 100644 --- a/src/main/java/gregtech/api/terminal/app/AbstractApplication.java +++ b/src/main/java/gregtech/api/terminal/app/AbstractApplication.java @@ -6,6 +6,8 @@ import gregtech.api.terminal.os.menu.component.IMenuComponent; import gregtech.api.util.Position; import gregtech.api.util.Size; +import net.minecraft.client.resources.I18n; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.nbt.NBTTagCompound; import java.util.Collections; @@ -16,7 +18,7 @@ public abstract class AbstractApplication extends AnimaWidgetGroup { protected final IGuiTexture icon; protected TerminalOSWidget os; - public AbstractApplication (String name, IGuiTexture icon) { + public AbstractApplication(String name, IGuiTexture icon) { super(Position.ORIGIN, new Size(333, 232)); this.name = name; this.icon = icon; @@ -27,10 +29,14 @@ public AbstractApplication setOs(TerminalOSWidget os) { return this; } - public String getName() { + public String getRegistryName() { return name; } + public String getLocalizedName() { + return I18n.format("gregtech.guide_terminal.app_name." + name); + } + public IGuiTexture getIcon() { return icon; } @@ -52,4 +58,8 @@ public TerminalOSWidget getOs() { public List getMenuComponents() { return Collections.emptyList(); } + + public boolean canPlayerUse(EntityPlayer player) { + return true; + } } diff --git a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java index 18f921b79a3..13a1c341d5f 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java @@ -14,17 +14,17 @@ import gregtech.api.terminal.util.TreeNode; import net.minecraft.client.Minecraft; import net.minecraft.client.resources.I18n; +import net.minecraft.client.resources.Language; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.PacketBuffer; import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.common.FMLCommonHandler; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; -import java.util.Arrays; -import java.util.List; -import java.util.Stack; +import java.util.*; import java.util.function.Consumer; import java.util.stream.Collectors; @@ -32,17 +32,23 @@ public abstract class GuideApp extends AbstractApplication implements SearchComponent.IWidgetSearch>> { private GuidePageWidget pageWidget; private TreeListWidget tree; + private TreeNode ROOT; + private Map> jsonObjectMap = new HashMap<>(); public GuideApp(String name, IGuiTexture icon) { super(name, icon); + ROOT = new TreeNode<>(0, "root"); } @Override public AbstractApplication createApp(boolean isClient, NBTTagCompound nbt) { try { GuideApp app = this.getClass().newInstance(); + app.jsonObjectMap = jsonObjectMap; + app.ROOT = ROOT; if (isClient && getTree() != null) { app.tree = new TreeListWidget<>(0, 0, 133, 232, getTree(), app::loadPage).setContentIconSupplier(this::itemIcon) .setContentNameSupplier(this::itemName) + .setKeyNameSupplier(key -> I18n.format("gregtech.guide_terminal.app." + getRegistryName() + "." + key)) .setNodeTexture(GuiTextures.BORDERED_BACKGROUND) .setLeafTexture(GuiTextures.SLOT_DARKENED); app.addWidget(app.tree); @@ -63,7 +69,11 @@ protected void loadPage(TreeNode leaf) { } this.pageWidget = new GuidePageWidget(133, 0, 200, 232, 5); if (leaf.isLeaf() && leaf.getContent() != null) { - JsonObject page = getPage(leaf.getContent()); + Language currentLanguage = Minecraft.getMinecraft().getLanguageManager().getCurrentLanguage(); + Map langMap = jsonObjectMap.get(leaf.getContent()); + JsonObject page = langMap.get(currentLanguage.getLanguageCode().toLowerCase() + "_" + currentLanguage.getJavaLocale().getCountry().toLowerCase()); + if(page == null) + page = langMap.get("en_us"); if (page != null) { this.pageWidget.loadJsonConfig(page); } @@ -79,13 +89,32 @@ protected IGuiTexture itemIcon(T item) { return null; } - protected String itemName(T item) { - return null; + /** + * Should return a localised representation of the item + * @param item item + * @return localised name + */ + protected abstract String itemName(T item); + + protected abstract String rawItemName(T item); + + protected final TreeNode getTree() { + return ROOT; } - protected abstract JsonObject getPage(T item); + public final void loadJsonFile(JsonObject json, String lang) { + T t = ofJson(json); + if(t != null) { + Map langMap = jsonObjectMap.get(t); + if(langMap == null) + langMap = new HashMap<>(); + langMap.put(lang, json); + jsonObjectMap.put(t, langMap); + registerItem(t, json.get("section").getAsString()); + } + } - protected abstract TreeNode getTree(); + protected abstract T ofJson(JsonObject json); public static JsonObject getConfig(String fileName) { try { @@ -140,6 +169,17 @@ private boolean dfsSearch(Thread thread, Stack> stack, Strin return false; } + protected void registerItem(T item, String path) { + if (FMLCommonHandler.instance().getSide().isClient()) { + String[] parts = path.split("/"); + TreeNode child = ROOT; + for(String sub : parts) { + child = child.getOrCreateChild(sub); + } + child.addContent(rawItemName(item), item); + } + } + @Override public void selectResult(Stack> result) { if (result.size() > 0 && tree != null) { @@ -151,13 +191,17 @@ public void selectResult(Stack> result) { @Override public String resultDisplay(Stack> result) { - return result.stream().map(node->{ - String name = node.getContent() != null ? itemName(node.getContent()) : null; - if (name == null) { - name = node.getKey(); - } - return I18n.format(name); - }).collect(Collectors.joining("->")); + Iterator> iterator = result.iterator(); + if(!iterator.hasNext()) return ""; + iterator.next(); // skip root + StringBuilder builder = new StringBuilder(); + while (iterator.hasNext()) { + TreeNode node = iterator.next(); + builder.append(node.getContent() == null ? I18n.format("gregtech.guide_terminal.app." + getRegistryName() + "." + node.getKey()) : itemName(node.getContent())); + if(iterator.hasNext()) + builder.append(" / "); + } + return builder.toString(); } @Override diff --git a/src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java index 901524ab46a..1966aa793f0 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java @@ -1,72 +1,98 @@ package gregtech.api.terminal.app.guide; +import com.google.gson.JsonElement; import com.google.gson.JsonObject; import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.resources.ItemStackTexture; import gregtech.api.items.metaitem.MetaItem; -import gregtech.api.metatileentity.MetaTileEntity; -import gregtech.api.terminal.util.TreeNode; import gregtech.common.items.MetaItems; -import net.minecraft.client.Minecraft; -import net.minecraft.client.resources.Language; -import net.minecraft.util.Tuple; -import net.minecraftforge.fml.common.FMLCommonHandler; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; -import java.util.HashMap; -import java.util.Map; +import java.util.Objects; -public class ItemGuideApp extends GuideApp.MetaValueItem> { - private static TreeNode.MetaValueItem> ROOT; - private static Map.MetaValueItem, JsonObject> MAP; - private static Language language; - - private static JsonObject DEFAULT; - static { - if (FMLCommonHandler.instance().getSide().isClient()) { - ROOT = new TreeNode<>(0,"root"); - DEFAULT = getConfig("terminal/guide/items/default.json"); - MAP = new HashMap<>(); - } - } +public class ItemGuideApp extends GuideApp { public ItemGuideApp() { - super("Items", new ItemStackTexture(MetaItems.SCANNER.getStackForm())); + super("items", new ItemStackTexture(MetaItems.SCANNER.getStackForm())); } @Override - protected IGuiTexture itemIcon(MetaItem.MetaValueItem item) { - return new ItemStackTexture(item.getStackForm()); + protected String itemName(GuideItem item) { + return item.stack.getDisplayName(); } @Override - protected JsonObject getPage(MetaItem.MetaValueItem item) { - Language currentLanguage = Minecraft.getMinecraft().getLanguageManager().getCurrentLanguage(); - if (!currentLanguage.equals(language)) { - language = currentLanguage; - MAP.clear(); - } - if (!MAP.containsKey(item)) { - JsonObject config = getConfig("terminal/guide/items/" + currentLanguage.getLanguageCode() + "/" + item.unlocalizedName + ".json"); - if (config == null && !currentLanguage.getLanguageCode().equals("en_us")) { - config = getConfig("terminal/guide/items/" + "en_us/" + item.unlocalizedName + ".json"); - } - MAP.put(item, config); - } - if (MAP.get(item) == null) { - DEFAULT.addProperty("title", "Missing: §4" + item.unlocalizedName + ".json"); - return DEFAULT; + protected String rawItemName(GuideItem item) { + if (item.stack.getItem() instanceof MetaItem) { + return ((MetaItem) item.stack.getItem()).getItem((short) item.stack.getMetadata()).unlocalizedName; } - return MAP.get(item); + return item.stack.getTranslationKey(); } @Override - protected TreeNode.MetaValueItem> getTree() { - return ROOT; + protected IGuiTexture itemIcon(GuideItem item) { + return new ItemStackTexture(item.stack); } - public static void registerItem(MetaItem.MetaValueItem item, String section) { - if (FMLCommonHandler.instance().getSide().isClient()) { - ROOT.getOrCreateChild(section).addContent(String.format("metaitem.%s.name", item.unlocalizedName), item); + @Override + protected GuideItem ofJson(JsonObject json) { + return GuideItem.ofJson(json); + } + + public static class GuideItem { + private final ItemStack stack; + private final String name; + + public GuideItem(ItemStack stack, String name) { + this.stack = stack; + this.name = name; + } + + public GuideItem(ItemStack stack) { + this(stack, stack.getItem().getRegistryName().toString() + ":" + stack.getMetadata()); + } + + public GuideItem(MetaItem.MetaValueItem item) { + this(item.getStackForm(), item.unlocalizedName); + } + + public static GuideItem ofJson(JsonObject json) { + if (json.has("item")) { + JsonElement element = json.get("item"); + if (element.isJsonPrimitive()) { + String[] s = json.getAsString().split(":"); + if (s.length < 2) return null; + Item item = Item.getByNameOrId(s[0] + ":" + s[1]); + if (item == null) return null; + int meta = 0; + if (s.length > 2) + meta = Integer.parseInt(s[2]); + return new GuideItem(new ItemStack(item, 1, meta)); + } + } + if (json.has("metaitem")) { + String metaItemId = json.get("metaitem").getAsString(); + for (MetaItem metaItem : MetaItem.getMetaItems()) { + MetaItem.MetaValueItem metaValueItem = metaItem.getAllItems().stream().filter(m -> m.unlocalizedName.equals(metaItemId)).findFirst().orElse(null); + if (metaValueItem != null) return new GuideItem(metaValueItem); + ; + } + } + return null; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + GuideItem guideItem = (GuideItem) o; + return Objects.equals(stack, guideItem.stack) && Objects.equals(name, guideItem.name); + } + + @Override + public int hashCode() { + return Objects.hash(stack, name); } } } diff --git a/src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java index 599fcbc8848..bc942a6fd97 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java @@ -1,40 +1,31 @@ package gregtech.api.terminal.app.guide; +import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import gregtech.api.GregTechAPI; import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.resources.ItemStackTexture; import gregtech.api.metatileentity.MetaTileEntity; -import gregtech.api.terminal.util.TreeNode; import gregtech.common.metatileentities.MetaTileEntities; -import net.minecraft.client.Minecraft; -import net.minecraft.client.resources.Language; -import net.minecraft.util.Tuple; -import net.minecraftforge.fml.common.FMLCommonHandler; - -import java.util.HashMap; -import java.util.Map; +import net.minecraft.util.ResourceLocation; public class MultiBlockGuideApp extends GuideApp { - private static TreeNode ROOT; - private static Map MAP; - private static Language language; - - private static JsonObject DEFAULT; - static { - if (FMLCommonHandler.instance().getSide().isClient()) { - ROOT = new TreeNode<>(0, "root"); - DEFAULT = getConfig("terminal/guide/multiblocks/default.json"); - MAP = new HashMap<>(); - } - } public MultiBlockGuideApp() { - super("Multi-Block Machines", new ItemStackTexture(MetaTileEntities.ELECTRIC_BLAST_FURNACE.getStackForm())); + super("multiblocks", new ItemStackTexture(MetaTileEntities.ELECTRIC_BLAST_FURNACE.getStackForm())); } @Override - protected TreeNode getTree() { - return ROOT; + protected MetaTileEntity ofJson(JsonObject json) { + String[] valids = {"multiblock", "metatileentity"}; + if (json.isJsonObject()) { + for (String valid : valids) { + JsonElement id = json.getAsJsonObject().get(valid); + if (id != null && id.isJsonPrimitive()) + return GregTechAPI.META_TILE_ENTITY_REGISTRY.getObject(new ResourceLocation(id.getAsString())); + } + } + return null; } @Override @@ -43,30 +34,12 @@ protected IGuiTexture itemIcon(MetaTileEntity item) { } @Override - protected JsonObject getPage(MetaTileEntity mte) { - Language currentLanguage = Minecraft.getMinecraft().getLanguageManager().getCurrentLanguage(); - if (!currentLanguage.equals(language)) { - language = currentLanguage; - MAP.clear(); - } - if (!MAP.containsKey(mte)) { - JsonObject config = getConfig("terminal/guide/multiblocks/" + currentLanguage.getLanguageCode() + "/" + mte.metaTileEntityId.getPath() + ".json"); - if (config == null && !currentLanguage.getLanguageCode().equals("en_us")) { - config = getConfig("terminal/guide/multiblocks/" + "en_us/" + mte.metaTileEntityId.getPath() + ".json"); - } - MAP.put(mte, config); - } - if (MAP.get(mte) == null) { - DEFAULT.addProperty("title", "Missing: §4" + mte.metaTileEntityId.getPath() + ".json"); - return DEFAULT; - } - return MAP.get(mte); + protected String itemName(MetaTileEntity item) { + return item.getStackForm().getDisplayName(); } - public static void registerMultiBlock(MetaTileEntity mte, String section) { - if (FMLCommonHandler.instance().getSide().isClient()) { - ROOT.getOrCreateChild(section).addContent(mte.getMetaFullName(), mte); - } + @Override + protected String rawItemName(MetaTileEntity item) { + return item.metaTileEntityId.getPath(); } - } diff --git a/src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java index c72f24f7542..b584b5c4a73 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java @@ -1,71 +1,45 @@ package gregtech.api.terminal.app.guide; +import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import gregtech.api.GregTechAPI; import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.resources.ItemStackTexture; import gregtech.api.metatileentity.MetaTileEntity; -import gregtech.api.terminal.util.TreeNode; import gregtech.common.metatileentities.MetaTileEntities; -import net.minecraft.client.Minecraft; -import net.minecraft.client.resources.Language; -import net.minecraft.util.Tuple; -import net.minecraftforge.fml.common.FMLCommonHandler; - -import java.util.HashMap; -import java.util.Map; +import net.minecraft.util.ResourceLocation; public class SimpleMachineGuideApp extends GuideApp { - private static TreeNode ROOT; - private static Map MAP; - private static Language language; - - private static JsonObject DEFAULT; - static { - if (FMLCommonHandler.instance().getSide().isClient()) { - ROOT = new TreeNode<>(0,"root"); - DEFAULT = getConfig("terminal/guide/simplemachines/default.json"); - MAP = new HashMap<>(); - } - } public SimpleMachineGuideApp() { - super("Simple Machines", new ItemStackTexture(MetaTileEntities.CHEMICAL_REACTOR[0].getStackForm())); + super("machines", new ItemStackTexture(MetaTileEntities.CHEMICAL_REACTOR[0].getStackForm())); } @Override - protected TreeNode getTree() { - return ROOT; + protected IGuiTexture itemIcon(MetaTileEntity item) { + return new ItemStackTexture(item.getStackForm()); } @Override - protected IGuiTexture itemIcon(MetaTileEntity item) { - return new ItemStackTexture(item.getStackForm()); + protected String itemName(MetaTileEntity item) { + return item.getStackForm().getDisplayName(); } @Override - protected JsonObject getPage(MetaTileEntity mte) { - Language currentLanguage = Minecraft.getMinecraft().getLanguageManager().getCurrentLanguage(); - if (!currentLanguage.equals(language)) { - language = currentLanguage; - MAP.clear(); - } - if (!MAP.containsKey(mte)) { - JsonObject config = getConfig("terminal/guide/simplemachines/" + currentLanguage.getLanguageCode() + "/" + mte.metaTileEntityId.getPath() + ".json"); - if (config == null && !currentLanguage.getLanguageCode().equals("en_us")) { - config = getConfig("terminal/guide/simplemachines/" + "en_us/" + mte.metaTileEntityId.getPath() + ".json"); - } - MAP.put(mte, config); - } - if (MAP.get(mte) == null) { - DEFAULT.addProperty("title", "Missing: §4" + mte.metaTileEntityId.getPath() + ".json"); - return DEFAULT; - } - return MAP.get(mte); + protected String rawItemName(MetaTileEntity item) { + return item.metaTileEntityId.getPath(); } - public static void registerSimpleMachine(MetaTileEntity mte, String section) { - if (FMLCommonHandler.instance().getSide().isClient()) { - ROOT.getOrCreateChild(section).addContent(mte.getMetaFullName(), mte); + @Override + protected MetaTileEntity ofJson(JsonObject json) { + String[] valids = {"machine", "generator", "metatileentity"}; + if (json.isJsonObject()) { + for (String valid : valids) { + JsonElement id = json.getAsJsonObject().get(valid); + if (id != null && id.isJsonPrimitive()) + return GregTechAPI.META_TILE_ENTITY_REGISTRY.getObject(new ResourceLocation(id.getAsString())); + } } + return null; } } diff --git a/src/main/java/gregtech/api/terminal/app/guide/TutorialGuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/TutorialGuideApp.java index da723eb8f9d..82f07ba1f1b 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/TutorialGuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/TutorialGuideApp.java @@ -1,73 +1,30 @@ package gregtech.api.terminal.app.guide; import com.google.gson.JsonObject; -import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.resources.ItemStackTexture; -import gregtech.api.metatileentity.MetaTileEntity; -import gregtech.api.terminal.util.TreeNode; -import net.minecraft.client.Minecraft; -import net.minecraft.client.resources.Language; +import net.minecraft.client.resources.I18n; import net.minecraft.init.Items; -import net.minecraft.util.Tuple; -import net.minecraftforge.fml.common.FMLCommonHandler; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.net.URL; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; public class TutorialGuideApp extends GuideApp { - private static TreeNode ROOT; - private static Map MAP; - private static Language language; - static { - if (FMLCommonHandler.instance().getSide().isClient()) { - ROOT = new TreeNode<>(0,"root"); - MAP = new HashMap<>(); - try { - URL folder = ClassLoader.getSystemClassLoader().getResource("assets/gregtech/terminal/guide/tutorials/en_us"); - if (folder != null) { - new BufferedReader(new InputStreamReader(folder.openStream())).lines().forEach(file->{ - JsonObject config = getConfig("terminal/guide/tutorials/en_us/" + file); - if (config != null) { - ROOT.getOrCreateChild(config.get("section").getAsString()).addContent(config.get("title").getAsString(), file); - MAP.put(file, config); - } - }); - } - } catch (IOException e) { - e.printStackTrace(); - } - } + public TutorialGuideApp() { + super("tutorials", new ItemStackTexture(Items.PAPER)); } - public TutorialGuideApp() { - super("Tutorials", new ItemStackTexture(Items.PAPER)); + @Override + protected String itemName(String item) { + return I18n.format(item); } @Override - protected JsonObject getPage(String file) { - Language currentLanguage = Minecraft.getMinecraft().getLanguageManager().getCurrentLanguage(); - if (!currentLanguage.equals(language)) { - language = currentLanguage; - MAP.clear(); - } - if (!MAP.containsKey(file)) { - JsonObject config = getConfig("terminal/guide/tutorials/" + currentLanguage.getLanguageCode() + "/" + file); - if (config == null && !currentLanguage.getLanguageCode().equals("en_us")) { - config = getConfig("terminal/guide/tutorials/" + "en_us/" + file); - } - MAP.put(file, config); - } - return MAP.get(file); + protected String rawItemName(String item) { + return item; } @Override - protected TreeNode getTree() { - return ROOT; + protected String ofJson(JsonObject json) { + if (json.has("tutorial")) + return json.get("tutorial").getAsString(); + return json.get("title").getAsString(); } } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/TreeListWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/TreeListWidget.java index 4cae842735d..2303c7f6d0a 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/TreeListWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/TreeListWidget.java @@ -215,9 +215,7 @@ public boolean mouseClicked(int mouseX, int mouseY, int button) { onSelected.accept(node); } } else if (node.getChildren().size() > 0 && list.contains(node.getChildren().get(0))){ - for (TreeNode child : node.getChildren()) { - list.remove(child); - } + removeNode(node); } else { for (int i = 0; i < node.getChildren().size(); i++) { list.add(index + 1 + i, node.getChildren().get(i)); @@ -230,4 +228,12 @@ public boolean mouseClicked(int mouseX, int mouseY, int button) { } return false; } + + private void removeNode(TreeNode node) { + if(node.isLeaf()) return; + for (TreeNode child : node.getChildren()) { + list.remove(child); + removeNode(child); + } + } } diff --git a/src/main/java/gregtech/api/terminal/os/TerminalDesktopWidget.java b/src/main/java/gregtech/api/terminal/os/TerminalDesktopWidget.java index 41118ea9127..be620147597 100644 --- a/src/main/java/gregtech/api/terminal/os/TerminalDesktopWidget.java +++ b/src/main/java/gregtech/api/terminal/os/TerminalDesktopWidget.java @@ -29,7 +29,7 @@ public void installApplication(AbstractApplication application){ new Color(105, 224, 216).getRGB(), new Color(206, 206, 206).getRGB()) .setIcon(application.getIcon()) - .setHoverText(application.getName()); + .setHoverText(application.getLocalizedName()); button.setClickListener(clickData -> { os.openApplication(application, clickData.isClient); }); diff --git a/src/main/java/gregtech/api/terminal/os/TerminalOSWidget.java b/src/main/java/gregtech/api/terminal/os/TerminalOSWidget.java index 4ecee188593..c580e4937ce 100644 --- a/src/main/java/gregtech/api/terminal/os/TerminalOSWidget.java +++ b/src/main/java/gregtech/api/terminal/os/TerminalOSWidget.java @@ -70,7 +70,7 @@ public void openApplication(AbstractApplication application, boolean isClient) { return; } } - AbstractApplication app = application.createApp(isClient, tabletNBT.getCompoundTag(application.getName())).setOs(this); + AbstractApplication app = application.createApp(isClient, tabletNBT.getCompoundTag(application.getRegistryName())).setOs(this); if (app != null) { openedApps.add(app); desktop.addWidget(app); @@ -109,9 +109,9 @@ public void minimizeApplication(AbstractApplication application, boolean isClien public void closeApplication(AbstractApplication application, boolean isClient) { if (application != null) { - NBTTagCompound nbt = application.closeApp(isClient, tabletNBT.getCompoundTag(application.getName())); + NBTTagCompound nbt = application.closeApp(isClient, tabletNBT.getCompoundTag(application.getRegistryName())); if (nbt != null) { - tabletNBT.setTag(application.getName(), nbt); + tabletNBT.setTag(application.getRegistryName(), nbt); } if (isClient) { application.minimizeWidget(desktop::waitToRemoved); diff --git a/src/main/java/gregtech/api/terminal/util/GuideJsonLoader.java b/src/main/java/gregtech/api/terminal/util/GuideJsonLoader.java new file mode 100644 index 00000000000..acfe9cb81c4 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/util/GuideJsonLoader.java @@ -0,0 +1,37 @@ +package gregtech.api.terminal.util; + +import com.google.gson.JsonObject; +import gregtech.api.terminal.TerminalBuilder; +import gregtech.api.terminal.app.guide.GuideApp; +import net.minecraft.client.resources.IResourceManager; +import net.minecraft.client.resources.IResourceManagerReloadListener; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.common.crafting.CraftingHelper; +import net.minecraftforge.fml.common.Loader; + +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.List; + +public class GuideJsonLoader implements IResourceManagerReloadListener { + + @Override + public void onResourceManagerReload(IResourceManager manager) { + if(Loader.instance().activeModContainer() == null) return; + List files = new ArrayList<>(); + CraftingHelper.findFiles(Loader.instance().activeModContainer(), "assets/gregtech/terminal/guide", Files::exists, (path, file) -> { + if(file.toString().endsWith(".json")) { + files.add(new ResourceLocation("gregtech", file.toString().split("assets/gregtech/")[1])); + } + return true; + }, false, true); + + files.forEach(rl -> { + JsonObject json = GuideApp.getConfig(rl.getPath()); + GuideApp app = (GuideApp) TerminalBuilder.getApplication(rl.getPath().split("/")[2]); + if(json != null && app != null) { + app.loadJsonFile(json, rl.getPath().split("/")[3].toLowerCase()); + } + }); + } +} diff --git a/src/main/java/gregtech/common/CommonProxy.java b/src/main/java/gregtech/common/CommonProxy.java index 32304fc9db4..36a0105abd3 100644 --- a/src/main/java/gregtech/common/CommonProxy.java +++ b/src/main/java/gregtech/common/CommonProxy.java @@ -1,9 +1,5 @@ package gregtech.common; -import com.google.gson.Gson; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import forestry.core.config.Constants; import gregtech.api.GTValues; import gregtech.api.block.machines.MachineItemBlock; import gregtech.api.enchants.EnchantmentEnderDamage; @@ -11,10 +7,11 @@ import gregtech.api.recipes.crafttweaker.MetaItemBracketHandler; import gregtech.api.recipes.recipeproperties.BlastTemperatureProperty; import gregtech.api.recipes.recipeproperties.FusionEUToStartProperty; +import gregtech.api.terminal.TerminalBuilder; +import gregtech.api.terminal.util.GuideJsonLoader; import gregtech.api.unification.material.Material; import gregtech.api.unification.material.properties.DustProperty; import gregtech.api.unification.material.properties.PropertyKey; -import gregtech.api.terminal.TerminalBuilder; import gregtech.api.unification.ore.OrePrefix; import gregtech.api.util.GTLog; import gregtech.common.blocks.*; @@ -36,14 +33,12 @@ import gregtech.loaders.recipe.*; import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; -import net.minecraft.client.Minecraft; import net.minecraft.enchantment.Enchantment; import net.minecraft.item.Item; import net.minecraft.item.ItemBlock; import net.minecraft.item.ItemMultiTexture; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.IRecipe; -import net.minecraft.util.ResourceLocation; import net.minecraftforge.common.config.Config.Type; import net.minecraftforge.common.config.ConfigManager; import net.minecraftforge.event.RegistryEvent; @@ -54,14 +49,7 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.registries.IForgeRegistry; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.URL; -import java.util.Enumeration; import java.util.function.Function; -import java.util.stream.Collectors; import static gregtech.common.blocks.MetaBlocks.*; @@ -285,5 +273,6 @@ public void onLoad() { public void onPostLoad() { WoodMachineRecipes.postInit(); TerminalBuilder.init(); + new GuideJsonLoader().onResourceManagerReload(null); } } diff --git a/src/main/resources/assets/gregtech/lang/en_us.lang b/src/main/resources/assets/gregtech/lang/en_us.lang index 3178ad0ea71..c64eb7f563f 100644 --- a/src/main/resources/assets/gregtech/lang/en_us.lang +++ b/src/main/resources/assets/gregtech/lang/en_us.lang @@ -3627,3 +3627,11 @@ gregtech.cover.fluid_detector.message_fluid_storage_inverted=Monitoring Inverted gregtech.cover.item_detector.message_item_storage_normal=Monitoring Normal Item Storage gregtech.cover.item_detector.message_item_storage_inverted=Monitoring Inverted Item Storage + +gregtech.guide_terminal.app_name.items=Item Guides +gregtech.guide_terminal.app_name.machines=Machine Guides +gregtech.guide_terminal.app_name.multiblocks=Multiblock Guides +gregtech.guide_terminal.app_name.tutorials=Tutorials + +gregtech.guide_terminal.app.items.tools=Tools +gregtech.guide_terminal.app.items.covers=Covers diff --git a/src/main/resources/assets/gregtech/terminal/guide/simplemachines/default.json b/src/main/resources/assets/gregtech/terminal/guide/machines/default.json similarity index 100% rename from src/main/resources/assets/gregtech/terminal/guide/simplemachines/default.json rename to src/main/resources/assets/gregtech/terminal/guide/machines/default.json diff --git a/src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_0_guidepage.json b/src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_0_guidepage.json index cc671653f25..d1152b62b5c 100644 --- a/src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_0_guidepage.json +++ b/src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_0_guidepage.json @@ -1,5 +1,5 @@ { - "section": "Guide Widget API", + "section": "guide_widget_api", "title": "Guide Page", "stream": [ { diff --git a/src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_1_widget.json b/src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_1_widget.json index 6ff3a760930..f6e568a0ca5 100644 --- a/src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_1_widget.json +++ b/src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_1_widget.json @@ -1,5 +1,5 @@ { - "section": "Guide Widget API", + "section": "guide_widget_api", "title": "Guide Widget", "stream": [ { diff --git a/src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_2_textbox.json b/src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_2_textbox.json index 416286361a7..15cf932947b 100644 --- a/src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_2_textbox.json +++ b/src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_2_textbox.json @@ -1,5 +1,5 @@ { - "section": "Guide Widget API", + "section": "guide_widget_api", "title": "1. TextBox Widget", "stream": [ { diff --git a/src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_3_image.json b/src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_3_image.json index 0305b73fa87..a4038795115 100644 --- a/src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_3_image.json +++ b/src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_3_image.json @@ -1,5 +1,5 @@ { - "section": "Guide Widget API", + "section": "guide_widget_api", "title": "2. Image Widget", "stream": [ { From c887e399fadd0d28e28f449bd79d77cf281af06f Mon Sep 17 00:00:00 2001 From: brachy84 Date: Thu, 12 Aug 2021 18:50:43 +0200 Subject: [PATCH 48/58] wrench example --- .../terminal/guide/items/en_us/test.json | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 src/main/resources/assets/gregtech/terminal/guide/items/en_us/test.json diff --git a/src/main/resources/assets/gregtech/terminal/guide/items/en_us/test.json b/src/main/resources/assets/gregtech/terminal/guide/items/en_us/test.json new file mode 100644 index 00000000000..0b3b81abafa --- /dev/null +++ b/src/main/resources/assets/gregtech/terminal/guide/items/en_us/test.json @@ -0,0 +1,33 @@ +{ + "metaitem": "tool.wrench", + "section": "items/tools", + "title": "Wrench", + "stream": [ + { + "type": "textbox", + "isCenter": false, + "content": [ + "Wrench this, wrench that" + ] + }, + { + "type": "textbox", + "isCenter": true, + "fontSize": 5, + "content": [ + "§nMinecraft Formatting", + "§r§00 §11 §22 §33", + "§44 §55 §66 §77", + "§88 §99 §aa §bb", + "§cc §dd §ee §ff", + "§r§0k §kMinecraft", + "§rl §lMinecraft", + "§rm §mMinecraft", + "§rn §nMinecraft", + "§ro §oMinecraft", + "§rr §rMinecraft" + ] + } + ], + "fixed": [] +} From 8f5c5fba91a6469b2f59314b108f2f92c24f736b Mon Sep 17 00:00:00 2001 From: brachy84 Date: Thu, 12 Aug 2021 19:51:04 +0200 Subject: [PATCH 49/58] fix loading on other os --- src/main/java/gregtech/api/terminal/util/GuideJsonLoader.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/gregtech/api/terminal/util/GuideJsonLoader.java b/src/main/java/gregtech/api/terminal/util/GuideJsonLoader.java index acfe9cb81c4..40997f29185 100644 --- a/src/main/java/gregtech/api/terminal/util/GuideJsonLoader.java +++ b/src/main/java/gregtech/api/terminal/util/GuideJsonLoader.java @@ -21,7 +21,8 @@ public void onResourceManagerReload(IResourceManager manager) { List files = new ArrayList<>(); CraftingHelper.findFiles(Loader.instance().activeModContainer(), "assets/gregtech/terminal/guide", Files::exists, (path, file) -> { if(file.toString().endsWith(".json")) { - files.add(new ResourceLocation("gregtech", file.toString().split("assets/gregtech/")[1])); + String f = file.toString().replaceAll("\\\\", "/"); + files.add(new ResourceLocation("gregtech", f.split("assets/gregtech/")[1])); } return true; }, false, true); From 8fb08a063a7d2e5825acb3ed46d037292e4cc502 Mon Sep 17 00:00:00 2001 From: Yefancy Date: Fri, 13 Aug 2021 01:56:08 +0800 Subject: [PATCH 50/58] fix crash in server --- .../java/gregtech/api/terminal/app/AbstractApplication.java | 5 +++-- .../java/gregtech/api/terminal/os/TerminalDesktopWidget.java | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/gregtech/api/terminal/app/AbstractApplication.java b/src/main/java/gregtech/api/terminal/app/AbstractApplication.java index 60f67a71684..48988b7da6d 100644 --- a/src/main/java/gregtech/api/terminal/app/AbstractApplication.java +++ b/src/main/java/gregtech/api/terminal/app/AbstractApplication.java @@ -8,6 +8,7 @@ import gregtech.api.util.Size; import net.minecraft.client.resources.I18n; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Items; import net.minecraft.nbt.NBTTagCompound; import java.util.Collections; @@ -33,8 +34,8 @@ public String getRegistryName() { return name; } - public String getLocalizedName() { - return I18n.format("gregtech.guide_terminal.app_name." + name); + public String getUnlocalizedName() { + return "gregtech.guide_terminal.app_name." + name; } public IGuiTexture getIcon() { diff --git a/src/main/java/gregtech/api/terminal/os/TerminalDesktopWidget.java b/src/main/java/gregtech/api/terminal/os/TerminalDesktopWidget.java index be620147597..cf4c8c9db01 100644 --- a/src/main/java/gregtech/api/terminal/os/TerminalDesktopWidget.java +++ b/src/main/java/gregtech/api/terminal/os/TerminalDesktopWidget.java @@ -29,7 +29,7 @@ public void installApplication(AbstractApplication application){ new Color(105, 224, 216).getRGB(), new Color(206, 206, 206).getRGB()) .setIcon(application.getIcon()) - .setHoverText(application.getLocalizedName()); + .setHoverText(application.getUnlocalizedName()); button.setClickListener(clickData -> { os.openApplication(application, clickData.isClient); }); From 0992ac47c2097e42af1101abc21940ab340c1ecf Mon Sep 17 00:00:00 2001 From: Yefancy Date: Fri, 13 Aug 2021 15:20:44 +0800 Subject: [PATCH 51/58] json loader, lang file --- .../api/terminal/TerminalBuilder.java | 5 +++ .../api/terminal/app/AbstractApplication.java | 2 +- .../api/terminal/app/ThemeSettingApp.java | 2 +- .../api/terminal/app/guide/GuideApp.java | 39 ++++++++--------- .../app/guideeditor/GuideEditorApp.java | 2 +- .../app/recipegraph/RecipeGraphApp.java | 2 +- .../terminal/os/TerminalDesktopWidget.java | 8 ++-- .../api/terminal/util/GuideJsonLoader.java | 40 +++++++++++------- .../java/gregtech/common/items/MetaItem1.java | 2 +- .../java/gregtech/common/items/MetaItems.java | 2 +- ...lBehaviour.java => TerminalBehaviour.java} | 2 +- .../resources/assets/gregtech/lang/en_us.lang | 18 ++++---- .../models/item/metaitems/guide_terminal.json | 6 --- .../models/item/metaitems/terminal.json | 6 +++ .../terminal/guide/items/en_us/test.json | 2 +- .../items/{default.json => zh_cn/test.json} | 9 ++-- .../terminal/guide/machines/default.json | 34 --------------- .../terminal/guide/multiblocks/default.json | 24 ----------- ...l.guide_terminal.png => tool.terminal.png} | Bin 19 files changed, 79 insertions(+), 126 deletions(-) rename src/main/java/gregtech/common/items/behaviors/{GuideTerminalBehaviour.java => TerminalBehaviour.java} (96%) delete mode 100644 src/main/resources/assets/gregtech/models/item/metaitems/guide_terminal.json create mode 100644 src/main/resources/assets/gregtech/models/item/metaitems/terminal.json rename src/main/resources/assets/gregtech/terminal/guide/items/{default.json => zh_cn/test.json} (64%) delete mode 100644 src/main/resources/assets/gregtech/terminal/guide/machines/default.json delete mode 100644 src/main/resources/assets/gregtech/terminal/guide/multiblocks/default.json rename src/main/resources/assets/gregtech/textures/items/metaitems/{tool.guide_terminal.png => tool.terminal.png} (100%) diff --git a/src/main/java/gregtech/api/terminal/TerminalBuilder.java b/src/main/java/gregtech/api/terminal/TerminalBuilder.java index 8ebd79385b8..1023d590a7a 100644 --- a/src/main/java/gregtech/api/terminal/TerminalBuilder.java +++ b/src/main/java/gregtech/api/terminal/TerminalBuilder.java @@ -10,6 +10,7 @@ import gregtech.api.terminal.app.recipegraph.RecipeGraphApp; import java.util.*; +import java.util.stream.Collectors; public class TerminalBuilder { private static final Map appRegister = new HashMap<>(); @@ -38,6 +39,10 @@ public static List getDefaultApps() { return defaultApps; } + public static List getAllApps() { + return new ArrayList<>(appRegister.keySet()); + } + public static AbstractApplication getApplication(String name) { return appRegister.get(name); } diff --git a/src/main/java/gregtech/api/terminal/app/AbstractApplication.java b/src/main/java/gregtech/api/terminal/app/AbstractApplication.java index 48988b7da6d..9de3df698a2 100644 --- a/src/main/java/gregtech/api/terminal/app/AbstractApplication.java +++ b/src/main/java/gregtech/api/terminal/app/AbstractApplication.java @@ -35,7 +35,7 @@ public String getRegistryName() { } public String getUnlocalizedName() { - return "gregtech.guide_terminal.app_name." + name; + return "gregtech.terminal.app_name." + name; } public IGuiTexture getIcon() { diff --git a/src/main/java/gregtech/api/terminal/app/ThemeSettingApp.java b/src/main/java/gregtech/api/terminal/app/ThemeSettingApp.java index ac7daceb6fc..76ff43966e5 100644 --- a/src/main/java/gregtech/api/terminal/app/ThemeSettingApp.java +++ b/src/main/java/gregtech/api/terminal/app/ThemeSettingApp.java @@ -23,7 +23,7 @@ public class ThemeSettingApp extends AbstractApplication { public ThemeSettingApp() { - super("Theme Setting", GuiTextures.GREGTECH_LOGO); + super("theme_settings", GuiTextures.GREGTECH_LOGO); } private WidgetGroup textureGroup; diff --git a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java index 13a1c341d5f..40bafc8205c 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java @@ -33,22 +33,23 @@ public abstract class GuideApp extends AbstractApplication implements private GuidePageWidget pageWidget; private TreeListWidget tree; private TreeNode ROOT; - private Map> jsonObjectMap = new HashMap<>(); + private Map jsonObjectMap; public GuideApp(String name, IGuiTexture icon) { super(name, icon); ROOT = new TreeNode<>(0, "root"); + jsonObjectMap = new HashMap<>(); } @Override public AbstractApplication createApp(boolean isClient, NBTTagCompound nbt) { try { GuideApp app = this.getClass().newInstance(); - app.jsonObjectMap = jsonObjectMap; app.ROOT = ROOT; + app.jsonObjectMap = jsonObjectMap; if (isClient && getTree() != null) { app.tree = new TreeListWidget<>(0, 0, 133, 232, getTree(), app::loadPage).setContentIconSupplier(this::itemIcon) .setContentNameSupplier(this::itemName) - .setKeyNameSupplier(key -> I18n.format("gregtech.guide_terminal.app." + getRegistryName() + "." + key)) + .setKeyNameSupplier(key -> key) .setNodeTexture(GuiTextures.BORDERED_BACKGROUND) .setLeafTexture(GuiTextures.SLOT_DARKENED); app.addWidget(app.tree); @@ -69,11 +70,7 @@ protected void loadPage(TreeNode leaf) { } this.pageWidget = new GuidePageWidget(133, 0, 200, 232, 5); if (leaf.isLeaf() && leaf.getContent() != null) { - Language currentLanguage = Minecraft.getMinecraft().getLanguageManager().getCurrentLanguage(); - Map langMap = jsonObjectMap.get(leaf.getContent()); - JsonObject page = langMap.get(currentLanguage.getLanguageCode().toLowerCase() + "_" + currentLanguage.getJavaLocale().getCountry().toLowerCase()); - if(page == null) - page = langMap.get("en_us"); + JsonObject page = jsonObjectMap.get(leaf.getContent()); if (page != null) { this.pageWidget.loadJsonConfig(page); } @@ -102,23 +99,23 @@ protected final TreeNode getTree() { return ROOT; } - public final void loadJsonFile(JsonObject json, String lang) { - T t = ofJson(json); - if(t != null) { - Map langMap = jsonObjectMap.get(t); - if(langMap == null) - langMap = new HashMap<>(); - langMap.put(lang, json); - jsonObjectMap.put(t, langMap); - registerItem(t, json.get("section").getAsString()); + public final void loadJsonFiles(List jsons) { + ROOT = new TreeNode<>(0, "root"); + jsonObjectMap = new HashMap<>(); + for (JsonObject json : jsons) { + T t = ofJson(json); + if(t != null) { + registerItem(t, json.get("section").getAsString()); + jsonObjectMap.put(t, json); + } } } protected abstract T ofJson(JsonObject json); - public static JsonObject getConfig(String fileName) { + public JsonObject getConfig(String fileName, String lang) { try { - InputStream inputStream = Minecraft.getMinecraft().getResourceManager().getResource(new ResourceLocation(GTValues.MODID, fileName)).getInputStream(); + InputStream inputStream = Minecraft.getMinecraft().getResourceManager().getResource(new ResourceLocation(GTValues.MODID, "terminal/guide/" + getRegistryName() + "/" + lang + "/" + fileName)).getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); JsonElement je = new Gson().fromJson(reader, JsonElement.class); reader.close(); @@ -197,7 +194,7 @@ public String resultDisplay(Stack> result) { StringBuilder builder = new StringBuilder(); while (iterator.hasNext()) { TreeNode node = iterator.next(); - builder.append(node.getContent() == null ? I18n.format("gregtech.guide_terminal.app." + getRegistryName() + "." + node.getKey()) : itemName(node.getContent())); + builder.append(node.getContent() == null ? node.getKey() : itemName(node.getContent())); if(iterator.hasNext()) builder.append(" / "); } @@ -206,6 +203,6 @@ public String resultDisplay(Stack> result) { @Override public List getMenuComponents() { - return Arrays.asList(new SearchComponent<>(this)); + return Collections.singletonList(new SearchComponent<>(this)); } } diff --git a/src/main/java/gregtech/api/terminal/app/guideeditor/GuideEditorApp.java b/src/main/java/gregtech/api/terminal/app/guideeditor/GuideEditorApp.java index 04d78eecd43..b637da3bba7 100644 --- a/src/main/java/gregtech/api/terminal/app/guideeditor/GuideEditorApp.java +++ b/src/main/java/gregtech/api/terminal/app/guideeditor/GuideEditorApp.java @@ -23,7 +23,7 @@ public class GuideEditorApp extends AbstractApplication { public GuideEditorApp() { - super("Guide Editor", ICON); + super("guide_editor", ICON); } @Override diff --git a/src/main/java/gregtech/api/terminal/app/recipegraph/RecipeGraphApp.java b/src/main/java/gregtech/api/terminal/app/recipegraph/RecipeGraphApp.java index c5d480e4fc8..ad830274fc8 100644 --- a/src/main/java/gregtech/api/terminal/app/recipegraph/RecipeGraphApp.java +++ b/src/main/java/gregtech/api/terminal/app/recipegraph/RecipeGraphApp.java @@ -15,7 +15,7 @@ public class RecipeGraphApp extends AbstractApplication { private RGContainer container; public RecipeGraphApp() { - super("Recipe Graph", ICON); + super("recipe_graph", ICON); } @Override diff --git a/src/main/java/gregtech/api/terminal/os/TerminalDesktopWidget.java b/src/main/java/gregtech/api/terminal/os/TerminalDesktopWidget.java index cf4c8c9db01..2858b5b2fe0 100644 --- a/src/main/java/gregtech/api/terminal/os/TerminalDesktopWidget.java +++ b/src/main/java/gregtech/api/terminal/os/TerminalDesktopWidget.java @@ -25,14 +25,12 @@ public void installApplication(AbstractApplication application){ int x = this.getSize().width / 2 + (3 * r) * (index - 3); int y = (index / 7) * (3 * r) + 40; CircleButtonWidget button = new CircleButtonWidget(x,y) - .setColors(new Color(146, 146, 146, 126).getRGB(), - new Color(105, 224, 216).getRGB(), + .setColors(TerminalTheme.COLOR_B_1.getColor(), + TerminalTheme.COLOR_F_1.getColor(), new Color(206, 206, 206).getRGB()) .setIcon(application.getIcon()) .setHoverText(application.getUnlocalizedName()); - button.setClickListener(clickData -> { - os.openApplication(application, clickData.isClient); - }); + button.setClickListener(clickData -> os.openApplication(application, clickData.isClient)); appDiv.addWidget(button); } diff --git a/src/main/java/gregtech/api/terminal/util/GuideJsonLoader.java b/src/main/java/gregtech/api/terminal/util/GuideJsonLoader.java index 40997f29185..89326758ed9 100644 --- a/src/main/java/gregtech/api/terminal/util/GuideJsonLoader.java +++ b/src/main/java/gregtech/api/terminal/util/GuideJsonLoader.java @@ -3,11 +3,13 @@ import com.google.gson.JsonObject; import gregtech.api.terminal.TerminalBuilder; import gregtech.api.terminal.app.guide.GuideApp; +import net.minecraft.client.Minecraft; import net.minecraft.client.resources.IResourceManager; import net.minecraft.client.resources.IResourceManagerReloadListener; -import net.minecraft.util.ResourceLocation; +import net.minecraft.client.resources.LanguageManager; import net.minecraftforge.common.crafting.CraftingHelper; import net.minecraftforge.fml.common.Loader; +import net.minecraftforge.fml.common.ObfuscationReflectionHelper; import java.nio.file.Files; import java.util.ArrayList; @@ -18,21 +20,29 @@ public class GuideJsonLoader implements IResourceManagerReloadListener { @Override public void onResourceManagerReload(IResourceManager manager) { if(Loader.instance().activeModContainer() == null) return; - List files = new ArrayList<>(); - CraftingHelper.findFiles(Loader.instance().activeModContainer(), "assets/gregtech/terminal/guide", Files::exists, (path, file) -> { - if(file.toString().endsWith(".json")) { - String f = file.toString().replaceAll("\\\\", "/"); - files.add(new ResourceLocation("gregtech", f.split("assets/gregtech/")[1])); + if (Minecraft.getMinecraft().getLanguageManager().getCurrentLanguage() == null) return; + String lang = Minecraft.getMinecraft().getLanguageManager().getCurrentLanguage().getLanguageCode(); + for (String appName : TerminalBuilder.getAllApps()) { + if (TerminalBuilder.getApplication(appName) instanceof GuideApp) { + List jsons = new ArrayList<>(); + GuideApp app = (GuideApp) TerminalBuilder.getApplication(appName); + CraftingHelper.findFiles(Loader.instance().activeModContainer(), "assets/gregtech/terminal/guide/" + appName + "/en_us", Files::exists, (path, file) -> { + if(file.toString().endsWith(".json")) { + String fileName = file.getFileName().toString(); + JsonObject json = app.getConfig(fileName, lang); + if (json == null) { + json = app.getConfig(fileName, "en_us"); + } + if (json != null) { + jsons.add(json); + } + } + return true; + },false, true); + app.loadJsonFiles(jsons); } - return true; - }, false, true); + } + - files.forEach(rl -> { - JsonObject json = GuideApp.getConfig(rl.getPath()); - GuideApp app = (GuideApp) TerminalBuilder.getApplication(rl.getPath().split("/")[2]); - if(json != null && app != null) { - app.loadJsonFile(json, rl.getPath().split("/")[3].toLowerCase()); - } - }); } } diff --git a/src/main/java/gregtech/common/items/MetaItem1.java b/src/main/java/gregtech/common/items/MetaItem1.java index c91e9d94116..503aa214a8c 100644 --- a/src/main/java/gregtech/common/items/MetaItem1.java +++ b/src/main/java/gregtech/common/items/MetaItem1.java @@ -374,7 +374,7 @@ public void registerSubItems() { ENERGY_FIELD_PROJECTOR = addItem(464, "energy_field_projector").addComponents(ElectricStats.createElectricItem(16000000L, GTValues.EV)).setMaxStackSize(1); SCANNER = addItem(465, "scanner").addComponents(ElectricStats.createElectricItem(200_000L, GTValues.LV), new ScannerBehavior(50)); /* CLIPBOARD GOES HERE - ID 466 */ - GUIDE_TERMINAL = addItem(467, "guide_terminal").addComponents(new GuideTerminalBehaviour()); + TERMINAL = addItem(467, "terminal").addComponents(new TerminalBehaviour()); // Misc Crafting Items: ID 491-515 ENERGIUM_DUST = addItem(491, "energium_dust"); diff --git a/src/main/java/gregtech/common/items/MetaItems.java b/src/main/java/gregtech/common/items/MetaItems.java index 17f3a0f7aa0..83404d74dab 100644 --- a/src/main/java/gregtech/common/items/MetaItems.java +++ b/src/main/java/gregtech/common/items/MetaItems.java @@ -414,7 +414,7 @@ private MetaItems() { public static MetaItem.MetaValueItem NANO_SABER; public static MetaItem.MetaValueItem ENERGY_FIELD_PROJECTOR; public static MetaItem.MetaValueItem SCANNER; - public static MetaItem.MetaValueItem GUIDE_TERMINAL; + public static MetaItem.MetaValueItem TERMINAL; public static final MetaItem.MetaValueItem[] DYE_ONLY_ITEMS = new MetaItem.MetaValueItem[EnumDyeColor.values().length]; public static final MetaItem.MetaValueItem[] SPRAY_CAN_DYES = new MetaItem.MetaValueItem[EnumDyeColor.values().length]; diff --git a/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java b/src/main/java/gregtech/common/items/behaviors/TerminalBehaviour.java similarity index 96% rename from src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java rename to src/main/java/gregtech/common/items/behaviors/TerminalBehaviour.java index 7b3e0b49e39..758a00fb521 100644 --- a/src/main/java/gregtech/common/items/behaviors/GuideTerminalBehaviour.java +++ b/src/main/java/gregtech/common/items/behaviors/TerminalBehaviour.java @@ -20,7 +20,7 @@ import java.awt.*; import java.util.List; -public class GuideTerminalBehaviour implements IItemBehaviour, ItemUIFactory { +public class TerminalBehaviour implements IItemBehaviour, ItemUIFactory { @Override public ActionResult onItemRightClick(World world, EntityPlayer player, EnumHand hand) { diff --git a/src/main/resources/assets/gregtech/lang/en_us.lang b/src/main/resources/assets/gregtech/lang/en_us.lang index c64eb7f563f..001249491f7 100644 --- a/src/main/resources/assets/gregtech/lang/en_us.lang +++ b/src/main/resources/assets/gregtech/lang/en_us.lang @@ -1960,8 +1960,8 @@ behavior.scanner.analyzing_failed=Analyzing failed! behavior.scanner.analyzing_complete=Analyzing complete! behavior.scanner.not_enough_energy=Analyzing failed: Not Enough Energy! -metaitem.guide_terminal.name=Guide Terminal -metaitem.guide_terminal.tooltip=Hope it will help you +metaitem.terminal.name=Terminal +metaitem.terminal.tooltip=Hope it will help you tile.casing.ulv=ULV Machine Casing tile.casing.lv=LV Machine Casing @@ -3628,10 +3628,12 @@ gregtech.cover.fluid_detector.message_fluid_storage_inverted=Monitoring Inverted gregtech.cover.item_detector.message_item_storage_normal=Monitoring Normal Item Storage gregtech.cover.item_detector.message_item_storage_inverted=Monitoring Inverted Item Storage -gregtech.guide_terminal.app_name.items=Item Guides -gregtech.guide_terminal.app_name.machines=Machine Guides -gregtech.guide_terminal.app_name.multiblocks=Multiblock Guides -gregtech.guide_terminal.app_name.tutorials=Tutorials +gregtech.terminal.app_name.items=Item Guides +gregtech.terminal.app_name.machines=Machine Guides +gregtech.terminal.app_name.multiblocks=Multiblock Guides +gregtech.terminal.app_name.tutorials=Tutorials +gregtech.terminal.app_name.theme_settings=Theme Settings +gregtech.terminal.app_name.guide_editor=Guide Editor +gregtech.terminal.app_name.recipe_graph=Recipe Graph -gregtech.guide_terminal.app.items.tools=Tools -gregtech.guide_terminal.app.items.covers=Covers +gregtech.terminal.guide.tutorials.guide_widget_api=Guide Widget Api diff --git a/src/main/resources/assets/gregtech/models/item/metaitems/guide_terminal.json b/src/main/resources/assets/gregtech/models/item/metaitems/guide_terminal.json deleted file mode 100644 index ddeac5c5ad4..00000000000 --- a/src/main/resources/assets/gregtech/models/item/metaitems/guide_terminal.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "item/generated", - "textures": { - "layer0": "gregtech:items/metaitems/tool.guide_terminal" - } -} diff --git a/src/main/resources/assets/gregtech/models/item/metaitems/terminal.json b/src/main/resources/assets/gregtech/models/item/metaitems/terminal.json new file mode 100644 index 00000000000..e79e3e6866a --- /dev/null +++ b/src/main/resources/assets/gregtech/models/item/metaitems/terminal.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "gregtech:items/metaitems/tool.terminal" + } +} diff --git a/src/main/resources/assets/gregtech/terminal/guide/items/en_us/test.json b/src/main/resources/assets/gregtech/terminal/guide/items/en_us/test.json index 0b3b81abafa..9f26d707b45 100644 --- a/src/main/resources/assets/gregtech/terminal/guide/items/en_us/test.json +++ b/src/main/resources/assets/gregtech/terminal/guide/items/en_us/test.json @@ -1,6 +1,6 @@ { "metaitem": "tool.wrench", - "section": "items/tools", + "section": "Items/Tools", "title": "Wrench", "stream": [ { diff --git a/src/main/resources/assets/gregtech/terminal/guide/items/default.json b/src/main/resources/assets/gregtech/terminal/guide/items/zh_cn/test.json similarity index 64% rename from src/main/resources/assets/gregtech/terminal/guide/items/default.json rename to src/main/resources/assets/gregtech/terminal/guide/items/zh_cn/test.json index 460662d7376..dcd7cbf459d 100644 --- a/src/main/resources/assets/gregtech/terminal/guide/items/default.json +++ b/src/main/resources/assets/gregtech/terminal/guide/items/zh_cn/test.json @@ -1,14 +1,13 @@ { - "section": "default", - "title": "Json Tutorial", + "metaitem": "tool.wrench", + "section": "物品/工具", + "title": "Wrench", "stream": [ { "type": "textbox", "isCenter": false, "content": [ - "If you see this page, §4unfortunately§r, this item lacks a Guide Page.", - "Let's start the tutorial.Rest assured, this is not difficult, you can easily customize the Guide Page with JSON. We look forward to your contributions.", - "------------" + "扳扳这,扳扳那" ] }, { diff --git a/src/main/resources/assets/gregtech/terminal/guide/machines/default.json b/src/main/resources/assets/gregtech/terminal/guide/machines/default.json deleted file mode 100644 index 460662d7376..00000000000 --- a/src/main/resources/assets/gregtech/terminal/guide/machines/default.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "section": "default", - "title": "Json Tutorial", - "stream": [ - { - "type": "textbox", - "isCenter": false, - "content": [ - "If you see this page, §4unfortunately§r, this item lacks a Guide Page.", - "Let's start the tutorial.Rest assured, this is not difficult, you can easily customize the Guide Page with JSON. We look forward to your contributions.", - "------------" - ] - }, - { - "type": "textbox", - "isCenter": true, - "fontSize": 5, - "content": [ - "§nMinecraft Formatting", - "§r§00 §11 §22 §33", - "§44 §55 §66 §77", - "§88 §99 §aa §bb", - "§cc §dd §ee §ff", - "§r§0k §kMinecraft", - "§rl §lMinecraft", - "§rm §mMinecraft", - "§rn §nMinecraft", - "§ro §oMinecraft", - "§rr §rMinecraft" - ] - } - ], - "fixed": [] -} diff --git a/src/main/resources/assets/gregtech/terminal/guide/multiblocks/default.json b/src/main/resources/assets/gregtech/terminal/guide/multiblocks/default.json deleted file mode 100644 index 8e1f44a4c3c..00000000000 --- a/src/main/resources/assets/gregtech/terminal/guide/multiblocks/default.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "section": "default", - "title": "Missing Guide", - "stream": [ - { - "type": "textbox", - "isCenter": false, - "content": [ - "If you see this page, §4unfortunately§r, this item lacks a Guide Page.", - "You can learn it from the APP §lTutorial§r. Don't worry, it is not difficult, you can easily customize the Guide Page with JSON. We look forward to your contributions.", - "-------------------------------" - ] - }, - { - "type": "textbox", - "isCenter": false, - "content": [ - "§c§lNote§r: Configuration files should in §n\"assets/gregtech/terminal/guide/multiblocks\"§r", - "Please name the file with the registered name of a machine to help the system automatically match the machines." - ] - } - ], - "fixed": [] -} diff --git a/src/main/resources/assets/gregtech/textures/items/metaitems/tool.guide_terminal.png b/src/main/resources/assets/gregtech/textures/items/metaitems/tool.terminal.png similarity index 100% rename from src/main/resources/assets/gregtech/textures/items/metaitems/tool.guide_terminal.png rename to src/main/resources/assets/gregtech/textures/items/metaitems/tool.terminal.png From d40e9beb381ce2f0380c3e2ae1a04aef75b86368 Mon Sep 17 00:00:00 2001 From: Yefancy Date: Mon, 16 Aug 2021 00:38:35 +0800 Subject: [PATCH 52/58] icons recipe chart demo --- .../java/gregtech/api/gui/GuiTextures.java | 21 +- src/main/java/gregtech/api/gui/ModularUI.java | 1 + src/main/java/gregtech/api/gui/Widget.java | 96 +++- .../api/gui/impl/ModularUIGuiHandler.java | 6 +- .../IRecipeTransferHandlerWidget.java | 3 +- .../api/gui/resources/FileTexture.java | 2 +- .../api/gui/resources/URLTexture.java | 2 +- .../api/gui/widgets/AbstractWidgetGroup.java | 27 +- .../api/gui/widgets/PhantomFluidWidget.java | 16 + .../api/gui/widgets/SimpleTextWidget.java | 10 +- .../gregtech/api/gui/widgets/TabGroup.java | 8 +- .../gregtech/api/gui/widgets/TankWidget.java | 26 ++ .../api/terminal/TerminalBuilder.java | 5 +- .../api/terminal/app/AbstractApplication.java | 2 +- .../api/terminal/app/ThemeSettingApp.java | 3 +- .../api/terminal/app/guide/GuideApp.java | 3 +- .../app/guideeditor/GuideEditorApp.java | 14 +- .../guideeditor/widget/GuideConfigEditor.java | 4 +- .../widget/GuidePageEditorWidget.java | 7 +- .../configurator/FluidStackConfigurator.java | 3 +- .../configurator/ItemStackConfigurator.java | 4 +- .../app/recipechart/RecipeChartApp.java | 84 ++++ .../app/recipechart/widget/PhantomWidget.java | 88 ++++ .../app/recipechart/widget/RGContainer.java | 188 ++++++++ .../app/recipechart/widget/RGLine.java | 191 ++++++++ .../app/recipechart/widget/RGNode.java | 441 ++++++++++++++++++ .../app/recipegraph/RecipeGraphApp.java | 36 -- .../app/recipegraph/widget/RGContainer.java | 27 -- .../app/recipegraph/widget/RGNode.java | 40 -- .../gui/widgets/CircleButtonWidget.java | 9 +- .../DraggableScrollableWidgetGroup.java | 4 +- .../terminal/os/TerminalDesktopWidget.java | 4 +- .../api/terminal/os/TerminalDialogWidget.java | 19 +- .../api/terminal/os/TerminalOSWidget.java | 5 +- .../terminal/os/menu/TerminalMenuWidget.java | 6 +- .../os/menu/component/SearchComponent.java | 2 +- .../common/gui/widget/CraftingSlotWidget.java | 6 +- .../items/behaviors/TerminalBehaviour.java | 16 +- .../gregtech/integration/jei/GTJeiPlugin.java | 9 +- .../jei/recipe/GTRecipeWrapper.java | 4 + .../resources/assets/gregtech/lang/en_us.lang | 2 +- .../icon/Communicate/calendar_hover.png | Bin 0 -> 846 bytes .../icon/Communicate/calendar_normal.png | Bin 0 -> 1382 bytes .../icon/Communicate/clock1_hover.png | Bin 0 -> 917 bytes .../icon/Communicate/clock1_normal.png | Bin 0 -> 1774 bytes .../icon/Communicate/clock2_hover.png | Bin 0 -> 712 bytes .../icon/Communicate/clock2_normal.png | Bin 0 -> 1114 bytes .../icon/Communicate/gmail-copy_hover.png | Bin 0 -> 817 bytes .../icon/Communicate/gmail-copy_normal.png | Bin 0 -> 1393 bytes .../icon/Communicate/gmail2-copy_hover.png | Bin 0 -> 860 bytes .../icon/Communicate/gmail2-copy_normal.png | Bin 0 -> 1427 bytes .../icon/Communicate/kontakts_hover.png | Bin 0 -> 778 bytes .../icon/Communicate/kontakts_normal.png | Bin 0 -> 1236 bytes .../terminal/icon/Communicate/mail1_hover.png | Bin 0 -> 838 bytes .../icon/Communicate/mail1_normal.png | Bin 0 -> 1429 bytes .../terminal/icon/Communicate/mail2_hover.png | Bin 0 -> 760 bytes .../icon/Communicate/mail2_normal.png | Bin 0 -> 1230 bytes .../icon/Communicate/mail_open_hover.png | Bin 0 -> 867 bytes .../icon/Communicate/mail_open_normal.png | Bin 0 -> 1398 bytes .../icon/Communicate/mail_sent_hover.png | Bin 0 -> 884 bytes .../icon/Communicate/mail_sent_normal.png | Bin 0 -> 1526 bytes .../terminal/icon/Communicate/msg2_hover.png | Bin 0 -> 840 bytes .../terminal/icon/Communicate/msg2_normal.png | Bin 0 -> 1376 bytes .../terminal/icon/Communicate/msg3_hover.png | Bin 0 -> 893 bytes .../terminal/icon/Communicate/msg3_normal.png | Bin 0 -> 1487 bytes .../terminal/icon/Communicate/msg_hover.png | Bin 0 -> 784 bytes .../terminal/icon/Communicate/msg_normal.png | Bin 0 -> 1211 bytes .../terminal/icon/Communicate/note1_hover.png | Bin 0 -> 899 bytes .../icon/Communicate/note1_normal.png | Bin 0 -> 1471 bytes .../terminal/icon/Communicate/note2_hover.png | Bin 0 -> 920 bytes .../icon/Communicate/note2_normal.png | Bin 0 -> 1552 bytes .../terminal/icon/Communicate/pen_hover.png | Bin 0 -> 759 bytes .../terminal/icon/Communicate/pen_normal.png | Bin 0 -> 1262 bytes .../terminal/icon/Communicate/phone_hover.png | Bin 0 -> 824 bytes .../icon/Communicate/phone_normal.png | Bin 0 -> 1350 bytes .../icon/Communicate/profiles_hover.png | Bin 0 -> 812 bytes .../icon/Communicate/profiles_normal.png | Bin 0 -> 1317 bytes .../terminal/icon/Communicate/skype_hover.png | Bin 0 -> 943 bytes .../icon/Communicate/skype_normal.png | Bin 0 -> 1616 bytes .../terminal/icon/Communicate/tasks_hover.png | Bin 0 -> 870 bytes .../icon/Communicate/tasks_normal.png | Bin 0 -> 1427 bytes .../icon/Communicate/voicemail-12_hover.png | Bin 0 -> 822 bytes .../icon/Communicate/voicemail-12_normal.png | Bin 0 -> 1403 bytes .../icon/Communicate/voicemaill_hover.png | Bin 0 -> 816 bytes .../icon/Communicate/voicemaill_normal.png | Bin 0 -> 1358 bytes .../gui/terminal/icon/Media/Camera_hover.png | Bin 0 -> 855 bytes .../gui/terminal/icon/Media/Camera_normal.png | Bin 0 -> 1390 bytes .../icon/Media/Champions_League_hover.png | Bin 0 -> 1119 bytes .../icon/Media/Champions_League_normal.png | Bin 0 -> 1945 bytes .../gui/terminal/icon/Media/TV2_hover.png | Bin 0 -> 1001 bytes .../gui/terminal/icon/Media/TV2_normal.png | Bin 0 -> 1623 bytes .../gui/terminal/icon/Media/TV_hover.png | Bin 0 -> 959 bytes .../gui/terminal/icon/Media/TV_normal.png | Bin 0 -> 1634 bytes .../icon/Media/VideoRecorder_hover.png | Bin 0 -> 808 bytes .../icon/Media/VideoRecorder_normal.png | Bin 0 -> 1359 bytes .../gui/terminal/icon/Media/WMP_hover.png | Bin 0 -> 767 bytes .../gui/terminal/icon/Media/WMP_normal.png | Bin 0 -> 1219 bytes .../gui/terminal/icon/Media/YT1_hover.png | Bin 0 -> 853 bytes .../gui/terminal/icon/Media/YT1_normal.png | Bin 0 -> 1473 bytes .../gui/terminal/icon/Media/YT2_hover.png | Bin 0 -> 813 bytes .../gui/terminal/icon/Media/YT2_normal.png | Bin 0 -> 1295 bytes .../terminal/icon/Media/blank-cd_hover.png | Bin 0 -> 874 bytes .../terminal/icon/Media/blank-cd_normal.png | Bin 0 -> 1495 bytes .../gui/terminal/icon/Media/camera3_hover.png | Bin 0 -> 830 bytes .../terminal/icon/Media/camera3_normal.png | Bin 0 -> 1402 bytes .../gui/terminal/icon/Media/ea_hover.png | Bin 0 -> 980 bytes .../gui/terminal/icon/Media/ea_normal.png | Bin 0 -> 1697 bytes .../gui/terminal/icon/Media/iTunes_hover.png | Bin 0 -> 892 bytes .../gui/terminal/icon/Media/iTunes_normal.png | Bin 0 -> 1440 bytes .../terminal/icon/Media/landskape_hover.png | Bin 0 -> 871 bytes .../terminal/icon/Media/landskape_normal.png | Bin 0 -> 1447 bytes .../gui/terminal/icon/Media/lastfm_hover.png | Bin 0 -> 812 bytes .../gui/terminal/icon/Media/lastfm_normal.png | Bin 0 -> 1344 bytes .../gui/terminal/icon/Media/listen_hover.png | Bin 0 -> 935 bytes .../gui/terminal/icon/Media/listen_normal.png | Bin 0 -> 1574 bytes .../gui/terminal/icon/Media/macro_hover.png | Bin 0 -> 885 bytes .../gui/terminal/icon/Media/macro_normal.png | Bin 0 -> 1489 bytes .../gui/terminal/icon/Media/photo_hover.png | Bin 0 -> 859 bytes .../gui/terminal/icon/Media/photo_normal.png | Bin 0 -> 1373 bytes .../gui/terminal/icon/Media/radio_hover.png | Bin 0 -> 918 bytes .../gui/terminal/icon/Media/radio_normal.png | Bin 0 -> 1585 bytes .../gui/terminal/icon/Media/sound2_hover.png | Bin 0 -> 966 bytes .../gui/terminal/icon/Media/sound2_normal.png | Bin 0 -> 1622 bytes .../gui/terminal/icon/Media/sound_hover.png | Bin 0 -> 948 bytes .../gui/terminal/icon/Media/sound_normal.png | Bin 0 -> 1586 bytes .../gui/terminal/icon/Media/touch_hover.png | Bin 0 -> 961 bytes .../gui/terminal/icon/Media/touch_normal.png | Bin 0 -> 1667 bytes .../terminal/icon/Media/video_rec_hover.png | Bin 0 -> 904 bytes .../terminal/icon/Media/video_rec_normal.png | Bin 0 -> 1440 bytes .../gui/terminal/icon/Media/viewer_hover.png | Bin 0 -> 906 bytes .../gui/terminal/icon/Media/viewer_normal.png | Bin 0 -> 1535 bytes .../gui/terminal/icon/Media/walkman_hover.png | Bin 0 -> 883 bytes .../terminal/icon/Media/walkman_normal.png | Bin 0 -> 1537 bytes .../gui/terminal/icon/Media/winamp_hover.png | Bin 0 -> 814 bytes .../gui/terminal/icon/Media/winamp_normal.png | Bin 0 -> 1324 bytes .../gui/terminal/icon/Media/zune1_hover.png | Bin 0 -> 1013 bytes .../gui/terminal/icon/Media/zune1_normal.png | Bin 0 -> 1750 bytes .../gui/terminal/icon/Media/zune2_hover.png | Bin 0 -> 824 bytes .../gui/terminal/icon/Media/zune2_normal.png | Bin 0 -> 1371 bytes .../gui/terminal/icon/Media/zune3_hover.png | Bin 0 -> 814 bytes .../gui/terminal/icon/Media/zune3_normal.png | Bin 0 -> 1385 bytes .../gui/terminal/icon/Navigate/Bing_hover.png | Bin 0 -> 873 bytes .../terminal/icon/Navigate/Bing_normal.png | Bin 0 -> 1460 bytes .../terminal/icon/Navigate/COMPAS2_hover.png | Bin 0 -> 974 bytes .../terminal/icon/Navigate/COMPAS2_normal.png | Bin 0 -> 1674 bytes .../icon/Navigate/Canada_flag_hover.png | Bin 0 -> 884 bytes .../icon/Navigate/Canada_flag_normal.png | Bin 0 -> 1519 bytes .../gui/terminal/icon/Navigate/EAAA_hover.png | Bin 0 -> 1031 bytes .../terminal/icon/Navigate/EAAA_normal.png | Bin 0 -> 1758 bytes .../gui/terminal/icon/Navigate/EU_hover.png | Bin 0 -> 1029 bytes .../gui/terminal/icon/Navigate/EU_normal.png | Bin 0 -> 1770 bytes .../gui/terminal/icon/Navigate/NSA_hover.png | Bin 0 -> 975 bytes .../gui/terminal/icon/Navigate/NSA_normal.png | Bin 0 -> 1630 bytes .../terminal/icon/Navigate/Navteq1_hover.png | Bin 0 -> 860 bytes .../terminal/icon/Navigate/Navteq1_normal.png | Bin 0 -> 1450 bytes .../gui/terminal/icon/Navigate/POI2_hover.png | Bin 0 -> 883 bytes .../terminal/icon/Navigate/POI2_normal.png | Bin 0 -> 1422 bytes .../icon/Navigate/Sattelite_hover.png | Bin 0 -> 910 bytes .../icon/Navigate/Sattelite_normal.png | Bin 0 -> 1579 bytes .../terminal/icon/Navigate/compas1_hover.png | Bin 0 -> 1020 bytes .../terminal/icon/Navigate/compas1_normal.png | Bin 0 -> 1844 bytes .../terminal/icon/Navigate/compas3_hover.png | Bin 0 -> 1003 bytes .../terminal/icon/Navigate/compas3_normal.png | Bin 0 -> 1825 bytes .../terminal/icon/Navigate/gmaps_hover.png | Bin 0 -> 885 bytes .../terminal/icon/Navigate/gmaps_normal.png | Bin 0 -> 1487 bytes .../icon/Navigate/navigation_hover.png | Bin 0 -> 801 bytes .../icon/Navigate/navigation_normal.png | Bin 0 -> 1283 bytes .../terminal/icon/Navigate/navteq_hover.png | Bin 0 -> 789 bytes .../terminal/icon/Navigate/navteq_normal.png | Bin 0 -> 1298 bytes .../gui/terminal/icon/Navigate/path_hover.png | Bin 0 -> 870 bytes .../terminal/icon/Navigate/path_normal.png | Bin 0 -> 1404 bytes .../gui/terminal/icon/Navigate/poi_hover.png | Bin 0 -> 746 bytes .../gui/terminal/icon/Navigate/poi_normal.png | Bin 0 -> 1203 bytes .../terminal/icon/Navigate/world1_hover.png | Bin 0 -> 918 bytes .../terminal/icon/Navigate/world1_normal.png | Bin 0 -> 1591 bytes .../terminal/icon/Navigate/world_hover.png | Bin 0 -> 1063 bytes .../terminal/icon/Navigate/world_normal.png | Bin 0 -> 1841 bytes .../gui/terminal/icon/Network/BT2_hover.png | Bin 0 -> 856 bytes .../gui/terminal/icon/Network/BT2_normal.png | Bin 0 -> 1457 bytes .../terminal/icon/Network/Chrome_hover.png | Bin 0 -> 974 bytes .../terminal/icon/Network/Chrome_normal.png | Bin 0 -> 1728 bytes .../terminal/icon/Network/Firefox_hover.png | Bin 0 -> 988 bytes .../terminal/icon/Network/Firefox_normal.png | Bin 0 -> 1715 bytes .../gui/terminal/icon/Network/Hand_hover.png | Bin 0 -> 1011 bytes .../gui/terminal/icon/Network/Hand_normal.png | Bin 0 -> 1663 bytes .../gui/terminal/icon/Network/USB1_hover.png | Bin 0 -> 852 bytes .../gui/terminal/icon/Network/USB1_normal.png | Bin 0 -> 1396 bytes .../gui/terminal/icon/Network/att2_hover.png | Bin 0 -> 828 bytes .../gui/terminal/icon/Network/att2_normal.png | Bin 0 -> 1354 bytes .../gui/terminal/icon/Network/att_hover.png | Bin 0 -> 853 bytes .../gui/terminal/icon/Network/att_normal.png | Bin 0 -> 1483 bytes .../gui/terminal/icon/Network/bt_hover.png | Bin 0 -> 974 bytes .../gui/terminal/icon/Network/bt_normal.png | Bin 0 -> 1602 bytes .../terminal/icon/Network/facebook2_hover.png | Bin 0 -> 803 bytes .../icon/Network/facebook2_normal.png | Bin 0 -> 1329 bytes .../terminal/icon/Network/facebook_hover.png | Bin 0 -> 814 bytes .../terminal/icon/Network/facebook_normal.png | Bin 0 -> 1305 bytes .../terminal/icon/Network/firefox2_hover.png | Bin 0 -> 1019 bytes .../terminal/icon/Network/firefox2_normal.png | Bin 0 -> 1759 bytes .../terminal/icon/Network/g-google_hover.png | Bin 0 -> 969 bytes .../terminal/icon/Network/g-google_normal.png | Bin 0 -> 1585 bytes .../terminal/icon/Network/globul_hover.png | Bin 0 -> 849 bytes .../terminal/icon/Network/globul_normal.png | Bin 0 -> 1411 bytes .../terminal/icon/Network/gmail2_hover.png | Bin 0 -> 854 bytes .../terminal/icon/Network/gmail2_normal.png | Bin 0 -> 1436 bytes .../gui/terminal/icon/Network/gmail_hover.png | Bin 0 -> 828 bytes .../terminal/icon/Network/gmail_normal.png | Bin 0 -> 1408 bytes .../terminal/icon/Network/google_hover.png | Bin 0 -> 851 bytes .../terminal/icon/Network/google_normal.png | Bin 0 -> 1418 bytes .../gui/terminal/icon/Network/ie_hover.png | Bin 0 -> 984 bytes .../gui/terminal/icon/Network/ie_normal.png | Bin 0 -> 1666 bytes .../gui/terminal/icon/Network/mtel_hover.png | Bin 0 -> 834 bytes .../gui/terminal/icon/Network/mtel_normal.png | Bin 0 -> 1376 bytes .../gui/terminal/icon/Network/net3_hover.png | Bin 0 -> 922 bytes .../gui/terminal/icon/Network/net3_normal.png | Bin 0 -> 1601 bytes .../gui/terminal/icon/Network/net_hover.png | Bin 0 -> 1121 bytes .../gui/terminal/icon/Network/net_normal.png | Bin 0 -> 1918 bytes .../terminal/icon/Network/netw_conn_hover.png | Bin 0 -> 986 bytes .../icon/Network/netw_conn_normal.png | Bin 0 -> 1713 bytes .../gui/terminal/icon/Network/opera_hover.png | Bin 0 -> 914 bytes .../terminal/icon/Network/opera_normal.png | Bin 0 -> 1572 bytes .../gui/terminal/icon/Network/rss_hover.png | Bin 0 -> 921 bytes .../gui/terminal/icon/Network/rss_normal.png | Bin 0 -> 1567 bytes .../terminal/icon/Network/search_hover.png | Bin 0 -> 943 bytes .../terminal/icon/Network/search_normal.png | Bin 0 -> 1515 bytes .../terminal/icon/Network/signal1_hover.png | Bin 0 -> 797 bytes .../terminal/icon/Network/signal1_normal.png | Bin 0 -> 1299 bytes .../terminal/icon/Network/signal2_hover.png | Bin 0 -> 954 bytes .../terminal/icon/Network/signal2_normal.png | Bin 0 -> 1612 bytes .../terminal/icon/Network/signal4_hover.png | Bin 0 -> 960 bytes .../terminal/icon/Network/signal4_normal.png | Bin 0 -> 1600 bytes .../terminal/icon/Network/signal_hover.png | Bin 0 -> 951 bytes .../terminal/icon/Network/signal_normal.png | Bin 0 -> 1550 bytes .../terminal/icon/Network/skype1_hover.png | Bin 0 -> 954 bytes .../terminal/icon/Network/skype1_normal.png | Bin 0 -> 1637 bytes .../terminal/icon/Network/skype2_hover.png | Bin 0 -> 1003 bytes .../terminal/icon/Network/skype2_normal.png | Bin 0 -> 1718 bytes .../gui/terminal/icon/Network/t-m_hover.png | Bin 0 -> 757 bytes .../gui/terminal/icon/Network/t-m_normal.png | Bin 0 -> 1253 bytes .../terminal/icon/Network/twitter1_hover.png | Bin 0 -> 795 bytes .../terminal/icon/Network/twitter1_normal.png | Bin 0 -> 1347 bytes .../terminal/icon/Network/twitter2_hover.png | Bin 0 -> 776 bytes .../terminal/icon/Network/twitter2_normal.png | Bin 0 -> 1291 bytes .../terminal/icon/Network/twitter3_hover.png | Bin 0 -> 924 bytes .../terminal/icon/Network/twitter3_normal.png | Bin 0 -> 1515 bytes .../terminal/icon/Network/verizon_hover.png | Bin 0 -> 774 bytes .../terminal/icon/Network/verizon_normal.png | Bin 0 -> 1274 bytes .../terminal/icon/Network/vivacom_hover.png | Bin 0 -> 735 bytes .../terminal/icon/Network/vivacom_normal.png | Bin 0 -> 1202 bytes .../terminal/icon/Network/vodafone1_hover.png | Bin 0 -> 840 bytes .../icon/Network/vodafone1_normal.png | Bin 0 -> 1429 bytes .../terminal/icon/Network/vodafone2_hover.png | Bin 0 -> 749 bytes .../icon/Network/vodafone2_normal.png | Bin 0 -> 1223 bytes .../terminal/icon/Network/vodafone3_hover.png | Bin 0 -> 903 bytes .../icon/Network/vodafone3_normal.png | Bin 0 -> 1604 bytes .../gui/terminal/icon/Network/wi-fi_hover.png | Bin 0 -> 856 bytes .../terminal/icon/Network/wi-fi_normal.png | Bin 0 -> 1450 bytes .../icon/Network/wifi-router_hover.png | Bin 0 -> 1025 bytes .../icon/Network/wifi-router_normal.png | Bin 0 -> 1724 bytes .../gui/terminal/icon/Other/Favs1_hover.png | Bin 0 -> 837 bytes .../gui/terminal/icon/Other/Favs1_normal.png | Bin 0 -> 1381 bytes .../gui/terminal/icon/Other/LIBRARY_hover.png | Bin 0 -> 795 bytes .../terminal/icon/Other/LIBRARY_normal.png | Bin 0 -> 1306 bytes .../gui/terminal/icon/Other/Llama_hover.png | Bin 0 -> 855 bytes .../gui/terminal/icon/Other/Llama_normal.png | Bin 0 -> 1375 bytes .../icon/Other/MB_0027_LIBRARY_hover.png | Bin 0 -> 769 bytes .../icon/Other/MB_0027_LIBRARY_normal.png | Bin 0 -> 1261 bytes .../gui/terminal/icon/Other/Marvel_hover.png | Bin 0 -> 910 bytes .../gui/terminal/icon/Other/Marvel_normal.png | Bin 0 -> 1541 bytes .../terminal/icon/Other/Translate_hover.png | Bin 0 -> 1036 bytes .../terminal/icon/Other/Translate_normal.png | Bin 0 -> 1947 bytes .../terminal/icon/Other/Visitors_hover.png | Bin 0 -> 911 bytes .../terminal/icon/Other/Visitors_normal.png | Bin 0 -> 1626 bytes .../gui/terminal/icon/Other/apple_hover.png | Bin 0 -> 902 bytes .../gui/terminal/icon/Other/apple_normal.png | Bin 0 -> 1452 bytes .../gui/terminal/icon/Other/b_hover.png | Bin 0 -> 847 bytes .../gui/terminal/icon/Other/b_normal.png | Bin 0 -> 1367 bytes .../gui/terminal/icon/Other/book_hover.png | Bin 0 -> 941 bytes .../gui/terminal/icon/Other/book_normal.png | Bin 0 -> 1567 bytes .../terminal/icon/Other/calculator_hover.png | Bin 0 -> 875 bytes .../terminal/icon/Other/calculator_normal.png | Bin 0 -> 1437 bytes .../gui/terminal/icon/Other/cloud_hover.png | Bin 0 -> 886 bytes .../gui/terminal/icon/Other/cloud_normal.png | Bin 0 -> 1481 bytes .../terminal/icon/Other/convertor_hover.png | Bin 0 -> 1035 bytes .../terminal/icon/Other/convertor_normal.png | Bin 0 -> 1923 bytes .../icon/Other/currency-e-d_hover.png | Bin 0 -> 1042 bytes .../icon/Other/currency-e-d_normal.png | Bin 0 -> 1944 bytes .../icon/Other/currency-e-j_hover.png | Bin 0 -> 1047 bytes .../icon/Other/currency-e-j_normal.png | Bin 0 -> 1928 bytes .../icon/Other/currency-e-p_hover.png | Bin 0 -> 1048 bytes .../icon/Other/currency-e-p_normal.png | Bin 0 -> 1920 bytes .../gui/terminal/icon/Other/da1_hover.png | Bin 0 -> 851 bytes .../gui/terminal/icon/Other/da1_normal.png | Bin 0 -> 1403 bytes .../gui/terminal/icon/Other/da2_hover.png | Bin 0 -> 893 bytes .../gui/terminal/icon/Other/da2_normal.png | Bin 0 -> 1500 bytes .../gui/terminal/icon/Other/favs2_hover.png | Bin 0 -> 882 bytes .../gui/terminal/icon/Other/favs2_normal.png | Bin 0 -> 1465 bytes .../gui/terminal/icon/Other/iBOOKS_hover.png | Bin 0 -> 767 bytes .../gui/terminal/icon/Other/iBOOKS_normal.png | Bin 0 -> 1244 bytes .../gui/terminal/icon/Other/java_hover.png | Bin 0 -> 941 bytes .../gui/terminal/icon/Other/java_normal.png | Bin 0 -> 1505 bytes .../gui/terminal/icon/Other/light_hover.png | Bin 0 -> 818 bytes .../gui/terminal/icon/Other/light_normal.png | Bin 0 -> 1358 bytes .../gui/terminal/icon/Other/pin_hover.png | Bin 0 -> 846 bytes .../gui/terminal/icon/Other/pin_normal.png | Bin 0 -> 1407 bytes .../gui/terminal/icon/Other/pliok2_hover.png | Bin 0 -> 1006 bytes .../gui/terminal/icon/Other/pliok2_normal.png | Bin 0 -> 1704 bytes .../gui/terminal/icon/Other/pliok_hover.png | Bin 0 -> 949 bytes .../gui/terminal/icon/Other/pliok_normal.png | Bin 0 -> 1552 bytes .../gui/terminal/icon/Other/plus_hover.png | Bin 0 -> 805 bytes .../gui/terminal/icon/Other/plus_normal.png | Bin 0 -> 1290 bytes .../gui/terminal/icon/Other/range_hover.png | Bin 0 -> 1014 bytes .../gui/terminal/icon/Other/range_normal.png | Bin 0 -> 1756 bytes .../gui/terminal/icon/Other/sim_hover.png | Bin 0 -> 675 bytes .../gui/terminal/icon/Other/sim_normal.png | Bin 0 -> 1044 bytes .../terminal/icon/Other/weather1_hover.png | Bin 0 -> 852 bytes .../terminal/icon/Other/weather1_normal.png | Bin 0 -> 1402 bytes .../gui/terminal/icon/Suite/3dmax_hover.png | Bin 0 -> 1037 bytes .../gui/terminal/icon/Suite/3dmax_normal.png | Bin 0 -> 1764 bytes .../gui/terminal/icon/Suite/AE_hover.png | Bin 0 -> 923 bytes .../gui/terminal/icon/Suite/AE_normal.png | Bin 0 -> 1578 bytes .../gui/terminal/icon/Suite/AIR_hover.png | Bin 0 -> 939 bytes .../gui/terminal/icon/Suite/AIR_normal.png | Bin 0 -> 1629 bytes .../gui/terminal/icon/Suite/Ai_hover.png | Bin 0 -> 898 bytes .../gui/terminal/icon/Suite/Ai_normal.png | Bin 0 -> 1484 bytes .../gui/terminal/icon/Suite/Apps_hover.png | Bin 0 -> 834 bytes .../gui/terminal/icon/Suite/Apps_normal.png | Bin 0 -> 1362 bytes .../gui/terminal/icon/Suite/Autocad_hover.png | Bin 0 -> 897 bytes .../terminal/icon/Suite/Autocad_normal.png | Bin 0 -> 1524 bytes .../gui/terminal/icon/Suite/Br_hover.png | Bin 0 -> 858 bytes .../gui/terminal/icon/Suite/Br_normal.png | Bin 0 -> 1425 bytes .../gui/terminal/icon/Suite/Dw_hover.png | Bin 0 -> 917 bytes .../gui/terminal/icon/Suite/Dw_normal.png | Bin 0 -> 1534 bytes .../gui/terminal/icon/Suite/Excel_hover.png | Bin 0 -> 974 bytes .../gui/terminal/icon/Suite/Excel_normal.png | Bin 0 -> 1681 bytes .../gui/terminal/icon/Suite/Fl_hover.png | Bin 0 -> 832 bytes .../gui/terminal/icon/Suite/Fl_normal.png | Bin 0 -> 1314 bytes .../gui/terminal/icon/Suite/Flash_hover.png | Bin 0 -> 865 bytes .../gui/terminal/icon/Suite/Flash_normal.png | Bin 0 -> 1395 bytes .../gui/terminal/icon/Suite/Fw_hover.png | Bin 0 -> 899 bytes .../gui/terminal/icon/Suite/Fw_normal.png | Bin 0 -> 1523 bytes .../gui/terminal/icon/Suite/Fx_hover.png | Bin 0 -> 887 bytes .../gui/terminal/icon/Suite/Fx_normal.png | Bin 0 -> 1462 bytes .../gui/terminal/icon/Suite/IC_hover.png | Bin 0 -> 819 bytes .../gui/terminal/icon/Suite/IC_normal.png | Bin 0 -> 1350 bytes .../gui/terminal/icon/Suite/ID_hover.png | Bin 0 -> 812 bytes .../gui/terminal/icon/Suite/ID_normal.png | Bin 0 -> 1341 bytes .../gui/terminal/icon/Suite/LR_hover.png | Bin 0 -> 830 bytes .../gui/terminal/icon/Suite/LR_normal.png | Bin 0 -> 1376 bytes .../gui/terminal/icon/Suite/Office1_hover.png | Bin 0 -> 752 bytes .../terminal/icon/Suite/Office1_normal.png | Bin 0 -> 1205 bytes .../terminal/icon/Suite/Office2010_hover.png | Bin 0 -> 762 bytes .../terminal/icon/Suite/Office2010_normal.png | Bin 0 -> 1224 bytes .../terminal/icon/Suite/One-Note_hover.png | Bin 0 -> 946 bytes .../terminal/icon/Suite/One-Note_normal.png | Bin 0 -> 1604 bytes .../gui/terminal/icon/Suite/Outlook_hover.png | Bin 0 -> 1019 bytes .../terminal/icon/Suite/Outlook_normal.png | Bin 0 -> 1797 bytes .../terminal/icon/Suite/Power-Point_hover.png | Bin 0 -> 903 bytes .../icon/Suite/Power-Point_normal.png | Bin 0 -> 1478 bytes .../gui/terminal/icon/Suite/Ps_hover.png | Bin 0 -> 874 bytes .../gui/terminal/icon/Suite/Ps_normal.png | Bin 0 -> 1469 bytes .../gui/terminal/icon/Suite/Sb_hover.png | Bin 0 -> 946 bytes .../gui/terminal/icon/Suite/Sb_normal.png | Bin 0 -> 1616 bytes .../gui/terminal/icon/Suite/Word_hover.png | Bin 0 -> 975 bytes .../gui/terminal/icon/Suite/Word_normal.png | Bin 0 -> 1670 bytes .../icon/Suite/adobe-acrobat_hover.png | Bin 0 -> 843 bytes .../icon/Suite/adobe-acrobat_normal.png | Bin 0 -> 1362 bytes .../terminal/icon/Suite/android2_hover.png | Bin 0 -> 919 bytes .../terminal/icon/Suite/android2_normal.png | Bin 0 -> 1541 bytes .../gui/terminal/icon/Suite/android_hover.png | Bin 0 -> 795 bytes .../terminal/icon/Suite/android_normal.png | Bin 0 -> 1282 bytes .../gui/terminal/icon/Suite/office_hover.png | Bin 0 -> 932 bytes .../gui/terminal/icon/Suite/office_normal.png | Bin 0 -> 1587 bytes .../terminal/icon/Suite/programs_hover.png | Bin 0 -> 925 bytes .../terminal/icon/Suite/programs_normal.png | Bin 0 -> 1580 bytes .../gui/terminal/icon/Suite/ps.com_hover.png | Bin 0 -> 911 bytes .../gui/terminal/icon/Suite/ps.com_normal.png | Bin 0 -> 1497 bytes .../terminal/icon/Suite/smartbuble_hover.png | Bin 0 -> 847 bytes .../terminal/icon/Suite/smartbuble_normal.png | Bin 0 -> 1387 bytes .../gui/terminal/icon/System/3D_hover.png | Bin 0 -> 978 bytes .../gui/terminal/icon/System/3D_normal.png | Bin 0 -> 1652 bytes .../terminal/icon/System/APP-info_hover.png | Bin 0 -> 988 bytes .../terminal/icon/System/APP-info_normal.png | Bin 0 -> 1693 bytes .../gui/terminal/icon/System/Base_hover.png | Bin 0 -> 752 bytes .../gui/terminal/icon/System/Base_normal.png | Bin 0 -> 1155 bytes .../terminal/icon/System/Computer_hover.png | Bin 0 -> 776 bytes .../terminal/icon/System/Computer_normal.png | Bin 0 -> 1246 bytes .../icon/System/Control-Panel1_hover.png | Bin 0 -> 849 bytes .../icon/System/Control-Panel1_normal.png | Bin 0 -> 1407 bytes .../icon/System/Control-Panel2_hover.png | Bin 0 -> 966 bytes .../icon/System/Control-Panel2_normal.png | Bin 0 -> 1661 bytes .../terminal/icon/System/Desktop_hover.png | Bin 0 -> 742 bytes .../terminal/icon/System/Desktop_normal.png | Bin 0 -> 1197 bytes .../terminal/icon/System/HDD-system_hover.png | Bin 0 -> 723 bytes .../icon/System/HDD-system_normal.png | Bin 0 -> 1166 bytes .../gui/terminal/icon/System/HDD_hover.png | Bin 0 -> 648 bytes .../gui/terminal/icon/System/HDD_normal.png | Bin 0 -> 1060 bytes .../terminal/icon/System/HW_info_hover.png | Bin 0 -> 1016 bytes .../terminal/icon/System/HW_info_normal.png | Bin 0 -> 1737 bytes .../gui/terminal/icon/System/LOCK_hover.png | Bin 0 -> 840 bytes .../gui/terminal/icon/System/LOCK_normal.png | Bin 0 -> 1311 bytes .../terminal/icon/System/SW-info_hover.png | Bin 0 -> 884 bytes .../terminal/icon/System/SW-info_normal.png | Bin 0 -> 1472 bytes .../gui/terminal/icon/System/apps4_hover.png | Bin 0 -> 822 bytes .../gui/terminal/icon/System/apps4_normal.png | Bin 0 -> 1295 bytes .../gui/terminal/icon/System/apps9_hover.png | Bin 0 -> 1007 bytes .../gui/terminal/icon/System/apps9_normal.png | Bin 0 -> 1736 bytes .../gui/terminal/icon/System/back_hover.png | Bin 0 -> 846 bytes .../gui/terminal/icon/System/back_normal.png | Bin 0 -> 1412 bytes .../gui/terminal/icon/System/bat1_hover.png | Bin 0 -> 893 bytes .../gui/terminal/icon/System/bat1_normal.png | Bin 0 -> 1486 bytes .../terminal/icon/System/expand2_hover.png | Bin 0 -> 986 bytes .../terminal/icon/System/expand2_normal.png | Bin 0 -> 1702 bytes .../terminal/icon/System/expand3_hover.png | Bin 0 -> 986 bytes .../terminal/icon/System/expand3_normal.png | Bin 0 -> 1709 bytes .../gui/terminal/icon/System/help_hover.png | Bin 0 -> 856 bytes .../gui/terminal/icon/System/help_normal.png | Bin 0 -> 1374 bytes .../gui/terminal/icon/System/home2_hover.png | Bin 0 -> 868 bytes .../gui/terminal/icon/System/home2_normal.png | Bin 0 -> 1436 bytes .../gui/terminal/icon/System/info2_hover.png | Bin 0 -> 716 bytes .../gui/terminal/icon/System/info2_normal.png | Bin 0 -> 1151 bytes .../gui/terminal/icon/System/info3_hover.png | Bin 0 -> 820 bytes .../gui/terminal/icon/System/info3_normal.png | Bin 0 -> 1336 bytes .../gui/terminal/icon/System/info_hover.png | Bin 0 -> 708 bytes .../gui/terminal/icon/System/info_normal.png | Bin 0 -> 1114 bytes .../terminal/icon/System/keyboard2_hover.png | Bin 0 -> 806 bytes .../terminal/icon/System/keyboard2_normal.png | Bin 0 -> 1251 bytes .../terminal/icon/System/keyboard_hover.png | Bin 0 -> 859 bytes .../terminal/icon/System/keyboard_normal.png | Bin 0 -> 1389 bytes .../terminal/icon/System/loading_hover.png | Bin 0 -> 936 bytes .../terminal/icon/System/loading_normal.png | Bin 0 -> 1586 bytes .../icon/System/memory_card_hover.png | Bin 0 -> 875 bytes .../icon/System/memory_card_normal.png | Bin 0 -> 1464 bytes .../terminal/icon/System/multitask1_hover.png | Bin 0 -> 866 bytes .../icon/System/multitask1_normal.png | Bin 0 -> 1432 bytes .../gui/terminal/icon/System/off_hover.png | Bin 0 -> 968 bytes .../gui/terminal/icon/System/off_normal.png | Bin 0 -> 1703 bytes .../gui/terminal/icon/System/print_hover.png | Bin 0 -> 934 bytes .../gui/terminal/icon/System/print_normal.png | Bin 0 -> 1557 bytes .../gui/terminal/icon/System/reload_hover.png | Bin 0 -> 974 bytes .../terminal/icon/System/reload_normal.png | Bin 0 -> 1646 bytes .../gui/terminal/icon/System/rotate_hover.png | Bin 0 -> 898 bytes .../terminal/icon/System/rotate_normal.png | Bin 0 -> 1546 bytes .../gui/terminal/icon/System/save_hover.png | Bin 0 -> 839 bytes .../gui/terminal/icon/System/save_normal.png | Bin 0 -> 1371 bytes .../gui/terminal/icon/System/sd_hover.png | Bin 0 -> 745 bytes .../gui/terminal/icon/System/sd_normal.png | Bin 0 -> 1210 bytes .../terminal/icon/System/sett-big_hover.png | Bin 0 -> 927 bytes .../terminal/icon/System/sett-big_normal.png | Bin 0 -> 1576 bytes .../terminal/icon/System/sett_small_hover.png | Bin 0 -> 836 bytes .../icon/System/sett_small_normal.png | Bin 0 -> 1416 bytes .../terminal/icon/System/shut-down_hover.png | Bin 0 -> 944 bytes .../terminal/icon/System/shut-down_normal.png | Bin 0 -> 1583 bytes .../gui/terminal/icon/System/sim_hover.png | Bin 0 -> 696 bytes .../gui/terminal/icon/System/sim_normal.png | Bin 0 -> 1097 bytes .../terminal/icon/System/skaner-1_hover.png | Bin 0 -> 770 bytes .../terminal/icon/System/skaner-1_normal.png | Bin 0 -> 1238 bytes .../gui/terminal/icon/System/skaner_hover.png | Bin 0 -> 783 bytes .../terminal/icon/System/skaner_normal.png | Bin 0 -> 1252 bytes .../icon/System/taskmgr-copy_hover.png | Bin 0 -> 876 bytes .../icon/System/taskmgr-copy_normal.png | Bin 0 -> 1465 bytes .../terminal/icon/System/taskmgr_hover.png | Bin 0 -> 880 bytes .../terminal/icon/System/taskmgr_normal.png | Bin 0 -> 1483 bytes .../gui/terminal/icon/System/tok_hover.png | Bin 0 -> 866 bytes .../gui/terminal/icon/System/tok_normal.png | Bin 0 -> 1440 bytes .../gui/terminal/icon/System/tools_hover.png | Bin 0 -> 871 bytes .../gui/terminal/icon/System/tools_normal.png | Bin 0 -> 1451 bytes .../terminal/icon/System/windows_hover.png | Bin 0 -> 931 bytes .../terminal/icon/System/windows_normal.png | Bin 0 -> 1562 bytes .../textures/gui/terminal/icon/add_hover.png | Bin 0 -> 897 bytes .../textures/gui/terminal/icon/add_normal.png | Bin 0 -> 1483 bytes .../gui/terminal/icon/appearance_hover.png | Bin 0 -> 911 bytes .../gui/terminal/icon/appearance_normal.png | Bin 0 -> 1626 bytes .../terminal/{ => icon}/cancel_disable.png | Bin .../gui/terminal/{ => icon}/cancel_hover.png | Bin .../gui/terminal/{ => icon}/cancel_normal.png | Bin .../gui/terminal/icon/default_hover.png | Bin 0 -> 1835 bytes .../gui/terminal/icon/default_normal.png | Bin 0 -> 1191 bytes .../gui/terminal/icon/default_press.png | Bin 0 -> 1810 bytes .../textures/gui/terminal/icon/down_hover.png | Bin 0 -> 2307 bytes .../gui/terminal/icon/down_normal.png | Bin 0 -> 2770 bytes .../gui/terminal/icon/equipment_hover.png | Bin 0 -> 499 bytes .../gui/terminal/icon/equipment_normal.png | Bin 0 -> 1140 bytes .../textures/gui/terminal/icon/file_hover.png | Bin 0 -> 722 bytes .../gui/terminal/icon/file_normal.png | Bin 0 -> 1306 bytes .../gui/terminal/icon/folder_hover.png | Bin 0 -> 708 bytes .../gui/terminal/icon/folder_normal.png | Bin 0 -> 1114 bytes .../gui/terminal/icon/graphics_hover.png | Bin 0 -> 978 bytes .../gui/terminal/icon/graphics_normal.png | Bin 0 -> 1652 bytes .../gui/terminal/icon/guide_hover.png | Bin 0 -> 955 bytes .../gui/terminal/icon/guide_normal.png | Bin 0 -> 1551 bytes .../textures/gui/terminal/icon/help_hover.png | Bin 0 -> 903 bytes .../gui/terminal/icon/help_normal.png | Bin 0 -> 1442 bytes .../gui/terminal/icon/items_hover.png | Bin 0 -> 897 bytes .../gui/terminal/icon/items_normal.png | Bin 0 -> 1483 bytes .../textures/gui/terminal/icon/left_hover.png | Bin 0 -> 2307 bytes .../gui/terminal/icon/left_normal.png | Bin 0 -> 2796 bytes .../gui/terminal/icon/logout_hover.png | Bin 0 -> 917 bytes .../gui/terminal/icon/logout_normal.png | Bin 0 -> 1472 bytes .../gui/terminal/icon/modify_hover.png | Bin 0 -> 865 bytes .../gui/terminal/icon/modify_normal.png | Bin 0 -> 1365 bytes .../textures/gui/terminal/icon/move_hover.png | Bin 0 -> 858 bytes .../gui/terminal/icon/move_normal.png | Bin 0 -> 1353 bytes .../textures/gui/terminal/icon/next_hover.png | Bin 0 -> 1612 bytes .../gui/terminal/icon/next_normal.png | Bin 0 -> 986 bytes .../textures/gui/terminal/icon/next_press.png | Bin 0 -> 1479 bytes .../gui/terminal/{ => icon}/ok_disable.png | Bin .../gui/terminal/{ => icon}/ok_hover.png | Bin .../gui/terminal/{ => icon}/ok_normal.png | Bin .../gui/terminal/icon/option_hover.png | Bin 0 -> 1022 bytes .../gui/terminal/icon/option_normal.png | Bin 0 -> 1705 bytes .../textures/gui/terminal/icon/prev_hover.png | Bin 0 -> 1618 bytes .../gui/terminal/icon/prev_normal.png | Bin 0 -> 1006 bytes .../textures/gui/terminal/icon/prev_press.png | Bin 0 -> 1488 bytes .../gui/terminal/icon/remove_hover.png | Bin 0 -> 757 bytes .../gui/terminal/icon/remove_normal.png | Bin 0 -> 1131 bytes .../gui/terminal/icon/right_hover.png | Bin 0 -> 2300 bytes .../gui/terminal/icon/right_normal.png | Bin 0 -> 2788 bytes .../textures/gui/terminal/icon/run_hover.png | Bin 0 -> 864 bytes .../textures/gui/terminal/icon/run_normal.png | Bin 0 -> 1351 bytes .../gui/terminal/icon/skills_hover.png | Bin 0 -> 863 bytes .../gui/terminal/icon/skills_normal.png | Bin 0 -> 1014 bytes .../gui/terminal/icon/sound_hover.png | Bin 0 -> 948 bytes .../gui/terminal/icon/sound_normal.png | Bin 0 -> 1586 bytes .../gui/terminal/icon/theme_hover.png | Bin 0 -> 978 bytes .../gui/terminal/icon/theme_normal.png | Bin 0 -> 1516 bytes .../textures/gui/terminal/icon/up_hover.png | Bin 0 -> 2305 bytes .../textures/gui/terminal/icon/up_normal.png | Bin 0 -> 2758 bytes .../textures/gui/terminal/terminal_add.png | Bin 2273 -> 0 bytes .../textures/gui/terminal/terminal_close.png | Bin 1798 -> 0 bytes .../textures/gui/terminal/terminal_delete.png | Bin 1987 -> 0 bytes .../textures/gui/terminal/terminal_down.png | Bin 1903 -> 0 bytes .../textures/gui/terminal/terminal_export.png | Bin 1934 -> 0 bytes .../textures/gui/terminal/terminal_home.png | Bin 1496 -> 0 bytes .../textures/gui/terminal/terminal_import.png | Bin 1929 -> 0 bytes .../textures/gui/terminal/terminal_menu.png | Bin 2798 -> 0 bytes .../gui/terminal/terminal_minimum.png | Bin 1672 -> 0 bytes .../gui/terminal/terminal_new_page.png | Bin 1902 -> 0 bytes .../gui/terminal/terminal_searching.png | Bin 1939 -> 0 bytes .../gui/terminal/terminal_setting.png | Bin 1712 -> 0 bytes .../textures/gui/terminal/terminal_up.png | Bin 1899 -> 0 bytes 541 files changed, 1253 insertions(+), 191 deletions(-) create mode 100644 src/main/java/gregtech/api/terminal/app/recipechart/RecipeChartApp.java create mode 100644 src/main/java/gregtech/api/terminal/app/recipechart/widget/PhantomWidget.java create mode 100644 src/main/java/gregtech/api/terminal/app/recipechart/widget/RGContainer.java create mode 100644 src/main/java/gregtech/api/terminal/app/recipechart/widget/RGLine.java create mode 100644 src/main/java/gregtech/api/terminal/app/recipechart/widget/RGNode.java delete mode 100644 src/main/java/gregtech/api/terminal/app/recipegraph/RecipeGraphApp.java delete mode 100644 src/main/java/gregtech/api/terminal/app/recipegraph/widget/RGContainer.java delete mode 100644 src/main/java/gregtech/api/terminal/app/recipegraph/widget/RGNode.java create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/calendar_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/calendar_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/clock1_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/clock1_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/clock2_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/clock2_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/gmail-copy_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/gmail-copy_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/gmail2-copy_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/gmail2-copy_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/kontakts_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/kontakts_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/mail1_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/mail1_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/mail2_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/mail2_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/mail_open_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/mail_open_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/mail_sent_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/mail_sent_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/msg2_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/msg2_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/msg3_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/msg3_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/msg_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/msg_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/note1_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/note1_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/note2_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/note2_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/pen_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/pen_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/phone_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/phone_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/profiles_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/profiles_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/skype_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/skype_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/tasks_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/tasks_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/voicemail-12_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/voicemail-12_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/voicemaill_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/voicemaill_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/Camera_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/Camera_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/Champions_League_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/Champions_League_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/TV2_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/TV2_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/TV_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/TV_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/VideoRecorder_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/VideoRecorder_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/WMP_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/WMP_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/YT1_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/YT1_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/YT2_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/YT2_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/blank-cd_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/blank-cd_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/camera3_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/camera3_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/ea_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/ea_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/iTunes_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/iTunes_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/landskape_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/landskape_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/lastfm_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/lastfm_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/listen_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/listen_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/macro_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/macro_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/photo_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/photo_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/radio_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/radio_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/sound2_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/sound2_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/sound_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/sound_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/touch_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/touch_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/video_rec_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/video_rec_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/viewer_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/viewer_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/walkman_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/walkman_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/winamp_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/winamp_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/zune1_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/zune1_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/zune2_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/zune2_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/zune3_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/zune3_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/Bing_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/Bing_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/COMPAS2_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/COMPAS2_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/Canada_flag_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/Canada_flag_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/EAAA_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/EAAA_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/EU_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/EU_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/NSA_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/NSA_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/Navteq1_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/Navteq1_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/POI2_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/POI2_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/Sattelite_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/Sattelite_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/compas1_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/compas1_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/compas3_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/compas3_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/gmaps_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/gmaps_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/navigation_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/navigation_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/navteq_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/navteq_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/path_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/path_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/poi_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/poi_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/world1_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/world1_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/world_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/world_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/BT2_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/BT2_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/Chrome_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/Chrome_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/Firefox_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/Firefox_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/Hand_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/Hand_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/USB1_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/USB1_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/att2_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/att2_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/att_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/att_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/bt_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/bt_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/facebook2_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/facebook2_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/facebook_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/facebook_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/firefox2_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/firefox2_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/g-google_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/g-google_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/globul_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/globul_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/gmail2_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/gmail2_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/gmail_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/gmail_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/google_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/google_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/ie_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/ie_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/mtel_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/mtel_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/net3_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/net3_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/net_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/net_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/netw_conn_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/netw_conn_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/opera_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/opera_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/rss_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/rss_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/search_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/search_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/signal1_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/signal1_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/signal2_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/signal2_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/signal4_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/signal4_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/signal_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/signal_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/skype1_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/skype1_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/skype2_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/skype2_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/t-m_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/t-m_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/twitter1_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/twitter1_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/twitter2_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/twitter2_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/twitter3_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/twitter3_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/verizon_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/verizon_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/vivacom_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/vivacom_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/vodafone1_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/vodafone1_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/vodafone2_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/vodafone2_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/vodafone3_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/vodafone3_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/wi-fi_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/wi-fi_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/wifi-router_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/wifi-router_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/Favs1_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/Favs1_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/LIBRARY_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/LIBRARY_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/Llama_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/Llama_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/MB_0027_LIBRARY_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/MB_0027_LIBRARY_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/Marvel_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/Marvel_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/Translate_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/Translate_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/Visitors_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/Visitors_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/apple_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/apple_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/b_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/b_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/book_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/book_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/calculator_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/calculator_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/cloud_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/cloud_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/convertor_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/convertor_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/currency-e-d_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/currency-e-d_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/currency-e-j_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/currency-e-j_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/currency-e-p_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/currency-e-p_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/da1_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/da1_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/da2_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/da2_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/favs2_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/favs2_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/iBOOKS_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/iBOOKS_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/java_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/java_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/light_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/light_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/pin_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/pin_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/pliok2_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/pliok2_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/pliok_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/pliok_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/plus_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/plus_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/range_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/range_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/sim_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/sim_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/weather1_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/weather1_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/3dmax_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/3dmax_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/AE_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/AE_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/AIR_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/AIR_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Ai_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Ai_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Apps_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Apps_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Autocad_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Autocad_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Br_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Br_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Dw_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Dw_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Excel_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Excel_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Fl_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Fl_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Flash_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Flash_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Fw_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Fw_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Fx_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Fx_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/IC_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/IC_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/ID_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/ID_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/LR_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/LR_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Office1_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Office1_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Office2010_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Office2010_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/One-Note_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/One-Note_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Outlook_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Outlook_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Power-Point_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Power-Point_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Ps_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Ps_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Sb_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Sb_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Word_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Word_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/adobe-acrobat_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/adobe-acrobat_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/android2_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/android2_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/android_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/android_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/office_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/office_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/programs_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/programs_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/ps.com_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/ps.com_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/smartbuble_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/smartbuble_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/3D_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/3D_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/APP-info_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/APP-info_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/Base_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/Base_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/Computer_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/Computer_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/Control-Panel1_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/Control-Panel1_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/Control-Panel2_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/Control-Panel2_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/Desktop_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/Desktop_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/HDD-system_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/HDD-system_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/HDD_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/HDD_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/HW_info_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/HW_info_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/LOCK_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/LOCK_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/SW-info_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/SW-info_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/apps4_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/apps4_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/apps9_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/apps9_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/back_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/back_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/bat1_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/bat1_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/expand2_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/expand2_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/expand3_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/expand3_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/help_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/help_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/home2_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/home2_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/info2_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/info2_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/info3_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/info3_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/info_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/info_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/keyboard2_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/keyboard2_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/keyboard_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/keyboard_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/loading_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/loading_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/memory_card_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/memory_card_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/multitask1_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/multitask1_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/off_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/off_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/print_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/print_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/reload_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/reload_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/rotate_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/rotate_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/save_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/save_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/sd_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/sd_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/sett-big_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/sett-big_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/sett_small_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/sett_small_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/shut-down_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/shut-down_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/sim_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/sim_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/skaner-1_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/skaner-1_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/skaner_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/skaner_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/taskmgr-copy_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/taskmgr-copy_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/taskmgr_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/taskmgr_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/tok_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/tok_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/tools_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/tools_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/windows_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/windows_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/add_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/add_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/appearance_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/appearance_normal.png rename src/main/resources/assets/gregtech/textures/gui/terminal/{ => icon}/cancel_disable.png (100%) rename src/main/resources/assets/gregtech/textures/gui/terminal/{ => icon}/cancel_hover.png (100%) rename src/main/resources/assets/gregtech/textures/gui/terminal/{ => icon}/cancel_normal.png (100%) create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/default_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/default_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/default_press.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/down_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/down_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/equipment_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/equipment_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/file_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/file_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/folder_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/folder_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/graphics_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/graphics_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/guide_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/guide_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/help_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/help_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/items_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/items_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/left_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/left_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/logout_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/logout_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/modify_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/modify_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/move_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/move_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/next_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/next_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/next_press.png rename src/main/resources/assets/gregtech/textures/gui/terminal/{ => icon}/ok_disable.png (100%) rename src/main/resources/assets/gregtech/textures/gui/terminal/{ => icon}/ok_hover.png (100%) rename src/main/resources/assets/gregtech/textures/gui/terminal/{ => icon}/ok_normal.png (100%) create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/option_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/option_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/prev_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/prev_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/prev_press.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/remove_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/remove_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/right_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/right_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/run_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/run_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/skills_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/skills_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/sound_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/sound_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/theme_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/theme_normal.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/up_hover.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/icon/up_normal.png delete mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/terminal_add.png delete mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/terminal_close.png delete mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/terminal_delete.png delete mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/terminal_down.png delete mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/terminal_export.png delete mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/terminal_home.png delete mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/terminal_import.png delete mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/terminal_menu.png delete mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/terminal_minimum.png delete mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/terminal_new_page.png delete mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/terminal_searching.png delete mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/terminal_setting.png delete mode 100644 src/main/resources/assets/gregtech/textures/gui/terminal/terminal_up.png diff --git a/src/main/java/gregtech/api/gui/GuiTextures.java b/src/main/java/gregtech/api/gui/GuiTextures.java index f1281d43ed9..71544551f4f 100644 --- a/src/main/java/gregtech/api/gui/GuiTextures.java +++ b/src/main/java/gregtech/api/gui/GuiTextures.java @@ -1,6 +1,7 @@ package gregtech.api.gui; import gregtech.api.gui.resources.AdoptableTextureArea; +import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.resources.SizedTextureArea; import gregtech.api.gui.resources.TextureArea; @@ -168,12 +169,18 @@ public class GuiTextures { public static final TextureArea MULTIBLOCK_CATEGORY = TextureArea.fullImage("textures/gui/icon/coke_oven.png"); //Terminal - public static final TextureArea TERMINAL_FRAME = TextureArea.fullImage("textures/gui/terminal/terminal_frame.png"); - public static final TextureArea TERMINAL_MENU = TextureArea.fullImage("textures/gui/terminal/terminal_menu.png"); - public static final TextureArea TERMINAL_HOME = TextureArea.fullImage("textures/gui/terminal/terminal_home.png"); - public static final TextureArea TERMINAL_DELETE = TextureArea.fullImage("textures/gui/terminal/terminal_delete.png"); - public static final TextureArea TERMINAL_UP = TextureArea.fullImage("textures/gui/terminal/terminal_up.png"); - public static final TextureArea TERMINAL_DOWN = TextureArea.fullImage("textures/gui/terminal/terminal_down.png"); - public static final TextureArea TERMINAL_ADD = TextureArea.fullImage("textures/gui/terminal/terminal_add.png"); + public static final TextureArea ICON_REMOVE = TextureArea.fullImage("textures/gui/terminal/icon/remove_hover.png"); + public static final TextureArea ICON_UP = TextureArea.fullImage("textures/gui/terminal/icon/up_hover.png"); + public static final TextureArea ICON_DOWN = TextureArea.fullImage("textures/gui/terminal/icon/down_hover.png"); + public static final TextureArea ICON_RIGHT = TextureArea.fullImage("textures/gui/terminal/icon/right_hover.png"); + public static final TextureArea ICON_LEFT = TextureArea.fullImage("textures/gui/terminal/icon/left_hover.png"); + public static final TextureArea ICON_ADD = TextureArea.fullImage("textures/gui/terminal/icon/add_hover.png"); + + public final static TextureArea ICON_NEW_PAGE = TextureArea.fullImage("textures/gui/terminal/icon/system/memory_card_hover.png"); + public final static TextureArea ICON_LOAD = TextureArea.fullImage("textures/gui/terminal/icon/folder_hover.png"); + public final static TextureArea ICON_SAVE = TextureArea.fullImage("textures/gui/terminal/icon/system/save_hover.png"); + public final static TextureArea ICON_LOCATION = TextureArea.fullImage("textures/gui/terminal/icon/guide_hover.png"); + public final static TextureArea ICON_VISIBLE = TextureArea.fullImage("textures/gui/terminal/icon/appearance_hover.png"); + public final static TextureArea ICON_CALCULATOR = TextureArea.fullImage("textures/gui/terminal/icon/other/calculator_hover.png"); } diff --git a/src/main/java/gregtech/api/gui/ModularUI.java b/src/main/java/gregtech/api/gui/ModularUI.java index 6296f508292..588d28d0ad5 100644 --- a/src/main/java/gregtech/api/gui/ModularUI.java +++ b/src/main/java/gregtech/api/gui/ModularUI.java @@ -57,6 +57,7 @@ public List getFlatVisibleWidgetCollection() { List widgetList = new ArrayList<>(guiWidgets.size()); for (Widget widget : guiWidgets.values()) { + if (!widget.isVisible()) continue; widgetList.add(widget); if (widget instanceof AbstractWidgetGroup) diff --git a/src/main/java/gregtech/api/gui/Widget.java b/src/main/java/gregtech/api/gui/Widget.java index e50b6172969..efdc9688432 100644 --- a/src/main/java/gregtech/api/gui/Widget.java +++ b/src/main/java/gregtech/api/gui/Widget.java @@ -15,6 +15,7 @@ import net.minecraft.init.SoundEvents; import net.minecraft.item.ItemStack; import net.minecraft.network.PacketBuffer; +import net.minecraft.util.math.Vec2f; import net.minecraft.util.text.TextFormatting; import net.minecraftforge.fml.client.config.GuiUtils; import net.minecraftforge.fml.common.FMLCommonHandler; @@ -24,6 +25,7 @@ import javax.annotation.Nullable; import java.awt.*; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.function.Consumer; @@ -410,7 +412,7 @@ public static void setColor(int color) { // ARGB } @SideOnly(Side.CLIENT) - public static void renderCircle(float x, float y, float r, int color, int segments) { + public static void drawCircle(float x, float y, float r, int color, int segments) { if (color == 0) return; Tessellator tessellator = Tessellator.getInstance(); BufferBuilder bufferbuilder = tessellator.getBuffer(); @@ -428,7 +430,7 @@ public static void renderCircle(float x, float y, float r, int color, int segmen } @SideOnly(Side.CLIENT) - public static void renderSector(float x, float y, float r, int color, int segments, int from, int to) { + public static void drawSector(float x, float y, float r, int color, int segments, int from, int to) { if (from > to || from < 0 || color == 0) return; if(to > segments) to = segments; Tessellator tessellator = Tessellator.getInstance(); @@ -445,6 +447,96 @@ public static void renderSector(float x, float y, float r, int color, int segmen } tessellator.draw(); GlStateManager.enableTexture2D(); + GlStateManager.color(1,1,1,1); + } + + public static void drawTorus(float x, float y, float outer, float inner, int color, int segments, int from, int to) { + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder bufferbuilder = tessellator.getBuffer(); + GlStateManager.enableBlend(); + GlStateManager.disableTexture2D(); + GlStateManager.tryBlendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO); + setColor(color); + bufferbuilder.begin(GL11.GL_QUAD_STRIP, DefaultVertexFormats.POSITION); + for (int i = from; i <= to; i++) { + float angle = ( i / (float)segments ) * 3.14159f * 2.0f; + bufferbuilder.pos( x + inner * Math.cos(-angle), y + inner * Math.sin(-angle), 0).endVertex(); + bufferbuilder.pos( x + outer * Math.cos(-angle), y + outer * Math.sin(-angle), 0).endVertex(); + } + tessellator.draw(); + GlStateManager.enableTexture2D(); + GlStateManager.color(1,1,1,1); + } + + @SideOnly(Side.CLIENT) + public static void drawLines(List points, int startColor, int endColor, float width) { + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder bufferbuilder = tessellator.getBuffer(); + GlStateManager.enableBlend(); + GlStateManager.disableTexture2D(); + GlStateManager.tryBlendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO); + GlStateManager.glLineWidth(width); + if (startColor == endColor) { + setColor(startColor); + bufferbuilder.begin(GL11.GL_LINE_STRIP, DefaultVertexFormats.POSITION); + for (Vec2f point : points) { + bufferbuilder.pos(point.x, point.y, 0).endVertex(); + } + } else { + float startAlpha = (float) (startColor >> 24 & 255) / 255.0F; + float startRed = (float) (startColor >> 16 & 255) / 255.0F; + float startGreen = (float) (startColor >> 8 & 255) / 255.0F; + float startBlue = (float) (startColor & 255) / 255.0F; + float endAlpha = (float) (endColor >> 24 & 255) / 255.0F; + float endRed = (float) (endColor >> 16 & 255) / 255.0F; + float endGreen = (float) (endColor >> 8 & 255) / 255.0F; + float endBlue = (float) (endColor & 255) / 255.0F; + bufferbuilder.begin(GL11.GL_LINE_STRIP, DefaultVertexFormats.POSITION_COLOR); + int size = points.size(); + + for (int i = 0; i < size; i++) { + float p = i * 1.0f / size; + bufferbuilder.pos(points.get(i).x, points.get(i).y, 0) + .color(startRed + (endRed - startRed) * p, + startGreen + (endGreen - startGreen) * p, + startBlue + (endBlue - startBlue) * p, + startAlpha + (endAlpha - startAlpha) * p) + .endVertex(); + } + } + tessellator.draw(); + GlStateManager.enableTexture2D(); + GlStateManager.color(1, 1, 1, 1); + } + + @SideOnly(Side.CLIENT) + public static List genBezierPoints(Vec2f from, Vec2f to, boolean horizontal, float u) { + Vec2f c1; + Vec2f c2; + if (horizontal) { + c1 = new Vec2f((from.x + to.x) / 2, from.y); + c2 = new Vec2f((from.x + to.x) / 2, to.y); + } else { + c1 = new Vec2f(from.x, (from.y + to.y) / 2); + c2 = new Vec2f(to.x, (from.y + to.y) / 2); + } + Vec2f[] controlPoint = new Vec2f[]{from,c1,c2,to}; + int n = controlPoint.length - 1; + int i, r; + List bezierPoints = new ArrayList<>(); + for (u = 0; u <= 1; u += 0.01) { + Vec2f[] p = new Vec2f[n + 1]; + for (i = 0; i <= n; i++) { + p[i] = new Vec2f(controlPoint[i].x, controlPoint[i].y); + } + for (r = 1; r <= n; r++) { + for (i = 0; i <= n - r; i++) { + p[i] = new Vec2f((1 - u) * p[i].x + u * p[i + 1].x, (1 - u) * p[i].y + u * p[i + 1].y); + } + } + bezierPoints.add(p[0]); + } + return bezierPoints; } @SideOnly(Side.CLIENT) diff --git a/src/main/java/gregtech/api/gui/impl/ModularUIGuiHandler.java b/src/main/java/gregtech/api/gui/impl/ModularUIGuiHandler.java index b2de47b31dd..14890e9a66c 100644 --- a/src/main/java/gregtech/api/gui/impl/ModularUIGuiHandler.java +++ b/src/main/java/gregtech/api/gui/impl/ModularUIGuiHandler.java @@ -6,13 +6,11 @@ import gregtech.api.gui.ingredient.IRecipeTransferHandlerWidget; import mezz.jei.api.gui.IAdvancedGuiHandler; import mezz.jei.api.gui.IGhostIngredientHandler; -import mezz.jei.api.gui.IGuiIngredient; import mezz.jei.api.gui.IRecipeLayout; import mezz.jei.api.recipe.transfer.IRecipeTransferError; import mezz.jei.api.recipe.transfer.IRecipeTransferHandler; import mezz.jei.api.recipe.transfer.IRecipeTransferHandlerHelper; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.ItemStack; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -51,9 +49,7 @@ public IRecipeTransferError transferRecipe(ModularUIContainer container, @Nonnul if (!transferHandler.isPresent()) { return transferHelper.createInternalError(); } - Map> group = new HashMap<>(recipeLayout.getItemStacks().getGuiIngredients()); - group.values().removeIf(it -> it.getAllIngredients().isEmpty()); - String errorTooltip = transferHandler.get().transferRecipe(container, group, player, maxTransfer, doTransfer); + String errorTooltip = transferHandler.get().transferRecipe(container, recipeLayout, player, maxTransfer, doTransfer); if (errorTooltip == null) { return null; } diff --git a/src/main/java/gregtech/api/gui/ingredient/IRecipeTransferHandlerWidget.java b/src/main/java/gregtech/api/gui/ingredient/IRecipeTransferHandlerWidget.java index ed2907ef0e0..20f451a8ac2 100644 --- a/src/main/java/gregtech/api/gui/ingredient/IRecipeTransferHandlerWidget.java +++ b/src/main/java/gregtech/api/gui/ingredient/IRecipeTransferHandlerWidget.java @@ -2,6 +2,7 @@ import gregtech.api.gui.impl.ModularUIContainer; import mezz.jei.api.gui.IGuiIngredient; +import mezz.jei.api.gui.IRecipeLayout; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; @@ -9,5 +10,5 @@ public interface IRecipeTransferHandlerWidget { - String transferRecipe(ModularUIContainer container, Map> ingredients, EntityPlayer player, boolean maxTransfer, boolean doTransfer); + String transferRecipe(ModularUIContainer container, IRecipeLayout recipeLayout, EntityPlayer player, boolean maxTransfer, boolean doTransfer); } diff --git a/src/main/java/gregtech/api/gui/resources/FileTexture.java b/src/main/java/gregtech/api/gui/resources/FileTexture.java index d45ad7e372b..5fdd0336f10 100644 --- a/src/main/java/gregtech/api/gui/resources/FileTexture.java +++ b/src/main/java/gregtech/api/gui/resources/FileTexture.java @@ -97,7 +97,7 @@ public void draw(double x, double y, int width, int height) { } else { this.loadFile(); int s = (int) Math.floorMod(System.currentTimeMillis() / 200, 24); - Widget.renderSector((float)(x + width / 2.0), (float)(y + height / 2.0), (float)(Math.min(width, height) / 4.0), + Widget.drawSector((float)(x + width / 2.0), (float)(y + height / 2.0), (float)(Math.min(width, height) / 4.0), 0xFF94E2C1, 24, s, s + 5); } } diff --git a/src/main/java/gregtech/api/gui/resources/URLTexture.java b/src/main/java/gregtech/api/gui/resources/URLTexture.java index 94cc92eaa4c..1f2a413e83a 100644 --- a/src/main/java/gregtech/api/gui/resources/URLTexture.java +++ b/src/main/java/gregtech/api/gui/resources/URLTexture.java @@ -41,7 +41,7 @@ public void draw(double x, double y, int width, int height) { } else { this.loadTexture(); int s = (int) Math.floorMod(System.currentTimeMillis() / 200, 24); - Widget.renderSector((float)(x + width / 2.0), (float)(y + height / 2.0), (float)(Math.min(width, height) / 4.0), + Widget.drawSector((float)(x + width / 2.0), (float)(y + height / 2.0), (float)(Math.min(width, height) / 4.0), 0xFF94E2C1, 24, s, s + 5); } } diff --git a/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java b/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java index 269666d0a90..9c2c75af9c6 100644 --- a/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java +++ b/src/main/java/gregtech/api/gui/widgets/AbstractWidgetGroup.java @@ -42,8 +42,8 @@ public List getContainedWidgets(boolean includeHidden) { ArrayList containedWidgets = new ArrayList<>(widgets.size()); for (Widget widget : widgets) { + if (!widget.isVisible() && !includeHidden) continue; containedWidgets.add(widget); - if (widget instanceof AbstractWidgetGroup) containedWidgets.addAll(((AbstractWidgetGroup) widget).getContainedWidgets(includeHidden)); } @@ -117,6 +117,27 @@ protected void addWidget(Widget widget) { } } + protected void addWidget(int index, Widget widget) { + if (widget == this) { + throw new IllegalArgumentException("Cannot add self"); + } + if (widgets.contains(widget)) { + throw new IllegalArgumentException("Already added"); + } + this.widgets.add(index, widget); + widget.setUiAccess(groupUIAccess); + widget.setGui(gui); + widget.setSizes(sizes); + widget.setParentPosition(getPosition()); + if (initialized) { + widget.initWidget(); + } + recomputeSize(); + if (uiAccess != null) { + uiAccess.notifyWidgetChange(); + } + } + protected void waitToRemoved(Widget widget) { if (waitToRemoved == null) { waitToRemoved = new ArrayList<>(); @@ -186,7 +207,7 @@ public List> getPhantomTargets(Object ingredient) { } ArrayList> targets = new ArrayList<>(); for (Widget widget : widgets) { - if (widget instanceof IGhostIngredientTarget) { + if (widget.isVisible() && widget instanceof IGhostIngredientTarget) { targets.addAll(((IGhostIngredientTarget) widget).getPhantomTargets(ingredient)); } } @@ -199,7 +220,7 @@ public Object getIngredientOverMouse(int mouseX, int mouseY) { return Collections.emptyList(); } for (Widget widget : widgets) { - if (widget instanceof IIngredientSlot) { + if (widget.isVisible() && widget instanceof IIngredientSlot) { IIngredientSlot ingredientSlot = (IIngredientSlot) widget; Object result = ingredientSlot.getIngredientOverMouse(mouseX, mouseY); if (result != null) return result; diff --git a/src/main/java/gregtech/api/gui/widgets/PhantomFluidWidget.java b/src/main/java/gregtech/api/gui/widgets/PhantomFluidWidget.java index 6fa9bf5dbf0..9a0430674ad 100644 --- a/src/main/java/gregtech/api/gui/widgets/PhantomFluidWidget.java +++ b/src/main/java/gregtech/api/gui/widgets/PhantomFluidWidget.java @@ -11,7 +11,10 @@ import gregtech.api.gui.resources.TextureArea; import gregtech.api.util.Position; import gregtech.api.util.Size; +import gregtech.api.util.TextFormattingUtil; import mezz.jei.api.gui.IGhostIngredientHandler.Target; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; @@ -37,6 +40,7 @@ public class PhantomFluidWidget extends Widget implements IIngredientSlot, IGhos private Supplier fluidStackSupplier; private Consumer fluidStackUpdater; private boolean isClient; + private boolean showTip; protected FluidStack lastFluidStack; public PhantomFluidWidget(int xPosition, int yPosition, int width, int height, Supplier fluidStackSupplier, Consumer fluidStackUpdater) { @@ -54,6 +58,10 @@ private FluidStack drainFrom(Object ingredient) { } return null; } + public PhantomFluidWidget showTip(boolean showTip) { + this.showTip = showTip; + return this; + } public PhantomFluidWidget setFluidStackSupplier(Supplier fluidStackSupplier, boolean isClient) { this.fluidStackSupplier = fluidStackSupplier; @@ -201,6 +209,14 @@ public void drawInBackground(int mouseX, int mouseY, IRenderContext context) { if (lastFluidStack != null) { GlStateManager.disableBlend(); RenderUtil.drawFluidForGui(lastFluidStack, lastFluidStack.amount, pos.x + 1, pos.y + 1, size.width - 1, size.height - 1); + if(showTip) { + GlStateManager.pushMatrix(); + GlStateManager.scale(0.5, 0.5, 1); + String s = TextFormattingUtil.formatLongToCompactString(lastFluidStack.amount, 4) + "L"; + FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer; + fontRenderer.drawStringWithShadow(s, (pos.x + (size.width / 3)) * 2 - fontRenderer.getStringWidth(s) + 21, (pos.y + (size.height / 3) + 6) * 2, 0xFFFFFF); + GlStateManager.popMatrix(); + } GlStateManager.enableBlend(); GlStateManager.color(rColorForOverlay, gColorForOverlay, bColorForOverlay, 1.0F); } diff --git a/src/main/java/gregtech/api/gui/widgets/SimpleTextWidget.java b/src/main/java/gregtech/api/gui/widgets/SimpleTextWidget.java index aa2b296e984..9135d98dde0 100644 --- a/src/main/java/gregtech/api/gui/widgets/SimpleTextWidget.java +++ b/src/main/java/gregtech/api/gui/widgets/SimpleTextWidget.java @@ -25,6 +25,7 @@ public class SimpleTextWidget extends Widget { protected final Supplier textSupplier; protected String lastText = ""; protected boolean clientWidget; + protected boolean isShadow; public SimpleTextWidget(int xPosition, int yPosition, String formatLocale, int color, Supplier textSupplier) { super(new Position(xPosition, yPosition), Size.ZERO); @@ -45,6 +46,11 @@ public SimpleTextWidget(int xPosition, int yPosition, String formatLocale, Suppl this(xPosition, yPosition, formatLocale, 0x404040, textSupplier); } + public SimpleTextWidget setShadow(boolean shadow) { + isShadow = shadow; + return this; + } + private void updateSize() { FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer; int stringWidth = fontRenderer.getStringWidth(lastText); @@ -73,8 +79,8 @@ public void drawInBackground(int mouseX, int mouseY, IRenderContext context) { String text = formatLocale.isEmpty() ? (I18n.hasKey(lastText) ? I18n.format(lastText) : lastText) : I18n.format(formatLocale, lastText); Position position = getPosition(); fontRenderer.drawString(text, - position.x - fontRenderer.getStringWidth(text) / 2, - position.y - fontRenderer.FONT_HEIGHT / 2, color); + position.x - fontRenderer.getStringWidth(text) / 2f, + position.y - fontRenderer.FONT_HEIGHT / 2f, color, isShadow); GlStateManager.color(rColorForOverlay, gColorForOverlay, bColorForOverlay, 1.0F); } diff --git a/src/main/java/gregtech/api/gui/widgets/TabGroup.java b/src/main/java/gregtech/api/gui/widgets/TabGroup.java index ec42c11bde2..6710345c825 100644 --- a/src/main/java/gregtech/api/gui/widgets/TabGroup.java +++ b/src/main/java/gregtech/api/gui/widgets/TabGroup.java @@ -61,6 +61,10 @@ public TabGroup setOnTabChanged(BiConsumer onTabChanged) { return this; } + public AbstractWidgetGroup getCurrentTag() { + return tabWidgets.get(selectedTabIndex); + } + @Override public List getContainedWidgets(boolean includeHidden) { ArrayList containedWidgets = new ArrayList<>(widgets.size()); @@ -102,7 +106,7 @@ public void drawInForeground(int mouseX, int mouseY) { @Override public boolean mouseClicked(int mouseX, int mouseY, int button) { - super.mouseClicked(mouseX, mouseY, button); + boolean flag = super.mouseClicked(mouseX, mouseY, button); Tuple tabOnMouse = getTabOnMouse(mouseX, mouseY); if (tabOnMouse != null) { ITabInfo tabInfo = tabOnMouse.getFirst(); @@ -114,7 +118,7 @@ public boolean mouseClicked(int mouseX, int mouseY, int button) { return true; } } - return false; + return flag; } private void setSelectedTab(int tabIndex) { diff --git a/src/main/java/gregtech/api/gui/widgets/TankWidget.java b/src/main/java/gregtech/api/gui/widgets/TankWidget.java index 279599b6080..59e239c5e8d 100644 --- a/src/main/java/gregtech/api/gui/widgets/TankWidget.java +++ b/src/main/java/gregtech/api/gui/widgets/TankWidget.java @@ -49,6 +49,7 @@ public class TankWidget extends Widget implements IIngredientSlot { private FluidStack lastFluidInTank; private int lastTankCapacity; + private boolean isClient; public TankWidget(IFluidTank fluidTank, int x, int y, int width, int height) { super(new Position(x, y), new Size(width, height)); @@ -57,6 +58,11 @@ public TankWidget(IFluidTank fluidTank, int x, int y, int width, int height) { this.lastTankCapacity = fluidTank != null ? fluidTank.getCapacity() : 0; } + public TankWidget setClient() { + this.isClient = true; + return this; + } + public TankWidget setHideTooltip(boolean hideTooltip) { this.hideTooltip = hideTooltip; return this; @@ -175,6 +181,26 @@ public void drawInForeground(int mouseX, int mouseY) { } } + @Override + public void updateScreen() { + if (isClient) { + FluidStack fluidStack = fluidTank.getFluid(); + if (fluidTank.getCapacity() != lastTankCapacity) { + this.lastTankCapacity = fluidTank.getCapacity(); + } + if (fluidStack == null && lastFluidInTank != null) { + this.lastFluidInTank = null; + + } else if (fluidStack != null) { + if (!fluidStack.isFluidEqual(lastFluidInTank)) { + this.lastFluidInTank = fluidStack.copy(); + } else if (fluidStack.amount != lastFluidInTank.amount) { + this.lastFluidInTank.amount = fluidStack.amount; + } + } + } + } + @Override public void detectAndSendChanges() { FluidStack fluidStack = fluidTank.getFluid(); diff --git a/src/main/java/gregtech/api/terminal/TerminalBuilder.java b/src/main/java/gregtech/api/terminal/TerminalBuilder.java index 1023d590a7a..5ff653ade00 100644 --- a/src/main/java/gregtech/api/terminal/TerminalBuilder.java +++ b/src/main/java/gregtech/api/terminal/TerminalBuilder.java @@ -7,10 +7,9 @@ import gregtech.api.terminal.app.guide.SimpleMachineGuideApp; import gregtech.api.terminal.app.guide.TutorialGuideApp; import gregtech.api.terminal.app.guideeditor.GuideEditorApp; -import gregtech.api.terminal.app.recipegraph.RecipeGraphApp; +import gregtech.api.terminal.app.recipechart.RecipeChartApp; import java.util.*; -import java.util.stream.Collectors; public class TerminalBuilder { private static final Map appRegister = new HashMap<>(); @@ -24,7 +23,7 @@ public static void init() { registerApp(new GuideEditorApp(), true); registerApp(new ThemeSettingApp(), true); if (GTValues.isModLoaded(GTValues.MODID_JEI)) { - registerApp(new RecipeGraphApp(), true); + registerApp(new RecipeChartApp(), true); } } diff --git a/src/main/java/gregtech/api/terminal/app/AbstractApplication.java b/src/main/java/gregtech/api/terminal/app/AbstractApplication.java index 9de3df698a2..48868392bfa 100644 --- a/src/main/java/gregtech/api/terminal/app/AbstractApplication.java +++ b/src/main/java/gregtech/api/terminal/app/AbstractApplication.java @@ -42,7 +42,7 @@ public IGuiTexture getIcon() { return icon; } - public abstract AbstractApplication createApp(boolean isClient, NBTTagCompound nbt); + public abstract AbstractApplication createApp(TerminalOSWidget os, boolean isClient, NBTTagCompound nbt); public NBTTagCompound closeApp(boolean isClient, NBTTagCompound nbt) { return null; diff --git a/src/main/java/gregtech/api/terminal/app/ThemeSettingApp.java b/src/main/java/gregtech/api/terminal/app/ThemeSettingApp.java index 76ff43966e5..ae60a1f6598 100644 --- a/src/main/java/gregtech/api/terminal/app/ThemeSettingApp.java +++ b/src/main/java/gregtech/api/terminal/app/ThemeSettingApp.java @@ -11,6 +11,7 @@ import gregtech.api.terminal.gui.widgets.RectButtonWidget; import gregtech.api.terminal.gui.widgets.SelectorWidget; import gregtech.api.terminal.os.TerminalDialogWidget; +import gregtech.api.terminal.os.TerminalOSWidget; import gregtech.api.terminal.os.TerminalTheme; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.PacketBuffer; @@ -29,7 +30,7 @@ public ThemeSettingApp() { private WidgetGroup textureGroup; @Override - public AbstractApplication createApp(boolean isClient, NBTTagCompound nbt) { + public AbstractApplication createApp(TerminalOSWidget os, boolean isClient, NBTTagCompound nbt) { ThemeSettingApp app = new ThemeSettingApp(); if (isClient) { //333 232 float x = 333 * 1.0f / 13; diff --git a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java index 40bafc8205c..b44bfddf8cc 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java @@ -9,6 +9,7 @@ import gregtech.api.terminal.app.AbstractApplication; import gregtech.api.terminal.app.guide.widget.GuidePageWidget; import gregtech.api.terminal.gui.widgets.TreeListWidget; +import gregtech.api.terminal.os.TerminalOSWidget; import gregtech.api.terminal.os.menu.component.IMenuComponent; import gregtech.api.terminal.os.menu.component.SearchComponent; import gregtech.api.terminal.util.TreeNode; @@ -41,7 +42,7 @@ public GuideApp(String name, IGuiTexture icon) { } @Override - public AbstractApplication createApp(boolean isClient, NBTTagCompound nbt) { + public AbstractApplication createApp(TerminalOSWidget os, boolean isClient, NBTTagCompound nbt) { try { GuideApp app = this.getClass().newInstance(); app.ROOT = ROOT; diff --git a/src/main/java/gregtech/api/terminal/app/guideeditor/GuideEditorApp.java b/src/main/java/gregtech/api/terminal/app/guideeditor/GuideEditorApp.java index b637da3bba7..c9129d5d5f2 100644 --- a/src/main/java/gregtech/api/terminal/app/guideeditor/GuideEditorApp.java +++ b/src/main/java/gregtech/api/terminal/app/guideeditor/GuideEditorApp.java @@ -1,9 +1,11 @@ package gregtech.api.terminal.app.guideeditor; +import gregtech.api.gui.GuiTextures; import gregtech.api.gui.resources.TextureArea; import gregtech.api.terminal.app.AbstractApplication; import gregtech.api.terminal.app.guideeditor.widget.GuideConfigEditor; import gregtech.api.terminal.app.guideeditor.widget.GuidePageEditorWidget; +import gregtech.api.terminal.os.TerminalOSWidget; import gregtech.api.terminal.os.menu.component.ClickComponent; import gregtech.api.terminal.os.menu.component.IMenuComponent; import net.minecraft.nbt.NBTTagCompound; @@ -15,9 +17,7 @@ public class GuideEditorApp extends AbstractApplication { public static final TextureArea ICON = TextureArea.fullImage("textures/gui/terminal/guide_editor/icon.png"); - private final static TextureArea NEW_PAGE = TextureArea.fullImage("textures/gui/terminal/terminal_new_page.png"); - private final static TextureArea IMPORT_PAGE = TextureArea.fullImage("textures/gui/terminal/terminal_import.png"); - private final static TextureArea EXPORT_PAGE = TextureArea.fullImage("textures/gui/terminal/terminal_export.png"); + private GuideConfigEditor configEditor; @@ -27,7 +27,7 @@ public GuideEditorApp() { } @Override - public AbstractApplication createApp(boolean isClient, NBTTagCompound nbt) { + public AbstractApplication createApp(TerminalOSWidget os, boolean isClient, NBTTagCompound nbt) { GuideEditorApp app = new GuideEditorApp(); if (isClient) { app.configEditor = new GuideConfigEditor(0, 0, 133, 232, app); @@ -42,17 +42,17 @@ public AbstractApplication createApp(boolean isClient, NBTTagCompound nbt) { @Override public List getMenuComponents() { - ClickComponent newPage = new ClickComponent().setIcon(NEW_PAGE).setHoverText("New Page").setClickConsumer(cd->{ + ClickComponent newPage = new ClickComponent().setIcon(GuiTextures.ICON_NEW_PAGE).setHoverText("New Page").setClickConsumer(cd->{ if (configEditor != null) { configEditor.newPage(cd); } }); - ClickComponent importPage = new ClickComponent().setIcon(IMPORT_PAGE).setHoverText("Import Page").setClickConsumer(cd->{ + ClickComponent importPage = new ClickComponent().setIcon(GuiTextures.ICON_LOAD).setHoverText("Import Page").setClickConsumer(cd->{ if (configEditor != null) { configEditor.loadJson(cd); } }); - ClickComponent exportPage = new ClickComponent().setIcon(EXPORT_PAGE).setHoverText("Export Page").setClickConsumer(cd->{ + ClickComponent exportPage = new ClickComponent().setIcon(GuiTextures.ICON_SAVE).setHoverText("Export Page").setClickConsumer(cd->{ if (configEditor != null) { configEditor.saveJson(cd); } diff --git a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/GuideConfigEditor.java b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/GuideConfigEditor.java index df797f5d4ff..d1b635ee92f 100644 --- a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/GuideConfigEditor.java +++ b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/GuideConfigEditor.java @@ -57,14 +57,14 @@ public GuideConfigEditor(int x, int y, int width, int height, GuideEditorApp app .setColors(new Color(255, 255, 255, 0).getRGB(), TerminalTheme.COLOR_7.getColor(), TerminalTheme.COLOR_4.getColor()) - .setIcon(GuiTextures.TERMINAL_ADD) + .setIcon(GuiTextures.ICON_ADD) .setHoverText("add stream") .setClickListener(this::addStream); addButton[1] = new CircleButtonWidget(115, 35, 8, 1, 8) .setColors(new Color(255, 255, 255, 0).getRGB(), TerminalTheme.COLOR_7.getColor(), TerminalTheme.COLOR_5.getColor()) - .setIcon(GuiTextures.TERMINAL_ADD) + .setIcon(GuiTextures.ICON_ADD) .setHoverText("add fixed") .setClickListener(this::addFixed); addButton[0].setVisible(false); diff --git a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/GuidePageEditorWidget.java b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/GuidePageEditorWidget.java index a2c078becb2..1c95327b26e 100644 --- a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/GuidePageEditorWidget.java +++ b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/GuidePageEditorWidget.java @@ -1,7 +1,6 @@ package gregtech.api.terminal.app.guideeditor.widget; -import com.google.gson.Gson; import com.google.gson.JsonArray; import com.google.gson.JsonObject; import gregtech.api.gui.GuiTextures; @@ -43,21 +42,21 @@ public GuidePageEditorWidget(int xPosition, int yPosition, int width, int height .setColors(new Color(255, 255, 255, 0).getRGB(), TerminalTheme.COLOR_B_2.getColor(), TerminalTheme.COLOR_1.getColor()) - .setIcon(GuiTextures.TERMINAL_UP) + .setIcon(GuiTextures.ICON_UP) .setHoverText("up") .setClickListener(this::moveUp)); toolButtons.addWidget(new CircleButtonWidget(0, -4, 8, 1, 12) .setColors(new Color(255, 255, 255, 0).getRGB(), TerminalTheme.COLOR_B_2.getColor(), TerminalTheme.COLOR_2.getColor()) - .setIcon(GuiTextures.TERMINAL_DOWN) + .setIcon(GuiTextures.ICON_DOWN) .setHoverText("down") .setClickListener(this::moveDown)); toolButtons.addWidget(new CircleButtonWidget(20, -4, 8, 1, 12) .setColors(new Color(255, 255, 255, 0).getRGB(), TerminalTheme.COLOR_B_2.getColor(), TerminalTheme.COLOR_3.getColor()) - .setIcon(GuiTextures.TERMINAL_DELETE) + .setIcon(GuiTextures.ICON_REMOVE) .setHoverText("delete") .setClickListener(this::delete)); addWidget(customPositionSizeWidget); diff --git a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/FluidStackConfigurator.java b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/FluidStackConfigurator.java index 789cf68ced8..f8380b79ca3 100644 --- a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/FluidStackConfigurator.java +++ b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/FluidStackConfigurator.java @@ -4,7 +4,6 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import gregtech.api.gui.GuiTextures; -import gregtech.api.gui.resources.ColorRectTexture; import gregtech.api.gui.resources.TextTexture; import gregtech.api.gui.widgets.*; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; @@ -90,7 +89,7 @@ private void addSlot(DraggableScrollableWidgetGroup container, TankListWidget.Fl } updateValue(); }) - .setIcon(GuiTextures.TERMINAL_DELETE)); + .setIcon(GuiTextures.ICON_REMOVE)); container.addWidget(group); } diff --git a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/ItemStackConfigurator.java b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/ItemStackConfigurator.java index e20b218cbab..99b0c7d9f42 100644 --- a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/ItemStackConfigurator.java +++ b/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/ItemStackConfigurator.java @@ -4,7 +4,6 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import gregtech.api.gui.GuiTextures; -import gregtech.api.gui.resources.ColorRectTexture; import gregtech.api.gui.resources.TextTexture; import gregtech.api.gui.widgets.ImageWidget; import gregtech.api.gui.widgets.PhantomSlotWidget; @@ -16,7 +15,6 @@ import gregtech.api.terminal.os.TerminalTheme; import gregtech.common.inventory.handlers.SingleItemStackHandler; import net.minecraftforge.items.IItemHandlerModifiable; -import net.minecraftforge.items.ItemStackHandler; import java.awt.*; import java.util.ArrayList; @@ -93,7 +91,7 @@ private void addSlot(DraggableScrollableWidgetGroup container, SlotListWidget.It } updateValue(); }) - .setIcon(GuiTextures.TERMINAL_DELETE)); + .setIcon(GuiTextures.ICON_REMOVE)); container.addWidget(group); } diff --git a/src/main/java/gregtech/api/terminal/app/recipechart/RecipeChartApp.java b/src/main/java/gregtech/api/terminal/app/recipechart/RecipeChartApp.java new file mode 100644 index 00000000000..cc96a00a73f --- /dev/null +++ b/src/main/java/gregtech/api/terminal/app/recipechart/RecipeChartApp.java @@ -0,0 +1,84 @@ +package gregtech.api.terminal.app.recipechart; + +import gregtech.api.gui.GuiTextures; +import gregtech.api.gui.Widget; +import gregtech.api.gui.impl.ModularUIContainer; +import gregtech.api.gui.ingredient.IRecipeTransferHandlerWidget; +import gregtech.api.gui.resources.TextTexture; +import gregtech.api.gui.resources.TextureArea; +import gregtech.api.gui.widgets.TabGroup; +import gregtech.api.gui.widgets.tab.IGuiTextureTabInfo; +import gregtech.api.terminal.app.AbstractApplication; +import gregtech.api.terminal.app.recipechart.widget.RGContainer; +import gregtech.api.terminal.app.recipechart.widget.RGNode; +import gregtech.api.terminal.gui.CustomTabListRenderer; +import gregtech.api.terminal.os.TerminalDialogWidget; +import gregtech.api.terminal.os.TerminalOSWidget; +import gregtech.api.terminal.os.TerminalTheme; +import gregtech.api.terminal.os.menu.component.ClickComponent; +import gregtech.api.terminal.os.menu.component.IMenuComponent; +import mezz.jei.api.gui.IRecipeLayout; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.PacketBuffer; + +import java.util.Arrays; +import java.util.List; +import java.util.function.Consumer; + +public class RecipeChartApp extends AbstractApplication implements IRecipeTransferHandlerWidget { + public static final TextureArea ICON = TextureArea.fullImage("textures/gui/terminal/recipe_graph/icon.png"); + + private TabGroup tabGroup; + + public RecipeChartApp() { + super("recipe_chart", ICON); + } + + @Override + public AbstractApplication createApp(TerminalOSWidget os, boolean isClient, NBTTagCompound nbt) { + RecipeChartApp app = new RecipeChartApp(); + if (isClient) { + app.setOs(os); + app.tabGroup = new TabGroup(0, 10, new CustomTabListRenderer(TerminalTheme.COLOR_F_2, TerminalTheme.COLOR_B_3, 60, 10)); + app.addWidget(app.tabGroup); + app.addTab("default"); + } + return app; + } + + private void addTab(String name) { + if (tabGroup != null && name != null && !name.isEmpty()) { + tabGroup.addTab(new IGuiTextureTabInfo(new TextTexture(name, -1), "Widgets Box"), + new RGContainer(0, 0, 333, 222, getOs()).setBackground(TerminalTheme.COLOR_B_3)); + } + } + + @Override + public List getMenuComponents() { + ClickComponent newPage = new ClickComponent().setIcon(GuiTextures.ICON_NEW_PAGE).setHoverText("New Page").setClickConsumer(cd->{ + TerminalDialogWidget.showTextFieldDialog(getOs(), "Page Name", s->true, this::addTab).setClientSide().open(); + }); + ClickComponent importPage = new ClickComponent().setIcon(GuiTextures.ICON_ADD).setHoverText("Add a Slot").setClickConsumer(cd->{ + if (tabGroup != null && tabGroup.getCurrentTag() instanceof RGContainer) { + ((RGContainer) tabGroup.getCurrentTag()).addNode(50, 100); + } + }); + return Arrays.asList(newPage, importPage); + } + + @Override + protected void writeClientAction(int id, Consumer packetBufferWriter) { + + } + + @Override + public String transferRecipe(ModularUIContainer container, IRecipeLayout recipeLayout, EntityPlayer player, boolean maxTransfer, boolean doTransfer) { + for (Widget widget : getContainedWidgets(false)) { + if (widget instanceof RGNode && ((RGNode) widget).transferRecipe(container, recipeLayout, player, maxTransfer, doTransfer)) { + return null; + } + } + return "please select a node."; + } +} diff --git a/src/main/java/gregtech/api/terminal/app/recipechart/widget/PhantomWidget.java b/src/main/java/gregtech/api/terminal/app/recipechart/widget/PhantomWidget.java new file mode 100644 index 00000000000..5d6fc4d9176 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/app/recipechart/widget/PhantomWidget.java @@ -0,0 +1,88 @@ +package gregtech.api.terminal.app.recipechart.widget; + +import gregtech.api.gui.Widget; +import gregtech.api.gui.ingredient.IGhostIngredientTarget; +import gregtech.api.gui.widgets.PhantomFluidWidget; +import gregtech.api.gui.widgets.PhantomSlotWidget; +import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.terminal.os.TerminalTheme; +import gregtech.common.inventory.handlers.SingleItemStackHandler; +import mezz.jei.api.gui.IGhostIngredientHandler; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.items.IItemHandlerModifiable; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.function.Consumer; + +public class PhantomWidget extends WidgetGroup implements IGhostIngredientTarget { + private final IItemHandlerModifiable itemHandler; + private FluidStack fluidStack; + private PhantomFluidWidget fluidWidget; + private PhantomSlotWidget slotWidget; + private Consumer onChanged; + + public PhantomWidget(int x, int y, Object defaultObj) { + super(x, y, 18, 18); + itemHandler = new SingleItemStackHandler(1); + fluidStack = null; + fluidWidget = new PhantomFluidWidget(0, 0, 18, 18, null, null) + .setFluidStackUpdater(fluid -> { + fluidStack = fluid.copy(); + if (fluidStack != null && fluidStack.amount > 0) { + itemHandler.setStackInSlot(0, ItemStack.EMPTY); + slotWidget.setVisible(false); + fluidWidget.setVisible(true); + if (onChanged != null) { + onChanged.accept(fluidStack); + } + } + }, true).setBackgroundTexture(TerminalTheme.COLOR_B_2).showTip(true) + .setFluidStackSupplier(() -> fluidStack,true); + slotWidget = new PhantomSlotWidget(itemHandler, 0, 0, 0); + slotWidget.setChangeListener(()-> { + if (!itemHandler.getStackInSlot(0).isEmpty()) { + fluidStack = null; + fluidWidget.setVisible(false); + slotWidget.setVisible(true); + if (onChanged != null) { + onChanged.accept(itemHandler.getStackInSlot(0)); + } + } + }).setBackgroundTexture(TerminalTheme.COLOR_B_2); + this.addWidget(fluidWidget); + this.addWidget(slotWidget); + + if (defaultObj instanceof ItemStack) { + itemHandler.setStackInSlot(0, (ItemStack) defaultObj); + fluidWidget.setVisible(false); + slotWidget.setVisible(true); + } else if (defaultObj instanceof FluidStack) { + fluidStack = (FluidStack) defaultObj; + slotWidget.setVisible(false); + fluidWidget.setVisible(true); + } + } + + public PhantomWidget setChangeListener(Consumer onChanged) { + this.onChanged = onChanged; + return this; + } + + @Override + public List> getPhantomTargets(Object ingredient) { + if (!isVisible()) { + return Collections.emptyList(); + } + ArrayList> targets = new ArrayList<>(); + for (Widget widget : widgets) { + if (widget instanceof IGhostIngredientTarget) { + targets.addAll(((IGhostIngredientTarget) widget).getPhantomTargets(ingredient)); + } + } + return targets; + } +} diff --git a/src/main/java/gregtech/api/terminal/app/recipechart/widget/RGContainer.java b/src/main/java/gregtech/api/terminal/app/recipechart/widget/RGContainer.java new file mode 100644 index 00000000000..5a92028e39b --- /dev/null +++ b/src/main/java/gregtech/api/terminal/app/recipechart/widget/RGContainer.java @@ -0,0 +1,188 @@ +package gregtech.api.terminal.app.recipechart.widget; + +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.Widget; +import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; +import gregtech.api.terminal.os.TerminalOSWidget; +import gregtech.api.terminal.os.TerminalTheme; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTBase; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraftforge.common.util.Constants; +import net.minecraftforge.fluids.FluidStack; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +public class RGContainer extends DraggableScrollableWidgetGroup { + protected TerminalOSWidget os; + private RGNode selectedNode; + private RGLine selectedLine; + private final List nodes; + private final List lines; + + public RGContainer(int x, int y, int width, int height, TerminalOSWidget os) { + super(x, y, width, height); + this.os = os; + this.setDraggable(true); + this.setXScrollBarHeight(4); + this.setYScrollBarWidth(4); + this.setXBarStyle(null, TerminalTheme.COLOR_F_1); + this.setYBarStyle(null, TerminalTheme.COLOR_F_1); + nodes = new ArrayList<>(); + lines = new ArrayList<>(); + } + + public RGNode getSelectedNode() { + return selectedNode; + } + + public void setSelectedNode(RGNode selectedNode) { + if (this.selectedNode != null) { + this.selectedNode.updateSelected(false); + } + this.selectedNode = selectedNode; + if (this.selectedNode != null) { + this.selectedNode.updateSelected(true); + } + } + + public RGLine getSelectedLine() { + return selectedLine; + } + + public void setSelectedLine(RGLine selectedLine) { + if (this.selectedLine != null) { + this.selectedLine.updateSelected(false); + } + this.selectedLine = selectedLine; + if (this.selectedLine != null) { + this.selectedLine.updateSelected(true); + } + } + + public RGNode addNode(int x, int y) { + RGNode node = new RGNode(x + getScrollXOffset(), y + getScrollYOffset(), this, null, true); + nodes.add(node); + this.addWidget(node); + return node; + } + + public RGNode addNode(int x, int y, Object object) { + RGNode node = new RGNode(x + getScrollXOffset(), y + getScrollYOffset(), this, object, false); + nodes.add(node); + this.addWidget(node); + return node; + } + + public void removeNode(RGNode node) { + nodes.remove(node); + this.waitToRemoved(node); + } + + public void updateLine(RGNode parent, RGNode child) { + this.addLine(parent, child, null); + } + + public void addLine(RGNode parent, RGNode child, ItemStack catalyst) { + Optional optional = lines.stream().filter(line -> line.getParent() == parent && line.getChild() == child).findFirst(); + if (!optional.isPresent()) { + RGLine line = new RGLine(parent, child, this, catalyst); + lines.add(line); + this.addWidget(0, line); + } else { + optional.get().updateLine(); + } + } + + public RGLine getLine(RGNode parent, RGNode child) { + Optional optional = lines.stream().filter(line -> line.getParent() == parent && line.getChild() == child).findFirst(); + return optional.orElse(null); + } + + public void removeLine(RGNode parent, RGNode child) { + lines.removeIf(line -> { + if (line.getParent() == parent && line.getChild() == child) { + RGContainer.this.waitToRemoved(line); + return true; + } + return false; + }); + } + + public void loadNBT(NBTTagCompound nbt) { + this.nodes.clear(); + NBTTagList nodesList = nbt.getTagList("nodes", Constants.NBT.TAG_COMPOUND); + for (NBTBase node : nodesList) { // build nodes + NBTTagCompound nodeTag = (NBTTagCompound)node; + NBTTagCompound headTag = nodeTag.getCompoundTag("head"); + byte type = headTag.getByte("type"); // 0-null 1-itemstack 2-fluidstack + Object head = null; + if (type == 1) { + head = new ItemStack(headTag.getCompoundTag("nbt")); + } else if (type == 2) { + head = FluidStack.loadFluidStackFromNBT(headTag.getCompoundTag("nbt")); + } + if (nodeTag.getBoolean("phantom")) { + this.nodes.add(new RGNode(nodeTag.getInteger("x"), nodeTag.getInteger("y"), this, head, true)); + } else { + this.nodes.add(new RGNode(nodeTag.getInteger("x"), nodeTag.getInteger("y"), this, head, false)); + } + } + } + + public NBTTagCompound saveAsNBT() { + + return null; + } + + @Override + protected int getMaxHeight() { + return super.getMaxHeight() + 20; + } + + @Override + protected int getMaxWidth() { + return super.getMaxWidth() + 20; + } + + @Override + protected boolean hookDrawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + if (draggedWidget != null && draggedWidget == selectedNode) { + for (RGNode node : nodes) { + if (node != selectedNode && node.canMerge(selectedNode)) { + drawBorder(node.getPosition().x, node.getPosition().y, 18, 18, 0XFF0000FF, 2); + break; + } + } + } + return super.hookDrawInBackground(mouseX, mouseY, partialTicks, context); + } + + @Override + public boolean mouseReleased(int mouseX, int mouseY, int button) { + if (draggedWidget != null && draggedWidget == selectedNode) { + for (RGNode node : nodes) { + if (node != selectedNode && node.canMerge(selectedNode)) { + node.mergeNode(selectedNode); + break; + } + } + } + return super.mouseReleased(mouseX, mouseY, button); + } + + @Override + public boolean mouseWheelMove(int mouseX, int mouseY, int wheelDelta) { + for (int i = widgets.size() - 1; i >= 0; i--) { + Widget widget = widgets.get(i); + if (widget.isVisible() && widget.isActive() && widget.mouseWheelMove(mouseX, mouseY, wheelDelta)) { + return true; + } + } + return false; + } + +} diff --git a/src/main/java/gregtech/api/terminal/app/recipechart/widget/RGLine.java b/src/main/java/gregtech/api/terminal/app/recipechart/widget/RGLine.java new file mode 100644 index 00000000000..ac12200850c --- /dev/null +++ b/src/main/java/gregtech/api/terminal/app/recipechart/widget/RGLine.java @@ -0,0 +1,191 @@ +package gregtech.api.terminal.app.recipechart.widget; + +import gregtech.api.gui.GuiTextures; +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.resources.ColorRectTexture; +import gregtech.api.gui.widgets.SimpleTextWidget; +import gregtech.api.gui.widgets.SlotWidget; +import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.terminal.gui.widgets.CircleButtonWidget; +import gregtech.api.terminal.os.TerminalDialogWidget; +import gregtech.api.terminal.os.TerminalOSWidget; +import gregtech.api.terminal.os.TerminalTheme; +import gregtech.api.util.Position; +import gregtech.api.util.Size; +import net.minecraft.item.ItemStack; +import net.minecraft.util.math.Vec2f; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.items.ItemStackHandler; + +import java.util.ArrayList; +import java.util.List; + +public class RGLine extends WidgetGroup { + protected final RGNode parent; + protected final RGNode child; + protected final ItemStack catalyst; + protected int ratio; + private boolean isSelected; + private final List points; + private final RGContainer container; + private final WidgetGroup infoGroup; + private final WidgetGroup toolGroup; + + public RGLine(RGNode parent, RGNode child, RGContainer container, ItemStack catalyst) { + super(0, 0, 0, 0); + this.parent = parent; + this.child = child; + this.container = container; + this.points = new ArrayList<>(); + this.catalyst = catalyst; + + infoGroup = new WidgetGroup(0, 0, 0, 0); + if (catalyst != null) { + ItemStackHandler handler = new ItemStackHandler(); + handler.setStackInSlot(0, catalyst); + infoGroup.addWidget(new SlotWidget(handler, 0, 0, 0, false, false).setBackgroundTexture(new ColorRectTexture(0))); + } + + infoGroup.setVisible(false); + infoGroup.setActive(false); + this.addWidget(infoGroup); + + toolGroup = new WidgetGroup(0, 0, 0, 0); + toolGroup.addWidget(new CircleButtonWidget(-8, 0, 8, 1, 12) + .setColors(0, TerminalTheme.COLOR_7.getColor(), 0) + .setIcon(GuiTextures.ICON_VISIBLE) + .setHoverText("Info Visible") + .setClickListener(cd -> { + infoGroup.setActive(!infoGroup.isActive()); + infoGroup.setVisible(!infoGroup.isVisible()); + })); + toolGroup.addWidget(new CircleButtonWidget(8, 0, 8, 1, 12) + .setColors(0, TerminalTheme.COLOR_7.getColor(), 0) + .setIcon(GuiTextures.ICON_CALCULATOR) + .setHoverText("Ratio") + .setClickListener(cd -> TerminalDialogWidget.showTextFieldDialog(container.os, "Demand", s->{ + try { + return Integer.parseInt(s) > 0; + } catch (Exception ignored){ + return false; + } + }, s -> { + if (s != null) { + ratio = Integer.parseInt(s); + parent.updateDemand(parent.getHeadDemand()); + } + }).setClientSide().open())); + toolGroup.addWidget(new SimpleTextWidget(0, -18, "", -1, () -> Integer.toString(ratio), true).setShadow(true)); + toolGroup.setVisible(false); + this.addWidget(toolGroup); + this.ratio = 1; + updateLine(); + } + + public RGNode getParent() { + return parent; + } + + public RGNode getChild() { + return child; + } + + public List getPoints() { + return points; + } + + public ItemStack getCatalyst() { + return catalyst; + } + + public void updateSelected(boolean isSelected) { + this.isSelected = isSelected; + toolGroup.setVisible(this.isSelected); + } + + public void updateLine() { + this.points.clear(); + Position pos1 = parent.getNodePosition(child); + Position pos2 = child.getNodePosition(null); + int x1, x2, y1, y2; + if (Math.abs(pos1.x - pos2.x) > Math.abs(pos1.y - pos2.y)) { + if (pos1.x > pos2.x) { + x1 = pos1.x; + y1 = pos1.y + 9; + x2 = pos2.x + 18; + } else { + x1 = pos1.x + 18; + y1 = pos1.y + 9; + x2 = pos2.x; + } + y2 = pos2.y + 9; + points.addAll(genBezierPoints(new Vec2f(x1, y1), new Vec2f(x2, y2), true, 0.01f)); + } else { + if (pos1.y > pos2.y) { + x1 = pos1.x + 9; + y1 = pos1.y; + y2 = pos2.y + 18; + } else { + x1 = pos1.x + 9; + y1 = pos1.y + 18; + y2 = pos2.y; + } + x2 = pos2.x + 9; + points.addAll(genBezierPoints(new Vec2f(x1, y1), new Vec2f(x2, y2), false, 0.01f)); + } + Position position = pos2.subtract(child.getSelfPosition()); + this.setSelfPosition(new Position(Math.min(x1, x2), Math.min(y1, y2)).subtract(position)); + int width = Math.abs(x1 - x2); + int height = Math.abs(y1 - y2); + this.setSize(new Size(width, height)); + this.setVisible(true); + this.setActive(true); + toolGroup.setSelfPosition(new Position((width) / 2, 0)); + infoGroup.setSelfPosition(new Position((width - 18) / 2, (height - 18) / 2)); + } + + public boolean isMouseOver(int mouseX, int mouseY) { + if (points == null || points.size() == 0) return false; + float x = points.get(0).x; + float y = points.get(0).y; + float x2 = points.get(points.size() - 1).x; + float y2 = points.get(points.size() - 1).y; + if (mouseX >= Math.min(x, x2) && mouseY >= Math.min(y, y2) && Math.max(x, x2) > mouseX && Math.max(y, y2) > mouseY) { + for (Vec2f point : points) { + if ((mouseX - point.x) * (mouseX - point.x) + (mouseY - point.y) * (mouseY - point.y) < 4) { + return true; + } + } + } + return false; + } + + @Override + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + if (parent.isVisible() || child.isVisible()) { + if (isSelected) { + drawSolidRect(getPosition().x, getPosition().y, getSize().width, getSize().height, 0x2fffffff); + drawLines(points, 0x2fff0000, 0xffff0000, 2); + } else { + drawLines(points, 0x2fffff00, 0xff00ff00, 2); + } + Vec2f point = points.get(points.size() - 1); + drawSolidRect((int)(point.x - 1.5), (int)(point.y - 1.5), 3, 3, 0XFF00FF00); + } + super.drawInBackground(mouseX, mouseY, partialTicks, context); + } + + @Override + public boolean mouseClicked(int mouseX, int mouseY, int button) { + if (super.mouseClicked(mouseX, mouseY, button)){ + return true; + } else if (isMouseOver(mouseX, mouseY)) { + if (!isSelected) { + container.setSelectedLine(this); + } + } else if (isSelected) { + container.setSelectedLine(null); + } + return false; + } +} diff --git a/src/main/java/gregtech/api/terminal/app/recipechart/widget/RGNode.java b/src/main/java/gregtech/api/terminal/app/recipechart/widget/RGNode.java new file mode 100644 index 00000000000..5f14d453745 --- /dev/null +++ b/src/main/java/gregtech/api/terminal/app/recipechart/widget/RGNode.java @@ -0,0 +1,441 @@ +package gregtech.api.terminal.app.recipechart.widget; + +import gregtech.api.block.machines.MachineItemBlock; +import gregtech.api.gui.GuiTextures; +import gregtech.api.gui.IRenderContext; +import gregtech.api.gui.Widget; +import gregtech.api.gui.impl.ModularUIContainer; +import gregtech.api.gui.widgets.SimpleTextWidget; +import gregtech.api.gui.widgets.SlotWidget; +import gregtech.api.gui.widgets.TankWidget; +import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.SimpleMachineMetaTileEntity; +import gregtech.api.recipes.Recipe; +import gregtech.api.terminal.gui.IDraggable; +import gregtech.api.terminal.gui.widgets.CircleButtonWidget; +import gregtech.api.terminal.os.TerminalDialogWidget; +import gregtech.api.terminal.os.TerminalTheme; +import gregtech.api.util.GTUtility; +import gregtech.api.util.Position; +import gregtech.integration.jei.GTJeiPlugin; +import gregtech.integration.jei.recipe.GTRecipeWrapper; +import mezz.jei.api.gui.IRecipeLayout; +import mezz.jei.api.recipe.IFocus; +import mezz.jei.api.recipe.IRecipeCategory; +import mezz.jei.api.recipe.IRecipeWrapper; +import mezz.jei.gui.Focus; +import mezz.jei.gui.recipes.RecipeLayout; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.util.math.MathHelper; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.FluidTank; +import net.minecraftforge.fml.common.ObfuscationReflectionHelper; +import net.minecraftforge.items.ItemStackHandler; + +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; + +public class RGNode extends WidgetGroup implements IDraggable { + protected Object head; + protected int recipePer; + private boolean isSelected; + private WidgetGroup toolGroup; + private WidgetGroup inputsGroup; + private RGContainer container; + protected Map parentNodes; + protected Map> children; + + public RGNode(int x, int y, RGContainer container, Object head, boolean isPhantom) { + super(x, y, 18, 18); + init(container); + this.head = head; + if (isPhantom) { + this.addWidget(new PhantomWidget(0, 0, head).setChangeListener(object -> RGNode.this.head = object)); + toolGroup.addWidget(new CircleButtonWidget(-11, 49, 8, 1, 12) + .setColors(0, TerminalTheme.COLOR_7.getColor(), 0) + .setIcon(GuiTextures.ICON_CALCULATOR) + .setHoverText("Calculator") + .setClickListener(cd -> TerminalDialogWidget.showTextFieldDialog(container.os, "Demand", s->{ + try { + return Integer.parseInt(s) > 0; + } catch (Exception ignored){ + return false; + } + }, s -> { + if (s != null) { + updateDemand(Integer.parseInt(s)); + } + }).setClientSide().open())); + } else { + if (head instanceof ItemStack) { + ItemStackHandler handler = new ItemStackHandler(1); + handler.setStackInSlot(0, (ItemStack) head); + this.addWidget(new SlotWidget(handler, 0, 0, 0, false, false).setBackgroundTexture(TerminalTheme.COLOR_B_2)); + } else if (head instanceof FluidStack) { + FluidTank tank = new FluidTank((FluidStack) head, Integer.MAX_VALUE); + this.addWidget(new TankWidget(tank, 0, 0, 18, 18).setAlwaysShowFull(true).setBackgroundTexture(TerminalTheme.COLOR_B_2).setClient()); + } + } + } + + private void init(RGContainer container) { + this.container = container; + SimpleTextWidget textWidget = new SimpleTextWidget(9, -5, "", -1, () -> { + if (head instanceof ItemStack) { + return ((ItemStack) head).getDisplayName(); + } else if (head instanceof FluidStack) { + return ((FluidStack) head).getLocalizedName(); + } + return "Drag ingredients into slot."; + }, true).setShadow(true); + textWidget.setVisible(false); + this.addWidget(textWidget); + inputsGroup = new WidgetGroup(0, 0, 0, 0); + this.addWidget(inputsGroup); + toolGroup = new WidgetGroup(0, 0, 0, 0); + this.addWidget(toolGroup); + toolGroup.addWidget(new CircleButtonWidget(-11, 9, 8, 1, 12) + .setColors(0, TerminalTheme.COLOR_7.getColor(), TerminalTheme.COLOR_3.getColor()) + .setIcon(GuiTextures.ICON_REMOVE) + .setHoverText("remove") + .setClickListener(cd -> remove())); + toolGroup.addWidget(new CircleButtonWidget(-11, 29, 8, 1, 12) + .setColors(0, TerminalTheme.COLOR_7.getColor(), 0) + .setIcon(GuiTextures.ICON_VISIBLE) + .setHoverText("Text Visible") + .setClickListener(cd -> { + textWidget.setActive(!textWidget.isActive()); + textWidget.setVisible(!textWidget.isVisible()); + })); + toolGroup.addWidget(new CircleButtonWidget(9, 29, 8, 1, 12) + .setColors(0, TerminalTheme.COLOR_7.getColor(), 0) + .setIcon(GuiTextures.ICON_LOCATION) + .setHoverText("JEI Focus") + .setClickListener(cd -> { + if (GTJeiPlugin.jeiRuntime != null && head != null) { + GTJeiPlugin.jeiRuntime.getRecipesGui().show(new Focus<>(IFocus.Mode.OUTPUT, head)); + } + })); + inputsGroup.setVisible(false); + inputsGroup.setActive(false); + toolGroup.setVisible(false); + toolGroup.setActive(false); + parentNodes = new HashMap<>(); + children = new HashMap<>(); + } + + public int getHeadDemand() { + if (head instanceof ItemStack) { + return ((ItemStack) head).getCount(); + } else if (head instanceof FluidStack) { + return ((FluidStack) head).amount; + } + return 0; + } + + public int getChildDemand(RGNode child) { + for (Map.Entry> entry : children.entrySet()) { + if (entry.getValue().contains(child)) { + int perC = 0; + if (entry.getKey() instanceof SlotWidget) { + perC = ((SlotWidget) entry.getKey()).getHandle().getStack().getCount(); + } else if(entry.getKey() instanceof TankWidget) { + perC = ((TankWidget) entry.getKey()).fluidTank.getFluidAmount(); + } + int ratioSum = entry.getValue().stream().mapToInt(it->container.getLine(RGNode.this, it).ratio).sum(); + return MathHelper.ceil(perC * MathHelper.ceil(getHeadDemand() / (float)recipePer) * container.getLine(RGNode.this, child).ratio / (float)ratioSum); + } + } + return 0; + } + + public boolean canMerge(RGNode node) { + if (this.head instanceof ItemStack && node.head instanceof ItemStack && ((ItemStack) this.head).isItemEqual((ItemStack) node.head)) { + Position pos1 = this.getPosition(); + Position pos2 = node.getPosition(); + return Math.abs(pos1.x - pos2.x) < 18 && Math.abs(pos1.y - pos2.y) < 18; + } else if (this.head instanceof FluidStack && node.head instanceof FluidStack && ((FluidStack) this.head).isFluidEqual((FluidStack) node.head)) { + Position pos1 = this.getPosition(); + Position pos2 = node.getPosition(); + return Math.abs(pos1.x - pos2.x) < 18 && Math.abs(pos1.y - pos2.y) < 18; + } + return false; + } + + public void mergeNode(RGNode node) { + for (RGNode parentNode : node.parentNodes.keySet()) { + for (Set value : parentNode.children.values()) { + if (value.remove(node)) { + value.add(this); + addParent(parentNode, container.getLine(parentNode, node).getCatalyst()); + break; + } + } + } + node.remove(); + } + + public void remove() { + if (isSelected) { + container.setSelectedNode(null); + } + container.removeNode(this); + for (RGNode parentNode : parentNodes.keySet()) { + container.removeLine(parentNode, this); + parentNode.onChildRemoved(this); + } + parentNodes.clear(); + for (Set childs : children.values()) { + for (RGNode child : childs) { + child.removeParent(this); + } + } + children.clear(); + } + + public Position getNodePosition(RGNode child) { + if (child != null && isSelected) { + for (Map.Entry> nodeEntry : children.entrySet()) { + if (nodeEntry.getValue().contains(child)) { + return nodeEntry.getKey().getPosition(); + } + } + } + return this.getPosition(); + } + + public void addParent(RGNode parent, ItemStack catalyst) { + container.addLine(parent, this, catalyst); + this.parentNodes.put(parent, parent.getChildDemand(this)); + updateDemand(parentNodes.values().stream().mapToInt(it->it).sum()); + } + + public void updateDemand(int demand) { + if (head instanceof ItemStack) { + ((ItemStack) head).setCount(demand); + } else if (head instanceof FluidStack) { + ((FluidStack) head).amount = demand; + } + for (Set children : children.values()) { + for (RGNode child : children) { + child.parentNodes.put(this, this.getChildDemand(child)); + child.updateDemand(child.parentNodes.values().stream().mapToInt(it->it).sum()); + } + } + } + + public void removeParent(RGNode parent) { + this.parentNodes.remove(parent); + if (parentNodes.size() == 0) { + for (Set childs : children.values()) { + for (RGNode child : childs) { + child.removeParent(RGNode.this); + } + } + children.clear(); + container.removeNode(this); + } else { + updateDemand(parentNodes.values().stream().mapToInt(it->it).sum()); + } + container.removeLine(parent, this); + } + + public void onChildRemoved(RGNode child) { + for (Set childs : children.values()) { + if (childs.remove(child)) { + updateDemand(getHeadDemand()); + break; + } + } + } + + @Override + protected void onPositionUpdate() { + super.onPositionUpdate(); + for (RGNode parentNode : parentNodes.keySet()) { + container.updateLine(parentNode, this); + } + for (Set childs : children.values()) { + for (RGNode child : childs) { + container.updateLine(this, child); + } + } + } + + public boolean transferRecipe(ModularUIContainer x, IRecipeLayout recipeLayout, EntityPlayer player, boolean maxTransfer, boolean doTransfer) { + if (isSelected) { + Object obj = recipeLayout.getFocus() == null ? null : recipeLayout.getFocus().getValue(); + if (head instanceof ItemStack && obj instanceof ItemStack) { + if(!((ItemStack) head).isItemEqual((ItemStack) obj)) { + return false; + } + } else if (head instanceof FluidStack && obj instanceof FluidStack) { + if(!((FluidStack) head).isFluidEqual((FluidStack)obj)) { + return false; + } + } else { + return false; + } + if (!doTransfer) return true; + inputsGroup.clearAllWidgets(); + for (Set childs : children.values()) { + for (RGNode child : childs) { + child.removeParent(this); + } + } + children.clear(); + AtomicInteger y = new AtomicInteger(-20); + recipeLayout.getItemStacks().getGuiIngredients().values().stream().filter(it -> it.getDisplayedIngredient() != null && it.isInput()).forEach(it -> { + ItemStackHandler handler = new ItemStackHandler(1); + handler.setStackInSlot(0, it.getDisplayedIngredient()); + Widget widget = new SlotWidget(handler, 0, 0, y.addAndGet(20), false, false) { + @Override + public boolean mouseClicked(int mouseX, int mouseY, int button) { + return RGNode.this.handleTipsSlotClick(mouseX, mouseY, recipeLayout,this, handler.getStackInSlot(0).copy()); + } + }.setBackgroundTexture(TerminalTheme.COLOR_B_2); + inputsGroup.addWidget(widget); + children.put(widget, new HashSet<>()); + }); + recipeLayout.getFluidStacks().getGuiIngredients().values().stream().filter(it -> it.getDisplayedIngredient() != null && it.isInput()).forEach(it -> { + FluidTank tank = new FluidTank(it.getDisplayedIngredient(), Integer.MAX_VALUE); + Widget widget = new TankWidget(tank, 0, y.addAndGet(20), 18, 18) { + @Override + public boolean mouseClicked(int mouseX, int mouseY, int button) { + return RGNode.this.handleTipsSlotClick(mouseX, mouseY, recipeLayout,this, tank.getFluid().copy()); + } + }.setAlwaysShowFull(true).setBackgroundTexture(TerminalTheme.COLOR_B_2); + inputsGroup.addWidget(widget); + children.put(widget, new HashSet<>()); + }); + inputsGroup.setSelfPosition(new Position(25, -(inputsGroup.widgets.size() * 20) / 2 + 8)); + if (head instanceof ItemStack) { + recipeLayout.getItemStacks().getGuiIngredients().values().stream().anyMatch(it->{ + if (!it.isInput()) { + for (ItemStack ingredient : it.getAllIngredients()) { + if (((ItemStack) head).isItemEqual(ingredient)) { + RGNode.this.recipePer = ingredient.getCount(); + return true; + } + } + } + return false; + }); + } else if (head instanceof FluidStack) { + recipeLayout.getFluidStacks().getGuiIngredients().values().stream().anyMatch(it->{ + if (!it.isInput()) { + for (FluidStack ingredient : it.getAllIngredients()) { + if (((FluidStack) head).isFluidEqual(ingredient)) { + RGNode.this.recipePer = ingredient.amount; + return true; + } + } + } + return false; + }); + } + return true; + } + return false; + } + + private boolean handleTipsSlotClick(int mouseX, int mouseY, IRecipeLayout recipeLayout, Widget slot, Object object){ + if (slot.isMouseOverElement(mouseX, mouseY)) { + Position position = inputsGroup.getSelfPosition(); + RGNode child = container.addNode(RGNode.this.getSelfPosition().x + 50, RGNode.this.getSelfPosition().y + position.y + slot.getSelfPosition().y, object); + Set childs = RGNode.this.children.get(slot); + childs.add(child); + + // CHECK GTCE RECIPES + Recipe recipe = null; + if (recipeLayout instanceof RecipeLayout) { + IRecipeWrapper recipeWrapper = ObfuscationReflectionHelper.getPrivateValue(RecipeLayout.class, (RecipeLayout)recipeLayout, "recipeWrapper"); + if (recipeWrapper instanceof GTRecipeWrapper) { + recipe = ((GTRecipeWrapper) recipeWrapper).getRecipe(); + } + } + IRecipeCategory category = recipeLayout.getRecipeCategory(); + List catalysts = GTJeiPlugin.jeiRuntime.getRecipeRegistry().getRecipeCatalysts(category); + ItemStack catalyst = null; + + if (recipe != null) { // GT + int tierRequire = GTUtility.getTierByVoltage(recipe.getEUt()); + for (Object o : catalysts) { + if (o instanceof ItemStack) { + MetaTileEntity mte = MachineItemBlock.getMetaTileEntity((ItemStack) o); + if (mte instanceof SimpleMachineMetaTileEntity) { + if (tierRequire < ((SimpleMachineMetaTileEntity) mte).getTier()) { + catalyst = (ItemStack) o; + break; + } + } + } + } + } + + if (catalyst == null) { + for (Object o : catalysts) { + if (o instanceof ItemStack) { + catalyst = (ItemStack) o; + break; + } + } + } + + child.addParent(RGNode.this, catalyst); + RGNode.this.updateDemand(RGNode.this.getHeadDemand()); + return true; + } + return false; + } + + public void updateSelected(boolean selected) { + isSelected = selected; + if (selected) { + toolGroup.setActive(true); + toolGroup.setVisible(true); + inputsGroup.setActive(true); + inputsGroup.setVisible(true); + } else { + toolGroup.setActive(false); + toolGroup.setVisible(false); + inputsGroup.setActive(false); + inputsGroup.setVisible(false); + } + children.forEach((widget, rgNode) -> rgNode.forEach(child -> container.updateLine(RGNode.this, child))); + } + + @Override + public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + int x = getPosition().x; + int y = getPosition().y; + int width = getSize().width; + int height = getSize().height; + if (isSelected) { + drawBorder(x, y, width, height, 0xff00ff00, 2); + } + super.drawInBackground(mouseX, mouseY, partialTicks, context); + } + + @Override + public boolean allowDrag(int mouseX, int mouseY, int button) { + return isMouseOverElement(mouseX, mouseY); + } + + @Override + public boolean mouseClicked(int mouseX, int mouseY, int button) { + if (isMouseOverElement(mouseX, mouseY)) { + if (!isSelected) { + container.setSelectedNode(this); + } + return false; + } else if (super.mouseClicked(mouseX, mouseY, button)) { + return true; + } else if (isSelected) { + container.setSelectedNode(null); + } + return false; + } +} diff --git a/src/main/java/gregtech/api/terminal/app/recipegraph/RecipeGraphApp.java b/src/main/java/gregtech/api/terminal/app/recipegraph/RecipeGraphApp.java deleted file mode 100644 index ad830274fc8..00000000000 --- a/src/main/java/gregtech/api/terminal/app/recipegraph/RecipeGraphApp.java +++ /dev/null @@ -1,36 +0,0 @@ -package gregtech.api.terminal.app.recipegraph; - -import gregtech.api.gui.resources.TextureArea; -import gregtech.api.terminal.app.AbstractApplication; -import gregtech.api.terminal.app.recipegraph.widget.RGContainer; -import gregtech.api.terminal.app.recipegraph.widget.RGNode; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.network.PacketBuffer; - -import java.util.function.Consumer; - -public class RecipeGraphApp extends AbstractApplication { - public static final TextureArea ICON = TextureArea.fullImage("textures/gui/terminal/recipe_graph/icon.png"); - - private RGContainer container; - - public RecipeGraphApp() { - super("recipe_graph", ICON); - } - - @Override - public AbstractApplication createApp(boolean isClient, NBTTagCompound nbt) { - RecipeGraphApp app = new RecipeGraphApp(); - if (isClient) { - app.container = new RGContainer(0,0,333, 232); - app.addWidget(app.container); - app.container.addWidget(new RGNode(10,10)); - } - return app; - } - - @Override - protected void writeClientAction(int id, Consumer packetBufferWriter) { - - } -} diff --git a/src/main/java/gregtech/api/terminal/app/recipegraph/widget/RGContainer.java b/src/main/java/gregtech/api/terminal/app/recipegraph/widget/RGContainer.java deleted file mode 100644 index 0626c57334a..00000000000 --- a/src/main/java/gregtech/api/terminal/app/recipegraph/widget/RGContainer.java +++ /dev/null @@ -1,27 +0,0 @@ -package gregtech.api.terminal.app.recipegraph.widget; - -import gregtech.api.gui.Widget; -import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; -import gregtech.api.terminal.os.TerminalTheme; - -public class RGContainer extends DraggableScrollableWidgetGroup { - public RGContainer(int x, int y, int width, int height) { - super(x, y, width, height); - this.setDraggable(true); - this.setXScrollBarHeight(4); - this.setYScrollBarWidth(4); - this.setXBarStyle(null, TerminalTheme.COLOR_F_1); - this.setYBarStyle(null, TerminalTheme.COLOR_F_1); - } - - @Override - public boolean mouseWheelMove(int mouseX, int mouseY, int wheelDelta) { - for (int i = widgets.size() - 1; i >= 0; i--) { - Widget widget = widgets.get(i); - if(widget.isVisible() && widget.isActive() && widget.mouseWheelMove(mouseX, mouseY, wheelDelta)) { - return true; - } - } - return false; - } -} diff --git a/src/main/java/gregtech/api/terminal/app/recipegraph/widget/RGNode.java b/src/main/java/gregtech/api/terminal/app/recipegraph/widget/RGNode.java deleted file mode 100644 index 34ccbc08d54..00000000000 --- a/src/main/java/gregtech/api/terminal/app/recipegraph/widget/RGNode.java +++ /dev/null @@ -1,40 +0,0 @@ -package gregtech.api.terminal.app.recipegraph.widget; - -import gregtech.api.gui.IRenderContext; -import gregtech.api.gui.widgets.PhantomSlotWidget; -import gregtech.api.gui.widgets.SimpleTextWidget; -import gregtech.api.gui.widgets.WidgetGroup; -import gregtech.api.terminal.gui.IDraggable; -import gregtech.api.terminal.os.TerminalTheme; -import gregtech.common.inventory.handlers.SingleItemStackHandler; -import net.minecraftforge.items.IItemHandlerModifiable; - -public class RGNode extends WidgetGroup implements IDraggable { - IItemHandlerModifiable itemHandler = new SingleItemStackHandler(1); - - public RGNode(int x, int y) { - super(x, y, 50, 40); - this.addWidget(new SimpleTextWidget(25, 5, "", -1, () -> itemHandler.getStackInSlot(0).getDisplayName(), true)); - this.addWidget(new PhantomSlotWidget(itemHandler, 0, 0, 20) - .setChangeListener(this::onItemChanged) - .setBackgroundTexture(TerminalTheme.COLOR_B_2)); - } - - private void onItemChanged() { - } - - @Override - public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { - int x = getPosition().x; - int y = getPosition().y; - int width = getSize().width; - int height = getSize().height; - drawSolidRect(x, y, width, height, TerminalTheme.COLOR_B_1.color); - super.drawInBackground(mouseX, mouseY, partialTicks, context); - } - - @Override - public boolean allowDrag(int mouseX, int mouseY, int button) { - return isMouseOverElement(mouseX, mouseY); - } -} diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java b/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java index fecc42d1dfe..5e508518c45 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/CircleButtonWidget.java @@ -3,10 +3,8 @@ import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; import gregtech.api.gui.resources.IGuiTexture; -import gregtech.api.gui.resources.RenderUtil; import gregtech.api.util.Position; import gregtech.api.util.Size; -import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.resources.I18n; import net.minecraft.item.ItemStack; import net.minecraft.network.PacketBuffer; @@ -15,7 +13,6 @@ import java.awt.*; import java.util.Collections; import java.util.function.Consumer; -import java.util.function.Supplier; public class CircleButtonWidget extends Widget { protected int border; @@ -104,12 +101,12 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender int y = this.getPosition().y + r; int segments = 24; - renderCircle(x, y, r, colors[0], segments); + drawTorus(x, y, r, r - border, colors[0], segments, 0, segments); isHover = this.isMouseOverElement(mouseX, mouseY); if (isHover || hoverTick != 0) { - renderSector(x, y, r, colors[1], segments, 0, (int) (segments * ((hoverTick + partialTicks) / 8))); + drawTorus(x, y, r, r - border, colors[1], segments, 0, (int) (segments * ((hoverTick + partialTicks) / 8))); } - renderCircle(x, y, r - border, colors[2], segments); + drawCircle(x, y, r - border, colors[2], segments); if (isHover && hover != null) { hover.draw(x - iconSize / 2f, y - iconSize / 2f, iconSize, iconSize); } diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java b/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java index ca45a5e71fe..677352b0ff6 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java @@ -29,13 +29,13 @@ public class DraggableScrollableWidgetGroup extends WidgetGroup { protected IGuiTexture yBarB; protected IGuiTexture yBarF; protected boolean focus; + protected Widget draggedWidget; private int lastMouseX; private int lastMouseY; private boolean draggedPanel; private boolean draggedOnXScrollBar; private boolean draggedOnYScrollBar; - private Widget draggedWidget; public DraggableScrollableWidgetGroup(int x, int y, int width, int height) { @@ -288,7 +288,7 @@ private boolean checkClickedDragged(int mouseX, int mouseY, int button) { } else if (widget instanceof IDraggable && ((IDraggable) widget).allowDrag(mouseX, mouseY, button)) { draggedWidget = widget; ((IDraggable) widget).startDrag(mouseX, mouseY); - return false; + return true; } } } diff --git a/src/main/java/gregtech/api/terminal/os/TerminalDesktopWidget.java b/src/main/java/gregtech/api/terminal/os/TerminalDesktopWidget.java index 2858b5b2fe0..caecc8b6fb9 100644 --- a/src/main/java/gregtech/api/terminal/os/TerminalDesktopWidget.java +++ b/src/main/java/gregtech/api/terminal/os/TerminalDesktopWidget.java @@ -25,9 +25,9 @@ public void installApplication(AbstractApplication application){ int x = this.getSize().width / 2 + (3 * r) * (index - 3); int y = (index / 7) * (3 * r) + 40; CircleButtonWidget button = new CircleButtonWidget(x,y) - .setColors(TerminalTheme.COLOR_B_1.getColor(), + .setColors(TerminalTheme.COLOR_B_2.getColor(), TerminalTheme.COLOR_F_1.getColor(), - new Color(206, 206, 206).getRGB()) + TerminalTheme.COLOR_B_2.getColor()) .setIcon(application.getIcon()) .setHoverText(application.getUnlocalizedName()); button.setClickListener(clickData -> os.openApplication(application, clickData.isClient)); diff --git a/src/main/java/gregtech/api/terminal/os/TerminalDialogWidget.java b/src/main/java/gregtech/api/terminal/os/TerminalDialogWidget.java index 41b278c9638..cd9435d2bae 100644 --- a/src/main/java/gregtech/api/terminal/os/TerminalDialogWidget.java +++ b/src/main/java/gregtech/api/terminal/os/TerminalDialogWidget.java @@ -24,12 +24,12 @@ public class TerminalDialogWidget extends AnimaWidgetGroup { private static final IGuiTexture DIALOG_BACKGROUND = TextureArea.fullImage("textures/gui/terminal/terminal_dialog.png"); - private static final IGuiTexture OK_NORMAL = TextureArea.fullImage("textures/gui/terminal/ok_normal.png"); - private static final IGuiTexture OK_HOVER = TextureArea.fullImage("textures/gui/terminal/ok_hover.png"); - private static final IGuiTexture OK_DISABLE = TextureArea.fullImage("textures/gui/terminal/ok_disable.png"); - private static final IGuiTexture CANCEL_NORMAL = TextureArea.fullImage("textures/gui/terminal/cancel_normal.png"); - private static final IGuiTexture CANCEL_HOVER = TextureArea.fullImage("textures/gui/terminal/cancel_hover.png"); - private static final IGuiTexture CANCEL_DISABLE = TextureArea.fullImage("textures/gui/terminal/cancel_disable.png"); + private static final IGuiTexture OK_NORMAL = TextureArea.fullImage("textures/gui/terminal/icon/ok_normal.png"); + private static final IGuiTexture OK_HOVER = TextureArea.fullImage("textures/gui/terminal/icon/ok_hover.png"); + private static final IGuiTexture OK_DISABLE = TextureArea.fullImage("textures/gui/terminal/icon/ok_disable.png"); + private static final IGuiTexture CANCEL_NORMAL = TextureArea.fullImage("textures/gui/terminal/icon/cancel_normal.png"); + private static final IGuiTexture CANCEL_HOVER = TextureArea.fullImage("textures/gui/terminal/icon/cancel_hover.png"); + private static final IGuiTexture CANCEL_DISABLE = TextureArea.fullImage("textures/gui/terminal/icon/cancel_disable.png"); private static final int HEIGHT = 128; private static final int WIDTH = 184; @@ -177,10 +177,7 @@ public static TerminalDialogWidget showFileDialog(TerminalOSWidget os, String ti } AtomicReference selected = new AtomicReference<>(); selected.set(dir); - dialog.addWidget(new TreeListWidget<>(0, 0, 130, size.height, new FileTree(dir), node -> { - selected.set(node.getKey()); - System.out.println(node.toString()); - }).setNodeTexture(GuiTextures.BORDERED_BACKGROUND) + dialog.addWidget(new TreeListWidget<>(0, 0, 130, size.height, new FileTree(dir), node -> selected.set(node.getKey())).setNodeTexture(GuiTextures.BORDERED_BACKGROUND) .canSelectNode(true) .setLeafTexture(GuiTextures.SLOT_DARKENED)); int x = 130 + (size.width - 133 - WIDTH) / 2; @@ -235,7 +232,7 @@ public static TerminalDialogWidget showFileDialog(TerminalOSWidget os, String ti dialog.addWidget(new LabelWidget(x + WIDTH / 2, y + 11, title, -1).setXCentered(true)); os.menu.hideMenu(); - return dialog; + return dialog.setClientSide(); } @Override diff --git a/src/main/java/gregtech/api/terminal/os/TerminalOSWidget.java b/src/main/java/gregtech/api/terminal/os/TerminalOSWidget.java index c580e4937ce..72bddbeab37 100644 --- a/src/main/java/gregtech/api/terminal/os/TerminalOSWidget.java +++ b/src/main/java/gregtech/api/terminal/os/TerminalOSWidget.java @@ -1,6 +1,5 @@ package gregtech.api.terminal.os; -import gregtech.api.gui.GuiTextures; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.ModularUI; import gregtech.api.gui.resources.IGuiTexture; @@ -31,7 +30,7 @@ public TerminalOSWidget(int xPosition, int yPosition, int width, int height, NBT super(new Position(xPosition, yPosition), new Size(width, height)); this.openedApps = new ArrayList<>(); this.desktop = new TerminalDesktopWidget(Position.ORIGIN, new Size(333, 232), this); - this.menu = new TerminalMenuWidget(Position.ORIGIN, new Size(31, 232), this).setBackground(GuiTextures.TERMINAL_MENU); + this.menu = new TerminalMenuWidget(Position.ORIGIN, new Size(31, 232), this).setBackground(TerminalTheme.COLOR_B_2); this.addWidget(desktop); this.addWidget(menu); this.tabletNBT = tabletNBT; @@ -70,7 +69,7 @@ public void openApplication(AbstractApplication application, boolean isClient) { return; } } - AbstractApplication app = application.createApp(isClient, tabletNBT.getCompoundTag(application.getRegistryName())).setOs(this); + AbstractApplication app = application.createApp(this, isClient, tabletNBT.getCompoundTag(application.getRegistryName())).setOs(this); if (app != null) { openedApps.add(app); desktop.addWidget(app); diff --git a/src/main/java/gregtech/api/terminal/os/menu/TerminalMenuWidget.java b/src/main/java/gregtech/api/terminal/os/menu/TerminalMenuWidget.java index 371232acded..c1e6c653425 100644 --- a/src/main/java/gregtech/api/terminal/os/menu/TerminalMenuWidget.java +++ b/src/main/java/gregtech/api/terminal/os/menu/TerminalMenuWidget.java @@ -73,8 +73,8 @@ public void addComponent(IMenuComponent component) { WidgetGroup group = new WidgetGroup(); int x = 15; int y = 40 + components.size() * 25; - CircleButtonWidget button = new CircleButtonWidget(x, y, 10, 1, 14) - .setColors(0x00FFFFFF, 0xFFFFFFFF, 0xFF505050) + CircleButtonWidget button = new CircleButtonWidget(x, y, 10, 1, 16) + .setColors(0, 0xFFFFFFFF, 0) .setHoverText(component.hoverText()) .setIcon(component.buttonIcon()); button.setClickListener(c->{ @@ -88,7 +88,7 @@ public void addComponent(IMenuComponent component) { Widget widget = (Widget)component; widget.setVisible(!widget.isVisible()); widget.setActive(!widget.isActive()); - button.setFill(widget.isVisible() ? 0xFF94E2C1 : 0xFF505050); + button.setFill(widget.isVisible() ? 0xFF94E2C1 : 0); } component.click(c); }); diff --git a/src/main/java/gregtech/api/terminal/os/menu/component/SearchComponent.java b/src/main/java/gregtech/api/terminal/os/menu/component/SearchComponent.java index 2965779861f..bedffaf158d 100644 --- a/src/main/java/gregtech/api/terminal/os/menu/component/SearchComponent.java +++ b/src/main/java/gregtech/api/terminal/os/menu/component/SearchComponent.java @@ -17,7 +17,7 @@ import java.util.List; public class SearchComponent extends WidgetGroup implements IMenuComponent{ - private final static TextureArea SEARCHING = TextureArea.fullImage("textures/gui/terminal/terminal_searching.png"); + private final static TextureArea SEARCHING = TextureArea.fullImage("textures/gui/terminal/icon/network/search_hover.png"); private final static int SIZE = 10; private final SearchEngine engine; private final List> results; diff --git a/src/main/java/gregtech/common/gui/widget/CraftingSlotWidget.java b/src/main/java/gregtech/common/gui/widget/CraftingSlotWidget.java index efc351da0ac..a17fb11d866 100644 --- a/src/main/java/gregtech/common/gui/widget/CraftingSlotWidget.java +++ b/src/main/java/gregtech/common/gui/widget/CraftingSlotWidget.java @@ -6,6 +6,7 @@ import gregtech.api.gui.widgets.SlotWidget; import gregtech.common.metatileentities.storage.CraftingRecipeResolver; import mezz.jei.api.gui.IGuiIngredient; +import mezz.jei.api.gui.IRecipeLayout; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.InventoryCraftResult; @@ -106,11 +107,12 @@ public ItemStack onItemTake(EntityPlayer thePlayer, ItemStack stack, boolean sim } @Override - public String transferRecipe(ModularUIContainer container, Map> ingredients, EntityPlayer player, boolean maxTransfer, boolean doTransfer) { + public String transferRecipe(ModularUIContainer container, IRecipeLayout recipeLayout, EntityPlayer player, boolean maxTransfer, boolean doTransfer) { if (!doTransfer) { return null; } - ingredients.values().removeIf(it -> !it.isInput()); + Map> ingredients = new HashMap<>(recipeLayout.getItemStacks().getGuiIngredients()); + ingredients.values().removeIf(it -> it.getAllIngredients().isEmpty() || !it.isInput()); writeClientAction(1, buf -> { buf.writeVarInt(ingredients.size()); for (Entry> entry : ingredients.entrySet()) { diff --git a/src/main/java/gregtech/common/items/behaviors/TerminalBehaviour.java b/src/main/java/gregtech/common/items/behaviors/TerminalBehaviour.java index 758a00fb521..255cf5a9b34 100644 --- a/src/main/java/gregtech/common/items/behaviors/TerminalBehaviour.java +++ b/src/main/java/gregtech/common/items/behaviors/TerminalBehaviour.java @@ -1,12 +1,12 @@ package gregtech.common.items.behaviors; -import gregtech.api.gui.GuiTextures; import gregtech.api.gui.ModularUI; +import gregtech.api.gui.resources.EmptyTextureArea; +import gregtech.api.gui.resources.TextureArea; import gregtech.api.gui.widgets.ImageWidget; import gregtech.api.items.gui.ItemUIFactory; import gregtech.api.items.gui.PlayerInventoryHolder; import gregtech.api.items.metaitem.stats.IItemBehaviour; -import gregtech.api.terminal.TerminalBuilder; import gregtech.api.terminal.gui.widgets.CircleButtonWidget; import gregtech.api.terminal.os.TerminalOSWidget; import gregtech.api.terminal.os.TerminalTheme; @@ -21,6 +21,8 @@ import java.util.List; public class TerminalBehaviour implements IItemBehaviour, ItemUIFactory { + private static final TextureArea TERMINAL_FRAME = TextureArea.fullImage("textures/gui/terminal/terminal_frame.png"); + @Override public ActionResult onItemRightClick(World world, EntityPlayer player, EnumHand hand) { @@ -40,14 +42,12 @@ public void addInformation(ItemStack itemStack, List lines) { public ModularUI createUI(PlayerInventoryHolder holder, EntityPlayer entityPlayer) { TerminalOSWidget os = new TerminalOSWidget(12, 11, 333, 232, holder.getCurrentItem().getOrCreateSubCompound("terminal")) .setBackground(TerminalTheme.WALL_PAPER); - CircleButtonWidget home = new CircleButtonWidget(362, 126).setIcon(GuiTextures.TERMINAL_HOME) - .setColors(new Color(82, 97, 93, 255).getRGB(), - new Color(39, 232, 141).getRGB(), - 0xff9197A5) + CircleButtonWidget home = new CircleButtonWidget(363, 126, 11, 2, 0) + .setColors(0, TerminalTheme.COLOR_F_1.getColor(), 0) .setClickListener(clickData -> os.homeTrigger(clickData.isClient)); - return ModularUI.builder(GuiTextures.TERMINAL_FRAME, 380, 256) + return ModularUI.builder(new EmptyTextureArea(380, 256), 380, 256) .widget(os) - .widget(new ImageWidget(0, 0, 380, 256, GuiTextures.TERMINAL_FRAME)) + .widget(new ImageWidget(0, 0, 380, 256, TERMINAL_FRAME)) .widget(home) .build(holder, entityPlayer); } diff --git a/src/main/java/gregtech/integration/jei/GTJeiPlugin.java b/src/main/java/gregtech/integration/jei/GTJeiPlugin.java index 3634b7a1cd1..1c85e5a0b56 100755 --- a/src/main/java/gregtech/integration/jei/GTJeiPlugin.java +++ b/src/main/java/gregtech/integration/jei/GTJeiPlugin.java @@ -39,6 +39,7 @@ import mezz.jei.api.ingredients.VanillaTypes; import mezz.jei.api.recipe.IRecipeCategoryRegistration; import mezz.jei.api.recipe.VanillaRecipeCategoryUid; +import mezz.jei.config.Constants; import net.minecraft.client.resources.I18n; import net.minecraft.item.Item; import net.minecraft.util.ResourceLocation; @@ -54,6 +55,12 @@ public class GTJeiPlugin implements IModPlugin { public static IIngredientRegistry ingredientRegistry; + public static IJeiRuntime jeiRuntime; + + @Override + public void onRuntimeAvailable(IJeiRuntime jeiRuntime) { + GTJeiPlugin.jeiRuntime = jeiRuntime; + } @Override public void registerItemSubtypes(@Nonnull ISubtypeRegistry subtypeRegistry) { @@ -94,7 +101,7 @@ public void register(IModRegistry registry) { ModularUIGuiHandler modularUIGuiHandler = new ModularUIGuiHandler(jeiHelpers.recipeTransferHandlerHelper()); registry.addAdvancedGuiHandlers(modularUIGuiHandler); registry.addGhostIngredientHandler(modularUIGuiHandler.getGuiContainerClass(), modularUIGuiHandler); - registry.getRecipeTransferRegistry().addRecipeTransferHandler(modularUIGuiHandler, VanillaRecipeCategoryUid.CRAFTING); + registry.getRecipeTransferRegistry().addRecipeTransferHandler(modularUIGuiHandler, Constants.UNIVERSAL_RECIPE_TRANSFER_UID); for (RecipeMap recipeMap : RecipeMap.getRecipeMaps()) { List recipesList = recipeMap.getRecipeList() diff --git a/src/main/java/gregtech/integration/jei/recipe/GTRecipeWrapper.java b/src/main/java/gregtech/integration/jei/recipe/GTRecipeWrapper.java index e18b4509c06..97d1def77f4 100644 --- a/src/main/java/gregtech/integration/jei/recipe/GTRecipeWrapper.java +++ b/src/main/java/gregtech/integration/jei/recipe/GTRecipeWrapper.java @@ -37,6 +37,10 @@ public GTRecipeWrapper(Recipe recipe) { this.recipe = recipe; } + public Recipe getRecipe() { + return recipe; + } + @Override public void getIngredients(@Nonnull IIngredients ingredients) { if (!recipe.getInputs().isEmpty()) { diff --git a/src/main/resources/assets/gregtech/lang/en_us.lang b/src/main/resources/assets/gregtech/lang/en_us.lang index 001249491f7..c570b97d084 100644 --- a/src/main/resources/assets/gregtech/lang/en_us.lang +++ b/src/main/resources/assets/gregtech/lang/en_us.lang @@ -3634,6 +3634,6 @@ gregtech.terminal.app_name.multiblocks=Multiblock Guides gregtech.terminal.app_name.tutorials=Tutorials gregtech.terminal.app_name.theme_settings=Theme Settings gregtech.terminal.app_name.guide_editor=Guide Editor -gregtech.terminal.app_name.recipe_graph=Recipe Graph +gregtech.terminal.app_name.recipe_chart=Recipe Chart gregtech.terminal.guide.tutorials.guide_widget_api=Guide Widget Api diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/calendar_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/calendar_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..e0747efaae65cddce576e5c52625b5945e382acc GIT binary patch literal 846 zcmV-U1F`&xP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-v$Vo&&R7i=X*1c<;brc8iPi}70v=^184GIq8Xchef9PA)e z3!>tng5t{{h;-1QjxH`miHlhT(Lqo_P!Osj4o*e7sAxO5iBnQdseMV>-g_L*d3v8* zZsODQzyrDYo!|Gof6s3wB6O5R+=Kn~`){1VYM0CX4(CVk2<|H*yX$PDjQxghaRS%2 z0-D(-q9^et9>5Um1=L)aDM#ipi(haYUv@Rr!xCP>6-9|k=4q=#lk#{ubZ?SvAIinx~FVX+I1flw!WPBdvV$3;*an=UdGkZy-;Vj z$fA#Am#yPpJXg93>vCZ)_HnS3hf}<}3y1JC-o|-+fgkX`Y~NR9(f^c#+n$$UVIS;c zpX`!N16FdilvlBUQ}_!<@oss26c0&CY9eW8WjFTyAJ>uW@SvRf?_~-X@Lff`j&qWV zwv?Xiv<=%AzoDWLcHtA;ji1Wc?WPlIudvs8I4$XBc8X#{oK5a8)!*mq`vb>hb2QSf z(QIL#?#cZBF6SpElt-;-?!;Ra(Mp|th{t3Hwwb-b*i+c6O^r_Ag_cs&7)vru!-{Mm zyKf$QHCeZvtO(`YB9?8jCdfK`Y`jl)viJ_j#rL9C%TLbEHQ5x) za-R$ep!ueOH{YP{EEmS6x$5#bxnD-M-Q%Q(U)|v2q%FJfsBX`#Z;YAyh7GmlrXG<0 Y0sIFoO~hf2_W%F@07*qoM6N<$f-EPHq5uE@ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/calendar_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/calendar_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..26d710c6db0a272640943512a0de27b3aebe7c1c GIT binary patch literal 1382 zcmV-s1)2JZP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-x;7LS5R7i=XR!?XgRUH2P-pt#X*-dA5CRrgO@lp&zbF@V~ zloSmiF=-O4h$v{WQ1oC=YLT8qJP6W56=|d%ym)fc#+dXEgya-TPE}|k3b`mqc6Vl9 zoxktRdmh|PH)#^L_`$#&-uu4y{eEx0`Jqw@y20_|$NMUk%Al0e1ppv~_}kmtn|JTt zt#z{>4-=Z6p4OF8FLBOa9@$ zoL`8dXedb%$vID?lmY^ROREs+``765>BlhHEG*O!5jp2k9LL9cdU{R)z!CufkW!AsaV$IfPKJht4t0Wv zaKJs$+Anb&ODW|D005piaiY(*?eBcwACyvZLWt?Q?)@Z5Mm^7aEz7bulv2D{EK)+q zgE)>+)3hE+sSf~32;oIhl<2ztU~zHr+}POItBkQP!Z2)VnnqpM-DHftNj%RR%=6rB zeT+L;U0sDN%Lbw-8p-p#k8^&NF?Llc^@5Z#@O^)_(P(@vrTi;Nl94Eio&x|45mno< zlv3n*?z*l!NR(1;D^?!4#!4wJrHq9THKmlhwYBwIp-}i^eSQ4{*LC0O?d^T%-o1Mt zQcC}nQfBR{?xs)%0J!>I^1XeKQpRBzK2HcSbX{Kt0KLDzznrG&9Yh>pjHQU!L`35- zE`o?YBBpyzvI|0pOb8L`x-OF>q5b{+-x!ARv=Czb=+UE3DWxh(seJ#lVhR90X*3#} znx^@Lkp0}DQc6QajSwO?Ha4O>&o$0D(=_exJkNixR4VVsaeSn+T&%Qfb>XP3gMs6#y7B48t##N}b6L z0H7$PCZ+WL+S*!82LK?1+_Eg|^(0B!izEQR#>U2#fq{YVl~Q?t`1p9NIS zp6A)NZO;-y&abSj?25Dlhm)zPsR<#(g(!-Sbvc~;qU-wQxw*Od{rCC{~aLz0o9n#XcYS)#sB~S07*qoM6N<$g3ecsf&c&j literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/clock1_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/clock1_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..c8a2dd7813c92a61f7b2d976b00da80fda75961e GIT binary patch literal 917 zcmV;G18V$000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-w4@pEpR7i=XmQ71lQ51%s`{7sSzpT@8KSg_g()*75qJ%}0=7ybNh&3m zC5=kTOIne%U|F(+-z&BmwNFvJM3K-XfqTGJ|Mezt5Xb}HfkoS8fJUGOSOF@$+5zA? zuw8CNX-PwpHY9zMv?}Sdq&`U}C1oU~EE&)B*=E%~8^%aSvExMdBP2OVPb3{K6W&mo zZJUdb-7iIS(XkFmdShTslDa*A$L~!so8AanUecvFQKh7}-sDwD0}q+61vC9N4K zd`?@JjMxttW67A6QKC*e&P$qb{E<{4X;{*hPuPs46OtZCTDJX`Z7S@OHO9O#J0+3y zndtB-sRf=zPF4@l4g7G9Yy$6rS?Ab>byt9!_E|7StuZ^oqucX;v@o6{=-4wu?fNo@RDF( ziu$L`yl#gKK{)cj6orsseHAc7ux|-V2zUy3;rAM2Z5w+j4UF5d5oq@EKLBrlp9bGF zz#oFmO~qE527Un}{%$pvj6I$t=qFyea**bkN~LAU_s zCCwS6FIF%cC3Q)O**DvXdb~e6Y#Ts9+R-OXxvb&Y9QM{E`v%8hwa4Hl=nQ(-clbrUxoaFQmmy_tI r0M4_&>(&T`#NIXbB8raxx000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-zXh}ptR7i=XR$XWu*A@Qmoxh#k+1VNGN{%bP)Jf|a+$Rem zg25U#sn>RQ2a-KX1s9LScLWr>>NxqjP$zjG=Q3#;{03jrjB&ne&%BPB=d`JlS zV0wBw{n|j)YV~B2B(HS4-R}lLz>_42dcSCI&Y~^SraJ>ox(Lu`H_r;I%K@=+voGC!#3&Q=`#nTb5f~ILN z&CSitZv%~vj;gs_?(Z8L8{bk@RqgBR`)jRM`#As{J9dngN~KrBF#I87Y@aO4JWW%Y zrYX;4G8>wvU3u`}!Q~q_Ztx!1uUf6v58^nE`}_O<<@^5kuU)$qQvfgwO6fYKR2D+Sj^jM^Jn!t_;NYtOu(Y()lqBgdnx^G~AmE(yaR8trBO|3G zNe(AT5^0*|#c{j@0OfM|Kpe;CJkM(qLbl)Z;K761jv^w25V)?}isSfPxm-Q~0C5~I zYMSOHNfISVa(HB9q(uAr`VKM1Yygx}y549sKEtEUXb=QN&Us39AaVYvPYEG9AtXa7 z)rAmpx7#fdLPi0g(P(@|DP0FZ8Dq9>+lQzS!WKekgb)g#Rj=1W01!faGmhiOX+to^ zpeV|J48!@PvtW{N2LqfCWN#IA(0S*1F(-CJ({W4>mecJuBxhtqG;AFs%DDoL&FP6*YJ^;9P@7`s@Fs@pbH9!ba#bZV( zRV~XJ$mjD{@7}$8834-Vav$gX#VCq=UDqk4bP4D+Y^T%tD4Wf$QcC4cr!%Ok>O}y! zb?a8Twzl@NX_}WxrIMG==dDa8V`nlMJD<;6rBcZ=P4iN{UVnLIWhDgwRaGx~o;OG- zm9yFGYNylrXe$)}{zs~to15((bMGS66DLmWBZNH57<&c)BuTm>g!sq&{QSc$pGu{2 zq0{O7)NvfQR4NrRnaoSGv$ONNfB@k1>CxTdmgXJ7a%glvk@&iF5u&x7$7E zy6*NUR}>|bWqH>qPt$ZDNs`RgC^t=0&1SP#BuTn3H8sVa2()FBlar^?G<~Jp?H+kd zoNP6!0CtI!Rautbo|&1M`?7dXlv|UNlQMuk$t?gM%*@PueYy3x{l5b8zey8;N{oA3 QDF6Tf07*qoM6N<$f&t-7^8f$< literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/clock2_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/clock2_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..0a61c50f76337af7b74269b4ce4fb38019856a38 GIT binary patch literal 712 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/gmail-copy_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/gmail-copy_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..206dcbb0017fbc9cfa4ea0d907d7326c900e9ec3 GIT binary patch literal 1393 zcmV-%1&;cOP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-x>q$gGR7i=XmQRQjM-;}tSJgE$)iYBwJ-U}Dfe48R=8}Uf z1Tia#2peVBQ^+k|BFRN_3qc48xkgX92qvc>gk%>ti=yJP9un~C67iVi5b)2=Z0~GO z*Hl-%9PHVwiz~b4UApO4_5J!)z4v&;%-D_{I&^6F*x1fE zW!al~o(Jb#9zrMpj5d%EB2r4#YPFh(f+4I%&*%59Y20tRIAl*27|#zX_^k5 zb6FVyJx_p30i{%IjHzg?zqi(YasB%BuqEiokt0!(B;T#9tei^IbQwU{3a|xG7-KrE zR_mAL<>gQA+_|%Ul+nh;tyb&n67smz-xdT|k2s`h`WV2ecDwxqz~>{s7`>c4d2%w( z^V4aXKG`W`GcQfkCwZQqK5^p2G%3S8N-?a?WLg!Qfz{(Kxye3LzXD33Da0~#V@$vE9#+U=nxtxe#jHxynjcZcMKt!Do z!q3*)H+sF^aciv=LX1>VMh^fGLZDi$R;83SilWC^mL<-)+&On(e0+R&)ai8gTWb^V zeWA6EwbpYXgopip|6^+{YpwSJ=mHQ*sYX#0YeYm*6vZKgOb8JHP?bu>HyVwf;yB)u z=lO3%QJn4f``&w>BuTPAV&t=%J~d@YXS2T>F)dGC)h zvlBvGBciv7=pQ0_q?9^btJUgJ6j7FCp-hTUY9|}(hyaA5D0;P8Ef+#WAq1rM1@g;yC_FYc1nAo*WK`b!Oh%Y&PGKQg*GizbmEo6-BW!N&*03 zgT4jO70b)Z52Tb`DP@%BdEa|~hKQ8b`pdDgv3tgt3Nyb7puW1gYP;R;WUtpdY^@zi zDMbk3Z|^;%lv*jJ07OEF3IG;DNGWBv+wDFeX2#^?xmN%Tz4t|yWlTh<*XtyNr~&8!7y?KDH~@l~eU@cfO4;mmI#=fB=Rb?e)V!g! z{?J;B5JHirsTV@Lj;Br6GjmZMLyd?S0M^#lh?xTsC1tt?B2vuEL_{G3-)uI85aPyq z!S?(8+gj@-rBuA3J{&U-0eB)p+5bXWxQwTr9RPf}X7r7j*;gu+SZlr1@Aq%7gBBJR zhD3D17*j2?Z$~X>lQ94?##Dt67Zw&4hU*{zn46oM*IHjT#_TGq{bgXx%rM66(pq1> zdiCo3$RRea>h*f(TdmfNF=ni6sN05>jaV3C##*h`Ot05FztR5;XmN3|AfhwIm`j~b z$CP)*F9MGIN~yTh=@?_oB_YI_#l^*E29+&`lc}kx6Gc&+&9dy^Hiwg?D2gu5&d$y~ zPw$1}*3{Hg1Yld^7J!?xv$H!Nw>I1V9U%V&1&h$1=;#D<00000NkvXXu0mjfK9Y?C literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/gmail2-copy_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/gmail2-copy_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..510bb3874bb0f1792cd2341e897dc20a4584bff4 GIT binary patch literal 860 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 IM6N<$f}DkBb^rhX literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/kontakts_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/kontakts_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..377848d0254b7ae496a805154b934c688e69f52a GIT binary patch literal 1236 zcmV;_1S|WAP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-xPDw;TR7i=nRzYYRR}h_<-7l@y@?UEu-`bOlqd*ek9E@(p zAq{p@JGRfI&_E&WA>`VYoJuM56eyHJN^|JhmJ_!|BrQRv2jfF7Erj$CD5cO6Tarbr z)$ZT_r-$yUvSXz-Y2R)3&&=CD^Z)yU%nV1t2ywayIrG{>KbEW07wInh-@K*<2VkvuKSY^;%2p4{q{&iGcz-k&1OFdg5aHYyB#T| zI>`?3umqeW5JI?8%1kboyB&t%N3~kb3?!PGnz9Rp!WX-{yG!kMy8!@Z5WxUKl2ZDf z=dCmvjrTV;HhQJB`<*?{`#2#<8@%sF5Rn1kP+~+xW;RLe(#Xij4gh@c+>Ykw=Pz}; z-LH3cc3J?ywr$&)OeUZDMNzb;wbn#5lwJ}2mm#z zR4OH<)JdgOx9^1Y?#f|}e*t>_h=@w5u2Sk`rBW%8@B1gT)`jFUJ{RyZFvi4M>q4PW zI6=%@NMz+`qIW!SlDk0vL-IpGh}cBL5dNcb9RMb|o78AD9$S{xBqIA?!;T3evMtMM zHk-}Iw7I#tok+dI&r5mF_I=-)n3xz!?Q*%CJ$v?Sc91_avk<}&LOj~s+}x&w`CcxU zJJ>Is-XQ>hN~LnTTrPi>+Goz3d24)p{JjG)`&y98<%o#x0SuNPF+4o{hvPW6Ez2^@ zY%z2A?Af#5hlhvDh^V6|`crEiyRQ3+F(wj1gh3EoXt&$bQ4|FSC8#H=b8~Z-!Z7R? zRV$Op$h6#!<1`WR*Dwqxm>C_%dBV(b7>47_90LGot%E3v0%oRSu{h#5&Xv1&@BSmI zDK1~W{As)0ez*UbNK1~077^K6>o6&|001<`ME!mM08+}5l=9Y{J9m1|#J;|?TCE$N z=T)VYqsba0V*0uoV@#BYE;4h>%qlTc5|UDmdY)HpwOTj&bMGUn*XuDNUX@bb@_k-z?kfy2qd!opk}$JaZZ&Z#2~CqLV^eRFknb?vZx yFC4cP78Yy(IMTQU0QXl{SC2n#9mLBHkbePkih5q3!V-o60000000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-vz)3_wR7i=X)<29?RTKvB-@F}mk<}RFPj82yl86ObV5x2c zRtt%V0ttyRny3W{386C(f>di^qlJlDiIRYc6^)dH|Itb+LKaww;7V{y)7ufxpj z15a|ZnSJMc=bU@L^WEF(^?DlGIy{Fp`TG{GVzxo4KE<0=MYrlb2;yf4e z40ho}nP?nm1bsXB4WEefxu@CoJt2s37%vEdT*Yfxtm*x_VAmX;!Zn=5v)G0^Bf4t~ zBAmue{EC+|W^-bntP@T30jk0lxt}$H1tGQj%md;3G%_sJ{3L6C_Ylk{f2gmR^eh^!D4r|l@M{E_!Z~_N1 zuH2dX>ASJQY9TA7Lo2KQ3-94)L5gkoS}4FYHi)y_j@w0SS?~l_FQ;`~L6BGQOD5f$ z-}d2CL5AA{qYG;%&;p+HFth6F?%-)LXUDM~d$QxZg4TmZpi1nyHm(T9tS=JPQ#>x_ zqtvNG>G!7~#8~=__r=O@w{WE`B;zt(5))n8H9_Hp0o9f^f#3W7*UJJfW41n{Q+TIv zsAu8rWfBZaT6a|?_CN`m7YsXtzdf3IuN0EAD!X|gL8Ykfz&C;%Eg?lU&6`*`5?wJi z4~c4R$ML?UYocj4WmkmS%;2L3RSdZJz7oTD)8k!yYsJO)t`QesN04Gh%*|v1)N2rU zy(TkeCNci=P-*fwc~NvW>Ty!xf=7Iul(qtIYWCbZjemv#EtjaY|Mh_U7f}e~*fmOa Qg#Z8m07*qoM6N<$f_xo!ga7~l literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/mail1_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/mail1_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..cc862ac6299b03dbe9372a252cb6f805172e24f2 GIT binary patch literal 1429 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/mail_open_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/mail_open_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..e3b2f22872c79e3a9ad455f36ef1df98ada77b1f GIT binary patch literal 867 zcmV-p1DyPcP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-v-AP12R7i=X)<0-oWfTVR-}g0*e^Mev)5Sp@ZNC@$5mBG^f+*eY&9jKQQf{gcKvZI8oyZt~`GZ}Nc$ zE+5}L=RD6n?|I(yzJrJ`qD|phJf8or;#Vw>k~}toe;P02xg>cgeRq=V7krEJxYvsm z5q-~WL|lxB^@z9?5i1d~6cNk$yOi&4Wz5CQ>BJj!EZqu*}{q%1GZ78eGDzPf{=iH45RYL``UV+$J#$ZMx209$sfgH!h(BA;&4{=Z z5zkbyCvwS_GG?)g-$<-Y?3(0ACN8!T8$42*v&q{ z2|QYfM`BJls++*eeQiup*Hs*75!E)IWM{In8N7lc z%Gl|%J&Ao~OgT?3;{|1i_SqNMz<0_ybQCvshz~^=m$BUR=sezR1$CW>U*d24)gMvQe9azUscWeZSPUUgb|D<^{G!`CXh;dT>)Y0^Z5@?W3g2LTUPo`8!Z# zeX{xB_Q7`w?sqPT% zWx1z_Voq7U30uPGs;u@+WX@b-Y`ds*-5DC2#Rqs^sqEiOZW0E{3Ot-2{Ik-Nue!i? tBBG3;!$!MqeWUENPTP&Bw*Pg3{0~9Wa7U2hWd;BM002ovPDHLkV1ky)myG}b literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/mail_open_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/mail_open_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..03a190ffd133365d838003f7fb1738a5c38f7289 GIT binary patch literal 1398 zcmV-+1&R8JP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-x@JU2LR7i=Xmd}sVMij^2j5Cg%#Iv@Ot)PEE5fZ(k?E%oD zf>wm2`{UBIT#7(~p5TZo)K*o+74^UmA&S~Vd&rLs&{YvsNPCMANJv4ji(1;!<8FRU ze%RiLXL?v?>kS)N)F)Z;_}T9>-+9k74@oIuJGOW4-qiT`_%0!Y1pt6CZmg`VEI)Yg zV0Am+qt}6EW@aK%%0ry<4>{+%ecw+?DWd=Y2q8~Vlo}!A86o61gwVbD`T71^gJx!C zj&jb=^m@JbUDp+yb5{t#0YCu&5vYm~LNra&a4Z(95<)J{&(Hs|Ezs1|6plut-#U)- z8DngXbKV>HG)>dv@p!}c{RCr73L*S~j}Q{0l&ZR}-|#%|i#vDjh;UpS9vnDuAfjp7 z6~@@fTCK)7=RJfF0szo;ohFmXmz2_vOw+tz+cw1*E5R}%&Uvp^t1-sdNlnwP?BBmX z5{|uTFg7;!O{>+KWsI!`@j*%{bzL`X+x}Bk)nkQ1;co!AJ~uZP1%NN>^*WPM`oV+* zV{8=wW=+$q0l>Le6lJs7wClRZ8Dq5of~1t7>pHb<`>$v;nhPKR08lIzFC`L*uWj3= z2q8tT=KvvufH78cUH5no1%{h02HO88zbq&L4Hk(cFO^|_Un&ujYQ743elyXpsF6Vsr#Kc4j+qS*S_kBwU z(T8;si9{m5`@Ub?v17;2>2!MMn;^Md?li_Y+ithNBZTOK=R%0S@B5ZzS-Y^5(h9bf zjXxJ-94{7&KY5;a-89V~j~qEN5|+#5P9ublK7IQ1gy(rRAp{AzWf0rKBfdxb_U()0 z^ZBCdx>qgB`XQZ8zdH)@;>C+k9zTBEQxrwtDi{C&MhGaLvL){mrA8#0K1+}r+4OZxf2MX zsprq1=N>(J)Eub-jx7)pBn&z(naHv|X9((xk zAsh96@SA9akY|-jWfceHySlF9&`vHf#;-ujs2^ z1qe3PPN#D}9*;licDwKO`+XlFBr25(-)g1{3k#J|DiA_0#u%iOQdQNMuIo=aoz8uL z(0P=}WYV7JeP6HFJCxEo#`v-jVhx6lk`X2qMezXO1IKY@d%d2UN~KIq(~jS|b!%Z0 z2mm0P&0c7?+b27nPF+=11BNQ`O(uj`TU%S}QcA}urPprWyt#2qY^t5UQX+&frSzS#v9VI4(KsLWZ(5ec#l=2C=oF>&S~8iWs;b6dJ;4$o z1Y2DLzpAP++qNmC^cu$a)Z*gerbcCCb22?Wo$2@cXL`Nfo=|hrhyN-I4K*iEB9X|& za=Cnat9Y+%x2C73BLJ|ib_)RRmCNO~Z?}f+|2B~S0!G%AyAWubvH$=807*qoM6N<$ Ef000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-v?ny*JR7i=X)=!AlRTKyC&wKNm8FjLhQK4v4Ns#}7B*>r; zf-*M|EgET&5fp@NT$JG6sKD9?(MFd>fl6S1poP$`RsSq-QL7-erhij2&zawAanAMq z=FRi*rVd_u@(#T}4Eu^t; z@G;I~@kT(cArU=^S8*?vFrPqWLn|FwgE4%G*KuZ4Lv0+#3+Q03so$sD+&qN|yoE?S>H*+4l5RRVjrZ`J29@nTeZ5lN5ZP^J7WVBO-5WlIkLD9LwKV^ZP3|T4OT%MPad93-d2W5A*SS}1s44&J0r@W?ll9SQxiH@V0000< KMNUMnLSTZU^P}_t literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/mail_sent_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/mail_sent_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..24e72506b86f1882c928208c39cee9abddb2a308 GIT binary patch literal 1526 zcmV000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-ya7jc#R7i=XmQ9Eq#}UV?YI-*~7V?K8w0X)~6P94*qD=xq1nl@0j4w_CIT@XNF_zIq(jmz%lD!D8QM5V=e6o#E zzy}{J<7oGN%+AhCzwYVE!SmK{g;uO_!!R>+cm1lmtN&fd%&?nw=+L3*nVFgW*4hLB zfQWkc?%lg{`}Xa%-OR^_f#&As1T(*&wSHb}{X|t&Q_SoG03f1r9B18i-OpUt{SXmX z78e)IcLvSP&HYMi{YswaKP$`9YOPCatpR}11SBHix^APK9RWVb0M`aw*A1nVUJwNDDy3e#e*L=L5p?wEQIRCcTZ6&i z#WYR30AP0l>;NPwWh;*3e|NjxbGL5Y+FD96J~)o!zt)ho+WxK}09z5;G)>n4;KgRM zxefq-8THfXq-nao8wfK$=s^I$!C=rWiejPNZqIHx!pv~&*fB4PqUE)< zwa2yAdF>sKCf>)ehzPFhhD7ASH_0)+(a6kzh@2$Jr&*TG-n@BpC;$K^CMKTE^ZcOJ zx<7&t5e7lfAfjpvMnzF*A%uvcXvtc;T9zdlV-yh~A_5{>$8k^y@oHI?zlfsfSpc|B z007q7<3&+yWeGE55Cp;GWn$70t z`}XbI8-`&c2m(I{f<_cY2moJ|Wr@su8~{KZIdWuLO8JD=x*T7!s;aQ6s>jN*>>{FD zFOSR2VO3RznS+xjPfj|H^M&iWfABnSAx+cFTB`v7s;bh~+P*R7Cx;Ioo))cEYrj$| zvDTVVCWm22jYgx7i1W;RS_lC($T7wYnOT)(xw&W0p5Hi*^V2I=uAJ+1Iya&y`bWRt z_lXE6CMNz@mZfWqnQpaO`vo&6wX85RgAgK^oSgg!5r2R8?p>SbIROATj$@n6rV~Zc zMWxhJM8sK^X+(Uv-ERNL^SnPsQFOxh{fhu_cVlDY&z|SK0|1W#K(g%|AtG37wNmPb zMD%i!BsNJB4*(oQv_wQ&>mM-lkcg0(ZI)&0i1<_-$Nve#@K5ve^G}~XeVRL+&P#*A z;KzuV0{{p_>>;88fT)hjY;0__i0G{E`xJ)ZJpjn+%o9qf31%Lhcmx2*^L${8X;xKr z>GI{v=PzBlG^3O{lV#bal(GPTp6GVFcchd(B6@_Gb$t%3F=iu*qG454b1N$=|3yUH zyLYd1;J|@@mSy>jwU&v-Fv+GsEoc?3=w_ z@3%^+bX?nf-^U;bK4#`FGZPVs;c)nKW}Y#|{4NZ`FA;HGYh8?@s~s33;&Efl5h>-x z<>lp91pojMeGmk}OG>G2Dx;KQt@V@ettN6+Re2bOI!ThJJecrF#?<@T zwQKJOL2yAzIaLpSSTQluHLl+<_Rnz~w}K$JFoJ9Y0RZ&-{nz6-UX)VKFf)yA&)qcs zrje9#CXVC9!C>(Ec>gxg>guXN#IsV$w_B~2bX_;B4eSUU^}DVcwpuMIrF@%+&aSSm zZYxxFEKWL|PTLssN}lHjcUhc#B7``000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-v!bwCyR7i=X*1eCERTKvB-@N-V3K4?1i47eVBEeu|X$%E| zF~&+Mh}sYmW1$TV`~gIQ)kb5ZB~+N0tVAkHJ3pZywh&!lCG4`yz`jFq&db~xW`OQ)Wz>|V%)%IqcVCI=dhBC=7j#&g?ytj z>xufjC`{7G+`@eAx{Y)Pg}YV? zu#6b>{;P&oWgV1FRZ_omApz8p4tDE8(<`epA-M&bRan`y{fKkZI0fb61JIQsJ^VZkh}_ zcwJa_3D0Ajux>fF31`;1p=+WH*3kNUT)Zz@L?gtI(B0bf9PAkDRhN@#65I0=iSGfxH}}>6624ca^k$lZQI7L z_!=*XyXcHKcAAU^j-aM+-IS?afVMLIPRdk{8b9HxkohZ7x3XE=iPcVTZrBIH6pPp{bnX@7 z(FT*CB-xs4787IOp)$?mWM2YKdYn}F-6kI=Wz6A_>7H9Z>YHKHL}mQ12joK~-{^vM Sp?-}30000000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-x+DSw~R7i=XR!?XgWfXt!&3rpMyW4MfHrsmf}Zj~HV-001KLpFMl_WPN>oV?X!t zc|;2f3$}>7#msLq^U*xdr$od706@gVvaC&|)MKU8Jw&{_xVV_TFww%o!n@3TIf|m= zaU2_Fj*T%H01Pi65!p(qa=BclN~Q8pDRpCUaq;JU5zWrdlH)j62ZO=KK@gv0F3iY0Kl?s`=umFoFqv?LL+HUL1aRyz|#(J^N30sz)(HAKX(0pMhkBp(=Ka7@?$0FarrBuQRvG#VGPEL$#>O0O|<0st@=3{1IPJ_`UVG(A1tV&W6YL_yd1}I ziiidgVbUQYNYgZA=0k`WB4P%x-44tgGxO2u>FE|Vo6RG6o_j?z4nfA4VITZwc^3s> z_R1P#vOLc{&-0FuhK*ObUIJ8);LPTQYw|oN~yJ z!F6{*L4Lp67WViOBaNk}>leS(Xio zDg@VciHPn16pw1Z-@jk2Rv(37c$k?ZM8q^r<1|eP5l<9_AtT;6j^q61y6$SZT)q~D z;X`B0)n2d1g)^X(s<^KEsNe732LK=dfOfl`BI0$ewNqFwxD5e-R77GCNruO=ECT>- zB6=D{k(=lF^=`LY&9aP(se)Q-hlsAX+wBx!&pbMR{`|Ed2tEmdU}Jb;Y^f4~>$;(3 zS+z7xYjGU+MZ^q4rnPQqt#97GeS2q2?3zd2Zug4kc`X3A5Cp*{Oc;E|7zxAhKrxGg zp@@i()_SU5uix^0|H>}oMt@dUS2IMsq_w`;Y&Nx0sv^TC+6^p>*vXqxs?uyWwbuG3 z5nWncUEQ^)Ok7Up=jY$cvg~pcMaTBJoIJ8^`^M7J((*Wc&t13X=jUwz*w?xR0C$&` imR@|_+Kd0YK>h>0oc{C(ceKd>0000000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-v_en%SR7i=X*1K<9RS*X7-|k)8Nj64AmIaDLBp%`sCqxL+ zPym7=fP{bwsCX1KRDmLY140R+prHYY0#ZQ}2O1Oz6@ns&goX-%1UM)X;P?@*mty8< zk2kyaB1XEp_MUU+n{VcuIj7a{_f2T?xCe9j|DX5~OOt%unPB}%JdQ&NGLvg-3HAd% z!y-1uIcjag=vkb=5%jQ{@6GaU2C@qcF5pdkGAU3Sr|>G)v4Y*{cqPFKQ2lWi(|8ZB zR{@O#>fn7mhs)T5zi=MEB+&hMP^7N5eg-**(|B2x%HbNlh3D}HZon7#8h7FL{P5#ZvmXjN_viJ&liX1+)40uXqT*iS$k30B#xsR+zQ04=>=;8fY3{;_lq^6~4nG z_!);qy*3hL)=&*bfOUoZAI5q+7mf*at>EtjDj@d>8L#5%4gkekSWchEh~g2wvMGvx z4!0%9f=F8@pCj0x`}Ph!v!ciP25Q_)-#Vh>7m`gM2Qz@>eDBKlQGAPUGU5_sNmWlY z_0eQr+F=3nopd~x8+*8=a?lfX>53Yj$q1)x?V-|BXGNNy$UuAP`(Q_?VuJWTd0!RzI2U6~ftF?`w;`S+h0gBDp@3rch^nIx3BaL5ZUR7o+|CJ$RL-Wi}R#AhSfUmz-yx58@X>& zq~}aJK8?o=TH-?b-ZE65!AC+IWiZy(&uC|=wYC^p$3^2mnn26O4Ao+9XVm2$Fiv5` z8d10NV#*)DKMDG-F~@|A_ydE3Z#y{`mW@c$RWS+XMG9Y1HUFriyunF>qkOqq8000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-yNl8ROR7i=XR!xW;MHGIox~l)Cr+a5+7Xu0sgv5m?1R*XM zT{oB*i9>dC62XH3C3s4XL2?rD>PZg)J$f>`i3)2XflY{60wQ7{=Hfw&ptJMSH8b5^ zQ-2w_wU@fv+*eU zxEs*Y(h{}S9+gtQCZ(L!TGy<#9smF$3deDpjIn!+u^$le+Vb+UdTgMjrKLBelxMRn zdoIs&Bc&{iF$w@IA_4#)A%rr2(x#y(wMUjFuxfQ}zOPCU>1IM4HU(=;7O zDGSD!&lp2ONMVf8gTVldF$e%)hX*jm!Z?oIAPBw`LVUQox@vX=nxCJil}hEaG)+&X zY1;HWF9^f1=Qz%fuIoN<94D7j9_(~FFA5>V@MbUuNa8rICP{Ls)oOik{X|g|r_(fTMp0A_!|>}UihfCwRRr_+hDEOU)9J7o|eB5=-| zMNyot*Xt*?04*#mxYpWpX_|_myKY8N^j8oBFLTZxG@H$RjYeZnv)N3PQa&P@9e@A; z5CAOaTv%(*Ei5d!4}qd6I+A7C0V!o3hGCB}b}I;i!<_R!IOoqd8jV(-=Y`ffx0{02 zTG(!kt|g_+@;pBfMbVLmF*3#+D~iHUN&^5`EtkuCrIdg6`~BHgtMxY`x&Xi!WBVzk zAtG7;m~lC0RSA=b&2CRH>H&CwA<~cl~My7%WrF~C4@NDYV{dP>F12G z!$ncxaLEIJ3W03|5n;Se5K&rdNuKAyU@*u4Kw4`DqX7U?DV67W&Wte;02Gt1C5YHY zL@~KAi9P%poUGLUjKMK?;@GqRfHrBhTK65tX%j-|b_a~SGt_eIWOJO@Gx}OiwM#F~%@N#2^S7zVA;FLIOfaI5s>0078gCL-DY&L2#Eb7Eay@5kYG`=ytn%vn+eRC<>~zR$6PTwYHQ}QYw|cuhnW9 zrSy{4dR_>jT-ObQAh_G>^{xYqJrnhM{e%$Wi)ORg8CL$5pj&G#BGQqYhC-4g>G{5Y zo-sBpgm@)Q(^vC6@7HRzDc|=`U%7JSyDdNf04GnL{DgD<9_M^x^os5f_>nkK6#e6Q z-fe5`OIemZm1S8kNs{R}jxS!meEH!su_eq@D!S(Y6ried{n8R<@tle?7CPghn}zS-8I-RRch;vxlr pN1|H*aBXE}000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-vib+I4R7i=f*1L;UR}=>D-#s&PM-dWaoZi+434{SH|HDjjBbDr6#o0jstL^lY{zk2 zXgV6=ijuz1Q*kDh?qhC>gUFkFhJ8xXP~Pk=zQme{5D|wW;zdL(N5q4O_&Xw&@~rPS zjEHLy@gy;p6Z23+ym_O8)@R8K?)9XsmbDFTKTd3wQt^B6()!1LS21rS&G#H6<{m6o z*sY}GsAaU7jO(%)CHC%0$&Pug0{fq2oY>pjb<~v3zV$v*DRr~z?c!}y*+<%}REfP( z;f~U7+J!l-cDiI}egB(D>^rkc%lHeQC@DI?3#E-*$FjonLp*JO>`b7sLh~2+RLL~y zaBE^es#EwPPBcJP6X<+8oy&lJz@Mpe8fO&h;ls2WnPgv;*qtp%L$Nj*=FQG2b7}!s zlZ8kJb&m|K7E~v|nliNJ8^E=}IKP*8hNBtO=eUu#5$YUZ_T5h@r}tI&^74l zfL1c{Xq_)&3E$R+8x6kSl)?8{_e`pXoQ6*Q-wtK)oit_ey;hQ9NqO8l+WLDFpb4$D z<85iPlo;y@zRz;pReb2y;ix^)TvbOF7~QB(fY0{Jg0F&r>?RN%z` O0000000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-xHAzH4R7i=XR!?XgRT%%iH}B14CYv{z$@bctmO@1Y4J#B% ziYdXEWVfC@Cm8yg$_GYeHJm3NdzX~DlY;0`Yn@DJBX^Ah=0ClzjBD@B5$UB7+2j3MWI z1^}!{RE#k_t#v2&4(I0PW*x`*V0(LeXDGC=uwYM5Pgfg_#>+~n1QF5qeP-MCj@J4w zA`+))kY!mK5noS|WWLksWJCl)2(MTy{@&?y-mcYZJq`d+C={+HNpeXkbp!xt+xCp( zINw*R)sH8Q+v4J)a9y{Wrs+#s>#kBNNz?RFp-{LA0J|)A`&yc&!zw{UMnr#1Dgpqo zx3{N==ubo(<~>bQV~n{50KiJ6Qc)>&Q7M&;RTw|U_TL!h6A@7Fhq%F54L>%XyM<0f{lD*J`!Sx7+RSk|e1rrS269g&)i1as>c@h#(BZ_gvSlGsbq3 zB-w4Z+h4_T%tyoLx-Mgk-3K^%1VKIn8RWU+oC_)Cl;?Rr*tY%I3>6-QVBuBjODy<$4%~QV8Kuj?s4`VI?AhK~BOjlv2ud#@LPh{rzVe z{=^MhE|*vO{r=4)NiI!zoczW)zq7fyx&1u8Q&)AlT;>2U(YXZxdz+h^XFs>b@qZ7< Ze*qeiY|;I3dJq5r002ovPDHLkV1i0NG&2AI literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/note1_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/note1_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..4ad0921bde9b155fcf66b356fce98461b864c173 GIT binary patch literal 899 zcmV-}1AP36P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-v{YgYYR7i=X)=!L`V-yDP-@S7?)0(O@o#}>Ps})+SiiH)S zC1pcrg-C3ybfJkR7XBkzx%!CJnuQ@d7tyPBEp0=k87}}-haheoS($GGr{-6xDD49$V`1(DX`D+E>5F6 zDo|@oMt9=`uE!ddD^Sm&RU6rkDSV1&@aCjIZ9IpEu!@V#^#g00&a;@tOE`}8aX=ls zjC*BS)`tWiWl@{lgV*tZMkxn-^em3yTsdtopi%YhZDLJk-@;#5kR&-iETf}%4NCUiq7Fh)@!IiR)pWvWm=`p;Ot0F|ibVPg<5f>ujr-(Qg5exPITtv)|c;+HvM?@Tn zh#$*GM7$jls}*xPA~rI*v+BB3<@y>o;sqS4a*WDmrZV{qAJ_X+RfWrBzfbjgbXcDy ztt!`yr1t(1K!Kh30Vico?y0~lk_hV+`&6fD*$dX|MZ114H=aR|OQkYAf#0NR9Fe5x z>Jwu><~!IYDY-VHJc9tR3t!^t0y&5WvCU@ktX1rNZS1ZxZ8~6MY?qXsUM7cd08h#T z+hpi^#ooP@)(vJeTOcQ8c@9X~If~zn(aw%!+KOy!GplH<>D2oLe2Bfc0*{w(N1nSu zYuERs4$erq*=u@yun%P(+)WK1ucDap1EWK(~} z<#TE;iHRW^BNId*M6S5X`6XHO@i~eA2$z!vi zM0Ic;J&%Xwn3$2Oyp^>I;G#a6=CO!JHWm#Te6L8o`o(`6d~;Hu@7EZ7gC*%oQY=d4 zoz-X4u;JJIHd{W66=TyyWs=LubuzPYmy@;}6aVUR(zI>3-DKCTcch>WwXJ}f_P;KW Z{{WIlL$ro|M34Xg002ovPDHLkV1kZ_p!5I$ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/note1_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/note1_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..ac5935865870b60ede956e11fdd898e2a49b2d34 GIT binary patch literal 1471 zcmV;w1wi_VP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-yIY~r8R7i=XR!xW$M-+bb(|^-F-P5xxNF+IG1SeiZ_7aRs zR+qS|yGsHgkbr@J>*(_IfO(INr>VhU}k!I zx}E9i>gukSLuO=Fch{9XXy~G#ZfTnK10iH#c6K&@YNF}s z=?N+2(IiP~X__i2WvZ0Q0ieHuP)fO`X{KqKv{Wknu4&ro+1c4k8zLGXAE$<4eA?}H z565wwNhy<_0^z zAf)ATxmu}I&WB<6?&9L&Ls#;_#h&MV5=GHW6h%!!2qlD=8{t7j1ppZ#gmgNcE+OPq z&-0o9@Zn>M4jw#sAWhS=K@hYUW7KgRMk&1m01^P!V?#tNNh!DJx-K~9zjeFa7YxG~ zHVotN+}zydheUh#?$vGE{=V64Zk1A|l}d$`%jIKt@7}%GXf(>}sk(pvelj*T_M+oB zUxi`#@xsEwx$*Jw@8UQf^?m=>BuQSmcI{fm0RSAw8BLO8N0wzR#+bnv`?FrJpPQVV z{GwW|?ovvnYe}iqYP#on0ukp*r4pT(n0PbK^PNJ7l^sIKb-5d|U&01$&jN-5NJ-SIr{HX@!v#LzU&ZE+lr zM^PjZF(-r&DP=09+&(fgGR&*h>NX*S-%G|P86qN>rdjqp?+*a@oKhOvw!O0`inoFw z;7TdkPYI<|UKEAz`~EhHh<>lEJhA8@B3PDHu2d?wlv1ZS=PlDTcX7^ZK@gl`jOnm4 zLa~SK^EEJ6m7?o1OAL&S&>vL+rUgoK0;0RZ-(DndyA zpCckCgrMU%v2EKw<#|5b>2$UzrQUz=;6Y+p7H5pHq9`84Cq3+tE-x?NW{icD(iNu> zLJ&$RGRE#HrS2JqK{)5LaU5SNisE%4#Ct&yBuc5gcPEb}8>N&p#=GTT4qz zP2OX^Vp-N3Y5FiPvDIn`0Qie@K3c6-bwsog(UMZ;jIq>loPKbCrfFH4rjL~>%d#k? z^a?<)sJ7eftF~?5>~uO?rIZ2@pWVNI|MPe5-1&@i{w)AVL{vpl03ie@r4PZfEQ9OU zum3SIF>x#m!$CDA%d&2^+wH3W14VUma`J!>;%pEEEnU~Oa=HAEQtE1!Wr7gGRt=^9 zTveE+`COjoFU4_OD5Vep$k5PG#Wc;gFJ8QOc?A&wz@bBjPR4QkP83B=#+XhiwKnif z5JW7BqUiLV3vgX`*md1A7cN}*pucEEq_tYD>)oRt%G_BMFKtc$t_VwpAO)FKaRo8XhGnCRJgRg5} z_NvF5nwpx-^ZaO%Bs(_PoZRG`pRU*IbF1O4+ip!wO>qF&P`d>H3-x;a>D#SG?f*8A Z{{oyW`Ta41Jv#sZ002ovPDHLkV1nxxv||7O literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/note2_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/note2_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..253a81d6b72a17be7ed32964ca55cee5f5779f0e GIT binary patch literal 920 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 IM6N<$f{LVlB>(^b literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/profiles_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/profiles_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..0c9aebbf0fe2bf904da6b3807d11ddf7611b0a44 GIT binary patch literal 812 zcmV+{1JnG8P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-vrb$FWR7i=X)-jA!RTReY-@Kh&L=;1CF(I+A1dMhjR)&Vv zZPdzE3N0)wv{+(dXCZ~qSP%-Op`en41hAu^Fmw>bXwQnS28}GR?Cu@h85`q3 zot727izU2@O*~3ae?li6c?vVQiIezlTA>D~@F5;!HGxm(eFOhif_>YAIh@5O=(P!T z@h#rNpXv2;N*u1^MhY+C*&$e@llyT2$JM_wBI@gOM65@|orqY8h`%G^R7AW~eX}vIgv0TS;&+_hfkex@%ZTgIAvjaG) zgkg8GSNd_dY;;Wik9~}T%F3H$58&S`{bY}wt!e=u;h$vPO!h$NvC_2qDLqMS)c7L4 zQDPIxI+^Tkzw08-;Q1C<|NZ^y`9*w*^9g^Hj5DgDJgV`Xv(@-|wx@c72lztSkgwql zyrBH9P&V`hysv6}qgwe4zOucQ*Va+?+-!m#000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-xpGibPR7i=Xmd}e6M-<0jy{ek->K(hMXLmyaISL{e1Ov;$ z5@bwPlw@^A|A8dr5IiJGAP__d1aASoL}H1bBZ7yb2B>^*z-?D2yK4?26< zPj&+}8V#nkUX)UPAf-H*=lQhO+5i9`gd~*GP0slv&iQYIkh?1@E7>c98jZ$BQp)pT z7`_w7u}af4R!U_6pa~%W00a>k=iD?+6D`a7i*tT;Wo6};J%LV~IDv*?T#lmX6VLO~ zG)==oP*6%4r8G;D#Lu!!7yC5;0O#DYZM!6d_&G_Ei??szRue%-j~->N>s}iS24_6a z+XMh&S(Yt?=rG3qK*T@OG!3&XyWn|V830CN1rTl9t~!p>>~_27?%%&ZI!ZQ9bsXor z!C-J^Fc@?gW2H)^!c5a#CWQQWI(6#QhjAP)Z*Fe(DW$wxt>%_xoo_aqx5k}0eE9I2l}hE;AP5`)*y-nMtu>jR zo~{^%@oBr=z6FI>P^;BSN~sH;=Oq9@ib%fL3K=@L!?&&L+Vi|bYki?stCdEea=Cmg zilReFl7v%JQ??M|daKo1eTm>?5+OuN8Aefbs9Y`|8-bKk$HOpGh{%KxPt!EL_PUU9 zi=s#=rH%st;QajjjFj@Alrk=rN&*poUtL{&vdjKGm69T=SW0tq z=NKUb7-P9R@j?FyJb)oIDaiJ)RLap`JjIpmA$H5&GPzVwDzJHEV z`cz6uw>YEA<#LLMH30bD_x)(N#t0!jLP!DtQ%WfnhT%S#aD}zjln}y`Bzdy2vGLEO z<2`xuWJzmX0)V*C?qRpveM~9sAtEaPd2u8YAI2El88LEbF3U27h>TL&>-Bn%aeaNg zQCIp-$l{L%XQdItdj5b=%>V%tA?9TP%)9!1exN~z4U zEJVaR07b(3zJE^$@sM+Fy+Tym?DXl=?cf7 z1BzPp63uPvjYi{mnx;SW`+Wrf+O};25wEPRt)(Ln06@Flz9ocMwrzX52x>c*k`u+YT*L7zAVA%Ln(PseQ zMV=rc?%%(EX=!Q6$n*T&JkJ-RD0(9Z0uKPR<2bX9<1~A{-lcKvZLPe~Xi%lph=0kmSyL| zFgz5;v651bhLd6sK}1$6m4?H~L&n(ER;$(CNpIJ2t6r}&0NB&G1ps$jt=6lLTU+h_ b4v_x>8On>Ri>=cA00000NkvXXu0mjf$#Yzg literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/skype_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/skype_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..690619adcc3ca25f6e8731f37f4297f19cfac459 GIT binary patch literal 943 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/voicemail-12_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/voicemail-12_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..dcfed9aad9d5e2b943ed41a1345efe78b46db47c GIT binary patch literal 822 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 JPDHLkV1lJzi2ncp literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/voicemaill_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Communicate/voicemaill_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..4fbe387f63113d6adb1b5ecca92fd9c962e1aa93 GIT binary patch literal 816 zcmV-01JC@4P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-vs!2paR7i=X*1wCCXAlSQ&%U>wnp1;#3W1b@KQWLZpp9Sx zMv+LGsFm8-1_ENGV3Fbou@R%Bi69|~g*iAl?ZhIGDnXM|@DH$2IR($tbAMROyzYC) z-m<$6yu7>bGxMEiX1+7eQ){=|`jm~>h7I}uDIVZ)KgRVw)(_%K>`W&sbM19H`yaP3 zjmC07wH^_DjWhTJO}t8=(x8?bS%neY#RUHB*HM8BIE4kwRrQzXR*lCnil6ZvTD=_A z@e7WKw6wZ_FDLEX~C7TuH zl9s>Xd@4`jctz)1T*nsCcR%I#YX3A7dwU_+v2uyRJU+ud?8YIS#kt(^hhl1+5^4GZ z-v~0js^GK|d;M~=t}U3?z_a}J3@^pBXo?y<&$Z`iQ@40pypy_MT1m$;s@3=lGx$4y zAHgI1DDq$68g67nxAC9F^(qp3wvPK^+-#~iT9LaxEaui$QLh@tQ)fDX*5L{+=J%0` zqmjhEUl$`|2A^hHRNnLWzFR7K$eVn(MP_F3xUA8%4x<{_jE{7v+OIV5u?}mC#O^wR z=0xpY8gAaL5@{dPWdtpVru;1(H1WX@PNZ#3(0U@V7abFmqNw8{zl}5+oopKjpgGnO`&5@XRtrJu{mE)iL;%SnNI u2E3e9Wd#oC@49tUr-uf1RF(I-K)wYW&EXwQCuMs80000000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-x$Vo&&R7i=XmQQRGM-;}tnccB>9cLUniBzc)mr7WXs4De< za)3rq2(+%PYy?rst@J{Bfm_v9oG3j}#HoiOQuSCh;1CCh00D^_DdkjDT13MExUz{I z%YSw~yYqU$P7RHz(>`f0`)0o1yf^cn9wQ=jV>@^592guNOlz%^0KhpfK701;;oZA; z-EQ`?SAiVIF^OouQfi-4YA6iDejSmbv}ezrNKa4CRo8X5E2V0dWkn3b*fNMQh9C&Y z^E_V&(K9eG@MpDJegF3D+YJ){;_>+2TCKLD(P)$`%Zm5*_Fjxeqf@n7EkZ<$F-AnR zDY)fhjFD~I%J==_VHoafG#b@;czA%PQmJ$phDoh;(0a*?u@C?bA3l5`5{Z0a zn&wbE9{Ds6tt#uHFVKSLara2KMn{8#I zpu#Y$XEK?$iRhijk00-!o}QklR4S(!W1nr?woUBXwMzmxQLR>wPft&O=(=uBYwhgb zy*o`rep}Gg)K2masU{+_0ECYoJz56HX1+O=!TLWn;`M@Mfuj&oKBaYiY{9mhGH%jLfEJdc^C`Q7;V z_&4cvdd@V>pYPnc^E>A}+NRH%+C{#$w)W64j3VdUY#oM(3?kA`o;;asG#Zz*)^Q^G z3BY2rgZDAUt`pI07>2z{sS7JBD<8Mcxe*2DrePSxVzKzpTwY#wGnvc-A;eo@7&e+~ z8UV1gv{VOhrbBu=nQG-;2w@2!9xN{}yJnMo-L~yX&-0+Q4gtI|IXU@SsZ8xMJJ(l$5d` z05Qe_##p$;F91MN%6{9nr&^E~KmbrGl};uSiM*6@kcfDvn%KWWHk4U Q000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-v(Md!>R7i=X)=!AlRTKyC&-?kDF&`2#O@xa!(IP8Fmj>A~ zmBCzuiHmIGCZY_&wQV#6r_Cg|F-6ceY6#X=iZ*RD8iQK2(7>2NB6R*Z^KOfKe!lCk z_hz1T;PT$@-gCa^+;hL@+}lbi8B)ga0>TDpC}2T6(`$M6N-QKYhJC?CgL@&R|laVN&wa5^a0t+1I1jN^lLv>O+2SI&6{ zcQ75_ZETUxeoE=L_&pT!&C!Z6XiZA#)0EP^0&60r^ze*!Hq!A2cEv6)=oM*-F^2c> zG2SfJ$Skc1)D3KvT=6erR`0M=r14d}hIK^{TVz&sa2>DU^GFr>JO$QlV2@YW7!fWN z3N5*Y9z=w7w4*o@;}|aD1N?&b8#@!2W7t^9>=-qeNu@lGzwu3D{tRC3zj47 zk}P6%pZSrM3@f>A=KZ^PYbhiAS&njlL+22_jsImQsRH|M8#m>ec{)I9GOUT{pDcpt z;v;;9ZTJ;iaSJE=I9e6hH`{W{m=1%5P^==tGx$A}Yq^C9xszediPM;= z@1v`DyHI!rXYpN;g7WTK!k3N6>-lwh#Hs?jZws2mecaYdSxxy;%Cjr$?^!wJYZWc1 zY^rbIyiATtrsdH0d?E8;*SD$GGKqKf-T}kjMYYsmVRb~zD1c7Q!=ePdb#hH#&WF_HdBG|$U|kA$H^vnXUjcKD*WIvA19@(#ty?hx4ts? hLR`^NDgWyM`46wnF#yeHONjsg002ovPDHLkV1m=Dngsv= literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/Camera_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/Camera_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..77154afd6c5a2f682e93cc4f79b8939006729e80 GIT binary patch literal 1390 zcmV-!1(EuRP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-x=t)FDR7i=XmQ8G1MG(hl_wCxxj=hfUxDpbVREQ>WA-Bc{ zq$(9e5lvjDQY7jNq7qWoQzf`mP;o$rUVu`ma0qG-NJeTa?8c!)Eu~5?m|Tk}MdE@$ z5j6gY-S@eEI~;h=bwa)>=C<$c&Tn^T=D$M_5%yw-4jmfGWHJYoQb_;+N@?@aqel-{ zR#w*bvYzY&nw_0xi1><>@?|OIsONcUL<|D}5JDVH)9Re_2b}Zo2qCx2<#P9_L9?^7 z(^ASarfI%l+qRNY+DfS|00avNrIc~bbzRqKG#b6nIloXYmlyX0nwpxT;c)l^%d*~R zx7)6i()3S2wsL^J1I~F=2oZ`zB3B&8d1q;9No@-{eE2X+CX=77udg3(x7!T>Pyo;a zY{TjYQXxbtkw|>qXf#gWyLYd5m8^eqB9VCChpYhrP)Zr4R1dDp^E_)ayl)c(5tYC8 z_~77R9RSY$=S2B@{-|x+m+SR<3jj36STq)k{T&L0enCWvh?;HNW2R|_2_ahs77+mv z9Yj>=bb2rx4xg-6tKalM6B84mfq{XWYin!IE2ZpsJl@fDy%7q9zAcx_ANxCI`Fwuf zvaDwSKnA}1PKSgLbX|A2)9L7pF@0!g=vTuqUcGzwuFC)bVzJl}(=-pduG<jdeU{>Gn%ITRj=3IT3K0X1c1rO$y6$pnxmAayWQ^3SFc{J1Z+e!f>Tkn6cLlYtn4a!`}gmE4iSw$ z2mk=AuCA5SYX8^Pj*g@r#$rP6Dz>wa$-hGE-x!sg@q@g8rZR8$3ASg+iwQX#CDI}4iE$Y5JC(IA?9z~ zxY2tiHq=q8)jF3*B+5dF3;@ur#B&!26+&bZiA1^8YMtx6X3A%vKxl%85%Uf$5CY}=d^3Wb?&w|mAk&4YVvPJUvHU8qzl)vf&P w*lraH1qJ|nYPSI3cBN8z`gUux{oe-iAGY?$vltM81poj507*qoM6N<$f?;WY3;+NC literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/Champions_League_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/Champions_League_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..23ffe9d5a907c6147c6cb8010dbc6b06029f26b8 GIT binary patch literal 1119 zcmV-l1fctgP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-w*-1n}R7i=XmRX3FRT#&A^Uc@jxDYCaR%S&7jUp{XQ5Qnp zq!KAXfna5{KoEpobQ4r`QC`>rUJY3YMx}(%;!-z7hN00SX<%x$%(%?xSj>$2&GPHw z{6FVYW^AAXhxfeidCvbi&+~tlw@GE3VV}CJlFEBq!CS>ny zl>H2B1GWHzVS?uC?N*PfN7Q4P-Pt=G*=1wlHI3rB3h+AcBv1qTfGNNw z*{=a7fu>kj2bc`B0PVmkV7L+VLPb^JUEra(#VFnZ90U#nyMQZzHNd4nGcXXjVPHD& zA+Yj1S6*P^8)_{sIvzK5t8EQ3SE;MiP3j@_bM-g%K;%2rfnc4(Zd7u=+TXy#2RXD> zeMw!Q&QbqV&#GOK-KZ{6=c(_9uZ}#IUZ|)=-KqAded;sno$5jL4|Pc0p{~niIvVDn z`e|@3SNExZ2Ww}r&ndbu06pq6b-*HEA#l1Os;Y^`c3^hCe-G>jmIAwhClVCh!5a=XRZ7OsV^>_g$ zC3KGiuK))UiFW{Nftv&R0`LxS8*nBUod?XU0Bw|v9{{H2@cxA9p> za_F^O<{zLJXaydjA=QVew@NNP&n#|=0RW% zaCbn~0JrBrCF|=czTcKh?FN3zC0i-gV?D5y!qu!`_f&y>lpwe)2j&BR0edJBQ=#y5 zhSDZhMB!ZE9!l+71H8&e$ypBEMB(ZLu&+w#CwqZgfPM-mE3-Zp*VQr~1g@hL)%s`x zUW{yezCA{XxYl5I)j8Udo1X>liqEeBzNQq}AxcHwmA$$G!b2x;1b7&DmJ(^TU~Ykt z>fHi-71#7dV33lKD=6f50-Jy(6khA2m68rqV{L!tWJ(8K2-NBp)hN+6AvbM~dp-+L zXXLhJU8S^$*}&Vt_FU|6yiy6)>R^xACOXn4PO1CVm(_{tqw0_9F7@eD{Cch2-cSc? z7i$x!Rdqx9NxhhMr7e7+ewp=db+P(@`jMrr_vFk#FshB%qqXv8O1L(*@;Vnolv33j z4yH$@AD9?-wFA#Z_S_gvQGF}}o(C3C%F~(fFdPo*b7G!*!pY{*z%Hf;$`8pR#`n9m lHP((g{!3Bg_+LMe{{mcYQ^DCmL~;NC002ovPDHLkV1i|(|HuFU literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/Champions_League_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/Champions_League_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..7737680a4f717ab14a4a4ab5b092ff3f96ff8b34 GIT binary patch literal 1945 zcmV;K2WI$*P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-!6G=otR7i=XR&9(_R~dfK*ZrEAd+*H7QYoP^sT5IasgZS~ zqy%Eg3PaeXV2EwvN1{J8nwn^A(=;|wG%=_k!2LQkr54zp% zxzndl_ipArx)IUT)D+cP-z$Xph!A3plyXFCZ2|xwgbG4PpE33tW9&FW==tgC>GEw8 zO-)U;gb)v=X?katWl9K*_LHt$8la|jP0AAo<4k2L=zJe*fh<( zS(be&iXtwANC_boN+~0R0Hss_z#vHyB&9R}Km!0U#vIpm4coS#E{fujqeqXb|4FoQ z<3?Jq*PjZ*aAz2X0RU**wo#>0nWvP#0RVq<9Ovac&uReu_sEeW=N2HB^k03N2|w!*tX4F*Zmsj{FSmSf5P)eJoX@(eM1ONnM><~hNq9}g0ZrwU^`0(LNrfJ^q zdEN!BwM^4=ZM9n63;=)u0F+W&vMf`EVPGM|vtwgp_a;fQp(u(BW2^xHwAQrS?S9vB zoM%QxMwa`&uRYKEBV+75=X~3W6)S$%YPCL*Bnd(Y1puJ3EK^FUEdT&?e0;p=y6zew z1XoH0)oOJ&V{By@h6{`R(~L34aU7En(mi$R)VDWm*zh_+=%u14*5`Ttog_)_0s!gz z{#Ojccs7pXyQP$c);bqLtQj94Z{kLyv06%5*IIKaWkpK4UTb~cw(W*#nvUZ*dSqne z6~}SDXc)%pyuh&;ot#w^% zZECG`wOXy3rum~djt_XA_gBlZR$z?p(po>&ZnuAP?J8)kS8J_rQA&jfA<$ZbQVIdU zWlE_bgt$#9RV;p}j;}t%7&F5#E(SrcuhZ%LInVR&6GCo_qG)-Z=Rat*TE`|PCf>QY z*p=DY*~5g8FVt!^000LeWL2xxx?vdYMx$||R;zU}#$;(>5kdomP@$BPQpy$0X7e5Z zm~$NGoBe)&eUc=X0RStdK46;W?OV5Q&3)f*PfSd_skMIDFpRUV>oQ8IW!v@}y$(Gs@v@>Q4AV5Mbc{s+4+vk|a;(dA^4+cDYiiR4Ap)vMj+En~I`nbCzWTDP!{KnOEK7wkUgmk;FMZ!n5kmI?z{5$B zypMDKUH}jXAp`(gDMgB+xTKW&=dNA5_GDRB&+~jlN?FuuH49^WY-wTRIDXM_oU@EE zC(m=Cl+uP_3@Vk%=$SKT_A$)b!_=!%Z!>`k$9Xob>D~h7eL{ZeE zlrr14nPpi$%d&oD+xFvGmhH^4?DJY{P6*j=S=K+Mr>Bp!TCI;FggzSt!F#eS1JCnD zT-W{a?Ck84O#GW3Ei5cNTCdle0I)NPqJ9)bB1sazTCIMGbN)dg1dZc(mGAq1LI_=y zQd--#ZTmUrd_0b0#yKxM&ue&|H$4~(9=$g9by7YxHAR$Cd($-iw!9(HRZLD!ZZFI7!8A?R=6S9- z=egFp1ONp9SZj?i#)L6u*|v=x$2m(W-8VBcGxy)(-Oz4LPEJw)xGB2@0MF0N%)EWO f^`H2E4dlN7AXE5WZ@ify00000NkvXXu0mjfd}*Da literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/TV2_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/TV2_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..8ace46fe3c10071c5d7a8499592aa3309565ed95 GIT binary patch literal 1001 zcmV000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-wV@X6oR7i=XmR*QdRTze!vuAtEj+CP_m4P5iazO(x!i-GmT9QHl_OI%#-jm$??K=yP;EsyZ()BsuoYNul7-$IH`(vN z1>ig|H6Ku^iAOtuL%>tOG%#kMs8F&Y4*+ezufS)(x2+Ooz~{ibzyxqFm2Z$ul`B9Q zI0hU5>dlC9-~_OX5SF@$7n^X}WKpT&f201N5yE>0=phMZ)?i^Tu$z$JIw2$@z&GAs zkdQ0^egG~L!dJ3R)fm0AeV5|%vZPT-xBT3ebVt&4NvkAnmGrNqs-!VVrzEvW`dZRm z%iogpx8I|Zc0~M0QkL|Sq+v<@l7=J=nrKAQUy@cz+9GKpA^B3$q{*u`4I4gykm?rz%`0qtNTB>71t$|6N_Lou+NoKa}hiSTyzBvSiT#0 z9{3YDnxwyE%ymF#4y<)aPA3AHy%=|84FC@jnl=ZXvoSgF3$WVN8TI3uHul;aXt%4g z8Y~IpkA#`_vyHj|ya9Yfm;xW#n8sF#p<4*FH=A`LOol_igTRZxL7)S8&Ce&m`?k8j z2^JYJLl>%CAXD-0M9s7CBOS^#H2yD*t&Z*>SG%*;Hcd6cb#G$E;4pC zhUjkoXSr6e}}R9W(4Or_)ZcIz5$BFwz6cyI|wuHZJHc>Q@~rmVZsot zP?YOjmy2|-Vx7arm~~NU<#Mu-B0Te5PBP#(?(=ezt_8q0TDxw2Pm!bhCQ8@;x000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-y(Md!>R7i=XmQ83K*A>Ulxp(fHk2mkmd-J45;2KjCVhrx0 z)G=C=IyQ+aD$7V<OSrm5q`>;#C(7fzr@TyJ!}rn^3i@hEnhomK;P(fH+H zFnBqNqAma!#u($A`&#SR7^6!X5fNCHRRsX8wN8l$0f0#QGc?EYPA{$L2zqhW8)gS@gm8V|e+&Ru8Dr0C zt$#;Et@ZWwwECdi|RZA3prS+}zyHl~S)G;);~= zMMRtpg5a%Mt(GDpAB{#ynx^M`-@m+7Nl&1<#V5+csWah!EJ z9jTQ1eYe}4IDPu`kA}nHcL#&Pe~O|wTNK5s^?LnVYinya7-N4&L>mzyO;clxnE?Q> zrl+STq?Bj#JXd8!86x6Z>le~Ay*?U^5@SqCM5fp4J!9MUYM$q@QmP98u(PxCb;j5? zf*|7^ZFbvORS=K0<5z6XeMNwpkIP^Ski!s(^jMcQ( z3K0b&KA&Y7^E{8+w*42S)M>5taO^)W0Aoy{wQe*TjWZSzHA-1I(78keoO3RO_@n1} z_wV1o|L0SuPMxtV>tDv0?=Z%GXxsLUBuRekIL8cIRJPI0Dkr8(W4K;FuXS$4u9(V{%cC9kcc$r{7K<}Az}{^v;9{dr@$Bk zX_}@=sU2fX9LI4xNs_OfJbChh5aLp;R%>Qi_DY(j!^85l?-?=x=vm!v_konM#~AyP zF(xllNQh`L#vI02n&-K$R;zC+rJjxBxMNw?+ffuv8exw^>R4*mYf2z8(fa@cfArCvHk9U$AX^+4H(uvs zR;g4z0{}%t)g(!#lu}0(4EnymBZT-b0Dv)ODvo2BWm$e$g7(J5{QUe}mSroQPNxsM zL#G<3sTCa>$)pr$N>-lK)>IAHwc23lyVYw8}N9W3zU;^ckoRHLD1^= z`|s}megL$&xmh6MvXt_JFbt&-!lUt|dkTPvNC@GDVJM}PA27z2H#avAEGkc2P8Jpx z=8K}Zo+Qb+V=gCuvn=cV)z#ItqvAbv-C9^!umIp#>lOffvbwtZ#n-LF=l@+G{|Bz2 VX#vYK=4}7~002ovPDHLkV1iAM0>1zN literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/TV_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/TV_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..6ab0bb1953d8a7e22a9c9b0a5cebb8bd90fc5fd7 GIT binary patch literal 959 zcmV;w13>(VP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-wIY~r8R7i=X)=OxdRTKyCU%t*XjWNbjQx&un!B-Fkb)~p) zBN{2{N^#+1BL!D=Z7F0p_b#TepYSD) zVres=p)D+W3@_piEaRU9>RlL0MRs8ae!wgEWKcm3Uc+-(#NYM#zO(h^QS8LqcmXS0 z32NaTJg(5vJ3N%Lsf0!DM&^?YP@oBL?LPYG0h+`3P zE+V=S@p44$&Asi+y?M8rSjQ53RnUQmn2(6rh&UAyBmY52Z;nL7uZcCE*sDI8O2_WN z4DLy%ZWjA(e1}u{eKYP#=U>1X+>)46_*_IxM8r1{(Mgj(iinS+jPuo8jEJSwG9uzg zWyR5mSjqK65iy-uoy4AKVKTK}PE8l^J8r;LN@NC3WYq1)81Bp8N!*Kb_ziF3?qug; zVox^Mt(27&B@bG7DNSBT;SCPr{sbD$=sJL>a(@JGDIwm=yOqS=-Slx^XZ~{aJyiMY zLnTKRl{|SMeRC4;RrlBVw?Q{eY$^?;>HTNn4}7JRoBaxXyVBD6JTshvn#Arl3iopf zyrLvpPos7HIwG#m^<5D$77zz zwZ9*|j_1=iy$(8@zrCpJ^{A#=TT-H{*MTQ+*d}d40v=Hs-`NDI8{I}7w%%`)YBG&y zQ~}hVuuFJ4wHa4Jx9*@Djo$uf-Z`8Y>mDkDJWg&;%eH!)H2BdrA1C!_;~|4Rx4y8} heYY*B9{=kB`7a9?gZ;P(E0q8M002ovPDHLkV1m60x-kF% literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/TV_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/TV_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..54d50ff61174720f491a77b4ab38fddbc5633d62 GIT binary patch literal 1634 zcmV-o2A%ndP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-y+(|@1R7i=XR$XWu*A+hJ{>;qI?#^gdT89eS8k$B~aO$`q zcLN6FR1QuX+meYx>6=4B(>$dwg;MfVLLQT+LU3`O3Z<$eS#FE0)V8FDc5&+$Cy+R_ zrB*|Tv#VXrtaf(p-oHM0R+b$r$n=BDg_(QLch9-!eD|QW7IuS!2M>-_tJMi(OauTx z2D;G3JBhGvuC`d>$GhK@e2JFnq7wZoj&^y1Ergww*N$!(YX5d@7FP79oT)#(c&Y zr<7_!NJa=rt+g`ukQ-xsV~nS@rb;QPloD|qw*cVO$jHb#0Q}-h9vwe^{D(q_bM1CJ zE*6Wv>$*)!=?8?68vyXJ*7`HXSW77-0RR|dTq!k1DIEuZ$Bi-H(ON$tgsAp2m8A_D+0#ypc{nIVKw0JuFlIeGBt(W8+ucN1qAVnno*Qb#Fu z{mPXq{{{ed>J>n@XwMgpe@HGE*oNo&kVGRSN5khKG z%1laGtJmvetWv2=2q7Y4j3R_^M9dIzjS%v8Aw)$8!5qi2#bWU$V=NUyd?QJcGGpwi z$;ru5wOW0AFc^HV+wI1Vh*fGSS)&+^K)x!Ygry` zyc2Qj0zgD|x>&}ThP%aykQc8I;t!tZt!G&#q?E6wY5IL*j4TuipLDz3-)}Q>#2To&W&c{PO92+ynq%X=&+G$8oMwN}W!p^UWklN`*qfqm=$;d3kx5sap}sZFfk! z-M&dF?GQqkwboc`gKZ~b0KoIHrFDq-JKy)wS__OZzfdTA+-kLE0RTAXXsr#bwT2MF zD5afFr*o4u8jV&i^`0?C8)HUlwHlRD%3`tDilXR?a=H8kB5vu{jT<-qS|}7&Mn^}J zN~N+vDSfBWXrurD2M!$Yj4>m|7|l8NIOiWV8jThM03d`cd7k&OB}uYwt(EEyhFN(3E4%%h1ppF; z;aC`k?{zwz*S9acr(joBRum$>5(L57N~IET&i&kg%{_$s#<2D*=iIMUDnSqgX9*#% ztgNiu)2Qs&oJ>zoA6H7fmZs^xT{b5lGREGXpP#?@AbVfgZcR^5GXU6Cy9EI6&(F_4 ge7ki&{@(`je?#3Ny^EgX-~a#s07*qoM6N<$g5S;pe*gdg literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/VideoRecorder_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/VideoRecorder_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..ba6799d3ded636dc7cee8ed2d4fa109da0e7188f GIT binary patch literal 808 zcmV+@1K0eCP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-vqDe$SR7i=X)=P+uVHgMS-?=atM$;HdSt6HMTgc93QnGSO zNGaJ_u(Ox4n_Lzy*{~2rgK|mP$%2GZin4GSLvlOJ9E4eV_kx z`#;b7mg@DoHl-I!&=cQ-c#aS4C|BE9@56d54#NLt6-5OYp#Vn#txQLDKq z)7k+1p;4!T7Czvof%+6^8mW zYEr=i9KdSKFq&Nzyv9r1lBj)nqd#Eb0WiXV#O5>*&+wtDNtSjTKl$PtUb`ei-S?Zs1=F}jb6%Bg=J0prpc>6rO zX*Nhp5@NyGfL-x>SSsME40x;*Y5XBg_>Td+DE_Z$w88+b zN6=*FTpo3&l$AB86|AdChgL`C?f)1l1=i8P9@P(5aT0Sfg~=EZ7$*Z0%@4kF67xQq z+`%_TI{0=Q=ivJzk)j{7r99WOrx|$hbcRlUV2o<^b}lC?q{zm*oRpML%ICd1@bQnVB9000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-x$w@>(R7i=XRzYYSWfXqzpZRBYW;g$2w@E;IG&L3~^pcXC zN`ltFnl`&9D|kpnDB__NFCxW*=rQfdOQ9YF5fOK{YhY=mn*{2i2N7(e6+}V7LpHm~ znEW&U{4@XWp|fQZvvI2r27Y++-uJ)nz5l(3T5A|YPMtb6GCDdsp_Ix401!et8yg!B z@7=rC8pIwC11gnDrq=pJDdh`N%Hv6r9MM|a004+648z!@l>SI5{RRG?U3>i0isPP)e^=DwVGX0-BqfBerdS7zDwh z@B5LIlBW^iK@N24fKuu*#w^EiJ`qB^*Jw0UU!c>cPn-FC{^RZK?XvItZ2(aH0QvwD z##q7gysz5r_M2;KYmcckdw=#k?}HSimHHnD1mJPR%J=;i0F;M^hc^M>-L9T=4`8Jy9V5fbaX8VHjSRpPw)80h*bav6NDmecu-Vpa~(wFboF~5BoBy zbDh#=n5OBPrs<|<i0_W@g3$NU6)^amo)oN>qXwS~hE(byIOc;jB zahx*%&@iW_rbZZJ$EB2^Wm!Y6>wY>uKK{O87%ycqnYSpVD{&mtG-nzS2_fXQqeqXv z0RW{S2$GeRl}`5-larI(vPLOoD5X3;H8nM277B$4Aw*s&6(b_iTKh{&OJTWOb~)$G zTCMice(KJjKYz{hJgZ)>|FK^ugfNDNhA?F+PLd>_&*vwI);gcIl`cJ`n`AR_w(X&OKL7dh^77jz001H6mg6|D3LyXy6VACEhT-JD(5{tIApk@{ z5Nw8FND%Q@n!*SGwBtC05OND3?F>6RJ9o0#?ET%{-Djng91*orDi|=&-3G6<)}ni$ zl)8@N+~3*RxdSPe&}=p%M7+uvvs0=Do9}%h1ps7>*@Td*&1N%t3TMRcNKdc!`9Z;70>f3jImLzHR(>zK@qgpgfTYid0u5} zYwJp{eh<*<>S~OL7a3#M3xxusl)61*;4lD9DRm2l0%MF_Cxl#FU0vO?sPtV<78Vxf z<2b&=IX^Mra&q4^&1=|?@^9owo~Gt@ R_PGE6002ovPDHLkV1gR0Zv_AV literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/WMP_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/WMP_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..022c7df6f415aa93f6a41202db2dcde4d020ff10 GIT binary patch literal 767 zcmV000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-vc}YY;R7i=X)=h6sQ4|K?=bWn2R;1`$Vubqm2P6hQCKwS0 z7!ZkpFp>BNBB_Bi5(W$z5d$_Q8_ z1E>lpVj*kLhu64%b4p%vzN74X#Mq@eIa7nzSw=W-2hQ=gyqyFwR>zMMd`8!u|Li%*Z>D35@eN zGVciKR^x?qe5Wmzr$9gUVimIBz@^I3Y4F{X z2H$53MO*|?tAU^*DX~c!e5Z98e1D~yn812T=L)0~NjrOnB4#2m7F|?&xt#2b%(`7p xO1!bc%SmqiIHHgx0$PqJxBt38{sRPy!Gl{%7%Bh&002ovPDHLkV1j{LRC)ja literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/WMP_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/WMP_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..7dd3a609f3128a14178c1b7b575255ad93701ff5 GIT binary patch literal 1219 zcmV;!1U&nRP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-xJxN4CR7i=XR!wLdR}h|gyHD1x)F`1&|7bjEH@OBl(;q&jOne0;CqX~wzSf#w7b&N zzUd)rvsNTmrr$|ucIKOz_ue;yL?o!DxB~1K zfZ_n0b6W_JvMlSzcDw!c*4CCDNHjAuV>*uWeWTG>ky6$GK%Ws15g;M~z-5F?2;t^( zxl*lG`*L@8_q>&6^5a}C_b4VgjpHK#5F!HSJk#xV+gj^xzv|-uw3PA`09Nw(d=&t` zIU#$4i^y-q?FY#3|AKx7H(W1 znw_0ZX|3-`Dcf;?WX5QkrWJX(RJNl^7*`rh$i*9wup#IDL)8;$!s=z?VLz!eLV;Q z-RqD95g`D;=H})}rBb;igm_pe6!>MW41z#wt*-+Bu<7aPQKi&`QYsvDh5MmgE`MiP z*3Ckp@K+|2$@jK0t}0YYO-xTuk22SF$D=56;>UO;l*{GcIp>Rx<2*ZSWs*#5-HoEi zaU5ry5s?$i%5b9hCfRAFQu#s%abF10LPR5BrZ~341_ih(i0C)NFd6`0^s_TW^boNP z177?vC>D!1+wJyNv)O!yh&l-q#<4xKR;wKfAw0&|+eDeCtFbvQ0yhFCPw|5##eY)S97=)#zrS}lARIk@R_dKr=MNub7LPW$lPjk*+ z?d|QIvY7d~Wm!X?SFu?9q|@m)k=>ppecM$Qh5Mm^D zq8`6?I-P$1=;-Jt&+~5AYBiZ?Rc}%R04RhQVT?WA-rnv2^vt8BrKNABl(&1v1Q>=9 z*|yC(olYhU!&bj45=ns&VpIsRUa3^h$HawsRIk?`IF2(404q|;D!d+i5Jiz8rDOom z`j1J=gb;;XE?4qA??KXj;R5XJ>~siHLw|m$3{mCJhlLON000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-v&q+iF|qoy6pN zqYn(sJkL4*^Y%Yyo}w&EU9Lgw#D@Hy#5g9pQEql|K8!=ylSX>;Y&MPE!5{by^D6-r z9U?l4AMgcU;Y9*f3Pn2dAwIyrxPXyv4K;8HXE2B7b@?T-b>%+v;Afn}LMKB_T*Wbw zmW5@&S6XE{xdGR3S}m20CBi@AxG3;yj7Zsq)IFY9?Za9`-{V(IrFW|_QeTyBKTcq@ zZm0*>1%01)Fw(69rKs6B4q&dL_d&s~sSZF3f?*%!ds*8rw9C*CBzl&Z2QgL|8Wt38 z391$;{3_qeH1Yr!@l^CvsZIHc=Dj$D{prMTWoQt)b8{U3VFr7#8UH6h3qN5SHi@2j zlwSAa&sy}iL@6ZpU=zCpCFj$d5v&n)yPv?*d3Fzve48Lo((|+U7&|hxGx#L2`zW zWVGkgfhke1nT&28UuR02Vj>ixK6f!uO@U~Ow zAKyGq;<9Mcz67YA<-n__FLf>_#-fW#HjQlS~#q`>(=k0x0YRR fGgM#ib%A^h&vD|JafVd)00000NkvXXu0mjf!hV6I literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/YT1_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/YT1_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..c1b1ef2397a61fb27322934b9227f3913778fea0 GIT binary patch literal 1473 zcmV;y1wQ(TP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-yJ4r-AR7i=XmQ9Ep)fUIkxgT9!HJw{sHPhoG=E)19VKjmw z2?Ijnh?+bm8D@eD(Un<95CnB6;!50VaN$Bhx326Val+s{GE6{(2yfv8o)P2vVP?8} z%I^BQbp|N0{{!(N`FM~_alTCGDw6afGTA-Xqj-n@SG z>eY?CtjD{778Vv1Ge2joeb!n#<(wO5W)A=W5eq5hrq=p@TI>HH;!3;SuI?GMu&{8- zTKh(trjO-$PS)C-h$;XWEkGfJ(puN+^|}axU|nl{zTIwrwI|TYlP87edGBXg_DYf@ zrL{I4W`K7Jz{3Dq>%bUO^L_vGqA1>3US6hMLC23DS5XvwytTD;CP|VG0MKrLU4X(E z6Nh2=WvA15?aGxa+oe>uejJA3dqc>^F#et(0NWW;k|Y}daHiR8ZUVsDqj@oUnVXxN z&GY!wrh6s*18K2Wgrf zZZsOt0Kl>W03f30vn+E;DJ7*;0D#W9(mCgbVAfiD&1UlkB7T&nX}Ps9ubv9^l+!s$>TVV znfY7K^SZw8AF$T`s+4MJt!-JBKQi+~v)O!_nPcZ%4-qj4f>)V&OeytH6h-|k%TfRc zhmsX-A8!BvYpwP???EZ$KL8-|Jnvu5xssXpF|!^XUyX&w`4a$?h*&Sn z@|&uvQbgPlTOeW=5exWTC3tulYDCnr*8Z%N3bHKwF94K8B!m!%h#-U*uh;935Rvsf z?{NSS&bdt~<^4hkKtws*SOEZC)#-Gu8)Lds%E_v#21NAle!m|u^P|k%t*YuFW}Yg` za!LsC{rdX)5)pkjIXNlAFl?-^uWuYVa^(ISH*WmgYPEv>`}a>Wa~%LC5K%}eyWMX0 zIx;iN&dz?&?RH-*iXxFx)|i?()OG`^{DF6T=#Mi#>zf=?j5Rn~TP&X1>M9iFX-05^8rPS*} z2oPdN3lIR9h=7RDIX9@Ps)(W}5JG&ttqlEs|MJ+_*tNl6@UXQu9Vzy$>M*>xRaur> zcTlH4sYtC>8}ohtTEE}FJdzDqU0p2^@k3*bH`?89K@jn;1|uRGV>}_mhpVfr-FBfb$$nEZEdYW#B;`&PvbZ?TI+yE|AxB*SZf``acqn+p9&$)t*x!? zFe000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-vr%6OXR7i=X*1L;UR}=>D-#IhRL`D>GtWpSeQDaJrKw=Tl zq)`iTVxu-Oa!a6ViWNJ7Gh(iVF=FXyzbo=dmZkcGxyxw z(FL3H*lT@jKfd+tU8R(aY5VaR_Qm(Vc#2o!1W%69{~b=^NFS z#Ej11D!xDuD*@C5R56fGFoAz?9e<3QsK$@Dj5REm{w?1!cm`9rjVtJnN;HXIa86#9 z{t)mkOEJiOxPwcIrL0@dH!vq}@OF|2-+si-1=gUmn9(WxjzydIp(@_HX3~CE*o*Hm zUnZKu-!grhJ=qn{jTmXq<~?bW*D@I<2}(KOEEY{V=F<_Y{Mr6i^FQ%Y$mrSvkT^g5;VAf+@FecNsKQc8<~wG`NDx#ADw zU5s!F&tz)1?MoaS^1rl4fl&qKVeGGQNTy^j9BV9ffE<(e^7x2ED+bHk3+zL+%#LY; z0;{mz0rCc)%KLZCa3=PO_kLjSZP(E_R>`&U!d4b`+N8|1RhiEH2%hNh-;MineLU~* zsax->Sgi3xmYW7V$@Cs(ck#`LBxE8qGo1+RC$+o`kFhfx)^VT%O`D0Bn}M00000NkvXXu0mjfwN`x# literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/YT2_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/YT2_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..3ac89b9972b9f06de30151e5b281aed3df3c3984 GIT binary patch literal 1295 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/camera3_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/camera3_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..0f48e55f93753f3650c2fa688e3eeed0e28ebcf1 GIT binary patch literal 830 zcmV-E1Ht@>P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-vxJg7oR7i=f*1d~VXA}nT-<_S^bzO<*t|?54D5mfmtOc<$ zkw_9OVk)( zJENXz=Dz1V=i`0OId4&xr5(tPaGw2_&i=x$xPqDa zfQl{|eT_rdj8}M>K$Ss}fh@uR{=iZE)T^Tgj^hBPF;&-}qgyu~#SqTmd$hVaYT^fc zBg)e106w3T8RQr)V!v7`8*`M8VUM`rew;|%R@&}KtoC6oqc3p*lNsHpsJ#T3%I^y~ zuXL8-TTIj)4dHh|-zhA{&5W+V2iTU5yY)kX|M4sXy_a^=6}@)|c1>agH}FLoRdNU) zCRmXUOF{Ei23z72Y{&D&+=0uLqn+9;8OCX>!Y)DU0#9(xn+>`i%d-M6vnt#3td-c8 zo1){_ zB?s{_R%S-G@f|K@IS12r4C|VL9mBQK6&d{_T-RB~u{uFEiu>4xtJs<)98An%ESuX$ zy~!T{5_4& z1!ER3;A}=v_<1_`RFI<@Q;o##ID)G2QFVGRQlEh>JT+$o)raa=I4>^ueaNh#T4&mX z7(L_KbF5#f?8XyoqB`ib_+yDRo07*qo IM6N<$f}ahA>i_@% literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/camera3_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/camera3_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..0812614595cabb90c79aabbba7b73baf97b1c989 GIT binary patch literal 1402 zcmV-=1%>*FP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-x^hrcPR7i=XmQ83>R}{zp_r7=E*Ua2EZzcn2K`bp8MZ485 zL`kSRBoj$=Q7Ckwb|Kx=Z7FVAx-G6+il9gfy2_-cCaJcu5f?$MlvYTi5Xj1i$;|UH zAMf+tF7hTCn=kPXZ}rYSzkBXI=iEc2l-Q2;@8925DwTSK5DoxPO6$*_J)66C@7~gO z)|1UZ!^6X>l=4UvMIS~{v?ocDqLfkx076KhD9SQpY?d+h8zJOYwOWl|8#FvTT#2IS zT&vZ3-}ikHMUgLrhyipK5K5`a7&8pRpq6F*!x+0ztyX{87N}eh0~-GMUWy($dndD2iH{OvcnS z?ST+t82~7yTnKS62m*>1$*^ugwux)ND5UZ{NNhssND9X8T&L*1j+d zU0v6WTrT(L{QUe!v$L~N$3wYXKBuZ`i4a1hl$}!*LWodGDJZ2(Q4}eq+}UU}4z^ab zFPqKw0hm-%>!a;nn-pd80>AcTOF(py+q`04TE$7>3-x3_nX zWm)<0@$m;z%HY_sW4jn*699-8QXL}Xc3jxly7o6YtJ zA-;{G$OQmh*DWdK$NqFjx*{yod zcQ%{-)HKa%5CkCrRR|F$N#Zz;)1yi$owTj2Ry-j@nV6WU1GvB5jUPI6sJLUtj(0rI zE4r?`Hw?pek|YOB)11!d^B+8U@}vzQhn4cu0XTG%4BAkPF)ht7JxP){-MK1+pp;S- z>trS+gwzQk0k*D>RZUGzElMd}%d!?Y=dNwrS|*dZ&lpoY&-<5Bs;8zT^Qmwc1@mhyehUQdLoudc9tsqcbxz zOKGb&e{tySMvFMgq21h8Dj=xY<6a5W=T!S zH%-(0*!O)TNfH4#QmIsg@B8Lvu)e;&cyV#j7ecf(O?$V$zyCc#$lfGLD1gK;3`!}z z38YQ6(P&I%GMR_XW^-2%1WnKL231u(xz!N@fTAc+6a_*EG@DH#gh<-$c0(amm^TdL^!4l4Zven*dXJ5b-7rn_66d@KKoUYEAq21a zNdS^_UNlYfQU|gI1OTqE9kJpcdz07*qo IM6N<$g6W%=X8-^I literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/ea_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/ea_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..37eb375bf546c590cd83c977913c8b0d846e0dbf GIT binary patch literal 980 zcmV;_11tQAP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-wPDw;TR7i=X)=OxeRS*a8Uv6%bmQ*FCDfL0cSMfy!#hnn{ zh*qq+kf>0fAZ``WmAF(9-AJKyVeQ5TT^J~+P!JR}h*I&LWOOf{!}VCg-w9M1bY&o`(T%V1GT!UdQ3J2x2`u2xx_*mp-M9}u*omjH zypp3Pc41hdWw{ObnItmE0lbSx)u?Q((JQzgzvgo{&P``^%9b&QRZ6X*_I@fcj^e3y z8QqO{Fq4MeN?ms0uZ*@H{bTqYmt^E!wQpVM#{(ECZzDuRPehDH#B4-Nng8VUG9f<`_sV`IL5J)Jy`H}Im;+S5*#<;31AA_gPklZcqg zv}Yn>Pefdpw62MWO%ZW%MC^=+LrKSN5iuVTcc$LHHWW@J_MnIuiiiUdak!>58xi+q z5Mxo~ME>5Ij=oKus?M7e_(%=saAFTNlgHi~b?0C=_9*l1ne4hIX7L4H!bRAM2QiLk z@w~D{=4#aSqQ7+?HSh=aEAwqJdGEz<%DCBvCsTJg!L}y&D1OdnIbH{DDxEfuwMvJ5 znbBU0o3RF;D*I+P9!kJ597~%kunCvpt7PTI3}zlPO&rXq*Qe1qZom(i#E+TbP54Y1 zu;ZD@Oa^d1wx`2&${>zRWEuw>%E&m7kyrE`N`(=8ugtHvaEmfpE>Ha~OyDP6ko1nH zV@dS^Oto&~3Dl|EorI?k$**K9H zJ1Qr%Klt8Mcs=Uu4!(6ty&q9K_!=$Bi+EUR)$^2Qh}vogUah{g*`64uT~s=`oNQJy zTj_Grz&HNm<)kjFaEH#WTOTML*;f9|QCeCcoqW0000000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-z8%ab#R7i=XR&QusXBmH<_s==^+&}NV=O!s*3U?EYI9T`4w;Dwjx_dCzu_lHCT+p#@+_Vf=73=BHwLI429 zSo`kXyEhjX7nir=j~_=gHZ~@R=#Vky8^)MjS(fz?kq-cXh$-j1DW$w2rTh~jzBxHL zX+JU1*x1;U#+Xxa96y#Mi8IC|&N&MJ>kh~m6H>}Tp-^DOV)36+%2y^QC#SbXboA&^ z=KKCjTI**zolegf6Xy}&{QxKjkWv~e^z7`cdmz#N{rg22hCg3jT^;Xq zIxPTj0B~P|oO~-GQ%cpV)#`;-tM!AcSFdiQQfzjtR;w@OB+CE*oO3RvtmI@HDFXm! zt?d$#bk6kvfbxi4?mJ$q)tUhC-2X&$?AWp4BuUOTo6QvfAjTN4)oO{9@-;-%M6~hy z&N&c5eAimr)mnc#ilS^&uOktWl(N|0-+wEL zqHoU4&GiHTK)GB#7{~E$W6TO70wOXgB?o|Shhg|styW_>fLU5v>Q*Y1hms`uPNUKI zaCmt5g-WF|-Rt#)bIxLJ#+X=Zy}Mj49|V9|mZ##d*4pI-X0=+)l*{Fp8DlRSV_vY< z{*Z{Cv)2An2=SRTO@Dp<{P`;r6BAEgzI^$Xl=5fga#?L{7Ok~&&K(8-U_(Pg{l=JG z#+U>EP)b?wegBYpn)=gISgh9XWF3t$q9U z%_d1Q=$z{@#-uUk$ta4jP$;~lwf_Ev3m5*F2XI;`)o3=Gf`}{tpmWYgRWO)V`gVVb5tilS&ZP1A`eioSO7;>EWH2M13#o6U!t&E^w_4jp=J zWMt&U>FMcrg%Ce2l}g1;9ZETNc+VUG01JX3Di(`>KY8-x*LUvRnHghReSLkN*1D~f z@<&ESPFQQ7>2|ve5y#^=c0vew;>3xLQtGeP+B;Dc?QqT|n}G!)wh=J}fD-521AxDA z&L1YCT|$T<&Us+1UGO~b=_E;h$2mV~tz8Vm@RqfCh>zuK%pf8M07gW;EXz{Q^GZPwTwhyTy8-~f008FZ z=6Z;DMk!Tr&SloxuC+F@)@mZk006ADiF3{%A`p?wvaDyVjjgp&e%9+}_~^Ot8DnSW z=H_}EL;wJdMq?%jg0o7gzI?K2^Lw-P-OG34){g)Hlu~^`5S+bq>C()`+-!DUSy_3$ zTCGkhr3Q$It*?{q7=2_+DK${7Rwq|hR-WH{e-F|8{JcfPXO&W~*6Vd8r7Y$E4~$;8 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/iTunes_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/iTunes_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..1134a1d05dd0efeb2178ec3340f4ae27b3bd4aa2 GIT binary patch literal 892 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/landskape_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/landskape_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..306680d6c22b8c9418ad0d351e2cc4dca354fa94 GIT binary patch literal 1447 zcmV;Y1z7rtP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-yAxT6*R7i=XR!wYFRTTct{ds>geKT)5XwU=`6H7>NXGq;h zAV`P^v?N{V4iXdMimfrYF-CXd#tjL^5aU8ZOQCga6;f6M2^%Fr6eDb*(<#$8^XB!w zd#{VW8K>Bi63^--@80vBpYMF6Fu|0eCRJU#0w$m6B0RUsH`S|hUd$(@gTHMNg zdKS?5__(mvzO9rxpp@FBwH~(Cx&S~#Dd)T)rMxSp{F#X6CnqPf=LQ-dAAeUVb-L5( zyx#40jZ&&>jL87>E)Zi(NGUzf^H>lBzey?2PEJl<-4f8DLx-5_x}POUa-!90ttzED zc?PtR1DiXLQU+ldI==6Jlcwp%wOY+=3bc3cUJ*sn*H4~2Io@iumH?Q|05$<+VHj3Q zrP8IPrKJyV+_=#%r5HS1DwRIXL3#~-W)Gh-0$}pH$IIn%1HecB$>`|OqldfQ?)gTe zu?)a+&Rx#A*9-V5hZ~`j*1D^;P65#H@Nn66-IG_YT$$+u?c2A{DHIB`i;IgRN~w

&YBQ#3);Z^o5zz~2 znu6mvPXWL>o1dRQCWJUuRh4oa=byD&?cKp(@Nu5!9mjE=C!&1-_?GYcFI81lIgaz& z+qZAOzq`A8Yw|Gc?CjiKTwL^A*L^NYl82;}ysE0CEXz~#^Yh23(P*5MQU+yNhH)G} zF&qwm=Xu_n*REa5!!UgJ)~#Fb4Tr-<6h&VrqPs+N_r!@4b7#+?K@Pol%@SQBnq*AJqQU*Z~oMc+-U?eL#&vVN2yr;GP_VV)bY!C$hbzS$z{eFK5 z0AeEgy;ACrjIp^SN%Fb5xrOuR&+odf8+o4hy(o%ailV3(9lz0m)D{2)hwc#~Dy_AQ zqR8<)?-xXLT`BcdB9e#*M0DJ;teH!fF8!(1YOMgk&$ZV7j^ntKrl}c4QOP;CrIf|J zio+1Ghln`?e$|CjemCw(ZCF_V&y; zjvq$EuSh9(8;!=lY};ntZuj9V%f|OA2Y?=RyWN|HVf2WIO;mzSe`9xIAssFW(Clu)nNPg|DtD*$-iw(S@ZO(J53Vf1>v-c8!x-tLT~ z-qwffRZ1zls;Wm?t=4O4n$Afn!!%8sNs?UbbUI%vih>YPBciIRssw=Nl~Ui8QudTm z9nQJSIsasPd%ME`0Ep;A$8o-&=lP*6Q%Vhp=$lEBEDwjnXw+8S@Ank|R3m*u08mMi zI7LyMF$`m=D2f39RF2~S5q)?dK~WTKIF56Jb3Qe$3K1dCbLjPYPljPwPDm4ss+bg9 z)LQGJDB?6tV<{ywO|#)R&h;pYHV#0Wo0|n9z9odPM#1!`caUY-STsLZ$?;Ru002S= zlZf8h+}tb3`+o<>{{e}cMrjd2=ac{d002ovPDHLkV1f)Z^n3sS literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/world_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/world_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..50a292d22c24ecffd38e5379249f82510493dd1b GIT binary patch literal 1063 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/BT2_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/BT2_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..c5762ceaf56653beda8aa92df66e2261b1d32824 GIT binary patch literal 856 zcmV-e1E>6nP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-v(n&-?R7i=X*1d~dWfTVR-`t(d<^$19vi4~N6NzFkN+3kH zhzbz}F=``eY)ldVg%A}jG-4Ai1XCqNNCF~ap`;5+KKuieAnUpi*|om|Lv%-~0y#)WB#Dtv&q(8o$Ur}5lO-i01M!#h}?MAXGO zyewo{F97%QxnKBJ33<=sO${ll)@sk-717`}3DKVm_zgQ+6?HOaF)_|G6PrZOKDY=LZ;Sf>(ugXoBG*UFem zR*j_kE35w-FD1sd0@+Gp9%&LSXt^X~2X5jiVc(rXvOV|~cZ6{Uw)R_MF4RQxIFKuC zSF?tLIFt#ugmhi}g1gu~Mukpd9>9DT`*VeZF)Qlell(o5C-FyCc@!VwPi2=55_^Az zInmIPbe;V3U3@HhatYVOhW;o?24kwK%`#WgwG;!<@I(3jkk~6j6XshpDlCg$lt^nQ z?ZuaPRcPK9GX5-jHVJ`Fa9Ewtj(fSnD`Mj=DG%YjiFL6~EFFBGi~04tt-F0)7-YRw zWld5g$$25^#vUsj000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-yD@jB_R7i=XR!?XgRUH1kH}iJp?QY)e%%-PadXYBR;wdFi zwWQP-j7gKV2N4vkDAkLtcv31z>8;ozsE1NO$6Q6a=YnxM#Uo)D?iWG?o$dkvpp=4b+mT@yrcz3^TCK2B zsf;B_k^sParBVrLnx=Og3J^j_2oZ!~xW8B|9@!9*QjUaS*p(%jtIT4t_-CO|7_}^G z$uvz%O4$m6z#)WO7ef52Y1;dJeSK0Xg?smhVJM}PBLDz+XlSTk2r(dph!$cUxu`dd*HsWeTu?QfmH2q70C6mNGT0072Vxv#J9m%DfGemF5P zv2S^Kx%Kqv(_^Jl=`TvD^^C@hGHw^w>-C44rnwkneXBniWBF34^i#E3{djP2@VusJ zNB8X6Gr4>B?l+Poso1vtw`rPrwS^kSSl2YobzS!%URYRI&02kLl>^3@=5o0O+qS2ifqiV$KFLLMwEEUe;;@Ft~nQ@o^< zaTta#JbCh@+GsQ?ob#HL5}Br%LkL|7g5bVk7;h&@(gy&WvW`-UF~&CmvV!$}|2Cy` zi4fB30@-Xf3-x+^U$fct5kiO%Qcz0G+`D)0Q%%#p;+&u3oaeI4>$E0MDP8h?|MrH^ z+}vCXA#{N;WC8dlziaEd-7X}6fes*2=okpWk?@4b30EjVWV2m%!&CRto zga81l)#`Oh>1D=PIWuZgaHW(10K6Q>@vrrI{iSBJSw{$UHDRR`FviN1(#zMbUAx}i z+m&gJM&pca+x-Ag;hfi?$+z;xw{fzetted z2%Th%U2+_UwPV&1Hyp=t+=MTKwmjweZSDhPu8 zI~-1ybX~tVJ3Cw5itm}@*5u@*4gfnEw*cVQ?Ck9Gk6XR?zXRldb}#d}^+X@J00000 LNkvXXu0mjfJRYmR literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/Chrome_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/Chrome_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..faa353840da66df3130557753fe73a5824771d9d GIT binary patch literal 974 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 JPDHLkV1mcUI|2Xz literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/Hand_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/Hand_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..ab35cd13af0973371a84a3935b718965d9b74959 GIT binary patch literal 1011 zcmV000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-wZAnByR7i=X)=6kxWfTYS-+P(bCMu;y#Ti$%741Tl?p!F< zpxCNlK@huepc_#^T`H&`4z(LmSGrSN=^|Q}MWKkIqOC*0jYP#XNo(`+nwR0Y_|9$a zdrdIt2bVj1_x#T}|1*7!h_KEzifgeY->2{+Cf6g}zmEMe+>Y(I5W@(}rLrIJDaNt5 zCQ?MKb?u3WBN5S#h}noZ5fRf7@l8Y=kBFIwn9RL){<~)_yv8cjHSszgK?f}~unBMB zXPm)3gS z7k}k@Us`-1L4M2c8}J2Q#7^9R`SfBkF;3u#)jYZzk6Fp0MpE%DrtusuRp?y8CD@9C zSjhhyDLa{1yL%N4;@Pw+Y68{TqR>=j+@g}|w<)v^;ryChB-S&DeOA$~bidW}bLH7` zdQlnCNY57VdwTnJ8qm!BR$}g|D;m?CCCf@229-Ef;O$hlkXI(ArC1Ut%9?Dph<`i9=O8m3IrNY*q>QRC@L>-dAE%$;_v+ z>b*++qnNA!$DK>vD1K3bSufNUu2N!Ed9#EGT%E?%sT;3ben{!YRf{>Jbm-5m^s&07 zgSa)HH>K>HQZrQ{59jwobwwS#oYq(EWd|2#m>wg^}{{eEK^!6i2w^INB002ovPDHLkV1oIO;vN71 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/Hand_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/Hand_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..4488cdbf7914fc361b2039594893a9630744d554 GIT binary patch literal 1663 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 M07*qoM6N<$f~UxP5dZ)H literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/att_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/att_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..7e31a4be46c30509b423becf73cb03a4a010fd06 GIT binary patch literal 853 zcmV-b1FHOqP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-v&q+ih&M zi0BaMCACABprA`9q1$3XhrpCN6osG{H5Ds7Nr%pc|1Ns-^Xu?DKjz(K zb{k#rg&*_#&HFsx@ALnC8&y>qa&5*ln9T1PT*ve<%B>;x_h2`kO_EOTb(8E0e#Qmd zUkRwOibrqZ6FiSa{F6YnLL&_s#Rx9rFisCk)WjEf9}Ac-<(J8p%HwF`YkZ8}YD6u3 zi+4m=dIP{$T2&f3iIX^}2xW7b@aNbo68s<}Qnr`6dlRd_S$Om&PGByrdk~Ux)w&bd zhchKn8<#}+&aZ)_BpVmy{|XlB(Cre{wGv5%bs~p@%Cr)d*DgGoPt0BPbF@dlN~%J* zQIOoi?R>8jKT?qViJQ4!uU=wnijLojdxbY+39yI_qDhb9#{_DNhMg6C)WI+KvM{8P zm^-n#g&m?K7n5W?&f!%4_jW2@z()KfO7~OT#fKsv-(B9?MWpiYncn z9-qz>jHM^DmbFMz^i4P4+qi+_Vw6lJaZi8Njil8_@oIYVWXjytAG$Su7jw;YeI@~V z=|u}iGTyh6;AMP|v)Gy*&!+5UypX?BmR98qt~JHTxSDSNn|YW@i{8TzX~1q#0MlZs zZ^ujGh7*m^g!D*ixZddI^Ze49kR4_M{k zyN~^%v>z97u8L<6c>Rp0&XL4ea#0!Pa`K#|4Lj&^($pV6LtjqHwGOWt?z;7p=)-~Q f|A@-9rVHeMm>2ACMCgz&00000NkvXXu0mjf>OPFf literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/att_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/att_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..24a57b4f5a7fe84d1ccf1684776fad63b8303f56 GIT binary patch literal 1483 zcmV;+1vL7JP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-yMM*?KR7i=XmQ9EpMHI*1tLo~R?&+zXp8Y@)a!3xwgs6*3 zSQH5xGzrAST|F7}U_2xULP9_g35X&hhzTNIg3+77KxWArSQ5>+K@j4>LpDg&I?Hendv0)Xc#mC76dywUZu z?qdJ`{djM&DQqhT1PaJ$(51=5270EJ*}? z-7cYyArYZ5h8Sa(l=2VH^JWoIbPEpvoQMb!x#xKcQp(>LW1`z&aU2_C%q{=`Yj}9L zUrM<}DV21$?Kn$2;*3zbUc#Ux4IV~oX?WgS99&lvN0v)PQQ)#@?VbzfIX1;&_MYaIkZu-PJ_pfgqo z07z@CIOjv9QfU+C{Fj-TnUm|+um6&Wc5}|}%d+e+5&cjs7CB>VW0qw%0N^!5e8Knq zX|46!Ns<@<(49II03hhKch`!=q6GloHyVwP7Z(?=D5Z++b{myaZjvNktJNwq#)9kD zuYcEUHm~*d^*usF=ZL63%Q7bn!yt}hwz6p$A~p~)h1+Mqwk+%CR;zW^b={AI5N`<~ z1R|0#CJ{p9p67XUb8{z$hK4?rQa(8|Gjqsw-9Z4*jIr2p9EY*q|6?b1gU!#+-{71# z7-JUP9y!vsZO#}w6-CjpMx*gNBIdSjKi+D!z9^T=X9oudH)yTvMATTfZk?sIp0+G& zsNHT~a~$V`QmI5l#28~1=e*HqG;Z*lH*ZE~&YXEP%d(+7&tpXN3x&eNN~vEFad!{| z&qq<@X|1=FN~H}+k~E0ur6`L2Qc7(EfMe};J5ow*bzS$dJkS3$#%#{AjN7*DmP(~> z>-Bog0svr)U347hK$@ly$8nlv*(T2UR%1+Rj6otw0U%0}WCQ>}YaMgW4*-DCTBnHk zgfS*&j6J|Pe<;uMMF23jv&b$2bcSlH)w*0Nm8RS6_Weq!$QYApt+P&&d-+~+Wq?wu z)m;;j1_0Drr&{Y207wYoI*v2lYPBx+CPTem&k*s1l(Nu0w1@~Rr_s`9ckvSdpp>$} z7&}p~*Rvi70AONb;)3Hir=^sAoe{D&F|pi;h(Jo&=Qz&k^XJcB=sK32qh_;t-1q&O zlyZQGSoii^D}jiZlyboL{aUlxJigSw3^X-0l_TO|DdnkZwJL=WZg;}|3xI?WZnavK zQp!_|vBOhSQ_Fy=SQL_+O|epO>zqW lE{%_m-@DveY5!M1{tcX72<~aAQ9b|w002ovPDHLkV1m1SyORI_ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/bt_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/bt_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..e13a490120fc335f54aeafc85c13a97c9e455642 GIT binary patch literal 974 zcmV;<12O!GP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-wNJ&INR7i=X*3XNURTKyC&-41~G)`hNjnyV-poL=;LYpaC zL_aK{vQ^ZgY||z;6=jS50ikk{6a>)^iVzB+$bJ&iP7=#V2iml#86igo(#ag1IW6va z-nov>^hO6RJonslzvn#Xe(yQAi3okl2sU9j=ch1%ll^S&_OZSV_u-~=GLUQM(%H}W z0tawmIiO~RKYAFua0}+~cLKE=nhfL$tin<3#{PaCb?_>l!W?F6`&@^G$|($C4c^4F zxxTEUF5bo?N?H~w{W_e-U+Hil$7}}F204sa+xT>1p5D|wWVy4PPWFr9Y$)WWRDga4>cCp)Vx1j&kES<81Xe zkz*p~oA3#?EB9#%FX3K1mNpYgx>}4TF*jqRi!p_g^Hn5`LfI2J{|r0umU3Q0$~D-V z1Ew>G_KYOvFvhyrkm;yX*Q8N>S>MfwUsI~V8+f5wKd;=I)s>@##NN=cytL`7<$Ih_ zQhvA(`<`?Z7M-(5jCRv1g?X)vDHrwve#h&0v|8`xp4wR_v1htCu9TaN7Sk6>3Py6i z1>fMkw7nG{Db=Eb50rZ~V6hxY$ER?-qx6$w8GS4<8qM$Z_)sY+P1@e5l&Z9nmZkyu9)yXR<5X<7r7;X;DGtkAiYDWysrsdT$>okH=pRt}`ToLNs`H=KnOv$D3osrG@q%egK1m&b1p7veLYTYPOz08CmsCc wKR!-sS*@_CpXb)+`G=R4e{)pJ|9U|F1Cr&IrB)9AkpKVy07*qoM6N<$f|*pw1poj5 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/bt_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/bt_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..3ba525e457d357b4d831dcd09c31ab80df4a9af2 GIT binary patch literal 1602 zcmV-I2EF--P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-yyh%hsR7i=XmR)QdR~5(q=ia&Vwd+}L?1Vg^kVqgC2qG^D z=E>c z=^K$Ksci2$v%9l1duQ(9!L!S{Z7Nq>Xa3_4PY9Zrs?|jh;RVRIAl2W+qA$d8Y_!&~F(w7j7myIbQcAh5>k8lZ-%?7QTU=aR-WBNN$&%%{rbR_)-bhH zD*YsfY!DHc8MbYErBbP*lzKr3vD#|2-t#=q2qE?n(U-N>-)Oa3`{Fq65RnPPa09^X z=;-JsfTurT(dpBtzZ%E!i<_I9TSUan49l{dv9Ym+@B2^8&(Hr80IJpMR1`(GR#sNR zT=yws%!`di<1-tv3TI<7;lau3O&z?OKS(cUa%Q#39DWzuS_W)pFVd0ft zuXonA?OzblbR5T@*uQ`OFNF~2?%uuo>s+%5U;xTJm1bF1E|<#_f|<*CSsA{$1RxVa zbov|f^YeeyT7M6~5o65fvn+dgZf@=eH*enT0f5$8Gjlo&+BTFO0A+y(FD9ZLWn*h= z>mLBxxm#}S_;~xCJg{&IB5D%R4wG|%==FMDf8*4tQxoIk<4Z)8G4s2g=l!f+uh;wU zZQHg0>_`S|hbjTk6pcpXj+C+~gcz<8oMoAkQjP&YwOak+=;-Jx0A4o6{K5DAcRHQU z4~giv^?LpB{KOF=+7SXFge9eHHk-{mVr^}0BQNzX|F7_oF-8*6K>%g~0)wGAsLzv_A3HZ zoIij54FGQdK$c~inWrqvI-I6yeQ|N|tz7aYt@Vz$c%CPO5U&FHg>ARnE1u`wR!aHI z%tVAVO`|N!CacxzXNSeE>-vR4p&Q5X*ZYv^>FIG}%p*gUg_Tmi=Xtl=?e@w5w7R<5 zBckVnAaL@eU}iR*PRApnXDgM8+Xwl+{~y~NQp#r*78bJMb00XI%*@O@mZs^GQ4}57<#2M_vaEAUOG}qN z?7WX0w`OK$EC9P2w*b7hw6yf`$F29T|961=FGxZp3Q>ApJOBUy07*qoM6N<$f(Gmi AA^-pY literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/facebook2_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/facebook2_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..fc52a590582c185dc0a44cf09fe84c5c23175a8d GIT binary patch literal 803 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 BGgSZp literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/g-google_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/g-google_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..27dba6d79085889edbd6a97fd76ea26345ebfbf0 GIT binary patch literal 969 zcmV;)12+7LP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-wLrFwIR7i=X)=Ow!MHC0{-}fbLG|@;%f(wNrQqe{%qToVM ztYEbu)|C}O6v0h#;R8ez1a~Sbg1YD?MMN$57Fvt=+(Z|Gimi`@RN6$bDJ_k8*(Ars zoSWW$xvdcoT<*OybN=V`pE=Wt2&>B+hIH1-2N z!fq^_4ybj8h;GND*oZ~UB~Yc%N=ME@7rw*Ocz3mi+ISxK<8MrN%ys9xE=yR0wb+4& za_qE*x-p77l(bZfTjziwN!T2=vi#TpB+*3;#K^NA-s+6 zaW!tjbxQgc6>@CDBpzHwiHPdCEh1(kVj?2OYwxLucqAgOjEI8~F&`1XM8w4r(H{|? zN5ovN9k1!mM#R<%zcR8mBE}-(SZ(1%L>!5TuX4>(Y2;A8M{|5r>P^(1@f;gV?B$|v zR@gP2d9I`f-{$vR)~to&xJF^z0nB#jwGwM%VlNxoqJt$VO9~0#vn*~qYjK{!vh@lX zn)b<3Vrwfqex$)Gm{AHnf-!}WLpUE_;A}jJ6Agx1i8+GdZfsB}x!B;*qQbb>@r1G= z58*F-gZESaxRraW(jUZzHU^YhG^MWc>O#DRuN4}iRXP^a zzy-KA$42o|I@;D;qh;w767?$o2Il6GPrZDYT3 z+;lZ8JQp8g6Mn_5xEt@_EhYcYU=R8l^t%#!e_J^+_9+aihu?#ra2Kw}i?}o+pH8E1 zCfLWyp<0(n%zZdq)o8bstm#$uPAGLbk!e`UvB?}?pOH67JF%C+_bUCQuNKt;*5&t3 z98*%&o6oRvYAj{cGab?NCFWjEZ4+DZhC+@|DBFX_lpeDV+i^+G|AtR-A8v4x=9TUM z?!000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-yt4TybR7i=XR!xW;#}$6Bs;mEIrsr>$K){Yb5V4>@a#(4I zu$2{#naJ7EjtGGq430^1$jOHMV2lsJ7(2e$$sv~rD+rtD5O!v@u@G|DC`$s1atX15 z5IzJ1CM25Qnx3xit?qh0sAoM|t;L!==tI%()%U(vRo{C^L~s~8apJ_n;^N{lV@wqQ zfH5|_ckkYvn>TOv4ik@$0&2J077=|@YyFhgdMV4YIuSVl0En1y&ig`$+d_yxA>s#} zPAC1`K<#$>+gj@vqA2=G9LGj$9UEg(0GI_JW6TmlxUTCm-}gThLcHDSbpCiKpk}kl z9LIT0DfN9R<*wE`n)}TV(E+F29iBjQJlvAUFUxHle;A4kNWT)K2=5{BU~8Dj|m;M_-2%7lnsTv=JM_kfDU;u)pX zajkWPb2Vd(ImVcO=F1on4Py-BIF?D0EH5uFyPWg8h^TUa`(;8zt#zc7I$kUm&+Gvi zW1dz@J#b6%5*S1*<-yyY=VbuEj4_6Y%1SB07&}Tt1^D#Z@0n7{7-OCW0AP(qV?k@Z zq_vLc*&rfhS*D2SRIAlm+T7gyyX(5|Rw|WxrBeBV>$-m>A`cON9>=lX50tZtwbo0G zMq|OM)oRC*B&ix>(m9+Nqbv+VPY7|L-EP0SySw|A>$)EcA*NEwe;he-8n?-{sjPj)^4{yCZeB?Mx*Hg%rM`3$OePK z9nSfXG4_B;5E1ykU#!(?*DT9gwQc*~MAV#2Cg0OqzuRiHE;XCYTBpH;XJ@CEOT9~To}6>1P$+y9hT#t^%Q_Xu@tggA|I1R!!eB6nMx)WU zEX%ssXf(Jn=FbNtNep^E}2FyAF^)*f0#YJkPr&gz#sqh$sbs$Mcx?f*=?d3WXZy z+~=Ho#bU8;+xCZ16dA_Ycjwzl&c^pV?^YOwTL5#Sy1KghOp+w;^!xo001zT#xmV?07tWVmh79-V)73)pgzHuUxtE{sTY& z0O!t~dtFNT!(8ftF~&=!lIMBe-w^StQtCg9G0(EBIshzXS@u*EMT_%qiHINwf`uRm ze!H=;vDYRZIKa_p^h&i_T>yadQp&zDCL52((000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-v%Sl8*R7i=X)=g+#RS*a8-}`72o2rB)AmUoE6$83)Bi#tr zf{41Xy0LCtx+s3&(uG1%TnGi}Msei_VqDm|a3i`91VOO`MG$l$CDpXHXXIde{{sw!j30`9_G)_-9cE8{qK$Iu_aVcZ>(sp!^2_7lFq zX$*D(YVGnzkKtu3ViUap)efx$GK~&?zzKXhE>RnA;W_lN*0kSZ+jO46UYx>l40j{y z;$1wcq-D4b_)bzK$T@t7XEjpU-eUX)jw%J7ghXtI@jV)>k+ShekKzNYCb~&Tno|4D z;wdaOiT2_vrG3|o3f;km(hQRjS4z#6aR~i7bq^`swT3;o8Gqt?TnOPL(hAmMu&>wX zNTQy?WxRq{@iuU@=L8X-kcrgLolE|i&)b_AH0PC@78@2IE2nbK6V!Cq}uRkeUm zlv=d{vVvQc;y$hHg)7l_0y3RIdqz!jrSbkx^vign9niB;4)8ke&HKefbSY6^&bL9< zwZ511_Orfd)Kq7&QrGA-o(Vt)FQf*mN}KoGDC16vcCdFGLA6mwsmr7TcE=IaR}QVI z24H1$&`nCx3f75W-*8MU;T_C3943|8XFga*(Vga&vv_000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-x{YgYYR7i=XmQ83~MHI)+IWzO_$9tKZ_u433E0#h;5v*}z zNvX9`QB247a9w(Ee$Cmp)M>~C>0li3Xvr5zIXH9 z{g|0M4N-Ilptxz2`p%opUhEI(+!>{;{#KgVx$6000riD=RCH?%lh$ zI?Q?84Ky<|!<}<)YORlHtq+xDxz9Q00RSLk!5CW;LOc{g+(yJ(?RMMj88kC9^N!Z~ ze43^&=6PFbsbcLR@aQ+usibI&tCzd7k%qmSyiJNuspY zX_Wy!&4H^N2q8i#Wi1GTZ;GP$WPX0$?g%<^Hc66I060B5I=Th`A8*)c#{09@tk!sO&+ zZ4=aJG>&FjHm;OPIp?C$Xf&cI`X`E_`}KOgOGIq1X=$y~EX&3ljmA-^q6Ta2@ia}X z5Te#>HrEmH3*YybIp-?Nva>}|yk?Baw)_|lb}8+~wk*r6@B7CAV4hD*Ozf9Z9x}!h zqoboG=lo)=RwJcUqh7C**4pztuV$?+YPDJ&5y2Q!Fvb`nl5?)Cf;B`W0KjRjwK1mD zTIX8pLlYAd`+2L?I+*8qlXLDP;&+TOrn7-Ro%&L_3je=^2i27vp{IhQ2K>-~QJfVI|?W!Y>tn+LgbuIZff7-N8lzd7du zMD)wDG}hYZiKy$G`@{3RHW7gk;+WR@E5=yKIX3{Xz!+QiJnuQJ_0Pr_k1_Tt05AY3 zE6HkZ>mzF|bIzf)7CGns`uh4WobxfpSVBZO09XK6A)-)g9W%zz7^49|6VVbP21Mk1 z-~Xv7iUV1eZMF|b#266^V~k~tjU(bUB0|O(5Ros0c)Qo@{od>K01?Y1N&b>jepD32 z?KDmQuGj0wthH&9BtHZ}a0U_0U@*9Whywr^MZ^LCV&3U=9!V+VvMir9#=M1yKl;AE zX03%V48>qDfHY0t(^_YUNB}^~%gY1C*t-D0(=^Qykr45XG)*%A03v$D7_(jl9LI6| zh?bU?R)r7`Ipn z|5Kiva}Wdp5z)=fhVA$Jck1=}gTY|%g4Q}s(=-790RYdyV+FUvINt(sLWnR3f(QM6 z{|-PUK?@5D3K1_!DLtr!5fL3CmWa5k3OtPi04SyOi0IP7!h+fa0RYU+&D{us;Hs2z zUv)?AMM$?M15(O;K@eQMe*OB54a2s=ce~w-Q53bMlw;00ay#AgI}n_6B&8gSqNv^N zb}w$VZv!nZE*eBUC#Ag7YPF;gBCH(j2;8s>A;MOxC8d;Ci0Itn;^MYJWyj%UdU|@w z7;`>N)A1pPlLwsh%d@kyb5HZP>$o*NJPa{b={@?WgT_`0ee R1~~u#002ovPDHLkV1ho8l!pKS literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/gmail2_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/gmail2_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..7fb8ee3f9c36f00c59f0a13b4a0e28704455c0fc GIT binary patch literal 854 zcmV-c1F8IpP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-v&`Cr=R7i=X*1?O_RTKyC&-~t-nQXFDnD9M0oi^fz+U z#z%NnY)gL(_#_!*kR5!AH&t8Nj3}SMF_GZSIFY*jv^|zs>x&hmm+%RetLRD~cPq^j z&_LvK2HS8POSPjpd@IU#B^6h5G-6Bt8N+gb`zr@6%;tPSl>hVSm52|E>MBmQ;wwCh z12`qBYfY4O84uta9K67&@QN~RrrjknQFy_<&f z-cRgHjX3d7q;kD2#o*d?0f0 zw5Y5{@wxRjG+H!kiM^{Ws$<^B0js2&>!0Brkq07o7qN(6MuIESPup#G>vcui_+D(| zPW+k-uVH_(9LHz~VA*;Fjbqiucesw{M0NGWw)`L(YHtFgCb5?rTovu6HKJ6ayPn@e z`Mo7dw~M{llMKg6E3vOOB9T|H#W3~Kr#d1Zy^OeYj8^`882eJUTiFj1^9pX199_oi zmC_wNf*0^uvaUgD`90STCBr+_T9eolTM&`pEn<)VHo3tLQuo1Rcsu`(Z9zS8Y0X!F zt0Eu03}kk~m`j^m8I+vQCuXluE3$+S#knYvZdQuTVqz_og>e_($KvAq!~eVZ7RAN) zh7B&hRZ$dYMGsp@fHKB`m$8sGXA@)Sp)$?mF9(9=A(zA#+c gn{rgkJv|`*1G}!_aku8HWB>pF07*qoM6N<$f^N5qz5oCK literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/gmail2_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/gmail2_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..ab8bb0f3302f327832ded99ce8713b3b0e68b709 GIT binary patch literal 1436 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�G!QVF^UUlv3?RqtWShyXPOy z?*gr?tQbUmM=5o=)oLjzWmpO92^{35lwqsYQc9`IjInoCR#tWmDtitmv$L}^#+b8N zmK_;#I9U}!T$-PsUwE9}6UVLD*;xSqLycPiaC3fse*fdvqw#+S$bSG@p6_p$h?YeF O0000000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-v%}GQ-R7i=X*3XNTRTu~G&wIUdZ#I=qGb18Fi$KU?CX~uu z5JWX#5iS}*Fe6&DtBrqxh}cdMDGEWzAR3~kAX>Q5ji!Y^TC~Vq1dTG&!lt>7_ib^W z*L&tNj`z+ytM|OmdA{H0=Q*b+%TkXril;Fg>sz>nnO=@t49 zG#2j%RICuuTR4Dm+{J$ZR2dZE$U|6%UvLOt_exa5$9Nwt+|KuR?ahq`(ZC6Og!W2A zb$o`mrL?q{0l%M=;p8w*W4|nwwXV&FF)0cDtPM0)v+P2XJ(hFhk zXgjdgrHOwA^8x-FZsH$2fiayzw=f{hO)G#K(hwiR4m^)Lp`Q=z(Hgc%Em_9}T*Qm< z|85Xm!XJ1Hf8l)mui*-=2WS&Fq}r5WKa6d4sXLnC=@}`f19&pL`2;)hEzV&x9*zi} z!bW@-|1ZV*ckBv`CWi7kD)A`J2KhA{3F9$5hcBfeoWLBeO5OEB*k6_A=)*|+oeI1r z&CNoDJ{k2n89+_Ej8kEBFw*o5-oOX=G*YxaBA>yJQrFc3d$uUcaui=lGt>^{pOL;z zvHm+ee+2)AQ*-zUd!@7SU5rG;bCH#S$jt6qcyJ{=S_}`iWJdFm_jN&1U_(T^h@bIF z?5P^$@kr(Rz@DjUG;Qg*S9Kem)~>!ut-A^DVJo(0`%0bJs|EI&j-YBdiwwNTbjuz= zE$Px~W`+-v9JG5~1lFOzUXrdU9G7a71N0-6%}8KP-ScXhi|=#k;=5^e7vG3<@x5b( zi*FJ8a8&B7L7n_B7h$d&44b2YvE-rB%j0BBifpCFNe#d1^Kp{P0AAPIbL)HAk<%|x dE^B%~{tw1Q?>$82EIa@J002ovPDHLkV1n#uhf)9l literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/google_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/google_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..9e6fc3964cddf37f6c76e0bd78598e97cec8b262 GIT binary patch literal 1418 zcmV;51$Fv~P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-y1W80eR7i=XmQ83KRTO~Fxifce?!56%<|U!1D7tBhrbtoS ztSqUvRAXvV7lKg1;-YlbE=3B0xNbplQ>kDVf(u`0EcQnlQxIYnf;JElqu3kwS? zy`0DUfu^RWTp~KCwSGx!JzSRM01*iQ07T3k$64i^FLBPlMa1j1TFpE#XliQeRju`@ zBuRE>S!T7?nYGpcK<5B5#$3*MUteDz^L_so=loo)R{Odq(BZ>}nGoW`G)>=*%qV6yd41$5u}vhdETaMq-kocwTA!z+|kj|L8a8N);g_JDt*51|EjfKl~Oje){izC zji<}9L_{QOZ2U^d!F~H=Xp;eV!zhIT0wQrSW+0a@?Wmy`=nC;jQ5lAT+W9(Y@!Zw@D8&b+e&bd#$jRQ2sm}awS(==7a zn9e)Zfe`21mr^b^o6Q?t(CqANfrw|7QesO4+mr4JAR=uU!UO=QloE`wv$M0aMHd7B zFf%iASxR|9DK*fUSv^FyRfvc{DK#Laym0B#rOO=!+h|p<*UyAuSW`+35fSS#ja>o} zF{RW{7>2cay?$n+eiLYJZq6X$38mEeYPG65HM<|MqvxFa)oN8KrOq?PPRz~CZCX^e zT}~z^Cnt2Wz(bY1t{^z`)1z5LyG-I|=7bOE5JbqfHlPft%j_`0=K{_g_$ Y4~dZSF42i_bpQYW07*qoM6N<$f)B`(r~m)} literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/ie_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/ie_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..460d781c08af3b92f06478464bec3bcb72454736 GIT binary patch literal 984 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 M07*qoM6N<$f&{e~RsaA1 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/mtel_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/mtel_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..2309aaafd6dfd342ab914b776c5ce938980e528d GIT binary patch literal 834 zcmV-I1HJr-P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-vyh%hsR7i=X)=!AkWf%wW&&^p+ko* z3Pt9Chy=Nv(o4qs(icn?ch$n|@4bK@rJ_#7W#r5{lZ zr*S|^%Ss9OTG9z8CvYBzWT~w7C?ChPRN!Gqgzie%P6t-^FpFp(&S5^h8-^s8!gd_* zU?wN3V^(V4g+3&?1O1%oNHx2LomeVTw_ED2ek6qyUDi)3fwd#BAJwR(r%QUg8;S2a ze2W_%KZ63ZRS->KEAA<8-x~f2-8(oI0ELqktJ^$}>Rw<^Rk1~C$>kD~s+58+!l9G+ z9WP3C9SyK*k6j_lfxV?Bbw@*a>Nem@T*hzsG#s0ihIu}8TDtWelh#w=cmw0TbCi44 zz-^qu6}%sS|KWdJ4f1Crq74z@9KO?2!&-RN#`^H09)E2dktX~jynz>R7JuTy&|j9) zIg6k13U=wHzK!`xr_-6jSCNu7ehKn9Y?lW4S8T#fyo$f$yAgj#b$T5K@jUJZQC*s) zw`$VL_z5rLzHVb2!gKgH0Pn{4EIz^Y0DBE@q~I3m?-Dbp4DMhPz?`6rG$*M9*3lx; zyuD}e876yxhLOT%GO%VId02Asossf-+ml^T~fuz`Hmh4PaBZ4rLMMXU(uV z5g4l;DuX;uwo8%qdz@79gCQR$xr}0u!Jb>+NOM>!k0Z+EsUDCI0gFQF&2ieI`v3p{ M07*qoM6N<$g6y_<^#A|> literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/mtel_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/mtel_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..b5972b5c926070d1d32fc43e28cd1de59046ccd6 GIT binary patch literal 1376 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/net3_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/net3_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..0a75a91c2139f7ad1c744cbb7d1a9c5784d0b103 GIT binary patch literal 1601 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/net_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/net_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..7c72be1d81db55e30a5bb2aa84c0a6b8d9baf7fc GIT binary patch literal 1918 zcmV-^2Z8vBP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-z_(?=TR7i=XmRpQnRUO9v>$dk^`#R^G88ldm;4}rSz9`Ma z8tXJbFxWU#FHIovLLx>I69~a5H8GJ8l?Uk)J{a*5@Xb!cP%{C-q!n=57c)+^#aJe- zTw3PLoU_l_XYak%+H3uNV4MJ{q{Q!et@X>gecwkA5w1kLckdpbn3&kPTR zKT=iIxAHvKP1Dq#=S8090b?vj#2z9#N@>eEmno&V*1F)F`&pKGQp(>br4B7DEV%y( z+PilzZ?#&F=Xri0&+~QP_ro}j%OD7zH^wX|rQQgFphYQ-%d$MjIp6Mi-e;SpxnndM zb*icwrD@vEvh2vl#>TxTPMp{}O8QP}mSqp;d46Cp7~_1qK*R^LESt}=EE)_38+o1|7#kaV__90NzkmN7N~tHh z-EKe2vNVq4-wPrB(KJm70ACV9q{HFx#j2_vXqv_)N%DszNdf@aRoC_5AP6RkqG%ao zzL)2D+39pL-}mpHpPxUrwWI0jX%7+a&+}YKDWfQg7NnH_mQvngt-XN|a#v9lCxj4t z0f16UK?pHj6veXE`ZJW$eV*stG&VLCODTUBMNypRxkAMIr>CdAEl?cC`^vK1Wvx|7 zl5BLl-NQ}O!0PJiUzySc9bGKDh<$T`{5%H<<@$oyYwG&|&md?5FP)b)j zoz827kgp=50RTY6sNHT4gb+6wV{X3cs;fM$b-I1~_Cur5=#Ns$LseBdDdlYdut2A# zrpApiHyUG<=Xr&5?p5d9m#eB;ruG-;aVYUkV~ z=iGJ9Ibe*95HWJj2|@@XgfK*8&bb5;M~FzQwc7!pFvfU^MgDOZFL7oBtGl~Qj-QM5!UH2{E= zQm?M-^N0vR5G+wjM@p$~7=|aCrdcI~dG;R$Hys ztxeOM(ptY!Rnl#|n(^TS7v z9-Y73dhc7eW@ctM09;Ys0)Xd^9zFWO>(+bq{}#yq02ihx5>#0zRR91007*qoM6N<$ Ef@dA2S^xk5 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/netw_conn_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/netw_conn_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..1c3c961f99917b62fa25f50d427619e992339323 GIT binary patch literal 986 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 Hu0mjfJ{3ab literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/opera_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/opera_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..6f5799525288cb52665dfea674653d8a18f963d4 GIT binary patch literal 914 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 R&%poy002ovPDHLkV1hMs>c;>8 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/search_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/search_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..3c1350d7bd41497cb36f4e17fa2e26fc89598108 GIT binary patch literal 943 zcmV;g15o^lP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-wDM>^@R7i=X*3XNURTKyC&ph)wV@_0q8U#X{ATqHK#9Bp* zzy!@8${_l+2%?46LjQnP5flYhw5X_{gs4{9&?4GbV5M$a1!Ll9V>-?cb>7qBp2vCS zdEXgd>B8lG-uvTw&iS72x%Uo5gaO+|+=KP`{~S(YYLLyH0p@pMC$^-K(VSaIV}Ia# z9KqFozZ;fA5 zH-euO`CjTn*Jx7t1b)ZE*nx}q4wHBlZ{%1gIXj7maJi0VcSOwgiKOo5BjS-<`*C_Z z9}x=?aV8?3Y|PCh&SYZlj)-eH+NGtEM!N~W;0Nr_Bu{6AXBAPrhfR1_sjr%mZepvH zioX|gdgWWwdMv;9;NPTXDEmBaQ;Pb8B8E=R%_a863Y!&4F0K#}%hlJ&tf9S?^kN+b9|8AZ%^YpE!9wMXgIM?bQF~w$2R2Kq-hbnexOe!gL3TT*lfPAh5}SE_#|BcWH3RbpQQpHOOLEEmsO zs+}G9COx0Y`TEqZOQPTPF_st;EWal9;>)CD1i#{E*A@pLlLb058< zB=$^tv{s?z$_*Hy)Y2hE?)n+(;8W$|JFEBNyPlCsq4=#}wZ}000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-yWl2OqR7i=XmQ8FMMHGPF8_%qFH}-CJH|0?9Oo61Sg~=74NjGnR(y5pLy@0QVO;s`}XY{*|B5CZYiY$06+-wS5{W; z-nw(*1B0s7 z>R}ulq-nH zlu{#{^Bm{A0{}7%!v+8x86F;P0>E2qy2;wd9rWu~+#g5~A zXj#_tH*em2uH9~r7K_CruIqm9I8KoeLI425Fl@$ge4<<~mo|XL#>O-$<=HR{dFF;e zh@zC{9mi?ty8hD4%*^>DNp_V=r8jr(-1(}M@{hT>xs$eSziZp}Q08hCh9Or%Ubhm5<{%z7zz(TkUrHeJSNn$BrGVUcP+! zQ`0o-x~>-i0E7^|D2nzL3WXQeK~l=`D2n7J04Sw^QmRu*f1aJ4{jpN1yuP}+`bw+S z3Zf`#b-UeWqtVE9yWNi_CMF(ElH^lO)B0;3iK0kKDaQc-$mr2lO##vZntYwN)KGQa^)@nG!QWd04Rirg%Ep2M@L79>$A;E=794_bhTO4GDQ9mjd(_U+pj3x&dGp63+} z!*C0Qg6DZ&WEjTT`T6-j8Dpn8=X9$}Q$+L;kpsZc;D)udc3oFdO5eD2>C*4n(z(Nj z4}Yy`+Ovqbnk30wtyc4^)#{lzj!T^L)qz-JrrW2jR_m^1Sw11;A*GZUfatF43d1l? z)oQgL0073v$Dc4wb23fSZ#tdMXNahIp7&I_Tt3Ft-@i+j zmX;c&Qt1w3>`Bgf9}$64${fdu^ZER1wOVZv0AO-*@-a&3=RpwcB7_{*G%WxC76gII zIfu-Wb%;_*X_}@p#_lXFEj4IHzG@i8%basiN)gjE6{Ym`dcD2~08p(~pGcDAOW*fL zIOl&MB0=AR_Fy}m&JDvbmKkHFQVIzn5$Ajv0O07+qtEpF z{jYrA_xk;QmkQy2oY`dpts6Yr4)LeH>~UWiP_oN?>2w{04kNr2VoeVY`5Dhj4?Bp%jrpy ztfpz2JOBhN%NnsP>%z>;%zB&H(2s&3c*k*^5db(6hGBEfitRwMcoEC8JlnQwzVE*? zxW3`RE-Wl0hb literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/signal1_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/signal1_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..26f75f11b036f3d4046daea9225ee229d0827631 GIT binary patch literal 797 zcmV+&1LFLNP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-vmq|oHR7i=X*1wNcRS*a8&%67$>}DZAShTP+7V;xdVM2%@ zA@SEXYNa-UjfI^w@GlS&Iuc@`bYP{`LW%J&@CR6_rGZs9#<#%Y?p}+T%R9Wh_x7?( za*}h;J@cJ2bG|ckdQH>lC-KZZ!L}ej9Xa3`Xr#< z6p!A=c^tzA9wkt#(946&Vg^6pBEIQrsKRA@ipN+j_mAu?mFH383!KB|G(&xSg%3nn zHphTZk|qziA7A4WMJTJ0&6n_@xZo~EnjAIea&0*=E|nWgkKV-%tfX>RPv8%6hc5}T zG}woa@NMZ)jSGTFTN!DJJ$>Q%$9P>3VlMx$2{P5Cp|=FPRy%sqOR)A19;CrG+`Ys) zme@}WEgE6T1TSjAu33DJllUHcivyIhnb`Uw;}7HE6mQz~-!Q-{_&vwpB9F%DJWT8Z z6%GkXZcOl`P0AXd;WTa=mZEV+TG_~bhx&pYJB<%rCFnZ9i-vbnCf~F>-AwF#qj@yy z#csjI6QZ$`gFfR$!B<39~xBX}dXL9~P)T)>929Aq{ zcT&*$SCNRj@g`ow3%G|@3#0PTOAKpWjqeh0Ad+%UWcQ3<&MJ1~7^F^}>$M=zz>t~q zq6448EjH|5?#y7reqVfG{dyQ{FG`_Q@G`@8~ ziYwS7;@o(e!lU5rm`|N6iSg7!rOV^wsPJssA literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/signal1_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/signal1_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..b28eb80cc5f3aaf0b4903020e5554c773d185172 GIT binary patch literal 1299 zcmV+u1?>8XP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-xjY&j7R7i=Xmd}e6M-<23tM2Nm?w+ZhUmMtCE)l_als!eq zs99o0cKr(yFOi(|m;@mZauhs-T!c-?#am`^Vpy1n>=MG_As`XN9HJiM&aZ8D`p4FE zy&UY>?3$T%Odd28-Sxho_v**%heQOk*ohM-YIAdQM~pFL0072Ve`{;&@%{VvJG1!X zVW8#ZWt)i3YOT*`t&e6|RwW_<0Dy?8Wm#R$`6JHx&xqJ=Hk+f@1}!fyf1tI#5=GJ5 zNs<_?bz+Pe0l?S+8Dlo*TuLdK=Xt+#&TllE%^zn1EiNuHA;ed49Dfvs;jY#?$}_-8 z0+b7I&ON1+@B6ee{v86U*?cbuKy~?I7)$tNJP6~70>G#L%ILy{3+Iz0S?PAW z14N`5AV5SQgaFrd|6+_KX`0SQQ6z|ns?};q2yv;^YTW?*!T`LPTI$ z78VKxQc8_H&jZF-bo}^n0sxZ-iCXI@j^ks6LgDlt$QW}jj$?C}J^&CRI*8~AA*Ap7 zpUuzDpHoWx>Nrl2&pQxg9LL5Oa}EH2Ei5e5wAM$p*2y797#+vKVzKx%2!aQNLSY9H zpWM22>lq>r5Yc+s2N6+gooKC(E-Wn6Sfx@ql4V&rzl@VIu>n8|Asi{?)w_4^HayS! z#kTEAK8HDVPe-=e4-YNuDWxbDiyN-%{$`9hMMMKcd;kDvlO%bbW!V$kw%;|zJT=DrDWyD> zW!W#mF;2S5M-gTdfh5Cl!7)Ep5pniTdFqZh`MQgcBNGzWvhwf)}@fY#U7 zM~HY?DRr|_sVL65mkUe+AawkGKv+HNf^E!hAtQ@aHK?bX%Q*KfC8w*T8e{tdDefhirk&f)+7002ov JPDHLkV1jXCP@@0< literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/signal2_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/signal2_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..9da0376e2ce7712011ebc342260f0c228084a426 GIT binary patch literal 954 zcmV;r14aCaP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-wG)Y83R7i=X)=g+#RS*a8-%DN-HDX$7iiikmyAagsPUs?A zjRY$$tP8Df1X09x_>Ye zLruJa`;@S>dw{PektDa`T|BH7%I-6I7JKkp7eGS^Pcy%ia4zS!V%t`dV-IGrua`%6 z;~mV`6q~p_0cMlHxm+7nGI1Wx8?56MurgPp(u;Dba z6L;kpOCoLM%uZq)OCmx6!QOOO-?B--G_kD*i@FRZ0llUCZD@oB#?2kmmSVSC67V{A?QDeD1A`T_H z3lY)k8W(cywTReJ)0;@Fxx^k55#tf@Lqwd8h}nqvDk83lh}{wKbAl~I#9~CuM8tHC znf$j8_(jX5CdeKZ65!-QVR8%qYeA5T3>r*j6*LD$Qir(y5mQE@on!)#+WAVG_6I zd>S7ou@CXMQW8rwBLj&&-^2-}-E6bAKeezO@8O`*U~fxhN>P7<=kNq}C`DWMWH7N$ zR0aDg9#D#{Q3ImHc#~4~0~wae!*)jHqD~>#^+)j*9 zxu>pE$v|SSf`6vmCnMIj{<`9d63Sojs}ib}b@oPL9Z&2vO?5Zk)@iEU?Aq9jW4X3V zNtW(NRJuKzY9%k?F`ainH_M7CC1i~rdnj${73*9Rl!JX!x%g)Nw~Oyeo!VNx_`2O* z#@=Kzs&i)5=mlQ)bToDM>Uya3^EkOh@ob~V$pF6fFCQm$*@Qdw_uM+7)KgFSCqs4l cUk}K?03T=g3nT}U$^ZZW07*qoM6N<$f|&lai~s-t literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/signal2_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/signal2_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..261fd096528cf95c8147445f543ed7864209fe3a GIT binary patch literal 1612 zcmV-S2DABzP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-y#z{m$R7i=XR$qu6XB9u^oB8JN-I+TxcQKL&v7)V-P!LRz zJcJapCRsPT_dd0hJ~U`;`_iHamC`3s!G8oq5rP#|sxR5Qo7-%*S#8)LeaJ%<8qxMa zDMA#o_s;Cxd*{zLGvDzcbJx4;ZrS32c^KxL-|u{L&i6Y9i3kp3Cr+Gb&Cbp~ET!}S z02pK8{rmUdy>sWz)?woDgNWMgwn{{2i=y~qQ52u9swyBN9RL6kb45}5ob$hO&VP@H z8{KZV{Ln=0cKgdkQM{NW$?+`9WKk5El(GbXNdPj&RL;3!7zVQ}>mAPdLUH?v+rccLlEQ+E?>J#9808|5T&Mn7rG}APHndkY->+9?CK% Pph8i{cL-C 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 Z{sRe|nxF$_K1Kil002ovPDHLkV1g8fxElZf literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/signal_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/signal_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..7e2709140a971c853978502b4c6341203b01002d GIT binary patch literal 1550 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/skype1_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/skype1_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..3519e8cca465bfb0ac8067a9c8b3c3c63139149b GIT binary patch literal 1637 zcmV-r2AcVaP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-y-$_J4R7i=XmS1cfM;*t1Gdr`pvv)U_J^Ku9g8&sZL~$xr zsT>m|f=f~oj2$}0R0o&IF1_t zaCYCmeVYLAz1}?Sy-ZC_O{8i1VjRbtj|5^XDOwj*7}J~r*kOJ^Mgl^9vx)0TJ1oZrlIS)f#-R% zi;Ii1larHEK@fcQ%$YM`p65>>;$WpxIUfW8xpL*okEW)kzGba_=G?h+ElR1}*w}bw zXlUqJ&-1?2>2z)^EG+!-ZnDwUs{K7IN*#@Hw# zGDLI%Af(+AK%VEBwf1zL=T5ub{uuydMNxcSYh42XhKNn2)LZp>{kxp=4aV4C+wJzv zD2mpMF(Y}NmmSB+t+hAPG$ln*Or~i{2_XmoKnWpDLP%z-;U*!h8hfmb-^ zAFQvhFO7|jeZAdo|6EG>uGV@milToDA%xbNmP)19q9}TjQmP%tX*Qe9b%Ka6F){I* zX0v%dP1Ba|`#}%{icyv_1+MG9<9XgJW9&ey)yf^md0z-I5=GIb@B0^&Qb!Rn z1%Uq`;>VRzRi#wN_k9_L;UAWkmcGLP04Sx`g%DrOvW#R|rm`%fl+qDIEC9d?A-+~F zmq&}D_?5Nxknj5!o6Y7;LdfCG&CREjQXN7_KnOX6h#C<)gb)xyP)h0b{)OG%-o8;P zm2P)Bou{?d2_Xa#G3zN#k|cNYJpTw|>`g>0;y6}>kSS|zZmo@b+SvUt0J!(t5JKGE z-rl~^m!OrEm7EZAQA+9cv}%`75@U=`(=^JmtX&j^F~)QdQFm2)rvM`W5GkccDZRL| zvXb{f000XM3rj+X%TmgL-6Gn%0=vfp0ud3UlmkMD%h#@5Tk1{FovWfKdc9h$&Pgfj zh)8?#y_e_;E0t2#tJUgU6h*J^oWBpWy1HrzAumfQFV$)_$vF@D()?%ua?XQVttO?E zmnfw#udc4%XH*_)PNt`)Cyg<$CP^}~M{{zUF*Z9tKfmyxe2=tS)6>%o0QO|J0O0NU j`T57UTf5``HIV-UmFj6x*r7u_00000NkvXXu0mjfW4s6C literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/skype2_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/skype2_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..ddec144c66b5729ab948adbc3e4242adbf5034f3 GIT binary patch literal 1003 zcmV000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-wWl2OqR7i=X)=P+%WfTYS-+VKUc`31G2*SvSE?&BA3Q3A= zQ$}U0YE?nhA_%I5Py{VnbfJrZ1Z}E?L@Nuz+!TbBw5g2H3QC0>tWl?OMjdnJ-{N^* z=XK^&Cpz%*eb0NI^FQx%F8}lNBr!`F#4=n^*9Wl+!?Q8&n}vQYZpX^%WNy`sS7$$9 zE4JXo>4199aH4y$9@k<5$0|@`&{IF;9Q0xbUc%JW1=i?0N_aoO!&;%7o}*WAKYqs|?8Zmfi_4T;H8~on zd&cU?RmZ~>;{cwVI(yPQ_ar%*WGKnuB%6~AwDgk9OLA_K^OCGg@@$e{>i&JLXQ*PW zYit{U{v_Lz{F&sBB)hsekz{U?!6b`X?=DHQHOXkp$-auUy<(qqbXSrib;DSaH>Nol zOtK-#&q+oq*vCm$SN*~yUsUk6vm+H-r$%t?w8ZXj<*mOK$P+bJ8?X&`Dy4iqM)9=L z2A!7eWX0B}bo>e&txhJfw6*zCtj18Sq~GfM5j=*g@GZW^=eVsFNKeIFfx!-zD|M zt0!s7d#_U)b+TeFJ{#9H@)OqJMy$dO_0%saz4T1ow?KCW(NSVOZYqfs8o; z=kO_Bz}ThX*HqG3|AIC@sI~5l0t;z`{KWkc!7buBeSN|`;6;;366fJ#;zgi#N zTd{XGeezbT;r1mtnB~g zGbpG%Cf3z29C7NLS){P}he|^Z*E|g=B@Wl&d8NPpu2ETx2ddqSdGtCSH}f7a2Md)# z`KKoNFn+D!xg7KAI||!u)EX1r2H(4;2H&Kq(rtR9J>>eU?zkzQ8&KHdA+5pJZIt)o zRWnC9)0)ufM|nfAQ-)m}HPT#8uBj(G)8(Xt@BPQiNn7UN4zs&%eWK*AtDMbITmIJt Z@?WApjT=99^9=w1002ovPDHLkV1mcL-L?P# literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/skype2_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/skype2_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..fece1ebba8c6ee01e6fcd31f79f8eabc586f70b3 GIT binary patch literal 1718 zcmV;n21)seP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-zFiAu~R7i=XR$XWu*A+hZZ+2%#n$_%%3x(piw34yv^relu zg+|74WNc~ImgGJbS{n)`f#N>&A+%|rA%vDf424i|N%Im4CFo~Y79z3Yt_iVhN}$vb zoI+@VF-^Uz-5Jg9+?hLbZXY}=R%sm+dR~SL_nhyZGv|EgBU)?Nk4;TYxd#p$IE;u6 z005=5^WedQySH!OZtcgPd>+uk!UES?&nTsyR!SX7)3mI$&H(@rLL$akTL|%i5aJpk zU(kEi5cll~R}b{r=-pN>oZoL`(o+;6Ny)TnLfR=kv5sDEwUrad~-pd2L@n zr%s)sxm@n0FbvQ8z8}YN+|M!~0HCw)uIVg*5Tan)wqcs)AEPMx`NqZuJ`(8Iv18nE zoL4>1Tl9UuO(_+IVH7B(1QE4TDnvw`0VDu`87|2HscqY(VzIciy}kX+jT<+1OUZ{( zi^bxLp64xkp4YN0Yt*u=j~Qd@jImGBH2o?fJ}srp0RT`+%StIb48tBGstgc)-){lH z;@H?&8vvgBuZ+%|IWs4ve67`LbuG&p85ixA=`OG``b!R2bTYTmndkGrl5j^lhK zj^nu~ihd9T!GSOgcLr6}T9b0QJeJGlE;JgAtGhtQj~_QI%UW->S`$f7woNHv>H9{}LoxpN2OIDW_fQl?l_W{-?d=La?T4{Ysj*aN~t52O2wt6Qt5D-rcO4Dkfy05gj8l`W*h*3IF26}hVd^%EL)cK zhq<}AOSM{U+Vi~MB}wvRqtRF%JPHwSa?bhCIZ4yhaUAC`)ml3ltqkUaq-h$p+ieK| zaP8W)u4$SVEz7!th!rX2Z^AIFTbA`F#@KhJr>A!VXQdq;RGr0k_RP_6dkz!8{rmU- z(d~9?G)=#)l&U02@}h0qqX6)$%-_;llkCxZ7=#l-I)so204xB|h?pSa z0mpH^3;-X^&dxsJy6&6ha{2Yu)zudOpqX{zPkX)I3!L-s4VZ&5W_*UBNEW-px3{2x}G>DJa(E2H}Sz(GnWwbmDAXJ-p*YisWthVc^T+)UH- z4bSs#A>w;l>mON`^*$lww*z)T#E=l8va)F*L|zE-!PeGRivj>pO5ZX~lMZrCl0*hU zFwQyuH2^@pUcW4aI72DDjEJ|i)(y`2rGCF(U0YkbJE)Uk7?aszL;wKOG%2O@Er5(v zgCKavvaCD3UT;Dv)hC2Nuh;VkA>XgnYGy8%`(?dezXxhRTWYq#57Ldc-ip-?CkEz9~;2yqnv-c6FE%@{KQ;L~=y{o%ob z2SG~tI3hmh`~H(b5bOW|DVNJ*`F#FDyyJjB_4PO8*G}6cN7`hGAYx82|v-w(Z)sePwlZb$3ndnWJvE`@G{gE&we0zTbw2 zi;ZZl6Degk`^ke%%LyTq58t9=L<|Ta)VA$%u~=N{bUM!u$EL%FX0w?PLN402eWg?? z*+Phd&Wt=XAcW|_l0!s^h*E2fhG7&+rIKyi_7zI$#b&d)N2okfoXpS9*ODZ;)bIC? z?o*uH;hbMySy^fPuXvv;x8~>PIRNZSZUMmCD=RBsTyA~V{$Bz4A4C6$uhKvGtN;K2 M07*qoM6N<$g1f~kFaQ7m literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/t-m_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/t-m_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..235602c5a35648d4f922ef2519887cb8e5b25377 GIT binary patch literal 757 zcmV000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-vZ%IT!R7i=v)=h6rVH5}O-%O|N)JUizf{L)Bg75*@m2Sie zD{OoK8=pZWc1;=^maKGzjfj<%c!`&Vg?K5EYMO|8nVK1k=Ulz2Gj6MKlAF1Ao^$^H z^PF>@bDmPG)lyK_VFw1{dkW7nS;V+fV0{FKuq#Mju7r4BnfigVb5 z2EGMQW>5-8s_4QaoX7Q|L}gsW8PqY8*Po}GH?E-vmv9!%PDB-4#xW@@%>}^QNh_Qj zz%`tf3uSqp@&z2161*4^q1z1GR{s&OcLN_c`*K&{ujG4e3W-dn~=2giuNi(pOr4v7dui;5A`lJfX64*j_taqEM zu&!9I#CyJkOMy9rb!F_7O0pr9;{)8ogp@l0@)EQ0Tg4ZAinR%;h-%?L)^Qqvy|W@! zM{mx9r}&72Sd;VqHZ}$*yvJ+o#jDWSg4Otp&7s$e{(P@%#SW_RJ%AVS`wp9=Dyrfk zK41gxU=VNd23vz{dqm(@Y^S9LS;I=~mvXc@cF>IX`%*qXVMTaf51lL*RjK*bq~6#S z*wYm}liJPtFdW3TFwUeA4wNIr4Sybk?EkC*mx5>t∋Oc#3^N)Mx`VtGJY;RP+V* zWOj~j__OaVhm-^R|F@vJG_|;u5pZEZO&jRBm!eBFtPC9yCMy~ zkCrz0)=Go#ln#UM2To!XtE4!$a?e8G*;5Of(ZKlaqEh5?vRm3&r^`thk1g_Yl9z5A nR_wZUQ-`zmH=?}!(*^P;wiCy@`EdDv00000NkvXXu0mjf3Y1$* literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/t-m_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/t-m_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..d7520a6b2c1f7ebc3b3b9d7e7ae288fea14f1328 GIT binary patch literal 1253 zcmV000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-xUr9tkR7i=Xmd}e6M-<23dtJ5NH9M(x+Fhe=evn*b!34a> zUV^M7BAAt3|ATmvob)KcQ^;9Qxd`Sz$SiII(cosyW$_Y{2xcLdBq+k}&Wvr(^pC2p zm&5iQ%jZ$jmT~jvqfhH9b9j#5vah03f3F=H}+cg9i_`##xV} zKub$Yf|)-v#(ZjwnJvq5KQsFP0En1-p0_Qfd?cm(5fSe;n@ziC(9+V<=f;?eyDX%q~%^$`Boj!e@FENGWSt>j|aQcX^(Fb^G>hw=3wxi4&sHXngzZ*|T$T9Jc_#?FQHdNLuSC48!kR zt=5-7 z$uv!m8e@9n=42!Z5sfjuG)<4z>-CcZkaO--nx<~_^1UlfQ|FvJ1pq*Eb8}P1m|0^? zhCA|!C_qFH{<|}bh_d=w**{?b;8hU_MD%#*2v<>M#+cc;xw$D3MbVKw&l}FUG6;fl za&q!lA~JcNAMAF!hpn|n2;tT1^}mD=2g|bJ_k9Y(@F(B*4_RxU z6h#3<^puGHA)=3!Qh#^5T~bQDYm5n#BuR>*m;nH)N>)P*g$mBOi9FAJB4X!UBM5>& z0U!c^r-*nM05*gWzVG|LS!*{v&pTkP{n;2Z0xW_ApmdyF!TKR^Iz)q`jnJ1MnvVDdxwY&032lIjEH8l zEDMq(nRU+9m^lXks(iOatJT`jTDOVlKv|YWk|Z-k^nO{E*-&mvYwa;(3=$DCvxEPa zKXlHOWm%R0kRu`zk?=gP-EOxxXnlQst19&Y001+W*4n&sG!Ot7=Uico$*r}x33Sw!4*yey>@5z!r}?gAu9a!)Ds zP)b?jai81~s-meWr5+|pa&G`yU0p2@@v7F^hpJY+2?qdBYwZ)!)z#J2VgLdFSXo)Q zrIfm%wccL^^*S(SX3$#iS4!QudGqG2zJZ2kbvm6ZVHh^G*3-;Pd)Y?b5oxWb!!T@i zI-M)S_7^~FYikw}FKDf=M^U8vIU5D++ohDXD2lY!`Z^I^SX*0rp;6hjIayp>T(H(& z?Dcv_$81g>3L&m7FE6jW%HPO#YjJT=0Ki!7769B`US8gNyY;f(w1NB=wtu0)EXI!v P00000NkvXXu0mjfC_hPD literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/twitter1_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/twitter1_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..a72a9afe6b4f8138a097e1a5f269b6c9b61cb498 GIT binary patch literal 795 zcmV+$1LXXPP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-vl}SWFR7i=v);o-hQ4|O8-;CKAnJQN^8h40A!5S`*!()B{^ts`v#` zhCIPXDZW*WS{W0%cW^(v{fvhNz1+#%p(;KFc2@=SH7fpac(@{tJr(aUUP_W4T)<9D zz(Jf2g2$oXiMwdW?7*I13GZtf1@;_IrM9vSXRrlF!@Dx}VmW%T2NQ7%GcX62rCOXD z*prIAt`r`bE#m=};4R)1!Z~2D|J&-YM*}#-oPVfK#002ovPDHLkV1i#KWvBoE literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/twitter1_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/twitter1_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..8d798206713660f6a34187bad2d5e2a9a8836e90 GIT binary patch literal 1347 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 BU>5)Y literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/twitter3_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/twitter3_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..458569d25178c474df2af8460b2ac1a2ce557c0e GIT binary patch literal 924 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 QWdHyG07*qoM6N<$f_e2ec>n+a literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/vodafone1_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/vodafone1_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..f25df8c2466b6e2aca3983eef08ba0b2a9cc7677 GIT binary patch literal 840 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/vodafone3_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/vodafone3_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..ddf2a21a28b05120c5d1ee38c2e98c80d452e02b GIT binary patch literal 903 zcmV;219<$2P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-w0ZBwbR7i=X);o-pRTKyC-+VLdF2U?dmi5(Wh>ai^t!yZa zjc#Jp!ibgH*eEgB&{!H1V{|KGq9#xnA2dEAVxz`_TBBH#=xPK6ltor|_gLKXF?VN& zVTdRBlJDGm&*Pr|dE8D!7?b932WFE$gP(9}9O2#=`}24Jcczia+*?j#Ki~^|j+HAZ z>WsM2qd0)Ou!>8ms1@j>BU9+&JG_Dq$2HX8bv%QAuvDKPI9m&E!35sK3s@UvsE0#% zTnWosr9AS#=3{_wl<YRv(%Z46`h>Lk(u`=>@?u&?fBjRKf`nXzezn6yS zxR|;xV>Ca2$rMgtU#{JR!->-$N`~zj!1qOblepEG%~O(L4mbQ~v@Oq4ojv7=G4 zV^TkKJ^YT}lAlyEZ?*EiljoOle`V+|{HovD)>3}!U>()e?k(pH>w0OaqaTTp)F^ec zTq$0`jY6^hV`W>N3-DevmyUr-sNDsGJACf}~@Y71nXVdV@ zO6P8A4{pQ1$#+xtiJsCje#AXW6QyL!b2x%ObL~JXZ5=p`zDA5N}T1r><78 z??yy#NO2DP7Dg59I4$V2h}bp4!1joE=V~peZmN$Y=z~plS}D{o@wHMXftwSP`NZse zC9|Qa4$h+mJZs}SpsTc&royo;$_qA*@HwTk?7wVz$lyDy48GHb55Ag)4Zdy4;Csr5 z!MB1Z)0-J3h1NOjx d>3=;S{{tYLHXU9uxS#+4002ovPDHLkV1k)yro;dM literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/vodafone3_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/vodafone3_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..53e64e0fdd87cc32358d99d244c739dbd02445c2 GIT binary patch literal 1604 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/wifi-router_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Network/wifi-router_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..d1a77e43821908e558e29709f80b232ce46a47c2 GIT binary patch literal 1724 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/LIBRARY_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/LIBRARY_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..af45968fafb6c78b1ea8cf8698a79a0b577de6f0 GIT binary patch literal 795 zcmV+$1LXXPP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-vl}SWFR7i=%*3FAfQ5*;G&wV`43}(SJhOF$w5JjTvX9HTq)y2`}-Xlg;%G)^}kC)&@y;tc?fRbKJr(eohBe%wW-8oWy$k z!uJ5m8;Ve5KIY*mPT_i|L^YhjF*Gq&m2Z=+Ztg)B&f)}GGZEEs9{VM?w59-`Zj_;9 zAFkl2iYsev!l!XS3h-=5glsGJ9tf<7#fn9Ha2X?^-E2szBk%3SLENYkb>W_rzGHtu zQYGt=(tit@*>&5c?D`iZ0%I&Nw=)r=U1lHnslMC)wE|mRs`xedCKcn45NuS0>+x<$ zZvGOog;cm*ZPqlU+WHpQ{dEjTDcQh9Y{X*Rjeqa35?}EaE2ONt6hQkih=o{=_c(+* z*c#XaH7Pr~LxY$299q7@>(Kr+-e3tHNtro{C!xr@@WNPp4+d^MuzTC000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-xlu1NER7i=XmOW@3M-+hHo1fjC(`i;6T#3$O+2^V+YF;fe1rVBnHP0hP1MNPPabY z?B2}HOX0mk5|%jG1CN>I?YwW^ym^m@La?O1Eu zg$MXD15_B0QkJyVfl}(nJkP(mefzfG6Lj+ANs%PU_swSWT$-jE0O0om>;Yt2>q;EQ zzie!5e6_T+)W1rx{pUE2zbznZh5dmb0DX^rnx<<2aBgH|WE}v$?&(=?arW%l=`72> zOw)Azppf0XG)>pDEc+{!G0A;9|i!FrfE(@7bhntgFdKS zE}u5W9JSWA2aUaF z-n7U0ogb+UnAxcupH;gf>Qp!)Ab4!gz;{)ehk|fDEBcgArr=lo2vbD8E#RJR%pn)e&oEX(w|J-ag z$HOq}Fvd~<2oO;fFY-AeR*1+J2XjP}XIZ9%5EukOr|?_>z;hzv0KkkfNJKJ8lE-P9 zelC`mm)EAJryp_7-)*&84iOW0k+i)c7z2QX7m4VKIYPv)a}KjC>y@#*h(|BseHez3 zl=9K?^70x30AP&WQA#mH^o0;2LLt7GY1`bpmj3tde*gfKQj9Tnr=PH`R_mTp>YbsNb40iPkW@&|U% QqW}N^07*qoM6N<$f)s;T`v3p{ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/Llama_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/Llama_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..851a84ce382f30a9b0d6490da46b6e55fe1626ec GIT binary patch literal 855 zcmV-d1E~CoP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-v(Md!>R7i=X)=P_AMHC0{-|g<{Q6oxB22sR?xX>gj=ob(- z(JXwdTqq(gL?pOSB!VD_ZnE&P6n6nPStYCJd~(%_RE?-{BIrX8|?) zc=Qs^;0f$tBZ0;WO&W3=`uG87aiJ?w51->r+``Rjt&h9%{|(%op54Hm7~*TZi%}c2 zmI2P;ZLB6qlWW8D=2In1oA?NexF^Y0Q}>*9S|XwzUqr-KL|n`9YmVy?@k>O!lKUQr zh*$G_AtKI4#B!y#l~}vjwMQ@DEt4v0YI`t;2bG*$#W%Tje|j{kbe0n9#dhe1_#nd( zEfPvG9L5_aRX3KW@C?=~10%7{B=#=RNu|2#oYc~!#eYp%8y7~ewf|;fo~(&ZX;sM# znP$X(GD>U%rQ?q)uDA2jC?zd_`?^b$n8&d&z%ixccV>{R=X_fUQCoUBX65z>jt!I~ z&zpp9+`&Wqj@NNb@qS0?ms&QkHiblD&g1a3v#v=Cuj4g*KV?rX7nJb4XL_-afXhlL z)>Sja=?)~Yg+ENsUoWwjd$^*U!u7@x9#NX}Ah{QhDP`W4eqvwgDP4RSx0~c=8z19n z2cqYcJhpQeiFp}I<8WQ_?*n!dPdnJFZ6$ouq?g#c;ET$Aawsj?QS$T|?rSMOgy*M# zwtMhUVlLK1x0Fk3zNN5+zgvJ$;*%Dr*1Soqvx&VYTo>_`NnS=u@0_-`P*!q`Wxe_y zlO9d1i{piMAHA;}NiQo!GKY6?hjOWn@UU_%e5mB-gvsgAOOo@6Rhh8&;u8`5i1;!h z)*@mhFTNW&Uyq2@i1@9VuSCSv{9Q}kejB&T0mjCsD{0DHYXibs8Lwx`M002ovPDHLkV1lU(lc)dy literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/Llama_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/Llama_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..788f922143ae6c0bc988dbe9fa48811005f75916 GIT binary patch literal 1375 zcmV-l1)%zgP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-x*-1n}R7i=XmQ9EpMHI(heRWUI?Dl*ms|OE)!H^}QD8xNw z*{}(V?uMD1a>zkFhz1V{=*5tWAxBB@ppZk56 z_EHo@Zy96IT5Aw7q5l>z&bd@dh`F#E_rPR&2xw)kSfu^RWxa+#twbma8LD03< zMq6`22(Fa!5z!)|5kmNg7+Y&QN~wbH`;O;%KgMx<<<6ZuxGQLUd|Z~xFs=*$<5|p9Dehyr<7H?-3$OB6{t}kt4Zh&z`LVz%Kv*VHmzj zL=_@R0e~^aCZfuMh{K8o; zfERL$h)J5J<#M@vR1#6SS62E0Ll zKf)LrB_jKR3(lnwqSb1(p7OP|wMMVh=ZJ_HV_=L)thHZB-ENrO zHXU_jHvcNfO7g-RZjVJdbnE?*jC` zi!coDd!F}LDV6WJ!Z?l{BDzjQuVfdGkB`4ztJOZpMn6~^dv5Zc=RFR?@O~e(va-@; zjNR~k-`!e}rYUs0-Kf!Mgjta5x^HvNuVfqyS|I>nzVEx7^BXHGE8RW_0AO)(aoO{{ z+rIBtdm?D9mDOtXQ^r{TM5Srk27q=(SZ5(b1itTAJ~a zRZ9KLIS&|PX_}^QNGab-)AUy%L}INS4T9jbF(zh=ao_i=#bR-`)oOkI@ZrN`M-Tu& zyn+ zX;ydF=A>4u%_K>3DT<=wTI+sulF7+nbMjb9d2@b#esL$gJ=?8XttJ8BK000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-vdr3q=R7i=v*3WNEQ4k04&wFmQ^(0jL!iGd75+#J#Sy&bu z5eqB?8Bo@5Z@1oVdYjNi0-B#P&(m2V@z4x4% z?{{X-%$ZZm^IXNz#5VND|2Rg`s-m1#SU-dV*byY%u{IfGFYpKtFuf2^Z4r--;1YIW z20sI+P^g6=Jy?NfxQu&MiR!qDvzWp}S$>XeS-F9gxQ>fxFGiH%298N#Y0m?`(8$Bc ze%!$srBK%A2w%Z*X@i$SB4pd4dpxi@izSZ^<2F8qbxR>Bk3zQ(Cvd+^v=UFH^qu$z zk}_FCO8@6Wg6|kmPr-A9Y3UcXiKiI2;pL`9rC$O zHg%N@te3uLLiT51H!}=MDcQz1sq!KtxKNzjN;%K~sRtlB4?S?{qo3}^-5Zfw9>JjO|E!Rm;}zLEZpyf?60#U4HI=ef5WqaN7*{|K6rnpSs^RPOH!kkkU}a$wI2*L{pgby6t& z4T-=Q2~5o2_-;y#Z_M8{z5%K6owi8ho5m>&V~tM170-O&#nT9#;lP-6QK@n{*(rIp z*yW^-=azUmDUU83RPDO;(CqqJ5>a{l(*^Q3rm@zGujxij00000NkvXXu0mjfa5H9& literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/MB_0027_LIBRARY_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/MB_0027_LIBRARY_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..778ddfc33c06eb685dc7ba3de04f09bd44cd45d8 GIT binary patch literal 1261 zcmV000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-xXGugsR7i=fmOW@(M-azn_T$~#m(xDoNwS-S5E3E`4u%xw zIwL1BCbEp=G-+c9IH~M11Xm%oO^P%QPM;zttQd?PEKX^J+X#%R6gDX$-PgOP_qA_# zQt0kt8%vz*3@j|n?);dY+1)=95lmvIPoJKho12?=&eZ?_7-QX?ot^DRj~?w#vL6ov zt*opFBKpJ_^RY4Jgtc~th$;X8h?sNE+fvHMQp(>E@jrkm;t^l z01X33DFdywrv|Z5zjivE zuQxU}#z!fhT^xqtcSFeTF#bdkfN{nyilSWrxHLUI-3EYfMt(M$T)cR3G0U>cQ53b0 z3VD$iMNvD;vdc?LON-Be78Vvf=iId@igMU5_Nzd~FaV$^igF^lwy?0^jX~9F^=z7^ zCyg=5q%}E|gowtNBu&$k)oS(Z804Hgm!_#ZeEZQYO;hKbI|l&38jZ%RG3JCZCIbLI zTtfiBh=>7z1OQG%2>Z<=hzN$=DuzA|0FsEsV@z(0Inih|W<|YTpU?BWhKP1* zYHF`23eQ^0gCIy4W8|FcBBEl9)vUEoVZW2#LPQGye=){t0D#uoHs^e1*yhIo;GZnZ zd~0pJR;$emBC0v(e9!ZIrPL2Zv?zo)RjE{dQc5L4h`pjHIOlv85ub9->t$KK=bRf< zDwQOTm7-KTu_b)$r^5hq5?MG>v28ieY z00bg-5izsYTF!Yx2(iT&+d;$+5s}KWYy&{RIX^{2$2jNVU@-VYDfRhaFnC8PRYgQE z%d!R$wc~ZWe1S2B0AS(2%Z#vJ7_HGR8hN#$=px#yRhHyWMTExw*N!xVZRON_i?x z(`b@=R1}37&C9YJzh}mnbkx~IM85C)Qp(4ho141~0Dv)eUn#{95&qAilwypr`!G75 zIF27GrM9G$0Uh)~9l?l*q?CbDYAcT8hhxzC`g(zgH?-E3VNG5KMgV|X>k4D+#`^kt zF$MtutgWrxRZ88~TF(rVdKDNE5ooPvlv20v+_`gih*fp!!T@Wt>=bM$;2?) zH>S0o3&XJ4>-DZb>wgZ^YPCv4yrQ+fRj=3esAh)&M}8?~P_Ngu*7_D>>`JTEdQPYu zC{C7_mzT=2yqYA*$qB{DmJs6R>gwv+%ix0aWe1prJWw*cV5>gwvz<<^V#x&rcF XhjyXGy1_h{00000NkvXXu0mjf%`r|l literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/Marvel_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/Marvel_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..2bbfe6dbbb012de93d807ff6b9a0b4e20a8ba84c GIT binary patch literal 910 zcmV;919AL`P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-w2uVaiR7i=X)=!AlRTKyC&wKOcJ##F3jxXqsRwDheGJ~*9 z(9)WP;z|qpqYI-&n_A@3t%U8QXp<5|t{f=TZA1_f^oLLh(vrl99LztDX~yxr7U%qY zzZst68@+J3_jiBie9yV(e9yhN((QH)*jjiJqxn6FllW&4<=O!M$M7cZ`Qi$jwU5{PGT0^j`mg7*$6?((D z)=tb#^y+9#FDK`7{cfDY%2XOkBY)vOL3bk0mrBM7$}daIF?>}M75`K!Ht=pLzl}HX z1@>W;sIAvhepQZb9LH~X4tL=d?8H>cw5nJqC^?%3rf~w_=KKQw&2b{-oA@Pn{3jm5 z1K5o#iB%DWK8khKRBGrIUp+yO<@ebPRk7a4JUk<)d^P72_#t;xkg1dM&G~iI)g!! zMR9C>mtn0Z_Qk5m$7IQaYgmJg3HBr2zzd=-9>o3l9*?HsRz_ft$jRsUNic5`CyIjo z7_Vn&&Zd{cBC%KSM2>$a&~cHkhecst!|BwU5_#I34jjZgMNE%m7`s@TUbk}od>UNaFYBG|Ck69n1p)5KUSQwW5!6kvsRV9{f~}>qMd7ay#F=vh&4^2@kwUk+-)n*Z zqbb`I`B<9cG7-kTi9P3<7{@1qJ%#7}TH(m`>~ids)|!bmenY9x#dknld>7o_#kW#i zd~aFc;+qxc+kO$6kpw7uKk%ZDq|W}tnDbB>};XONmZPEi+Y@t+psu^2YGHC k6}0c$Ze^(4?&tyeKhzrXPwzX(0{{R307*qoM6N<$g6R#mk^lez literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/Marvel_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/Marvel_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..bc16d2274ed2ac879111991d7672ca204333932f GIT binary patch literal 1541 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 Yze{IW-&5Cwk^lez07*qoM6N<$f|pk%rvLx| literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/apple_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/apple_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..a2ac85ca3b6ed85df8bfb4936d903a1ab18b2c7e GIT binary patch literal 902 zcmV;119|+3P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-w07*naR7i=X)<0<7RTKyC&wF`!NsNZZlEuYhQL!!6f`d8= zf(rhdjEi(~=p^l6ccCDnA}FF$1wp&0Sd2~%F6wBtb#W<@Dx{kJ3o+5;INbB=@8Vs)?PkW# zCstdEs&r4`BP{328em@Pfm6BKW>u5QN&5g_CF#SsUD=Nbe2!mmcV>40S1XKJJd4vJ zLPWe15!WJOG5umh{2UPv8YT4L*EIrd|<+KX`Hgh~8>&xU|)XMMbj`<1B z;vnu*_PDmq#GW1OBTC9EL%!e0rnM({SnuiPD%Prro49p{L}ze8DSKUsZelNYaZXX; zu^e2-UCMzN)t2#c5{*}6V~KsPt4PLKZNshMP8`}{Rv+R?MellvHI>*)O}Q4drE8k? z`5h8b$~UdesGHcDX6r}9H`#295%Ft8EJehjA&t46cOqgTBCaIHrNrzFgOrt(UMzQSnGWuSm`wrT0RSv{Q=6UVlRjyUNG#nypuP zFMVCBARTQB{DqseSNSomq-{&oSo1hJnBdzzPA2noow38mNp0hJ%xKT8FEX>C_FqJ` c{jUe)KSReF=WW+Y?*IS*07*qoM6N<$f_4L{n*aa+ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/apple_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/apple_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..3890d5b3f8bbfac90be910837f496b13b23c6605 GIT binary patch literal 1452 zcmV;d1ylNoP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-yCP_p=R7i=XmQ9EhM-<23tFG$ln(6J{nT(K&f*26PDhQ%` za#=}?GP>@V%MuSsBpz~8NXUoeB$AJdUV@SwqB#d=cN3CjO?EKku*gCVisD&91b3X> znwkEp?s_@cqwAtFOWv)UuJ`Nr{`EePh+q)gyLWGO)22<^jWJ~a0LEDR;lqdbZr;4P zJji)`8K_>bb0T_EYyF1SdPkOJuMklI000qV%d%QRh`U0F-x2Y8qtQq=464`bN3_e*Qv`@B8OgS67cK zrIr!VtO4{x0V(B>@B6=2tJPz(v$IziV@^L}L^MjN<<-^Ir8Nhy8TbxWmE$t{&iuOi~o!oos(YHI3j$8o-5jA5x%@;T>{ zo(fJ%shEh)jE|4o002DC`GFt^Mzq!|h=@c)LI}tA{fKk^9b@cIV+>=AjX939`NWA6 zml$I<0DLqwH1v-#<~3u?JH1}-^1@F3Fq7{ zm&+@*ZGSK`GqbcN)z|mz+2d9!6?cAq{=u5}f7NQWA4{duw@H#5Ns=T000_g-IF54= z0Ot7U=xEjRyd7HWsIQCby27^Y&(}c!0AOipsS5zz_3s&DThlb%N<_MUIkeW1)_TY2 z=xCKyDwXY7mX-5j1k17tobx-gv$MagclILNw{M>SfQy|@XSdcm>0ef3Oqyj`xm+%9 zXGB!a+Y03%8vyRnpiK|}s@3X97>2vTFkD$z5|sNcv*(;cL<|On}CJP5V4Jj zF+8ms0|4cXP=X-1Bc=RT2;r>D1m?cm?9rn~_bkh5GsZXoK$c|*5pCPKbEg;-)ND3a zY}@{(QmGV#5CU=;7-QVBtaiKIzQ-097nk!^?*IT9W0EvYw{70MdDljwYBU-@*|t69 zx~>8M-mgU=#NEZk#buV0=cSZ=y(o@j$Fi)cjer0E(lmX5h(*Xdyp)nL#^wR?7S!!_ z7o?Q8g%CvmfGCPONs=6|)oKGrl{eLMK@gOPD6?(5D5bpJ?RFQQfSS!_f`}J9&nv*= z8D%=1j?EbRx>l<>gMcO`CQkQyz5P)XbpZf9&nqy-E;O6X1Yq6ZJ9g~YmrAKqN~vWc zf}x=y-}n7L5b=wVk&%CH-MY0q%d)qK$YYHC%{iYFLd0<#zZ-_(C+&7SCZf#qysGDU z-_Oj#L1y}&Idv8UZ>MZk|YTbkt3p&_p$znMnvR9 zghZr;5YqEJyI3q7SqH@1^V3oMb#7y+dHZN0000000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-v$w@>(R7i=X*1eCFMHB|`-~C{h1x+BZv83cfqlwW%6B`;} z8>NDTLTGF(h+5#kurX?7W1|)ps0mak2_-gm8bK2Z3L`P>5+d%hF7EEJnDes3yYJn5 zjVHO8`<|J3&c{4+&h#R}gfff6*q7h;@Cz0u**u(Jeh$a+TpF3qxz#lGGrq$Wtc?Qd zZ4=Q+T)+!h$KMImZ0MyUJ2AkIn8&3_4fXL6-ohg+SHNA;0PMyTKE=D(*v`-ppW&2} zmUTRx0D%XogB>{sD|ncZ?ZZW!Q>C(fMjzlb?&kM2zQHZbqyu{r@HQ@|;aBjQlHP^H zSj0PYVz5l5>vKSac0L_COyiqaR{&C zfX#}~Pwe}B+*HcVV2pt&Jd^(iIHQ~|r3#$K7wNES-96kKDkb9vUQ`Zy)WPmlYS^k$ zKwrjnoK@1-G25+Nhk<%?-OAt7Dru8EPM*&wwtJlP@st1fIH_d^PMGYu^{v9nP8nyYmjCsD Z{1-93C4>`!qICcO002ovPDHLkV1ob8m?!`M literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/b_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/b_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..16c42f8ae61f917fd2bafedd916aa7e295764ad6 GIT binary patch literal 1367 zcmV-d1*rOoP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-x(Md!>R7i=XR!?XgRT%%h_vX#+Y}T3VH1(oKX$@8o0wH*4 zNztSb(5%RJtD-}}AqoA3R;k63GQ5R8tF4jn#x_^2_a0sxfK){`es9^Jcl zZ|xxVWIv+W*;&V0`?i$wEh*)&*7}gOwg3Qxkc2VTeMM(C=|Yo5C_Co3Ovj#!%MMkm) z0L5a_EtN`hgpfasF-4`+yX|&6pp>$5x%{W&I17Xjt+gI)x7%+@DZ80%b#QR73E;E* zY?=>FpFTa+?RL)!A)0xV9LFhg&VOh$8dnw<7caZ6D*!lz5Z86xzZ#9k*SBuny2?5K zl`-b!5f(x;yWQ^D>FMdIEkxtvntnE(JfHa0dSr5u)0cDH-83-a|Hj_=s`%&V@Ha(HZP zY>0+ocvNd$$sXgLh~qeAjHQGS<~RWWT1-8H#qqNqQN~Lm?T5Btrtn4d#D=RCC zb6yX_@K6v0DS#jQmZ`P2_jvm~&Cae+JO}3I=fCkh??X!I`wI&Tt34Jgrl1^~GIc+(V&ID1>2neR6WL_W1GRUpk%6w~Vo`s@3XCyY08uTF!ZqbN+C3b#=|j zm>ZtweUK!{o*ucbt2&*|pb+8}V@zy}X?mXb#=yY9Pm`0AD*!rL>k*|?C%5rDk5Wn- zKqji~cKgo2z`%n}r*mYxIuJrE0F+84E2UJ%n8;e25<(EiaVJTVK}u;A&oVDI#v}m1 zIWKvh_n_Tw-vKgZSXx?22_aW}-!CB3s+=f)U-$3d*8uv}gAhW9wN@#mHkDEv#+Wo; z^L@WSDZR3^w3Gtd>d~1qXD$mNKF-U8>$=SIyx%FMO#p71ro&MbdDuHUt+f`u?+^LD ze{F7Vu2&|uWZKiGPcKy}l_3CCAw)AxQ>~PGjS#{CSYu3-d9_0cvP7c3?;i?+;6|&} zy41hE<-sm5FDpXGdEfW1g<+`#vw{N>OGc)4=I8eI<;C8)UfBtrBJN|D2 Z`48XGnw!@VyEXs-002ovPDHLkV1j?)kO=?) literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/book_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/book_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..fcb6c48603d37427f7ae82b04e712fde20a76db0 GIT binary patch literal 941 zcmV;e15*5nP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-wCrLy>R7i=X*3E03RS*X7-@Um_n#O*_CaA@w3!6%H;l@p~ ztX7H$;s+GejSF?<#=oG8Qs}N&ic(PoU5J6=2ja%qRY6dxD1r+Y1|&+FrcF(nWL%s% zxo@sXxX}Zb%X?<#nK?7h%sH)y(B~S*VI0iwzwi@g`!VkHAwPk~@lZM$O4(96yM{0D z8CJFeYHf3(r|~8p#wz|!plZ;{Kz3sQ-{TBE>DN&k=kN-aajU7{quVqd!5}W;4XkbF zsDn#*PD#t!Cg5AG$RH2mBfPAU%654xH@TP00RxcXxLX-D{W>I119>?Jy1`&O-i=;ss1K9S!1Zg}%422jAgsOyhd$JeVmN$2+*% zaP&yZjw{63qtJg6%OXNVoQ#OYi1mju7!FVXT=nmDC;zMAN=6wj<9~_w@pHMdbTM2ttobVSTX#7t81bc4o25pg&o z4mI}bZ(l@AM8sHQZ!+mUlbF*HG2T{2#*YePYB3k``&`Pd;9Go!`!d?M6qJ!1N!o2Bj~0w zK3Z7psaa&LI!X`K3{(OPW}piSQPxLLWze#6X$@roZ|gR2voBgo^Un7KQ1$MllU8D# zN$d^R#1t-ItP%ZASG5^Stf}<~H@W!URr30$|90_>DfNEIHW%LtUc`Cbh721oyI%16 z8%dk P00000NkvXXu0mjfO?I}r literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/book_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/book_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..20ce652f6287c05c8f83cfee6ed554b68e86f41f GIT binary patch literal 1567 zcmV+)2H^RLP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-ynMp)JR7i=XR!wYNR~7!wegE&-cjnF5mCD8}LPLNmLW&}b zM2e!ck%>FbOvIuB7Jv|{SfGksg-RC)iEc<&uqX-$7IalR8QigKIwMDlgd)lUqE@Lu zVuwm>&zt9YzxTa+S@exHX~&T(j`UXNp6|Q&obQ}>NGXMr*!lD47Zw*6PfIC%0AP#_ zA3b{X@c#Y#dnbvfClPfz9bGB)yb$6!A;g)oESpLx3jl~H(==`0FpLij!}v21?X0h_ z7oVA^)9Jh*gm^iQ<7d+}l|qPAN?8Dy1Q26PHw?qJZJW8S`wzn~-dJB>|I>+xR#sM+ zWm!K@lH|K#80JEVxOxH20#FrzVHhsw+;kl0w^^3`WNT|n9!qrT(k0#Z{a=knqZ?ru z9srQX5gbFvIOmO8t@if8!NCvj-o1O2N`3lptycS4MKUQcDWwOu&nl#-@t zG612JGG>g~0P1<3t1QdL0MKkU>y~AGuiNcz9uZx>eA)Co@14E9y=R0F@%;R}>v`Va z4a4|-p6B;^z24~T*|X--($W{ovivp?EdcmK9LMkV`~B$R#fwg}*?hJrif^T9dSx^k zWtyfr3kwS$Mp1NaFc{>dltQc3T8ZQMcf;W@Fimr=Ua#ND^ZZBse!o~-Tf0yc#g~XE z6haKPx3~XWi9=gmUAxg``)D{EzI*T9z47(y*S{YG!E1+yhf%#=uX~>Noo=_g zr2~MJ@@kSKvI5Y{viw)S-!EFN)^Cy|X=hnhGR81BH#cs#+uumj^!-+=wRL!S_~oJ~ zl%{Fq`~JVLUAy)ifWI)t003#4O2=`o0@%`*mzNhf=Vycv=|o{fWCK8wBu@uH5G$qP zs+RTn`T4pK!YPX4>CtEu5>cU)VnkHab=@&d)11^_2$2dQ&MYr4FR(_Vak?x^ziP%$ zN>&gNs4@U$r7$(aH)-a{Wg(?3%Chu*-#^WiQhqg7J~blL$A+m-O+b$G&491~`1%Yd zCZvX8c&_W#iAYmQG0UkCgH$+qS=26on|ul1<@Lg+0^{ z4h|l2&WDV#r=*mkI=}$n_U+rRFD)%ur%s((0`SjXueUV?^2)h$=jLm*+UJB2@ArDW zw*jElYMrTa22Im+P1AWndA+x7=pmi=I7XXm3%r*kukqN_zwxVo;Vwr&5_b=}wY_V!#UeFr8em>9hFY3DfUKB-Xm3qb)+XkwkIv$Vvp65M?qUaeRL=;8Qx$$^RLWuo|gaN2H zjz>jNTp=Po&+`y~s(dm@k|59XhOX-`+TicV!&7Fm{!l~Tkxw-{qL2ZKR=L<9icZgqGyZhKkJ9ar~x7)3v zC|-`^_$wz|P9EsG{>H|}Mt2t86W6VFyR8E_(Ygg-XJcdIv#(p9wEuU3{2yrzO~_bl R7bgG!002ovPDHLkV1kq9`l0{; literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/calculator_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/calculator_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..3ecee9a146c5a0183183f5a2fe705f9186eefc23 GIT binary patch literal 875 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/convertor_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/convertor_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..ce7cda792c44d19440618ec927ee9f1dd5c02285 GIT binary patch literal 1035 zcmV+m1oZofP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-wg-Jv~R7i=XmQ840MHGggBwu1sTwdFQ+{=gc&yY*IRbJAsb$r+`slax;@Fn;7o}_5gPWXdpx{WJe%n^mjoaOTwYS5MifzN5~mOX^GjC*$zE z`ja}UURI~ovDnRLZsSHk74^8foJf99pN#&1`j&cYY@5~H>i6o^EMOvwJDxdf0v!p+ zym~awR@>a8zNGF?zf~PfL=)mN|Xm0=()c2#iNxfgaxyJ5Q3t3W6sqN}6^{>$T zN5HD;Q>%emvJcDZP{Mv#{W<$^Mtz_L?11{adRRRe-HGUb3sAYYEww;>S;1wsTWwH( zv^WssiE?li@5i!79igvL?MY?Gy|LjUJOVZ@L?SG0H0)TBQOBG0`viAfcXGy z2X@7GC!uO2N3^Ggnl|;2I-tHDU5|RvB2mwW+LP)Xbx!AQi)0>AyDLC@!d*y7DPq@Y8nz*2XG454_vLWYY5$wv1Ps*1aj2>S+kkI?L!q%P&bNfVm(%}O zD!_E2=>Q&zvz8cEfE~awV7VreA>i4JJ(?(10$47#GtpcGrYpd?P}T*!ok_&um%u@a z4d0s;4*^e8Y-$}GPe5N#zf(U~ zw?%(Cj4a2;x)&d6lf`vBANs~D-U@S}vb?gV)6QB{>_x9%c002ovPDHLk FV1lFg;8y?u literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/convertor_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/convertor_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..52e02f59cfb2c1c4703ee573022e30716ae0d73a GIT binary patch literal 1923 zcmV-}2YmR6P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-z{YgYYR7i=XmR)QV*A>Ul{g}HmyE8kpYg2`WwM_G6YRg+K>^`!-=X^SFNl_E;3RwZqtmZVJ+sjXBa6SMvh6cDBnP;3QJ z1xpB3NW35;>>Yb&*K>F7%)PfSHZm6!vNMk3byCU(t#t|j03j3+Ldu3=+%yd1 zJVNN)@bGZ*xj_R113f~BgPimAQ4|?b6a`AD7yuB)m};#xLI@1QFfGf%>2&&rVHj@> z4-bz$7O1$lrF=?CnIVMu7~?qrFr}2MIpPfFJ3CFoFb2!z@^kfiog;*FHk)m59Ow5VBO{0Z zE2Bc8(9Jo2S!*pF$N5XCR61CxR8oaPVdLh_o1Nu%rfKd_N*xzMyuWwv-m|7@nn{v; z&vjj8+cqVH$RG&H^?Lo4LZQ(85U8!KjVYxLa?Yu3+t-31_(8E)Y_@ItBIkT8pUr)`wbKTiF9p zI-PFgoPUKe#sT2S^z?KRhT%_r-+$8g{YBsRpB6&=c*~Y81OQ-seEe<4aXyOU_@kMb znfLPfym{ipiPvhi+B8Ba3jiR52s!7^*tXsF0Hl;^kK;JS82fm9eEia;O`AL^Wup*c z5dgFhVo^%@1Y?W=02GVGEkO{pXswSmG&DTv`+mJpC~UKB`#mXT$}o%!Atc2)ms;y~ z007+F+}s$)@j3ud2%!l8fQ5yH3S(@-b=@y8#vIpm8x6zw+r-2KFBA%GobwOn=H}9~ zv$I(#<;h~PxZARCJup^G+cjxElNgT&KlgW5m>whYxJ{}qxI=Qkt zJ32acFvk9rBuPG>&#$EbkkeY501zRB%F7QgUAnXg06$qi_w@9%EkSS`$K1B+rdl+xeczkff8<9HczSt+$2A+%Zuv8`IIVuX;w7^iL9j+Pp%5dcht&@2GVW8e30 zQA&LwL{h8OepD`(M;8|tPf|)J5JHDA#-WEa#Lda8|=e@bGu&{H@ znl*p!?(WV30NlBA=XSkbe}OU9ZWuxm0RZ&%^&Jg@;6SBPnF9bY41?wK`KoD}uMH0mUquMP#*G`D>({SW zo0^&o06tE($R2sv7-)%I$wjchji?#gfCAy7+83(e(nzpGR#Uk`$ythJVm zF)N$R#*DEK5klt>LRGExmk>fPQc7nH!}yL6;;TZ4A6Bc?^%!I7dESQ$3k%=Ac=2NL zNDu(Pz`y`eN*xKq@TF?CDufUr#+am1DVq?Y06+nNA%qaAR7x|(W~7u)2q7}2Y069{ z^MPR)Zww6$$(3RXSe!2CZ_WugVe*;yvs89P&7x@4H002ov JPDHLkV1k&zk);3t literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/currency-e-d_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/currency-e-d_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..df74c2e1243f865208f008fb8e7a2e7784ed8a49 GIT binary patch literal 1042 zcmV+t1nv8YP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-wj7da6R7i=XmP=?|RTPH5+@#U8ptK=Ht>Un#MI0y=d=x1( zZ6Q=e>PQ5s1BX&j2RiWqcGOhG3J$8K0TD$xS z!TB#az1%#&4TpQqx_hmEJ@)$7ZcHzKm+VedI3<9GoQEpkm|2u*0z@~uQl>cS} zHUJz0jsVvdwWKcgJf)sdXVh!zm^!TfnfKZ=rB>Dc=rpv~NLW$3)qm7Ebs~VHF?dn^ zMIBVHs^jXV?3<2mWjUZ0wMU&#B&XFKYO}gmeOtXVdsnHQ>M3IaLY;ePcc_33=KsV5TAka{^b_AdssE1}P*2h=s{yXtr9JEe5IVzK5D@mh7G`d89> zAz)SY$$FsH)L~xzKC-uB@ckHXDmk@RJ+JOl--zsRGxP**&-sy-So2a@+M z)yEp7@K9>hp7d4JZHer%#Q~X)Z7MnCJJTQiz^S~?0nNY#;K#bI*aB^bM-Lk#(vg7L9r_sX3|M-5|A{7R`KC-O>WAO}I0ml-l|U*bJ-( z&V`0POBB`6Q6I1?+1L$yQPLmHzBXWOg&Wsw-S<>LI)R?lYz9~tkZ0oPG2lJmIB;8Z zo63e-fbl4|CxQyl3Yh;l0EbeyawNNfNnj7~IPhYk-T(|!)V__P*5jxhYG0adB)_BT zb@gj?llpm%|CIWzdTXf`TT|cP)aNbe3iUM$GVW75YMT$n$Yl!}nTYW+Irgf@)zx)H zU#;#`ze$5X8~MpNd$8O`N0PGI6s!WTQykCMq;wy}QJ<-+;~t4k7Bn_z0}8@|0IMbXm`LusTp-gy^>6jn zy7V=xoAdsm1u;+CfK_zq{*f4b*q3Ktn9jVH0;rEEeBLy|LX$zA8T>(QqP3b(f|Me M07*qoM6N<$f&fYFwg3PC literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/currency-e-d_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/currency-e-d_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..aa2a971feb804c11f49f6af0248874ff054b21a0 GIT binary patch literal 1944 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 JPDHLkV1mUEkdFWW literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/da2_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/da2_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..40d05bff7b502bf5394aff08c95b88fa64779b07 GIT binary patch literal 893 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 IM6N<$g4S=2%m4rY literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/favs2_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/favs2_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..de4fc57104456bdb16282b556e08381c48acb7ef GIT binary patch literal 1465 zcmV;q1xEUbP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-yGf6~2R7i=XmO+RUXB2?n|If@nGuz~!OyVB4hf+^gu=FO| z?qOMLU1htPEIss8s3+;6Xu+0JJQVTJgGCDMMX=D5P-|A>;-ZTXTWl+oJycj!aNEP; z!AvHZ-DLjBKl8sHoC(>u%1R%EWHRr)@4f%MdGiP&!ggfu-n~0UM@M%lrCb02N~!qc@7`@}$DX_hRH;;SM0`(5xnD}TJ4uofBANgIgpf$nG|w=M6~i!=2q8DC)oT3G zph~6kzLfHKx7&SF2%)5uLMaskKxRNFrMh7lmStIVWMt%T!!XWOtJQ1U0v$Yfkea4> zCJe)mgCOWhDZ6O~1ON~bX?m?vdjtS53}b|I&TQNMF^ZzE78e)Qb3v1nle+7=KeXHJ zxgZFd0H9JpUo6Xt5s^euqz(R`0x9Rb=s3>hX0!Rp?c2BeN2w1gJC1WYg)~zCWY7^~ zESJycuOQ+`k|gg+DZ5!9>9-1kpaB4Lg+jptfG;z9n*BI@`0$Jn;%E>A-Y_H+(=;`u z)D=R=b<;G>;rkgc2m((CaddWec4iZ3YHErprA`Dv5W&-8KLa6z7>u#ULWtj`l)o~@ zJVJ;zte4ti5Cjn-o|u}NVtr69m)jSH;hyv;0G`%P%RWjejWL$fb^VWey}rJ*wDg!U z_LpH8d8L##sGDUarR;`bxF?s(?d#V_DRm$WLzPBOEz4>%#sC29v_4>2mQE?{x2~pX zwL+mV8AXv8=$EdPl7?Z(5mALil+xjxe}Cl2k^M@kuWPm1-?BuUTr{g&_hA5cnvnwXfdhZU!%rwagZ(f9pBzVA1a zB$4U!^i0=MLWoZYiH2`xBPWjIo|JO+&Ye5quU3ZK6>fs^fLkgsMTrw&K{kN^09viqDaUcDobypcq=<;mY1?5Q;8UTT^HIlf zs;yS*)S%KPP`zG{2_eTg=jV&XBF}1u!&M$SzN{w2Vv%#s&r?c|)$8?5i^_AClXAH{ z8^`hSZnwK000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-vc}YY;R7i=v*1vB}VHgMS&$+$rEfvyK2a(W)LO2=Xm z3~It+Fk1W#BC!#%Ffxcvm?R<+5(d8`kqC>>A1w8w>K?=UoZNG-_PQXD}uucrheGw;r}*fz?O`#youoXCf`*?EgQ4W~D=`ra3oDCCLKobYM4yYaAD_x@52v5`l3c zFfsqZcUe04CN1sYTP+=YN3}Wl=5Pe(uu6(^UV7#OFP^@zITsjBmDtJUWUI8Zc9)Zi xG`1FXIVnpw_UP=obyFHk^U9xy%JNqi$X_9l)Q)86&O!hH002ovPDHLkV1kNASI7VW literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/iBOOKS_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/iBOOKS_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..cd50a9e254b70074e1c11b7f3e4c215a86a8abdf GIT binary patch literal 1244 zcmV<21S9*2P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-xR!KxbR7i=Xmc45nR}jEwX7}CQo=$JICo3N&af%eOK_Nx3 zQ7R)RF$P6KGWiGM$^;j769~aoNNrbX3{IUUC!`pR9V||j;xq=E7!gt=#Fcb+(nGgj zv->86_6|w0j*~s`V3v7re$339w}T=A!^pXF=T1yaOiWs90{{Rb>TGUqZajYccx#yR zI0&@3xaf+=XUzO5GoQ)xd|X7z004-XIF8d&NT)oS&rQtEc2(fDO3(4|Y4s9Y|8A4SoZ#+a0u!y*EF znFA>tD5a`e>yqbrKPE}??fv`r?UA7K=g+%A5d5&Svvb)P(*^*06yOLTX|3zN@BiFx zx4&9jTkEIN-M`uQ{qG9MR^fjr2tYq#YmC_ffXicJV=Vyqre~*~GCw~*8^`e#V@&I~ zki$GD#D|2&mvj;#kGczS??G0m00(-@N6-XZj0Ah?uMC8WI%uJ~ds?};2q9~eT z=5W}W3?v~UGlx+WP1S0(3w@Ba_F@!8cJT4zOB6-cT6+-yfTpLXPcZWtW{wLxi3q{o zMR7$0df$Z(g^q_70f5unhls$;F*Bc;o}ND8*6a1jBuN5mZAL^?tyV*&l;nB70{{*Y zy(=Ou5orU!`v718;4dP28vtBp1|kB-abgk4L?mS9x8gWPYi*Y2c@PA_q$?tUh?GS{ zT-U7xLGW9tRC*f6@e9XsJP|pW=XqEzm&dX!Yg%iwQmLfVG;I-4Dk7(?wVRbn#p!mt zPki5hr_UNs`~0`3WL^ zAtD@x;U6NhX06@uJa1}rbo3N6w~6Rq$8p^KkAaJb9Yjn3V8mLRT5C@Oz?+EJ%Cf97 zGBWaYp6CB`yWO9N=o%3vVHn;eqRDEt`cayurvPBf81uqfdn(WKQD#1At<7*x5&-D9 z?RI-ZYu#}i=M83#jWHj0yIq2!m$EDqB05V%!ps&C(RJOk)>;Gro9B6ki0?U$Lq%&K zGiO8w6yXve*?#@g@pwd0EQa30N~-$($ewAt;6!V1LS|0jHh??$4CMI0000000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-wCrLy>R7i=X*3D~NWfTVR-%KWxRIN6es2~a=DmG$8aiO@^ zb|YP>D_yzJoi40@f)w2eq8qbQ@M|H_u5{5w5ky){1wXs+qiKw_G&N3|nb*ZRH*<3{ zQv)8jF!SE`JkNWc^YPwRDa9^r4)@@O{J)BCv9cTI&Mw{`!sEC%Nv85$FUh{aXIRAM zSfot6{X#XC*O?)`9ENJ%M*|z6M-b!5(~oW!#RNMHM!!@}0rc__!WX7e_=T zHA$-Xr}15qtmBay@V3L}S`RO$?-tQxIAEBQ<_Y_vwC~Q}$8&F6@A{0 z8dXvwslcwsgXw%L{!Xwzjqk@nVrz?zpBHj8qiLrEZ{u@O?yGnhzY1B7;b%-Xd|Qb* zkGT%^r!0Lttt8l^_&S~2xpyW{JSi%0lp>Yn``hU-HDY6>`y}oX{qqkl3)v>|7Y^Fq zxOE#O_RN)LT_xjkp7M-f$a zSllP~)d)9h;H^|(IwLtHa`MqAuqzP}5*@U=&#h0z)EH_1MO3%{^#S=W%9BBZ^eOZY P00000NkvXXu0mjfsr9ys literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/java_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/java_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..fbb53d23e0bf38c1e2fc40666529b0c242c7c71b GIT binary patch literal 1505 zcmV<71s?i|P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-yTS-JgR7i=XR!eLf*A+eYeaM;Na43pWfTo{ClhhU9AVC*` zvaz8cF$^fOMK8N*0(hSwt0Ks%$U0dDDA3QM%UCkh07jBVi)>T_U9@%K8fem>3!|__ z(jHRtX6DU%Hwz6FkyZ@{J-Y#U@0oLdbBLMoBv@TtU0PmVKI6Ub0)P-=bpQVSJ2!9M zJb03LdK^)|-&f51so5oc5k=A8wbmbOZ*TwciHI&2t-8I+H5cwq-mO74T9jqbLY;fleuReI-Sn1 z9zJ|{B~89sszqu&^)y@XJROUAlB> zBhT|U(li~+k${;IMNtsP@ki};`%5Wh4B+mR0#z2Uuo zD^1g4`t~#R6+&yR|EZMvmvin%+6kUqBxFUHpZNt z_GB)Q{Sg+m*3U7sH^%&#h_X6f)nvzn)1Db)&c<>4@-dP3{(>>a<592>LNpo;RhDHp zP16_4vOF8d@zX?<5z%23MWbf3sZNQ7F~)oEF93j8TU%SQ)~;A<^HbD_R;yL?dcEIA zQS`-dIJCpzaHzFjbP3Ni8leo+*l=>%FfY zEohr>Hbl8l59PcgGS@h6vMSwuu{d+-0v z%>Q9#LqyJdpBiHbK#PdJhi^xG20{oWr5ue$qdRJUfB#@(W8=2g`h}t>%IV}WGl+r5RE8`6aco?rkGoFX68nt5ooP%@9*y)sG9kcFbscQ6vd2e zDJ7Ir`|WmnA!HSb!M)-_dRA_$n*TK-g~yz{zWO(;@OWH1E3^H znnH;8_xAS6V?_Y4ySw}G<;$0UlO)O2`qWFM)IA|YRusi6Wm*20nV$g=F!T4Vwa)=? zM6}?X3vslt%*;rVq!)(audiRf{_!;b%pN^>@ZjBUx4Q)3%6L3}V6C-TmThKPwo+9U zGjqwzOhiBQ-j`C!*8q6uoT*7fk|e!Or*myI8ofKy@cB=9zu%YM`}eXe`^983nR6C&#+b8n=42W`LI|a`4r+69 zODXli&d$#6Y55*&x3;#n6o4nPTL3=Y+1dH-c55F0uYvpqs|^c64sZw-00000NkvXX Hu0mjf`M1yK literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/light_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/light_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..ae6e9781d1b1b52302aa18c10e46bbd682903727 GIT binary patch literal 818 zcmV-21I_%2P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-vtVu*cR7i=X*1wBYR}csA&%66e6D`DFAw>d03V)zrWu>5E z%%+H@Q3$9>k;X~|L;eC4Nm8Y;F_6m2N=+wXWx6D~7Qs%p*dGY8n{`+B9g8!^cfGm$ zeB!|6zISKl`#oo7&dlkglnf{vu@&p%|12J2dJyN~0rcZIj2%HT7P`eCyN^F`6E9Z+ z>h#&sQT%{iSjO`JDh{1k$SMrsFI>X)L5V8-jPJ38`MQ0>w(k5PMsWpa(d|bxjH@^% zhou|fDc)mxp<9YwrkYJ9hxZ!3RSRV^N0)INQ?(r=j9|5#kAFh9BcA7Y5w=~qIF4fm zXL@^2sXSk$lonD-lPRSqwf9u~KABP)t=W&Hl)gzRJx(c2H+&`o>qxOLp&P{=xqRmv zx%eQ$(3)g?iQi*quh%c<>>>7HsS3sCa&@(l-0edGH*hz*fm8emfSlm+zVZh}L?u)CJZ;U~jCjO)kmh7JvmDltZ|ZjNy_NjbO%Wj(s zYi&VG^3WR7>)1`lVSHWtb|eAX-RV{=r_oN@08l$Ya8W5_{sZ?@^cz3ZIH{!&RBWB%Sna5 wz2oJiE+cX-2DxtClDkN&yp5000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-x$Vo&&R7i=Xmd|TkRTRg+=e~F6ci-eqCTTW>>cS?pA-ggN zHl*0nnxxH?E=1iZ2t@@8u0#qI5tr@CO+fbrI|)%Kt#n8hAr!i@5-Ny)KqqgKH}mHG zxbNQUB5&eklBp@4-Mjak^SS4qch5PbwZ>88?Af#Bk&%&8N+}xv7-P*BFJ3%<^5jY5 zDE9O+P_qbI| zP7=WZT_S=`7CGlR%d%40Z1%@648MBt;DH(lnx39EZQK5SXJ_Y{>$(mAl>jsVG7KYa z7)BZZq?DnQG6bM|beLsXrDCyo-*KEz*4EbcuF~wK7K_Di5=euHx(CswY4UtNpW&Qu zGRFP@0Il^z6h)^!&kN!>7PM=iT-R*?xHdF2v<2YH0})-ha%DCMf*-cFwzi2#_d-gg zQk=rG zJnx-)y&f?DC=?3kecwOR58<3=Ip^zxAOKLS)gE%r*Er|7?(Gl}2_ZVZ@1H3Y3g-cU z0f18KqVM~v--%%uDF9CgLAs)~ergy7?_c+QUn!+70syO2DrF(Wgb*U=M$_wqhzkD& z0#Lxe@2fYeKnO8WsZ`3WR4Sd4QrgL5>{Wyi!q-~QoI7_eH;6DfIhod4&m;%kx2Kef zrIfa9+ozb;+D^*Kff6C5jDjF|V`ymTgF&E^Cr`c`hT-YtP4$aTeA{f0gKkuw=XpYi z&o5uT{CfZX+}zv=DdiWQ=Xo#l0|1POnnV-==+6%Tkd#uiTCI{{7`LaUri|{!`1m*@ zqT8)jYg9@p4#{tFRtf<$nd3Om4Z~_($K}6*Hek%;aH%CWD$GYodV`HO15WLmt zbXo%-V2qiDVKke~=5upnW1}%UJG;p_p9;e;8epWOC_$w{SB8P56U#>Pg&Ovn$j+3b5^cvwDn?UYg=qG_%5coJw?DRpQhUCCy%j4}2Q zNQ!E^-F}?U=bw3=x32{C2yxEIah%WA*Vq3BfJ&uuBA3fO#%^x+{juE=l+9+JwcG8- zKvEg%^?F1^cPz_FA7%&uQc81VWMsbkef;?GSt%tyL{|eK%d*mpu{-s8Jp%gr(bcP0 zzjIypL;JU6 z6VVOJvKC9Fl9g0s-R-bRB<(1QTHUqoKIc4FDwQnDvKAR*H&$0y_m{Lm!^y(J!h9UZ zH#?oqnIjG-&rH+2yR@`)XiItNxV5mbU;;SOxCP+R($dnak6Zone+S5a0IuP<;OsEi Q6951J07*qoM6N<$f|d1$fB*mh literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/pin_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/pin_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..1522768084d6a355e05853f99ee6a1d49017a9b3 GIT binary patch literal 846 zcmV-U1F`&xP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-v$Vo&&R7i=X)=!94RU8NK&%5(x#(yM}THByDX%x6lY9rc& zWNj=cDuQtBq6o!ZixS)k5}`tia1rXF$%Ts~Xc-ix7DTl%Xo{iK8b@bti{J0^j?a7F zyz&PR-aY4czTe;fb9!}M8&kI6QEbZZKX4iI;~egfu|JF5cq~b#bMI!7eT(y$!|g7h z-UyGL$J=-U%UDdH=0GnES%V3DjrVY7T%rm`@g|mVqtq|{*ZDo2-mSwFKEMI2j3Vme zB=(80tPFvdQm0WriQN5@x|?tsuPZ`X4IMs$7e#_sBUytVMgEQ(6v=#I94QZ!M9*Qr zK^1k8G;$w)#$R|Rf$vYu`NZ1WC^w;-!bK5+8>@IyW1|S!%lM|)KZry4Q{?Unp2AY& z(JoP4Z6w3hGJ_wmXNUye#anr1F)?>B2;HoqDk-dApB}8mg9*L|zjS#0A-)nhTuE$w z(ec|1s-}@%{x0AXT*V`zIj^=5JdMM6ATj?IDcOcCeQXsKvpjULN{^1>%UrwI;l(UY zU_%pv7>_kUcg6~6h&~$AQ~%)Ju}=#rS#IW4LFBqTXgo} zR01v<(GnFF#0cpk?TKpqt!3}ww0Nn5q)P0C3YWyVnHW;4MKW)tH&^f}-Y9f_6(R2O zWFoOI^+gwdhwX)Bbt+AY9NfegqM>()P@Tk+?k=Lz(6xy@--K(Y1Yps56#xJL07*qoM6N<$f&_Sp>;M1& literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/pin_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/pin_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..75ae6bbf5b2f5fd23543fcf5d18bdf51f4939a6d GIT binary patch literal 1407 zcmV-_1%UdAP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-x`AI}UR7i=XmQ83}RTRh1x$k4eQmHhh zlsX%R;R{g|X{A)8wN3zF+W;A3re#^#Y&Oesx!f<7WnHXRt3MtHbo}^nmdRv3?sPiu z20;)jrNV9m*k?=K?M#}c(zb0bgs?g1-%2SzSXx@r13^cR9yMLpz0_*8%0Un`06^~n z=z(&%9Lwc$e@ZFGgCOVt016>I$8qKxjmCR-@80c6$#z;gjx*PVY#`#k5Jb#mv)Mlo zvFy6;H=gHthzPA#Yopa_l?#Q!+)jfYXl7>SL=;7*gCMAP{SSfw5kV%C88!^#uNyaR zY|hWme>glm{JHD8E@O-ZK~RsP==AjT^od=dVzFpzt2+BSf|rDtdt7-<)X(6hzPXSz&UqDMn->hK58w zpXY@_;Tg~K?wh9h=GCiL|K2O)IF7%wZTn}_G&7w}M{BJo0RYU2iHT7m#37|rv@;qa zLe4n~A(l!y^lMMSEr3_ccyG63MRK@JcR zl~QrNUe7C~zOPg&ll^x}rBXSL<4cW3Lo21^K6M8S5q(6Iuz%fb5z%`8zLfI0cDtQP zk|Z7g!LDzgH5!eFhGF=OF|*G(8HQndo|o9R{rc9{)^C+c<%d$K^v?F3IFA1zqI6Is zj4{(N4Bz+thir9qb)(zrv-Dr%BSbV@*EIp)bR5UAWm!w>>+8iZ3_qz>(nKODVsq*Xw2+$6Jgs zrnOFd-%lHj#;G6(EO_#@Zby^joZoA=+jn}P<>loV5ibZKG5~;D>v(f>^I6~bPc@s( ztu#&5jyxa{k(9Enwce{Q5000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-wXh}ptR7i=X);ow^RS*a8-}mh!F)Nyw#9(EmU?K_@f`z0} zG%-HXsHE^!h|fYTL@dQZ18QM>HJVC%K$;MZRf3=qBpA^Z#7c-U?yfP<-Th2Z%W)oD#`;#=j%zE(3Un}4!G6H! z*oX5=B1Obf&-REo6cLjVaV8?hBjWdnI2IAd>wUb|Cd+pFQh1$3sO#c2Jc=I9_N@=$ zh@`R8njgV1-ovw)=?CqnYB!$1DV(eM25?B`PL}U(eQD_rv=jFi*dzwZ zA z5=z<-5eFjTbVPg`5r<2OZU1wHJxkqIeJZJ){e^AV(VAb0%jzVz;%2;!4Hk}>!qzSR zH_7C87BTMO-g@7GuW(4_s*CUNa8Y%kZ=;iiy?ziIrJ5R}Mory%MvD8*QVbXHx0Lae zthr6*lo>6I3x&P0i#4()8tOU)G$CtgKVFb+Xh@2sCzW*v&frD-BB^c!(NMPnYZmKu zodWz=D(hs;pEkb;hb!omtgRDx9IF<=)GdQ)b2T+13-vkN)v|qG=3_(AF(8X_8n@sb z*?8Nv)vfgtgBUHEF0UY+I{q|X#W(mF$8Z}S!8+{4mj!s0RO7h0Vpp4)!04dl`bXR# zxo-@61-MNnTsh5aEj13x{0v9|G(~$+VUIO*?X$4&X;ILTD%*#bE&Pv-%0{}nZ@ybT zvkv>swf?g$qjA~6_sTroj@@S*v?hF|d%uB@QV z25u}$_DFHe;7{3vPf6viD9j!f{P)2bD;M4 cUl+)K03^Jh`Rj3V;{X5v07*qoM6N<$g1PM7rT_o{ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/pliok2_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/pliok2_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..d93dcc6623749b6fc058edb073529e0a47d8bc2f GIT binary patch literal 1704 zcmV;Z23PrsP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-zB1uF+R7i=XR$XiyR~0_z-np|oyR$RiS*L{;q$sGyQVhH# zSVBtbsz^o<03jrTBISXHlsAO(P$J+3M2iqqw52bl5F}!+7wjmFDl8Pm3W|hC zq!1NQpOBEfJNE4S?wxxN51Dn>R$Hawyv?0^&Ueqf-#O<)B7!HelP6D(9yxMkOlw^S z0AP&y+uPfZ?%ut-^CbTGaX`z<%LWmhky1V{r5smEHHfGL0Dy=Y=e#3?cqoLpg^2I0 ztgPgp7-)HUd0t9+IgaCrG)=XXGSyn=06>f}MnoDBg%F}#E|*!QQn@dLczI=I<&RGU zG&?)XN~O{dk|g&-07zIWrs z4Lux}4S$?IecC9O%dZAOaIw?r^rVytBJP7Q#)NI#J3@$-5MpqJh=?eqj60o95Cp-+ za=HBKsZ*znj|6gE_v+r>-nk$Mb^st@jBx^gyR~n7R<#M_F zl~$|u9U_7|ckaZdY5uuVsnm%G5z#mUX2UvoLm?X(w9LKZGX7l`DeSCbpeCEuV`uh6%_Pu-emORg!HBIvk z!!VvY%-|$RwAOkW0Dw(SPL4_`$EB3%Ae&)}qDX43&jA1|E-t=s^ytx>oby`?3kyG< zn3%w8*RI`HN_{;H!zvM};e$#kQz_;6(ax+?&1s@-nCu(r1LFV1-=gfNOdz&RI)7}e|btkr70&N=@@ zsZ`n_B7Ha}0DysrJ|boSP=&|T*8P5;_xt^CJC5@{0Q?RBAkXu+YPDLEh(4d^d0wm4 za>FowcKi12?CjaI&uXoI8by&p#1uZDITo>f*6ns5an60l*q~*gQcC&0-;d+?`!h2$ zp9KI|Utj+(BA# zLWqZ3TU$Fufqc`ltgmHRw(pFHKt!Om#<{sUvY8_Giz=#>PM9 z=jY$9R4SLEDC!QX#Ih{L7`q8jbcQet->p`w527e~MoJkM8<}Ak9nN`7M8EI#de0_F z(y!HOGnQq&2LQjFpPxU5h+joSP)gmkZTm}EmOYc_c_xIYSeEr548wN;hUQVT*__L= z?AM)6XLkT3gm}MFsn}_nekM)R9uYyQRB~O{eH#(qLd4(ndcCKLIn^PezXw4urj)8Q z8V#phE?-z%Tl>=iAOL{H#l;^5L2$9?;28igM6`%V7T}18CD(QTYMQ3)`~F0hWnnS1 zI3l9fy6-s7(~jf(s?}Of8E5 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/pliok_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/pliok_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..09a395069c87f4762433002b83b98fd12bb62f17 GIT binary patch literal 949 zcmV;m14{gfP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-wFG)l}R7i=X);ow@RTKu`@0^)Tq9Z0T4r(WY0b|fkun-#y z6MRjjHbxtfh=mGTT8M=Pe1H$MGL`s%G!h?GQkg;m5i^2_g)o{p6Jy5A>n3xT#a?Ib znS1X{M%-}V-o4lQ|Fzfp_u9LP2%8)exDC7V|2h1GnawzlZeo2u?#JFF*@_BFN%kYY z#!*~e7bzmv`z9meL_{n`#Knl1jfgW5@kd0Q&EK=RwwSh)>)};HQdi?mJdF_i-%e+B>Rp7c+@*Xg#8b@k|;vQJ&05C$Iw_;yp~`&)i`<_YLt(Vm-3DkTn{^ zaV76fO~w-NRa~3DziolOjpuMS3A>8wsw5v*p$n~sS2i1=b1 zCEXYi$0FjNi1wwD z8e-g0iaTs9DpG$cQ?=3;=wf0|)Yzk_sWEDbTPwLA*OT(Faf{M58fCUIRuX$pjhzY9 zq^`mxrM=840(fZyqF?a}eo<1rqL-O&V(%Q*>#E$zXNs~eY(UaP|BjxduU5|Ano;9C zmi4yXO~V)Q&=p9Uai1cHz1E(sIRD!M?{@;)7}Tn!$T)N@=7!`sVBOS#|hE zul3KjjAoS%{-sifj&ewUPT<{mBJID!-HEZR9E($ly-L)<>-faltKm01i<^_Q3E-|w z$q}U^bn%zcgy$6HZB5J$1}?t05_mSFs?zCFi+meS;2PYCi@7$EK`h}Wyo=`>;C`Y} ze2hnvEDYW|a&A{r X!eEDFcSN#=00000NkvXXu0mjf!+*kd literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/pliok_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/pliok_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..3bfbfa6f3b382a37cb31f459b2bddf66fe4c7a33 GIT binary patch literal 1552 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/plus_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/plus_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..c6b685a82b51f882db32df279109a74aeaf12c8c GIT binary patch literal 1290 zcmV+l1@-!gP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-xgh@m}R7i=XR?ll2M-={Mc1NpKq>*;*l$_FI2&A`Qd*`43tsghC-Xlv3J|LkT@5^w3M7?WIt9h#l;PkhC!lIfz^v2s!5xkS$p&c~`sh zF z0WB{tyF|30l=@I9bC640{ zhQpy%N)4^G8o=lR2x|@JbwImFO+Ukxn8e-pMz}W_KP4i=@?^-Mmo7eHj1Jx0GAq##x{U&-ePp&!iA59 z!{N`{+uJ)u14SUmaagHTssVsfYM`~Y)AWdl&CJX+JkR@VZEfvO0N?=7Y&J{Q+N)6% zr6bR$M91-cf45eveO0T~u2iel4r5GA(PIE8ilUT=t~Q&^(jHK?T0NU2$tk5&d_Yb( z=Ul&h`SSOB_wM~cL_;Ft(-awFOeqy7Nph-Mt)ATjveqspNn)p6nzV8J`0?toW5+yW z%zr+TBuT8bb`b#h{QUf^QtG5qYFJ=HM1*}lj4{TDh)p|3US~P0p;GGP{QUf^8;0SD zG))6*tu97Q2m#OY%6OA6;ro7~wMHDr@O|G0PyyhKoJ-SmsP&uXV6D~0m>>v(6D|=2 zd0Qz~u2ZR0hMwnrT`HB@)>@uBsb9T%wHrl|bzS$%TCL^*u$*&it*yGQd!yIuH2|1G zWIO=DSREB}K}7b+lP7=o`~Ch~hm2u;eZ4jL|H8t;b-d2InLKkDV_n8r3gAeAl}Xdo zJ$?H0kIiN?%`ZEi=M8$j-gl)^DLZ%W+>I>DLI4`CJBX{4s^-57KCu))*X?vVFQk-R z&iQ*pq(+ppEOWKi3jp}*+>>w|XDbZD>y1W(X|0=a9KR1BMP56`m|XySMa(&O9mnZ* zyWJPO)oN|!t-efe`U}gGxofTM8)F96+P<}Rmx#bQhcRYgjOiD@Q7CpIA|XUs2=Tnt zYHjfx`GN2IQ;Tm>9LKT7n8VZ@eBbAs^9RUdkHKK@$oKtcLWoL%)my?Cvr!bOcDt=G z{z}IrXH)Tg|Jh(Lc(ez!v9Xac#%@X}y`1_qBPPqTBjs}W*Tu!f-?Y{t05wIA05B<~ z$2q^bv9XZ>6K((E#fv{gQS|viW5RKq3IJxUjfrTodlL~sN;xZ~ynXlX-Muj}R!2KK zJJ*6Bm<4btilS|d4?YF}TI;Y_UZfeHZWhv$DFbw4= zXT`iR#!zfkqjModB@9C;rM%5Kzr4A*Iku?myPPa7Eq$W3z7ogrsY5O&&s^8NwYs{x zHqG9F>(lT2AtE;Q;zHUv*|6L&e1=KFNJ|z2@%K!iX07*qoM6N<$f|i_@% literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/range_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/range_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..337622f93e66ff74cdf25e6ec4e1913a057fca47 GIT binary patch literal 1014 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 JPDHLkV1jZkD&YVC literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/sim_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Other/sim_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..5ca72831cc7a8e7bb94a1dd561a626fc361f516e GIT binary patch literal 1044 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 IM6N<$f^{*I%>V!Z literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/3dmax_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/3dmax_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..d43184570cfda51663ea748ac891b2c6648338c4 GIT binary patch literal 1037 zcmV+o1oHcdP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-wheL%U zBH2xOSKSEJl|>XmS3yTI3PL(iU3gL5L=05cRR;}{pt1}CJ2E=WXfvkcDaWUa{eJvk z!}K@OhQ!<=Y0ULnhz+_Xu@!!nr z-_w9z;AP-`;AAI9-N5U>9h9`x%2lKl>27>G3H${dj_v^P7H~I>R8FtaGr)RaH1oNU zqre0(4*Zezy^&#HAMgZl9t9lh^KD~0ey!zJ^@zGBa!B2#Zd6yO3)HTL{&d-@j;q7j ze?(nZuh*&T1wN+0cM>=qcpi8(=UEA?237#)01LCHO4=qU@L!lz3e2Ox{~F+U?PzWC zIv#}`z#8BpN^!3R_5fc1Kcs#qqI&_bDrx(Zg3uZy{i*j*9ros=YFIt2Zpil`%Xmp$ z)FEv>>OJbHIubj>vAJ0Vbx{389ZPQasms*?^>=lrIwuAP)F;)?)lb!T)qB}IP z0~W;L%IN*d3>?}`LE153eoini;qHyWiyQhMMV0_p0r9HC8Bb%w?(U>60h ztwb~*I3M^C_$5)Sns&h36Tu|#8>JR?2Ks0dZ!5NURTRqjjzTpi%Bv{=*q-RN01pFK zC7L1NP2h0~TQ35>it#11S$=M8kJWv!HvKcK?pJrHE%kDBw>p)6I+67;+vA}6q1vx5 zR)0=g)IGVj69t_?p`T3@RNewyN}-v))NT~`3HXM>Bml2c2=xHdD5%-p>l&mwl9NBC zp4)*DQ0J+u)wdH}M^dfFbHIJ6TSbBH1h6|rA5Y74liJ30G zHz-87j{^5r4ENCPDdMn3TV4E$_QiJ>jf-!ltGop~%YR?x(1tOTn$%bM135%{;|z}K zQ9n+WC$dhDlZpb0Q+k{-+uLtDcfPbc%2FCxz00000NkvXX Hu0mjf76jQ_ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/3dmax_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/3dmax_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..f755cb8b42af62ff32c514c22fb13c5b9ae238ff GIT binary patch literal 1764 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/AIR_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/AIR_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..22f793d0391438fe07456721afb99686b51b5c08 GIT binary patch literal 939 zcmV;c162HpP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-wB}qg3+Q51&1b9x;ViPt4wBZsa4YK z$Y+tHw~{&ozahsOT^B~Q5!l686(v;K6yUN)5ZY_ts;4pc>2j=wICUA&=($!zBJ8kx zf$J1oPvDcd&mdMzSxB@NtFAu&Bmpbyi@=L2M9YDp;5%`wm5x11w1LVhk&hH>)VshD zpPPyuer_4CfZ`q+aqLl`r9gi`k^$2l@B-FTDR2sS2s{AxM^VR?IObBITmqJ0sTp>s zDZoeI6430xU?sa1Q-i$MegbEJHcUANs7(E^V=qa8X_%~xV14ogSOe?}NEQR@eFKBO z(;g=VxXqX}#i<()Obg39#q!(;e25%!xd~0d|INTF-)LbfQ{b!bG6UXWA{pCD;65-5 z>-Y@I#5Lb_FK{Rz&&g89{)(isq(C4F|X?~Xkxd@aB>Pvd4_CMGK>){Jwo3VH?H z0G<||1J<-1Sn=ekYq1lxon(?8N$U2UbW8dnsn18RM?2tiO_JsoL^LlD*lx$nBvq() zgQWgIt=psDxiWV+VXLH7(HUOxO|?5#Lp~p0d?&Fxrka8iR8&3Ipm#jwYk>J)fwO?q zz=7N;CMsc)vjzBsm2MGPPFRQaP73_+Gb&?!wVgo!imviH;5fxsc}yBQhgbO_ta!#8 z3y5;dA15n3viNb5U>TU;5w-G000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-y*GWV{R7i=XmR)FFSry0E+8^iRew=g9&24F!w_2=CE5(-* zd`UCJv^BlCNnU2qCkMoF1ey9K!@#J>pomjn1gYSYpp4v`HmMD5X-I{_q&_GHC73s5 z=uDe?a(C{WuYJy5K6r1u3GL9q^>jFA|JQHrwa;E_ArZlg*!lD48%K^DIc1Cq000001H)*LBOaTJ4{Vv1@srZwVp3l;`=?Uaxm7j^h{+ zndfBym|BEfn;lOaq-W_ zm_KA$Rx!rpN~xy+uvn|rb^ze}L*H!pFgG_hnK)c=E zM#N<)W%<7uMo>!aBuVmGv)P@Z!u!)I@hSvJD);byd!i0#H<2b?C*jTAntNpfADt#RQ*xcOQPi))1 zd;IwEJI!YE+W-LNa+!$eAmM+zO0?FeCnhEuqF%3`O4Bqj#^i_yuIrX7mC8p_%J+p3 z?M|oj0RTX=+5DAK>Xm-K-$g|3`~JJFRx97w*tmZA^5qXX=i`H5_o2p^yeNtw2!d0B zhyo(AiHL05F4bzazgU*_t#-Tp;ZQI$GjocFruX*tJ_Z0oM4*%cDdj7Oc>T(iEB778 zxtwJg97-PzN>;!|UNXmV@}el-8HE4wZwFR2oDi5YehutAUhqg^0|(d-wLFly3z=K!c!$ zFhs-@07BO7cDFd^AtC}}?8x}|__4#FhYueXmSug{_x+podOd428hh1h^=Dxi{$jXh zX=!QAvaBDL%jFUg0TBUXOmNP_Fbublh+uYh_UGMh_f^h01wnA*@#DwedGzSfGgB}< zJsk)k*y`%)&f#w-Po5MfPMlZ`!|-#)nAEmyF9?F)-MV$_djbG}F?Ppw-LLKL?(Pa9 z=8hgcI(G5m#bsj*3L(xA(J@5KIp^Dsk3e!qXeTrO`$QS^DGR6j|QFLTZ(2L}#CQ5Zx7A%t*U_l;Jo^+#jOJIl+ zGc(5#@oZ5PiDg+O*L64h{r-J`L1kE5TgwpfJeIO~No-B%*e+**rglv|6pBwr&43j^i;RDm>4#8DsCQt*vDMhx$>g)p}Pc_07X= z;*b#$fn`~4wOUO%=j#9v8e=A-D0(T1qQ2*O4bStg-?(vOzfBzIN4vYbZwEop0DwiM z)DDa^z7a!2ge=SAZnw*Y5MM<^rnQcYF`xLp-|&6E6Ncg2qoUCZ3+wCaIU>I9dEWJU zz3xdVOT+4Vcw2~wL}aoo+e_25$2pf{V`IMOdB0|iy}rJ_eqc~}?r<_cKi|yr{LLte z&W;WzFmf3gV?s*lIF7?grP8Jl;@Z;E((<$Xed@S1KR+)3;DyF50JyufwDj4>t;6>J b4v_x=$s;Pr#TU4l00000NkvXXu0mjf$o3y& literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Ai_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Ai_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..3568d538fdf9dc6c21a38b3f1fefc0b3e0d0030a GIT binary patch literal 898 zcmV-|1AY97P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-v{7FPXR7i=X*3E02RTKvB-@NH0QCnk;0a2{DG%dOjaUs~H z7K#-Gs|%|LZd~a`{1Zf|Ah>a(J9VWXMB9~BD%FLhV$O~>uiyff$1&bD#{MBZi~|{DD)-hi*mw983%EMU zQD>VQJ%(3sFE;U4I;sYpJjgUAa1O8G!*K&OIF1*vfwi{&fNtCP22A2@yo}y_V$AK*DHD4PN0*Kt%y@J@nA-Co)rO<(=Z){P#;`&iA>)gbl%ZvGAY zZ7Xbhlsx^>(%*}x@KHO^Bu**xT^qPbHT+$HqKljLb1;dMx&K7!hmx}kcnBLJLPQ*n zh|3YN6cIlSd@B)gCL-n{;`)f#7ZHmQ@oRn;(}##S84;^#x0F5)N5sE5I%I$)t=mlF z>%@K?KjJK|Q)qu<=HwvmNLZ`%(ziyb`2DzIc=7|EWe%Rs-#*WE&C{z&N$k;QS|@$( z$6SMXg_4^?f=nnhKaJZn2Q|)rXEEO>?3gkfx@j!p7o|fS#6Dca z_i5K;u*-RiHY&Z;**jQAZHZJmo$LD*XdcMDGkK8E@0la(u2Je{-L=Kr$=_?BH}f_p za(&8hxCi~OW3^GBSyA%QmM)g?O|ECK8#m?pEBu^#qon3|u~BGyUZHDcQKj`+rP}B5 z1-`_`3WUq}Rv*4WiS&6M%N4E#TcPXZX%=#QpVAFBaF;Ths@;UbK(2+dsXl5FPbl-G z-GctaoeHHNS6H>FFzI>RhFg_dc_weZJ9TOcI+wn;G}R+`Prs>3!)`jek|*q?lPUdq zHIs+Clz~Pz)hch`Mg4ccu;v;@)3`dD!&`W%ZVVfI?<#}uH~($$-J%S>XKge1uHsmp zW=4T1THi3|?XfVEw#N)SRK|In+@suVyT?hRP<=;_leTp6i1D6VpV&Ggb`+>B|LXzy Y4>CqY2OFH6v;Y7A07*qoM6N<$g1i@`761SM literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Ai_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Ai_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..e1d9a1e77de6ccf65c83b37eae4d8227a639b9d7 GIT binary patch literal 1484 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 Ueoz&)=Kufz07*qoM6N<$f`MCjTL1t6 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Autocad_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Autocad_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..d14c52da3d5ada859448802a8c57ffe2ca25e3fb GIT binary patch literal 897 zcmV-{1AhF8P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-v`$@9K%Pm8fx$wo=&ev2{uSW=PEd7x ztqjfMZ9FE@(%>|H!W#DAZmg!EdX$tO;sZRPPGu>jo{OcFQ7PrOoaag@N2~p7N-5u# zQvS^SQ@z>hjS_1UyQw^S2nTg6YCT@9Wd6m=f)M?PYMtf8dbr(a4Q616@+SZv_6(Hm-M4WJR|BhhrjWQ zI446v?|QV#S7oGQL7oM1b3EG$PHKGbh{m^^-t9;a*LC%p)FRr(w@Wm>$5oAQQY)Xs ztD=>!=`Pht2Bx+0=k%_$Sso{M=&qt^kCO)9yUfQ)J+_InGRt%8GhJ#g+fY6J*8}oD XBA-CiIvrtY00000NkvXXu0mjfqJ^iv literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Autocad_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Autocad_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..d938802ff3e2124d34ea6d382c4c1febd431cc17 GIT binary patch literal 1524 zcmV000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-yZb?KzR7i=XR!wLeM;88GbyrV!Pj`=IJQG3=yV#e(M)`pS zN8p1|aD;@`mgMX1vcwPwyWk{bFU#VSaeRyk?82@O%jOyq$#$r3R>3A2Yl46+a2 zHQ0tYmNZgj)PL1gm4kbPG%Fd0)TxSk@B3c8pL&msF?gPJ^ytxMtJP|2t?K~580$TG z^5pKVTenu9N1vWWG&eVA8)M#-Ql5}f9#%>nFve5>fQT~7ver1~E1dIx6VX@m^Yg_| zCYqa@`?Zwvy*Q3vPSaH9d7c_$3IGEIVvO0GbJulU=KKD)obyZb^YdRk7t!S8B&$>^ z7m_4-O9+t{MIjku6#xW4X|3adE&!MkfOGCgQRH}@_s=ZL{&M5S4ZSbX@#DwsdcFR) z&CSizLWp(CvRD{~-#dwma;^X9fI z?VZB4TJ3yEvRYahIgazMPN#Do0H&sAlP9Nl5sij?m0V`F1YDdk})Wjg#CBGR^P z3jlch`0-Yr=SL47JotM6*x1sCkY!ntG4=xh+`oTc6-9B*^Ss{z_)VIo z-vhw)>({@tZTnIX1i@a$me@UeeSQ6I6h%G8*bBxOIV6==DwPBP9zA-r1z=$>YgblQ zK54hxvuT?CD$BC|AgLH*wq;qpUaxo8US3{aot~av;hevkWm!HDA|f)zNTrknfJ284 zv1YT`48t&VUDq|n_(U{v=gys*_wL=xrl+URhhg|xp63jJHpakl9G7#xvb?;!%1Y)h zJwdB`F+9&> zjIl3)vS9oD{@0%8-R7Kc*8~v}V=R66@ZnZ@w&FN$2qCx-!U!SqwY9Z%rPLp%rlwi| zu(`Q;(f9p3j4_9E?t7khyWj7By-l>Vw3HLkM^O}2@U(RpB4Pmg4<0Wf=ot!Z55b#y(nFTFQZ;el#;Pb5RKKwh&^K zh%DdtMWs^tA7d;kilPz6aVX`kd@;rtSeE4z5eJ}^Qb`zwBT*DxzH;TtcAMDMk2W?o z&eiMnCV000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-v)Ja4^R7i=X*3FBRbrc8i&%JYJMzflH87wFwh#)5n72LR( zg%M@+wwfs@6Doot$VL4PAti`zT-a<<+msb(iy(raWfo}>(bh_1pc>7|xlfC89-iku z-g~=K2Ogfc^YT02bI$koYZXOdM486D*qHCX;X7O$#ke!V|2=pJ_hpdD{C72jeTz?U z8rKFnY7NQgNxXskv4X$SQEAZ1g{;9CzQ&vQVAMcuyp0#JjHSAML$_|c4ih+v{pb!0 z)WJKL6R>pqI3FZME^;H@!#*`A+YRLdm=^_JO%SQuP22hORsF1G^f*ppQ3c6b0Y@3I zi!1oM=Dc5KEv&~=I8_fcfzL(zE~R1{-{VJIP6yN2fm`wCzXV$++J6?yWuQj|u8TFp zwW77ZY&f|Mhwxwq8w78WS4|B_J4?(x+U-Bb4vw%H+}0Q z95Vv@(s}bfD+)X#=IWQ!{~e!Vd+MFS3z$;Xa|Y8LY!NNFG5`Yj89(80zCVIH1slAI zhjBKueFhsc&`SE=(h)dLHlQn|%;Cup-_E4NXB)n{`M$n6M}uS+o)+D9 z7O#jFFYPDsK8^|4uH(G6=(MY@A6}}WK96_t5pKqZ_(HTWY{uQVq?eZ3>3gw_^MY>1 zhGbMiaTjjL=ekXy8e%HQ$5QWnM^MH&(K*Zd&&5}wbr(dz$5a18BlEg#A!hL$E|zee z)*renc|VB9L>)Ha2<}la`;uPBN@=I>p%gTR&+vn2({bF6ow!5L(yys=6LzOgVF(4m z6F8xlRBu$ZaG@H)<^0ykAS;3?>JauN)lv@PWz{)gHQPkF7=mq%sAjM4#M||}bCl!O k8NEZhsz7!5UkAv407VY#F^q!a%m4rY07*qoM6N<$g7=w=d;kCd literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Br_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Br_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..7815eb5c517faefc27743c41d6a125a9b6515cdb GIT binary patch literal 1425 zcmV;C1#bF@P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-y3rR#lR7i=XR!eAHRT%#MbMDE#b7wsBNCu@r7b4a|ePOME z3L(MN!6a>_vGMPyx zo%`sSdyWh5q?1XeqQv1l1%#*|X8DW&#AQPgjYu>pXHLeBY$5aPNJ;x{6?R4SEP4^31o7AKTa zr##PlHV6W(lnS)gEdXr?VvJcr2*+_8=DO}RA;h^-sWiVMqC%m-Y}@|K_x5;EgARXjRVq+MxzSgNG6k60dRUtMu!d^8V`ct zyOoudRU$F~z!*z#&igu|)=?A%T5Ht~q(^ep-`}6HZTrOB+}y$j(a6Y1Uox5ewOXw{ z9ruK6+h(a$>L%y>HUN)^V2tV4TEFOd-lLx9-R(tYj4?t8cVJ-PX0zFR+2?wNb~_fxm><9Iy#ygA0K}+iXt0;z7Jt+09mUW zyqgOE#>U2mCMG6!1wpVF1i`gTCi7t;k(eeT1^|UZ!4^XNxW2yritqa?09xoejf{xu zL=<*!06_ab2_fF~eg7xNaemHZGLOv9&o6M!mpJDx0C3Lpp65NewzgK&TAR%f6auKT zTCH}2b6#hR^~^4cA{~ZdOKbf^8yrB5F~&Q}tUAsT0RUsn;+)s(_4*CAw6s)>rQR`H zrJMkuudnZ~Y&JUs;Dec&nSb`}+b4+V`6!Bl7|?Xu$HYbm;RqqFFD)%qt=RBlB9VA2 z48zWx5k-*?0JF2R=K-7tfMdswr}JZ9Bww7;y+>8DnT2fIypHx z9){tDs1gx4=P4o*9o1-y>OCTA_aFrzYPDK-+of-ds^d5(W@l&bi)wovK79C#Mx*gw z`f z$;HLRO_J7gIGLK7nryXNr##QwyTjq+Z_BdImCNP1?eHErZcR;1Spar4ZUMMdE|(vE f-0EKccYypC2WZ(Kpx8-s00000NkvXXu0mjfmQtH% literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Dw_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Dw_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..987db6f2affbf070535775683a5b5662b0df5437 GIT binary patch literal 917 zcmV;G18V$000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-w4@pEpR7i=X*3YX|RTKyC&pq$H_tK}CsT4L!C#8}FNkx_w zlx72K;xi{1LeoGn!T&&_z=0qQ`T<2hCO(X`QP3cY27*$Gq!T9&%&xEU=Y99x25ar^ zd5`;^*V=G6=j^lg_q+C5-?h$ebh}*xjum(q%kup)&fwA@i<<*{--<0*mn5V4?Pikw zf^TsQQ*!||=GoC}*oXD#;6?(K1&ws%E)3x$4&cb3L>1o0TeyX*b^BSi^~GZt!3Wrb z>G_D7_z2@7EYp3!=NjE~av8qFn`)t~W*NVW9U{SZLLzOabM21A>V2&3XdAvjE4}L% zra_2{-BP@ci8|2;z8CVnip6Q%$@{Pf!`}lEc16z4U=wZ?d2bf#x{{y=@e}?O;eAlZ z{3RjlsoRh>(&6=q{dLLFRy~yriDZ5wBzqDcV>{kXM@G!7!Qot2c3a*%iLDY9zZTbP zUY4Rfir+-;mf#b7CTi-B8qx2$gCVqW5tE`k)?!74HA0e|J|P%Q@5iw}=O(ZV&j{g6 z;%V%~efSDb;5Zf}_L@qlW7Nz7D?6JO`M83oa&8hUg^VxaT<-2?A(j&voySBzN3nEv z9nCfBO6%hJd_I@JcjFpP;j9qPLrH|lQ7b3W@4YNM67>Jj|xG#AHZ%r znIYMPoeA=SkbWzHAH|QNn?Ek{v>>rBm2e%ag|3^ssPHL16oPpt-`YJw81Bl^BN$Nj-FBG(}$< z7j5Og{P>oOUb)LWKfWovfkQ&tV+l~Me&FRA%Qc4*W5z*cki*F%VrTOmPD=6K(cz>% rhVin&j$6k?&ianq5!J{4IzavdtIPoRjLd5u00000NkvXXu0mjf&NH)z literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Dw_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Dw_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..ce088ba38377d1d6a58425be25e5eeef66908de9 GIT binary patch literal 1534 zcmV000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-ycu7P-R7i=XR!xi)MHGHj-PKjyGgI@kJLsOogKkKG00(~J z>V!p+h_lQh-jx$_fy4wO1~1059E=`F@S?_eaF$s|2pGt6VFg1pVhBn!Bpytdou6iV zrn;-Uo(Fo!U;vl+l1{qvs@_-ie!lkzBEm{!^XARt<#Kt_7*hlQpporM|j3FWi03d{fmSrt5#;!BQz9)p7tJmxCV*}03&c3R( zKHTs3*D0lp)>;{3VgMK(Ae2&@F(!l%)bqSw7-Prl_4>Cf0@}4}7v-FPI2a7x^nE|l zTKCfzkOvvS)Bt15lTtda>wXr7;d^J!oG}jts#Gd=u~_`1*X!-|eZLI==3xL20i;sO zQa+#mrrmBIym;~AJy+VJoAden2PsG^wZ9?|fO{`CzVEjHU~i#NSOS1|hk82vnVFf{ zt(4mD`~FgTLxPAf@~tF22_Xc0-(ONn?XOm=yYDFw5w>sN?qo8V?^>s;i2ZO=dY&JU$0B0xwfH7vLQpx}T z*tTs0z&DLX<7}(d`b8;qte?RXeB%81^GlB7{Ovf-AI)a7n;<^ZwwR|Gawj>fF_Cc%isSg1BuS#- zIZ6oW5JEzDK+57>0U<<&bN*ZE&M~d^HbMv`gj|c`_{xS28@5kQPP&AUg*$id{N=jt zR1`%y0Kn9Chql}88=5o1mp-}kKw(XBo-Hsp#o~~3XlY_zFhg-L9 z-Qb+RJTWoxRIk@Nd+E}pWkj6PS|^lJ+p?@qr_;GX7Z(>>Db%Uj4)#supdOZk&IFre|&}cNS-Mo3T8;0SOWm)S_pFVwM)kYsDB7 zjIryBi;FD^06-}{D})%v3zH-%?%TJ|I(6#Q*Yor9pXYM9!pzLfp(u(@_`Yw2VW^BT z&mBB?(3_f?TG#LQC*nBXbmYhpv1-+-ZBZ0GX^e?o*QJ!wvj7jEAOIM6p64^hx`>z{ zqGybGLTjB@N-ZZz5)(p*5W+Z)(?vv~l*-z+9W%x{h?oh2z@?OmQ3|@(CaTry?l25b zE-fu}2_ZHi#7Yyyqzx|_VRS@9N(ixsB`{ngq5*(pY;3F`gxKF`G@1Y->^(m}-*jE~ zq?B?D5w$T!A)-RWh!8UDOT)}0DY62mqkl?HC3-R`kb{e3_S3kxwJf;xIH}cY)i{n1_xt^|D;!R)*|vRrZfOV07*qoM6N<$g29W-5C8xG literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Excel_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Excel_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..50fbb0c4e5ac271d08989e00debf55331ba9dcd6 GIT binary patch literal 974 zcmV;<12O!GP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-wNJ&INR7i=X)=6kyRTKyCU%m`A#8#715nNT=v=xgk+^Gvu zG!kuHXhqbDQW5FG33p0Saj4c+i@H$}oE9pAZFg311Q8V5f*^_zt#pVrW@?h}xVYz; zm#<&aPrPt=@7;Iq|IFu}u87d#T7z|1o!`fC7)Luf+|$ATVO)ocQ^<<^HxT!>hgb0sn#&35 z!E3k$f1^M5$7|N~Cq?qir2>&kuEx8#Tg{cNG1`eOIEioYZGzs2mFUGGe4fD9;)0s6 zrji_6a10MF*d9^QO%X8_5x+&mv55FOB6{=R)`*ykh$9iPF83}^-Xr;}Xf&Tw5wWSl zuUyxMPnGnoVlsp`l~}s?8f!6%hm~5nA^-oXl*&+IRRWv&J=k#isx(@KC-EcB!Hy*O3^(JA zRN_DieH_0iAz74(4JD{E`ChG+cptCi_sIm>h&yxdKBdp?!Ii1h32aT}RwU*O#(I=W zKaTU#)b0fS5SOM4n>E^jKa$?Uc08&i#~rD_`6-|`u@ChqE#n|AOE*-p+GXKNs9ZX$ zWZZtG|4k^@#Ll$hW!$9{{$DBlAdXh<+FNs7q*dKY538t8>3!GW1^lig(gEC#ukdub zcs#KhiM?bCYHcaip~(b(M~TM+>7KRe>RCLIe2ZF8{hHXM)XP{})vkXv(sl4Ne!}w> zI>tQ~VmgT1Qi0R%qnA?4Y7S^;S*1j;QafGvLMh<;m0B9YZnbNo-NpAhZdLA+<`TkM zh4w4%A5S6gDQW)i#n)P}b4u3iR*H1MLX|HyT!a#nS*6JLB*vmarIX?0lC*5O;iQ4@ w{m0>?zIt)J&c>~MX;s^GCPDS}zXr&E0L2@!J+WSnQ2+n{07*qoM6N<$f?wd%%m4rY literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Excel_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Excel_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..aa8539dc14c6e2e4042a4b438701bdd892a90562 GIT binary patch literal 1681 zcmV;C25$L@P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-z3rR#lR7i=XR$Yi3SrtC#*1h#NUAMaCCj@-lhcOuOZ891m z%&N04GdwPlMb1kLJwbms73>1(MLK$PO>$=4E{eLmWUTrp;7Y+opu&_WV zr7!n-y|2b`Tu3Qj8ZDmTC2Vt0|10`J|2eQUmiSo@U3gtuI-1C z4x@%)_@hpzb27`aF6aE8j^n(owRX$0e6rK&RBYR}gCO`fW9;urDN_{1=ephQVXd|5 z-&n_Sd>;T#R;$$(0K7P`O$IMZOG^uRo}cb^yDei3FvhB_R_n(b8yhcro_D@ltwx-4 z;kxd(FI>3r14LZ2ENe<@JscuLM2O?KmFM~CTCKJ)0yH-_XKSs`#BnV8ArWbse&W!f zLq7umSX*2BLl}lveBb}g>gwvv`T6;P5c2bGx9b^WMsfiF2mmIIV_}RrGdDM9?*mmT zmB+IzJK9e?A|j+|+R3u)simc*MF4=^-QDN!-o5)80D$Yd-|Kd}9~VOO21PQ0goskg zUY2D?E0xOQ`#I8D&u3XS5`w;0Ib-aHi;IifTU%SV0RU>X+86UYeA5Y;5eeN~t0Ug10E8PlaLl^2Ef%9pCrK;8p`6h}cF%G5BGO0nhU) zzVENCudlxe0C4^K^>}l0^Giypqsz<7PxsHhljpgklzPP&^O?!X$?sPxl{RDSdEfWn zC4@NrR0#lR~uO`t5&OS5CmUVN=0=2)XQe-XLE_DP^T;YNcsfrfFIxNmAx{Zo97gw&!_u#@H`y+rDSp zb`=rd+S%FphEnPumSvsG^ZbdTC=vhw&+`Z&3QBZW6U2+b3`Ysujm_B^?@N1M(H;&_VDW$EoHnwg1p66{RNwNtrv?gk` z+JX?`jaIAGK}7Sxs_9oFVT_G=o(GQO+_7!@KSGFKxUO4xp7&%N$ES97c9_;$PfScy zUDrLmwzhV01PB0Nd3pIKaU6d=j^q2ojW>e!z5)_LsBPQKbzNYL-B3zhE{fvWBuOI9 zdBiz?eRXwpe@%?+qfV!DE{dW_05}=PaSPt>^bxS3O9MoQT$%Tk767;w&iM=5=7YinzS zs63LK)a&(HS(Y#KdcC6uBq!UH(pOhjR@NWt)Q8cndc95o;6QW>0Isa8tbBC3^+EZ6 b3FLnP5|3D4CGBhJ00000NkvXXu0mjfH_Ik1 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Fl_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Fl_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..9c061cdbb2903697a6a765e2d15bf1357ee4dec8 GIT binary patch literal 832 zcmV-G1Hb%000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-vx=BPqR7i=X*3XJuRS*X7U*GOzj2#U_CT?^ixG@^VC&*4r zAgCLSAZQSM0A2V7f(Y&c;zoBGK^zbgXDQ?b6chJCf)F)kOfs2dy356>+jF|px2K~8 zXL0YT`s&ob@0?ylSW=GQX&lb)Kk+NBEn_@bV*eyw!n5gQCHJ<|*)RA3=dsfT)LRhI ztN0MlV}v^i)Ee~iAP=FBpYSohTh>v7Pw^h^;#RFcqgxvfu^*q~eT)}58sH1OuB2r= z2fRxn4|y2pa7LBNW=8oFoK_0F$Vpee$7y>yu_jVS^fJE2^$Ms_($O%N0j>9 z%+t4eJ*?sltk;hA<42`^Z>3^S>8#%?W9j4|*6H<%AR_vy*RB^M;_rxfBEP?hh#Qsd)x^4;*poRrX{Jjm*~(~+Wtz6} zWJWejoqmVyII+JUC=>ro1z1b_y^3#B_g-~?S-n}?t;9ak;Hc7)qmEOxMh`2sIf#8q z9rog{QDPq*?;!-cg$74&GF{bgvm3C-&-ITqnWqVWax@0$y9fb|M31Znl+_ z%!_KI%*$CEQu6+k66IdfB=+?IE-Q5NScfA@O^&C|jxwxU9lEvj6Z>+bP{t)3&|Tb6 zrvE1XQBqm6#XP%6%uBe|a@~3N^B%jMxH$(b(kb2dP?Ok`f!$EkEYISI`1RZI$i7dOd-ow#_9Nm z>D0CJvzhyC>RO$(#9E&i%(?i!R4%?h{I`p5O}Y5qw&3F1!CQ7`W@wjcx;m>}!?Zb@ z7*h?h%;V%aC9*}2lLkL~z{g1~`*6Z?&#eolJMV!U)$+d{kpBWru`zS-{fi|40000< KMNUMnLSTZT293S| literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Fl_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Fl_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..2cbedfc97f0ac2b7c1b266fa0c38cd00e80aeb47 GIT binary patch literal 1314 zcmV+-1>O3IP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-xoJmAMR7i=XR!xW$M-+aqx~jWpdbVa~cJ`2yhd{){u%2Wg zh^%HE(Oq}ei;zo*5RfDXuOWB}A(sR^c6N5ZF{T6nz!>X1fByXG{rmTu zd$Gq?0j;jCaw1w(N`0u5I-s?lAtDC=01;!$vRXojCqjrn5b7P9?DX_>3jn@+DWfxI&YX^- z=*L#8)kVb214Bf643I&@ZQHgBh-fLLf+R_jG%z9}oSB)Kb{yyY`uh6y9iWAU1>5ty z-SiE_=s1q^cdOM};hd{`_wMN|oocnZVB7Z3-EQ}K zqtW=cTCJW#L=FIPYKuy#a4;AgEEEdI0HDDE0E{sw27|#!mtk@@O}SSuh*+?ZEfw-S}V&M+iW|+7~_^@ zbvm8SQ?|Le*-WY4rI)Fk(y)k#LSsx|jOi1Rg0%gI^+pU|JX%)>@nmyzv&mBA8@XJL zjS0#C06cp1Xe(O}`_fwX)3t^%lFQ{7W9$Y%N~-;S|CZ-@kAol>rl7lqmaU743D(Bo1LP!8G z+uPe)T5FS)j4_6`ZBM17+E0>Xr<@t7x~_Zv+O=!fM}PnTR#sNN^?m=-?3*B>ofnxt zPJ$s8*!4|NwkM^mNGY#ey?S-$n;5y5Znt}>SS;41l(R&{0Duq?h8SRk3bL~_C?Fyx zrJOAmi}h}|dudpA1ZZPpBSFLqQpzjka#;!?@{|fpknCItkuR6aQc8J+F?L~NV`GFi zCJraHT5UN=l8a#&9^B(_@|bged2MZNeVo5nj$5@_jRU}*#w`H2xwf|U=Hu3G`M(3? Yf4s<;lnb%OSpWb407*qoM6N<$g8Qp%zyJUM literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Flash_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Flash_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..90b5432b5a39c5e29e44f1eea46ce994fb25ab26 GIT binary patch literal 865 zcmV-n1D^beP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-v+et)0R7i=X)=!MxQxpgA&wKM`raGl*bZnFa3(?YUtXL2m z)B+*cVPk=X#)6HNM52FmRgs9Om5?SRlF}6tOPh+;j)W9RRjE#?n8LMdfmwYF*Blv4i8xr?QgN1AWViDvMsP*UTT zQMMHaakw>pgSe}bZApk}rgq)^LR|}END4ONTf9+?-zt>$HFhLHC$aV<_A1d{EtQP0 zX&f@RX|Y4YwF%hfamjNz7fC?_#Hj_>~P# zvl+*PYZ{;n@B6;TsI}+>R2__$9LKPJ?FHopV-^laWu?|2+S|> z;{@}ES`X)iJGNMVsz&Ms?^WaXif~xKzqk<>hv0V;`+QGa@Ht#p5!K3>$H(}p8hb&= z_MhCyl7XyiYg~T1D-?4ISG5SP#&+Sdm#XnQai6%Ci%GUTgrp?qDV%NY=(x3cZ&oD6 z$3=|P@_k*z(_A1e`C|a}DXLPs; zNAW!V+Taw8fMyeOnf3MPFkTd?{$2cpyM)TNV9kMN8!h3_(+#@k7{l&2d-QmQs5O30DKSo2Vs000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-x?MXyIR7i=XR!wMJRTMtwzIW&S%)IyJ&7^{gP#0PY?ZQos zP%ViXLKE{-$x=blQe3reij;y_)Rk1kpG8#!p&K< z+?jcQ_su;nI#Z`qON?;Ru}*pBVnx36c%jvc#{Qa%6xW2|!L&Yc@q zuU=ice0|#{9_rFd#l>PVZy3fqv$M1F_Zao{^<|V&$Al0u+`a70K!AuK zm&POhm`}`uZ{e06G9bE|=>Mf?$u7vf8CxKtzGv?2V!*LqrK8qLeZS!*EY7m+J?B^9%q$DK!v=q1p_f(=5y4 zjIpn7-MW>wTJ;0~oGq8j1Lbnrj^h~NzvmBO7%HXI0002%?d|Q6Qtp;gMq9DbG|e;& zx5i5uo13(rY zWJLgg*=$xJ;!kbo;NakXMEoF0l7^;fGELK`(lo7aQXgBjD|)$HzTvuVg)#OR5y=iB zKt$lWZjWVIQ|Hc|yK?XAbp3F(T74ys;~F9&5hX+vZ+uLQFei?#c0nr6oHyq`VKd+X-Sn-g<$b8GEBAmWKeqoKoH!QJv+EX!hyu?2vZGSut! zOWAC8rO{|Sn$(8|zf4X}Ug=C69Uc8x2(dqo}9 zI4q?Uj^q5uIsZc`^+KAaF9ktR41z#xq3mrk;JR*)>$+!VW@bKY2lUQU)oS%*p-|`% zLW~O`-eZjMX0zFpQU*lSX3|xr0D!r!Tl73{vQnv>?2O+xu%%Kd)imvh<2c{hwyjGk z<2a555v8p=c>si3#yPhOg@Wt4?it3|k;|7a-zRBZmy@xvvDecyJsJeTo^38CE3M^Z zcC&h0u3KYcV>$qAYuy5X3)9onkG^hgwEw$6{tMq5x!tC1vw;8r002ovPDHLkV1gV4 BjV}NI literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Fw_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Fw_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..e2e77f99c604fbee9c8b7431b743531e24a24247 GIT binary patch literal 899 zcmV-}1AP36P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-v{YgYYR7i=X)=OxdRTKyC-%KY>LmF*OqaYO&RJ2xu6(9I2 zB52LVy0WfXH*Q?njT;wkRnS#7f>`Lnx>68gMKHJ(@!b|w>I)xG+o)|#GkHuG=UnH@ z_;otb1D8AB+f zbRnQdpNJmAvzWv(&LvP$Xrv<>unwQ&1-vz=p(b9&Q)uICb$`#^s`4n-<5ld(NJ)*#CF(UV_r0$-?>Mm9ydK8Cn3L_#7)o>dk zjY}7Cpp)yH@dVzk8d{GJ1%2E25He$o*&JBFQT7kWP|*fp1)9K?Yd zfP>hL(-$#RqMuCccZ#7Yt64IX^Ub(JoS8PR5_E3hOh!2-Nc2}mI+prp@_VWnn!rt% z*Uf#Ici}~GhSuR{ye3HWAU0tZzoqA6_y9lRF5HmV6D@2Ll&s79LXJPuPy^2=@L}8| z&dl+i@9*$_VvJ*3Q`BU*Cv`;*;dVTbDHux639|f}-osIG_I|>3BJJ~uy}9=s^~xN+ zNsqr5HMuX>j*GT4j4k*C-{zj3xTNZQE5R19u_mg$cn*Jxw2cTRH4=0l*Wg-whL2M3 zeo=~MV$ZcIAzxl&XcSx1iE@^%#`QRoQQe9if&{ba%nn@woy5_mXcz$PPjNTy6m*^yHQk!~M-ux)snLwpeeYb(3;r$3qE03H$xPp-jQCzrx6)*1 zsBb}w_&8I#J=3sQG1L^D;l1?up#+}AFM^?0CgwjasM=I_;|<-Wx*;R`yC>R?$o*LU zKAq8(4slkb`Z6_5wa6=YTK65WmTRIoL3EpGJX03xF1`ce;``lyyZE+L-;rp|O?ta_*n@;JFgMAq+d(!>|m_&BM`5FRnubL(BJ*|{b|Rry~J Z$nz$C{QhSUa>4)r002ovPDHLkV1h_*p-cb( literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Fw_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Fw_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..ca85a2ca4f167d6e62fa9361dc0f7b8c32c75fc1 GIT binary patch literal 1523 zcmV000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-yZAnByR7i=XR$XiqRTMt=&b>3UondBo+ZxgM7eNB4LV{ue zO#@Z3D1?^ai*J&c5MRU>jToMc(FY%RGBG5Y_@HmJ{AgP+l9t3Y#9)*nU?>VjRQj{K zv&`@PIX<{s+rl;_o@6qa+f|`3NGyQewk~4Q=i1?W?rb1poj_X?b#T^77fU zXQ!5Oo-78`+uO?!@kJrT3qpw1N~u;vv;Y7IA*o>))132*obzu9A*cHK`s6(W_4fAe z5JK#aqUgyaNwg3m(OOFYXdEDvQpP#AZQG_TEiLCc=ZE_G`c5nfs8lLZ%d$R*%=b5=&?(;NF-y0kp)J=i9y1H1QQ23-;t?mwjUKwf!1~;Y+7a zpUxNnfa|(jqbTagvaI4bPM$IL)xf~OmkSe=N~KRJr8}gQw;MnW(hI&xmSs^K#~rTg zZUulr1^}S7-WJF4>@6XL@Ot7kgpl=0smw5pOeyscrPSt}6RmZKh>|hp0szxm*AP)N z#vB0PTI(>5V`ba+HUJo8ot>R+p69I=LL_r)PXGWo=iRq&-~KpF(+U6>rfJ@EUH1z@ z2u;(pO9wbH zBVtA=tx!s(;GXHvj-A zrI$G8O8pkc@pUPsLc~n~0G4I_ zZdumYrAwF0wQJY5GRA(&<#JcAUArbJrJJRc%Mfw4?~D*qCWNE_;4EZSDwST%vh3|F z%c`bnk{}3d$8kCcA!N^EP%rtWEX<_ll$dP^L38 zGnWm+C{s$=LfunJwS-~#KoA7WYqi?_aU3h9)WhA~-7AtLxfle&_m1N{#Ta{TY;0^I zilQ?sR;;k4l;)OafZ$N)gpADv~HYgyLj6DLlL z4-F0dETw!lNs^~;-nJvh!=Xo{Dvc5w^JBp&MN-4{A-7}o?Ka(VRzFMs=r{kVwf+YNGUZ8!*BrrrIa;9M8=p)2w_U8P$?x_TU+zCZSOsH?AU*z+K64dc6}HG z!Rw7N0nO)KGmS$;1mE}DJkL9P^ytyqF){Bys#Gcmec$i%eZRfF*3?kc=hZxH0HD6_ zxBI@|SE*DE&Rv`bG(0>k2_gGD&pTW!7Cp{+3)Z6IP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-v@kvBMR7i=X);)+^RTKyC-^@<-BNL6A%@%4Y63mJzM6eJP zM2!(qK`;tI1(ASSC=y#cQ9-d-3qd0`Y9We&jg|qyN+fEMQX4Ul$YRWz&1N#s;+)I8 zoxGjQ>Ve0+dH068WlWjJEtt#yf8rF*jAPsxV|^d?;?{IBm1`H%*)RA8 zOXzI`)Ebe|V|WdFa2cx!R18`f$TTK!9B<;waUHes4xYyvR_gjgx^?3&Ch-AYL4TB^ z4i4i9QI>uK_(oD?kaPGP&#INOJ*50L_KOYPj1#HbPuu;8HCU`=^awt~az;0Stqow8 zaA8CcRj$qANqkjzG>K!PeOJ=SU-;Sjtb3x(cZ&wuNGh>sr*JpcN_#&bx@$S3nZj>) zya8k{zQ{l}l2!)1C$WzdNBazQNiCDDsoWMVerHC!J#EhCZx>rqXEkm6iG8FaO0nR| zx|jEPe2AGetnj0lo9(za*S^EAxCwU{?BxRHJEGomM%R2b9beAOX7Fl${}gwLkyydk zVoWZj{v39+#|Z^cD#`~@8i96@)GXHKef_LVfJcV*AkreL+#ty z{PuJ@JtoSwfI~Rf1k@3ob`jeevg+e{G3nESl6I!e4m_8RDm;W6@P|PowG(@}jgx|I zCN{`w5;tR)*w5Mg{}OWp%(|>yn>H8n*`a|{ zi@b{$4DJD&IVMWB1e+}4<+9Lp@O><%{H*_W@a+`i@Qe`$Ur!9;qTsP^0+go-ygc2s zSxk&|7nN}?C%1{rMqN(Y_{kW_(0l*@ N002ovPDHLkV1gkNm0SP- literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Fx_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Fx_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..d33792ad675861cecd01469062940f23cf25704e GIT binary patch literal 1462 zcmV;n1xfmeP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-yFiAu~R7i=XR!wMJRTMt=Z{C~tChyIgnV@b}Obc}*w9P`O z{jr_?B$<>3#YLe7X>ns$f=F;7)@?=5Mb&O9?wmAC$!W-^oa zd*8dq&6_lxOiGGp`R+O2cYfae?jeW>yRicY4wME52ZxkW4gdh9w7I&v`fz1srM{bZ z@-(9H@o|obZ%QeTNh$XxNm4{a4FG@;5;Dftgb;rUAr=TB^VMoKerBTa@$oZK$}67d zy&438l2QgrsTcsd0fbV@g%G-~>(nre`$C9o)oOKiS48DQu7 zq0wl(x3sjh*-F0E*|zOZQj+@9s_18_uS#Rj=JWYA0QhiQMWdsmr-LB)c5Q8~1pr70 zVU$t>9?zufFA*^SfSr;+L?p#xF|TRb#hICzA2*2(A3mHhO>?eZufHOt^eCmwG|e_+ z>;VAKEm_A(sgmb;d!&@fP6Z<(3L%VAsq~lYx~J~kxf5{!fLtzj#Phs;Qp#4^1&wq5 zXklUDd@o43Ts|tLyctDNJ06}W$f2)K*SIc14Q(bB#}Z0-F4l`TCH};w(Xyb z#iHl?{)M@@xeqi=lK{ZdPQ^)*IF92CQABi7S=lBLgb-4%*Z(Diyk(l^Sg}|4`v`TWNK0F=_NHBI|!X=%wD9UZ;o`~J}=iu|-Wm|{D;7rdA2-o1Mv0Q}nhaPs8I zwN9tA!8w0tWMpJ^W@hFtA!ONg-92#}zu)O}I{kn+A*4wN2?49I@+PxAa#ct9@qw$b2)})kftF9|! zuIs+kY&KtRG#Y!_?RFjjK-cvRDdjgQ8flpi zD)pNVJ#$j&FB>YQ0;N=Jnx?Jm`pwzd*_DZjiHURP&b_^`uuvC5e4fkYjP7uR5V{cJ z&*kOiI!&2xXS3O@3IL3;7y!WceU}h|-3mG9nqe3Zu3o)52>=j9(M2icB>;fw>FMuv zU7ycnG6o_-Hk+lC(%S$#OAxm#YgN;<`6Nklp68wLJWl`sa?UdY0|US5y1o*}@pC~C zoB{xr&1Qe%oc|q$;ZUd3c^whiRtee^)sc~r(_t8HiYjA_Gsbd=sFEb)|eix zLqr7Iwo8^}UB7kf*5)%ow*s_Utx4OqtCnRArf1ksp;O`PO#lIa+O|Dt+jh0pYE5oE ze1d3kaWN)@T(&IhdZAFTgb)U%wvFv^b=Z9t3Wb7YS=Mz*>E*@6#U~_f$K|9_sf@&N ze8uy;eY;#v{@|Qno0^)M>4*2!b*oaTZ~)lVx&;99Q&UsVzHar}|6L&e1F|R%!y07d QdH?_b07*qoM6N<$g7r+OzW@LL literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/IC_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/IC_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..717f0331a7106a525845dbc94de33da8b2b01627 GIT binary patch literal 819 zcmV-31I+x1P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-vtw}^dR7i=X)<29@RS*X7-@ETE3$94`vo>}lmal(Vhw*HZEauuI$-c)`T*k^;K!Z6M zy^Qzq99Hpn0yPeU3}hpQ_y!;1Vqc;PAL9+&$GF_z+FLp=VFS+MT};v&i%hJm^7Q=bo*2 z6_-k)4fs;XciaNIo>3meQ)Yq~2ocCknll;X`jU|ULELXjcSxwKBx!&?z}xsiD6Ga~ zndu}m9TudG?>I3JF*~CpS}G|VmhyX;Bv0TwyoTqoPxRT(S((zNiESi0eh>cAUH|g8 zC47OS_%kEkfnTwy73?4}_h5O1-9nP99VDdJR!g1*iSUJ#{fg8M3? zt+5LSlCah>g36(K6rX!^s6H-gJuafH#29KO!2>ah%1g0xs5W*QZ<)OV)^klLh?a2% z?=%Zt7vHDi;=AL&U3@#l#dp%2i*H4U;taNkI@iTt7kGIlThjN0)I4NxbFY5Q)x*|l;Y5zu4+W&e${sSt8-=I;@G+O`w002ovPDHLkV1ihde7FDr literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/IC_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/IC_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..6e38d1483739678f5bd605d5d2a5a4a976e8741f GIT binary patch literal 1350 zcmV-M1-bf(P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-xz)3_wR7i=XR!wXhMHGH-c4l_HUXQ(w!#P5NDpEL9NL4PV zaz(0&G-(oUoS-VAaB6QLR3tzMiBnHpA^~R(*!cmX7O6@&Gz!NeqQZe2D5_&STX}yx z-gz9@4NmjZR6J>=)y~ZKz4yJhZypj6oW{DPJ`h6OZZsOJry{y^=@PST`?DyD-U@=CueA=d z2=FKX$^e8Au2M=C3WcweB>8Y{ZOt4@bpHH#?)(0idwY8eK@hY7z#K<#3?WlWRm3WYCLI9)0ssX;kPy+$dc7|9i9FA{5Jl01);b)@30jtA zg<<%`>gwwIobx{r(Iz62QWi?3l2WG~s#Pg?%Dp%*7~* z4pd2gMoQ^s?}CWPb=^{}R{O0|sk|eltncjXyy7^{g6DZVh$x2-M^R*qF&6;<*yQA7 zO=~@_wT_RfFe1WSF59-fN~N+TrF^~FY_2+v^W6CO_}Mf~k%$~3+IKdKD%M($PfkwO zc(qzRlO&06j2S$ovRI)|=xeP%T3J~MXJ=>y%t(x%)sMC4g?dz^E~N*qpT%$Q+!Si9YRXjxV#`yo#< zZCTdX*w~oGIsds-D*ah37DqYfMccML#u&g8(lN%kWm%n0r}L0)Zf>@+R`1Xet|1}; z02pKXTI&}kCMGT~FE4ix@lD_NzpYlQ8;ks^`S7@$)5W*2cY;SIEwsI-%6bgkm zk|a5#SRBXs$3Yl|eJSO~3kwU~rKP2H0C+cZModjj-A6@bf^FNs*tXs2_xmqDe*AcpbIwbp5^&D%1Hg7B*YjZ*PWE~| zo&`ff2)9KUb}biUVpzk&&CD!Nh(IY- zQ%Wr^EiE0sCIA4s-R`Y&x!h1njb@#hhCmJh4?kH)XG*Eja=F~-cDuKR_a7iyUtb>} z;&r9eVzpXTLI{`gJK-41*M$&nwOUn5sYS-v_4W1j1B1%3!^zy-+{|DwxDkfo#3_f9 zUpeQuo6Y9RQFtegTXS=B8~{!=ZUMmEX0!S1000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-vrb$FWR7i=X);o-pRTKyC-+cQ5Rs@1uS(=!*zOW!9G!%xg ztcj1p@CXUo&{%0>ZDM0cSetEVAfW&%w;-TWnHW1`Ac}=1HdMj}n%!lQnV~r6%iNuv z8NQX1e7U*bz2|@Kd7oCd+trX}@EZ2!ei?t_UK8f=2Iupb!y74ND$mwa*zfor*YRW+ zP-}!nAK^>9jW!-7P|eWFhit+F^|ym(Y(GWDQGg+36Voz<1h~9cM3n?g+j}kI*F|k8UMQQ z!65s$igiqw_&2IDN})@_#9!f#NZ^{nou28Q`jv`crE|EBkE)Mh-KWVM9KI=xR*5RH8_2T|D;NY`f78jcm>3%dl_tZ000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-xw@E}nR7i=XmP=?{RT#&=^O}3_JkC5aS-32SwGtH(N_JtY zmTH}5QpANDu~H~*Y?mTksn}&V>LQ>!7cQJUtd6a;q#_-%vx+4`6ojrauN;#5m~+qh zT=d>)l4fFxA6(|nz4!co=R1%8`3NGyVdD7ljv9`Lp+Br;n zau8^4ZjK}3D_ZN9wbsXsF%yXB000m|BF0!(2yssc@e?8BMzh(B9~(3`H}|^M`l9dq z&xT=Wwbr4vHU@yS0il#~A%yF?F3o1MzX>6(Hk-}w4h1@O>J)Vx=aV1^-cd>owbp); z0ohLg69FMaR!W)iJnyS0iau<$T6QdGW@d($%jM5EH#g5JrFsBh#{tFwsg$x(EEd1* z^?L8!zI}T%lzivM#bWWJ1ky?LcXi|-X3`<6lV{!>u3oR7-UX`FY8h+oC8bo9h!I2t$8ornaR2LDTM(5Dy1Ssyi}{zG9yqvpFa@u#(AA6qnv+w(xLI}nfd)iw2rtkYNDW$fP><9or5CqnB-ID;&qSMpURju_g zt#!EH3PVJa{t`l%wf2{0v-vCM{0T&ySX^AZw!FOjwv_UVTrO8gM={AN)LI{#o}RAK zN~Lnt7*kF*<9`OFlpi^ABx9|ekD};@Mx*g{y ziiqXJRt{%+0N^+d3Bz!^*XwO6rCtSqH}2lOYX~8CIOp!}0YL`<%5;p@LGfVi69R+~ z41yps#ypuk+ZeaODIug!2#HdG#|cCP&N-u$4wCyc|yL&cX+NJc_$hCdnH`#3V z?@Fa|$8nr@mzI|Pn4O)SiR1XiIF18C2p}Q~AzUHEy>`3Z;R*S==Xq~MQS?ant+iot zs|g{*TC4BhzaIm@+4P%6qj7RL9A4Sl+OkQ92mpZRd6ZIm9U!rqTCJAJ<#OM5I-RFd zcR)mNU6`WUJNc zpWEBpuid(JYdCV}dcA%+ilQ&O-R>Y6E&>3^InNP7gta!X)`pC+JRu~LCTxru8e<}O zc%&dAl8K3llIyzXmX?;TjWSAOc6RntrPTR@j*0zFYt zU@*8`EEbzm%1K0|_`rA4Ju?#Bd!+Tw)j^nHKokj2UGob#&-3k%Ep z=^a>ZH5v^L0Ea5K0N}>L!ouU1TYKaG7Lfk}fJ?kiJ`SgH00000NkvXXu0mjfO38he literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/LR_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/LR_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..8167f2fc8360f24a54e342120bb0067a99c9dd12 GIT binary patch literal 830 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 T(_pm_00000NkvXXu0mjfy>THF literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Office2010_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Office2010_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..a50e50501b9f5ac326513420ef3cbeaadb51b814 GIT binary patch literal 762 zcmV000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-vbV)=(R7i=v*1Kv|K@Mc!^i^0W2)M z6(SaD6>WR~8=oNvc0#Z*r50j9h=QQlh^^wK(q5xP(HPC;Y>Qc&jK_F5x!{6zB`+_Y&ye*>t8Y|g~4}sAg{f+SH zjdX91^iCILSq??Yb_HN1@A>$y{)@=}LV(Xl|6;Z;&1`NFcyDmF9=U&wLlIRcb<}zt zELR#;(Z0r1wMUcwKKItcYJvU#kDxi}((3Vd;jM7G-wwIN2|)tli_JhL=|O sILWOGCv^7QdSI!DS4@=KnjVn90WGY~G^o$H@c;k-07*qoM6N<$f}x&Lwg3PC literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Office2010_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Office2010_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..657570e41ffb54e13f6ec9772dcc3dbae8aaf231 GIT binary patch literal 1224 zcmV;(1ULJMP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-xLPUx{JC@PGw0k?p6BDt9033z;!zL;2U5yiDdn$-__SKBW@iSitgL+DoV(NMbgo!y zy>rfb?=t`>9v~43Ddot>$Ox56r9Y*V531GbFGGPA78WRqqVLi){n8lIbRl~O+(9UXnMv9aM#1kKLQiX=(CKRi6VX^g1@fIkUv0+6)Ul{k)ns@LmZ zZEbD!Ln#I?$8r2^53=90KNJL@@3A+=>;u5fv9YlO0QkDlQ?a>mGO@8`*+@0`mA>@Xry5vqZ2;T1XOtaEN^W@hGss8lMG*4l)K zf;f)u*G4L=*rZ5K#d@=DjyW6fyG%03o$}Jc^<*0H|rLo8@vj6+)B{v4n_84}t&yL^KWnwm1t!Y#^fTcDsr9ex8|s^xj{3 z`SRr@W;OuuP7nN^bM7xGrOESrw%hH#tCadT3`1$H4Vl>>V$95kh*)CgHW9s#hz$T} zhJA-1=-_ZJrzccqk{SZj@QZkRgi_pn~s`D1!!W)8!!ET!Dt-rnA)UOb;D zr3ew>tm`yUN)Zt~0q7NMyWM`Kl-iL}mWsCjHp0v-r7S6>cG~Usvp%R+t923azScT| zV}*Af4gjFmIwGR`wOXy)2LS-AudhE=Nv5&jqqViQ$Ay9hZ#A3E zdvP3Bwbm2NOlJvWuQ!s`dLoYFYO~qAH>iINw7I#NA>wVV^}|Y~qKllJ1}yYa%2K6L z(OT<=M09&|bMv)9<;3A+d3kv$%d$J2PG@?^;bcb$@nCgzb^T5DP93+FmzM000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-wEJ;K`R7i=X*3E02RTKvB-%P$t(;Cw>1iR=$Txcr_BDj(+ zTLU5i@q;e>Ky;x9y74~{q@uV8g>G~ub)%x7?$lM6Qmb`i-AGb39g^CHBx5qy#W`>1 z?R1ikdf_tj-h1wI&Uwzc=iEjq#eic5_hLG~Tlg8vgB%_nV1EwBabGGK%e~E1_9MQ= zm)P0~sIiMj^LP^vU>h3=R2^ufA-7=&=kPW@9aK>h@8Tu2u~wJwk*yz|z$i}R4Rm%> zG>i}Ml%S>42Yjbd(#UCijOW#;Z1xDB#MAf_d$1pOq+BQ0rZAZX)U9l!%yMF!+{vTI zaRw`bg3m>uC-DOI=Gr;z!wKB3hoV&8NQ0iiXR%s}Qp#v4OQn>hJhxc;znYk%rIhQ`9TVBLrW=zzH7no2V*WlXQoMz4YH=9r z3B_7s9#h+x+kpZ}({Cc1?h-K@!6!-cnWXdk#2Cpbzvn7NGdO~E{WI)@h|dC+5@aJi zT*9w7n;w3I^SGFD>xn%xjKd-&w|f*+N*_wgPUDogFWYzveT6{$$!=c=(vUYEcy79zb zu1e5jq7bg=)~tO=)wML>swhoWp#MmVhw*!^O{8a4Voiwx{Y9l{6yJ#sTD67VJJk}G zbtvb>WMeu#znW(zQqhFyz(>)p5}+-b)>t0}@?a;uTgBz{_+ZjpCDgcXe8v*9&CUJj zJ-nj(4yY^b*A^Ngv$kscMO2#wynbD{PviSg@Os&QYkUVpyq~j6pF07*qoM6N<$f)~raD*ylh literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/One-Note_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/One-Note_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..6de98ea2801e2c0133e82bf2d8715bbccc5507ef GIT binary patch literal 1604 zcmV-K2D|x*P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-yzDYzuR7i=XR$Yi)R~7!&K4+hwd+zKr=gyr;ipB>+ItfIi zBFRVs!xSxnXfn4CQ3M|pEXAkRH<9>Kr1)YB79Wg1h%Z9Lnap&Cu_+xUNFD+jYNH_! zRv%2PW^(V%nR|ZsJ$w1!xzn35DN|f<;K1JN`}SIUuWv14X6(mKoH)^*o}QjH#zX)h zgy`M7cklM~>({sU<4+$()ai6=X8wZK`tw@rV^vj6F|!K*L{wOobze$(OG^0`5nWkY zS{i<2qE4stMXmJ+Aat^t4m zfQ5wx#~AZs9LEI!wr$%ZqNSCUmDkqS*I)KLZ#4*l8Dq@a%F4=X8yg!xa2%(QQZ`11 zty9N!gdE3l!OSl%EG#&?M9pUN=`72RYpv7Kg%FWHI$~LtKXM%BZ;s=<)ai6Sd+^{v zM=8~fqUiUnR;vnv0Jd$r%q*B0Lpm6Y;(-EMc@7;`$$^ZNk)BBgv_S=L)Z2rx5@F~h2=q9}@HZDx*YS$U*HBuS!$ z5YHVxeE3(hv$H>A=7UF$9PyGQ(SyO@$uvzr76ic&t@R&0&&zjqcK%RR)f2{;s(yhk zfXIFn__&p2nKJWJM~@!utgWrR4xoGT&H*UmQ>xq89AC+a$Z_m!e3VgTfMp5y!e8@6r#No##(Fc^G> zna$+n9I_`WZM z5N`sts162$w}T+KnIy@RwK||~52F?V03|c~Wm$Gd;KrD3Aw)|E@kszXs0DzTA*F2i zzJGHt7`%ZS<;$0M+k_Z@ z&;5S?Vi<-?N~!5uAjg6C7BttVAJ*wI%uGtD=`akJ`u+aJ@y!nrZEbB0iRgKy)TLId zrKFS%t__c|(Ylnf(Q37nQtFZr;`yzut%oG-vBSyY;^LQv!{G~QnjYWhaB|bO?N^tV zmscN!_o3s~;^LwWU|-`FfGf+(%O8E*+H3#s0Qn!l1U-tPv5|}b0000000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-wbxA})R7i=XmRpFHRTPGw|C`^LA!kULM!e|4$}H_*MNpzc z-I-IC1(jV@P(dJw9SEYEh>8faE+PmzT!dgzQBXz@B^|twC@T%ZGKe|UIE|+nXU4{- zi@m;??Z^MuA1&B?`?TJ7@BOWJ?Oju8(RzX9Ku@$sfggd9R-EfCjQ0cA0T%~JM~qDc z*$==+z=yzJ&46nEu%nxSM}U>UDd0o^l@7I7NGH$+>;;|y-ffkr0Gz zolrMaiQ3iOG4Y7HBLm&4o>GU@Rnga{js?jP^$YbD^(u9<`g0I{71*;x>tkRbzV}D} z$^aaW-M$n3XQFo4RVn*?qksr?t=3Fegl zWX#zJyaZfM(%5F;EK)jJ2D}O^Aql(#SV)B6fr<{s)yJ}*dyd)_^`+|etc|)@y+(ah z-CNPw0d+$?&TfFVw|dBCkvjsZUbOJi&l*k32zC;LdDJWWcDABV%vDBYy1 zqQ6427`PKy3k;9~;#c64SoHkB9;pg;P(74ofNFV9U87#0zM$?>pH(l+=4=U}mf~OE zC$H{km??^=8(N!npya?jpPR8eQdWz*gYCSmk&HEVpJ?`Gd@*w5CL*m5-B4nLDy(kCOuUj{o>L$!#96 pj@F)AJ4r{^(Eg1mxBvBk{2R0Zd=Vf%@0S1o002ovPDHLkV1i9C&IkYi literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Outlook_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Outlook_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..0d2f77d0603d635962ac31eda78b7b17967e7fa6 GIT binary patch literal 1797 zcmV+g2m1JlP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-ze@R3^R7i=XmVayY` zlMwP-gwTAYQVHKPs8lNDf*?5Uy6#@j^H>lBlye>eKz{+k7>k4uMNt&2Y1$GYe|&0c>IG30zl9Jw)o!<) z*t0$a0RV5e+fB~-q-mNh0C?tqJSr3lSxV`PtyarPrBXyy)yHeK+8+S`ipAp5APD~1 zXf*x?0Fck;Uv9NpBfjr<0RTi%R1`&#F~&g{hJ;e;nWm{Jit^cdz1{!-zyJUvBO?-H z?CXx>_=FIZ5c0b|tC=eYtpi; z?^>4SxULI~vC|_XBho$4z`($$=Xra2y`D=55jp3t#}{J{rSyqrv)Qz5+hB}+4FI6k zYF!ru;VnYQfUfIrGRD3k%kp2!INnhh zhHuB;`#jH+IOkEX*IV~}f5)LihX$@(x#9u9iX=(ND2iSY1YucGlph~HeE9v7lasp} zjmDxN2)_@4Kw*qc007|O;o)=;1iOPEpeQzsasQG8{R2k`0me9Dj79O70sxqE?lu~Y zx5F@eecQHe4M~zd1pt6CZiivm3&U{t@bGXNr&6h1Q50E>u`u=m3xcpC7Qd=#T2~MR zSy2>IlB7RhzI@pm8yg$abv>C#Bsz&i;xU8}+_`h-Y`filYI=J5M-vkh1Dx}NVHkF! zD6%Ze+J!miR-9Hi06?4pK8X;*jYi{+EX&^?8XCf;X)Xc44*&ox%X&-@gkS2q{&88B zZ=5)B;?&lyTL(Gkf6eFfI}}CviRXDAjH1YowJp5q^&$je7*gN&KT;}{o(2G@R;#}d z1mP2_tE-RJ>-E3qa=GoIC}x(ImuF^XX5O5hp8lrmx@C;<2TaraimIx=b{uDXeSN*# z4?6&Wh!C<7LOuW_`d%@{Tu~H1IyE)*Ro8WA>h=0R00533KYm!(^(QH%KU`Q?SnrF> z&d#m?zzP8TA(zW_5JJzy4;aPTHad9lU^qkdNM;`%z zBZ45f0PtbP*lMTKIWs#uySy-v%;Np%2twNj~UI*+ljvCPGb7q4;7H`SXslpmv%{>HX# zFP%;silTg`R;x8OfdBvsg~D^4PUnlR>$<9{N|Ge~D~h5wVo?MDoH0f*#u5Ms8zBgx zfOGz#_4V~_s;VXp!+7ER`SbV6#HM=WIL>!W(;VWQmmJ4gMF^RKAdK`O_X}s=IOm9S z9_YG0U>HWlw(W0k+Q>Ugd8t$q7-MH#*L~7)oL(4)Zh!8B7ytmGC~C=MQqnZ-SA>vf z&z(CLZJhML=A>9G=EE>N?YizBN+}D1fX4aoLCwhxQ52uAR;%^<>Ah>aRV)@o0C=c& n3jpS;)#`h1x87<0Zv*)sw?Axz<-_U^00000NkvXXu0mjf@B2uW literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Power-Point_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Power-Point_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..0e6cf8e2aef75291c84f90db397bb66bfbe46636 GIT binary patch literal 903 zcmV;219<$2P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-w0ZBwbR7i=X)<0-pRTKyC&+p}zq?#gx8nJ_e6bBozAVNEc zA_!_xL=mf71#xll&!AfeaS%}_7abII&`D8HK?f~r+=^l=2rf!QO-m}JF-gtuI-K*& z&F}Y;{-g&U@7??E{hmMfobS24Qi?HU4%cH(j?dsnERD0dKgR#VxC=L=lIi@nmdbv> zr}!BEYzNfa!K3@}EDm4;s|nO@=%pdMFoEyzBHkZYQG-|TIM#8#UO%+9-aLaTypE?a z*hx_zZ{mmu%b){%J1J@89=wM~RiPX{qnGe7{>+UtA~dx%J)54E%8*_fwv-sB@l=;b z_u*YEC%`UzjuWX+0u698ZtYN}8qeYpd=RsxD5Xr5QWi=nXG0J_J4{F8_E(< zCx>t_$JgR9yq!u1SlC8UD}%(=h>D-b-?qlO$+?vrw}-hKSLFAG?X$9%`{yy&$9|EL z8#`aCOl01Q@N&gy-3=0Z_F`P8 zvi3Sr0vE*D{ee4hIUW#)-WNqW63)J;o3*s6%d1w=yeMe+Ow+wgP-wJdbu}^ zTd|eNrxSCX(SGzQp0Ifj=wju`1X;$n_(f!3QyDmi*KE@!WSHI(aXqcO@wFQoao8<^ zwvF#fao$H&jjyYfPvB*j*22lJDB>7*LlUgQmxACr9pNN$2l#3~< d<&rLt{{p*6Lgu^n%)I~r002ovPDHLkV1f>Zr+@$e literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Power-Point_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Power-Point_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..0b2a165e642350d6f19d184841f128f286ce602c GIT binary patch literal 1478 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Sb_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Sb_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..519723ecf822a15b44406f18ed37b9703b40fb2b GIT binary patch literal 946 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Word_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/Word_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..c9d033bee530836972eacc7e6638afbc3c3258f8 GIT binary patch literal 1670 zcmV;126_33P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-z07*naR7i=XR!wXjR~0_z&i$Er?`7&3`{O-)$pTiQ_qP*|A4N1hJB5PuOu{00U;?vq)Td1FlGy|)0c9)OH7E`$ifFl3cV<)#qgm6@5D-)xKM#EBD3 zDfP0}`kQH*7RH!vc>~-UT*eXrfDob*$FYo}=ofjOfB(vrEB>KGM~)ofNs|0zWo6}b znx<_4U;sdf=t{tVh!`SzB65hxdoVlz_&AOS`uh6Lw_2_5EG#T+q>}ft_VxAsuq0_k zQKXep1rZ6Yb>y65Q4|%N^EKyOWUW;~h!hbC0LVFqTI*VxruPBhbbo(;69B%qj?LCT zPM$nDk!9JLG)7k}wE@Z}<22 zAKSBM&v><3{iT$02LM2trp+wN&P+~DPHZ9?8yl0}`xnzR%^#$m3=uuHu&|I{zI=Hp z2!eY;2EMD5fQ!j)>`|>?%lhG0RVy^cwb7{URhar3jpBSwQK(=isC&X#LJCFquOXR zs?NCs*4i8q0TIy{)74t1enBmdU(Lq+P*Y`T-l5!X~oSbvUIrmur z0O#Caz4yNd07#PL8(|m*-uoNQxvOPHo-xMQvOXWA#e3_VOOhnn%ZVr{*UF~Jb2mzI{&N~Ll@YyD}Z)bP^MlD>KKW=ARYl(lw2|vk5fAkE9W=&ls!xw$iQQ(cR_jg>1Z~C`-|A$HaRBgS&%cqP zDC~NZ000Of4hBIW5K+*BU9>^S7~??@wA=0W9V8-{n3(u+yWRd;p66-VdBhmwob!rO zs>L~f69AM_YL~V4eJSN$@BKf#_g+f*wzYQ681s3p^l6c}~Wde^#s2_YiRr03Iizk)kM`27uc_ zh0ateiTK&jiTs^ zG3JS)D4yJntG~OqtS36h*f>oz5IU&oePOIXRK% z`Ollp=5o1_k#im?rBEsLj+F9GK@j}gT04~I`7>JUPX$2$N~ym~DgTIw%}%HD)z#J2 z2mokcV4yz?!!s8zUc9u42ms*JsZ&2n)AUqHG z*6a0H2vMQZ@PUD~R%cnJz4usVga81flu^B2kK;K08Ds4E`T6-xLgk_2WNK<^(pvjM zx7*#nO>uIIbN000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-v#Ysd#R7i=X*1L~YRTKvB-#K%cVKN3nU7(y(dAUp~Stt_yBFj$xviH~Mbz+^yR=3a`m4tLK9 z_W`Wt-gEX@-?!G<-&%WDy*!`$={U7jYho zgMg|b8GV2wcpFRjKY<#DDg#-G30%QfI5RF$jj!=39$=yT9@Cl4Qp;}!llTUQ(H%zA z!3lgM%F<2n(k|mwtZ$L^GRUeXW3Hsd9&3Ux%y?`Jgata|DEAAZ6CoXh8FF>3zA zkD1vlZewHm*NJ_rgX?14tS^X~)Ekw3i#M~XO=l3l;|9LKLopp56yG)tz6r18HxCPpIm|bGbl&oDG$n@TuVNDH&j=fUstBn0 zT@-R&EZ)_L{TTd`I8SCW!X>dMH-ySIi}Pq$pOx0M!(&K*`9C#LY0q_md<6D4 V*ls>)1Xut7002ovPDHLkV1g17f64#= literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/adobe-acrobat_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/adobe-acrobat_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..4a38ed24ec9c97694901e0e087e1c507dbbc27dd GIT binary patch literal 1362 zcmV-Y1+DstP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-x%t=H+R7i=Xmd$HiRTRL_x$oY2bLZnuW+qY5iY|(!(jq7= zaaB@mEyOgL;y++PDB_~kl}J}bbk{D#O&9(Ff|H_)&`LuJN@y1rEW|7XsdOQo%;de7 zd2imkAIC-C#7UaO6wm6x;hf()pZ6dU!G7fU@#EtY6BCD=b9Dd!##rz1>k`KZ#%(T{V z9>LIgk%%%PvbjA000<#UN~waB^4l~`KVMi_aJzy|oH)Vj_4+qK5S$CcunPbVa{>{8 zl#(iy%Ka?MUWuY;B8Ne)CjekdsYb0<`@Y-lest%~oy}CTQEIJLyOKjXh`0&KBl3h0 ze^)A%6-4x&O3f2-VHkFTAUHQRHg;uHzX>{f_U!avFgPEE;o2}wJNPnbnil%~KHH_X zh=>q|;o4v@I6pHpGra{gH8oXm&Rq(_Foh?@-VOl(Z~!m{0INcX9soQQ)er^%6oz3+ zM3<(frV5*&N~Ll#Ns=R4>v%L>qe4WMh?>S2DijI;|90PwVQH=7BuS1`DwUI)Am`la zBuU(Eh9e?~h;z?qIqYx4KzF%UDEftH!S;m-GE|-6nQYz;h`%`5n%4ToG))lz9Aiv)p4aR3daHbSdATz^J-s4?cq2{I3=uKkYf>rod$n49 z7{~F$EXzKPloL0{~!*-IP+Y zJQNT@_)4i?o6Y7QM6_y*X+=@w06-(+aIfJoH~FWr)((isU2N zDdhtpM2Uz<2w|m^_pG&l_51x}Q4}3C#-w}ASq|OIyAYxzrF^ilv2lA7w79sKA>vh~ zl%Efpi=yaMr_(td1i{-$lJx(Bv89Iq0F_ccW9;hU;$jA{?LC^Eo&7Ql!w@da( z007RpY?p1mBZP=RDK)N?x_;xvjn9UPE$`9#`ugQst=3jbO*rRF4#E9E^6kKsQWLdW zt-Zd!etA^C1+=uZWDxO!QtEo6(NM#h?X^6IdLcxq(P${8)OE(#g{7sXEh}x;<794b zZpIjMF^=OS`#eq_aL%vI&(Hs`lfOOBt+}~54gmW)w*cVQ{QUg0pIh7I{~nP408?er U)Nhv$;{X5v07*qoM6N<$g8r|G0{{R3 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/android2_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/android2_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..dcff94d4398d380ca7618d388cda0b38bcdd0880 GIT binary patch literal 919 zcmV;I18Dq-P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-w5lKWrR7i=X*3E02RTKvB-%Q5DG(@fG2Ne-25^em1H}J`*L~Xo{m(j&ib-J}Akc9Qx4vgbHyq23A0Ij8i zk8lFll4MMA(eK!sC)j~KIETNIXen(@B*s8khEMbkUcsNW4(`MUN<4ncwOKrjD-m%qBIc{#>k;v0M9fsW&9g5e-j9eILpB!^>sX`P7>q~6*@##i zGFXg=)2VYjA`Vp~k4D6E`Tv`UxSDpg?b*cc5zR%!aw;@LixIIJ5l?S%lHup2h**n= zg$iRnG3O$p7qBB$mbCKu9{1r9+?By?8_c>;>S=$*?hhQ+ucwW~KHX6&{(w>^t<0() zlp;NrBwr^{L(&T|Zem&~*e~%d9?T7_B=+u3?q&w-X*{N+DJ{{ohW;D!p2NBe8c57i=RVciNO;mu`}_;+|E5U7~SgcSNGlPk{Am zy`9(#ZJbvsyY}m@RJzB1cX+9@SLt}&{`e1-e*!U#l5N;AEH z2k>{UPbT)I#$9J@cHP0;-7`vxPUp7+O8UYbxv8T{cFij3-bg#Kdrfs*sg>E>T}wY9 zrqcKc{D|*x6?1qDpDEe3Y_OQ8lnMMey3HxN%FvpqNE)M+d~XtCT|e+QlcaH#%61|# zyUo!W`4p#=M5qly3F@wVpH{{O>`RPVSL&WhOttG8>EJ^=kIVW++)-xKWu=pZGMnyI z3cfjEJ4rsqi`Dv;qkIf+**wa}ldy@!q~f|J_*43${G`Ep8tHO!SU(P1T~2P#ll<%! tFDJF!hNp~n-TK^MYTpu3E&uBR`42XR+2wP2`LX~2002ovPDHLkV1j_qt}Flm literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/android2_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/android2_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..fd21455d5a71526ea3487d77eb2d1020ade9b990 GIT binary patch literal 1541 zcmV+g2KxDlP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-ye@R3^R7i=XR!wLf*A+hJ{>+=XlIFd6vV*{(B7xL)l|Z`@ zsy9YB7Ba5PdmBWLt+U+Ev|KAfm{!EC&EAj}l`{SZi|tKq;l?`@Z9O-apbbeS39v)jkpE^y$+g z2!g+MI-U6_igp3OA|kKVYFkRFsN3yM5>XETfH5}2Isd%d?T#5^ssLaCfcd^(uU4yz zySux;zj^cKK`O-{YPDLuQi5zF_8kW+gm}U8ybn3&AEjw}kBFF3>Zd}8pA*q!7=~ea z-bPWh4FL1CT5Sga{`5Z)UAS=Jyw>{K&d$yrB2xK}s@1CR`~Kg1pR6qPe-b z**K0r*xTFND^q}osFYH!<2b)wTU%Q_j7bBLy^*Hr`;Q(y>Jd?lh(JV8tJP{ssY~s4 zdsP4cSZimJBpowpRDQ9ru;3R(A&CeFS%-)ugvfl~Kb~dTJt^hC z(=?q(k|YNJNRq_5t~&z&t72+u>WJ_ACyg;0_V0!#rTk)TZEb#GVc~q9=d~z`{*`5! zD1ilTV`0i<`o1dTmK1q^ZQ51Cc?AZ1!Y?qyt%ym zih=dhgd<}As<455Ds2bs5G5D@CHQYmen{vE>wR=Y3=uJX%wV4w`C&?jqU`sn z-K=&Q+JdZKPJ^?5h((Cm;^E~g4lv4G3pS4zNt)p(Y zdkFxR$H&KCBq9ic;Qe~Neuao&e0=<6BKo+~>C9`bJ7pwDL?ES9p6A`^^?IKj0IjdD zXNY*!_x(y)Nb0wdIF5CaBvcfI0RYJJyeQu#AR?o+wn>ucvhn~WQ+?mBFvhN~udinZ zKmY*kc6-J1ylcMikCstU$r?gLp_Hm$ym%1-U|0y@0|0Q&$8cYu?;sI@@B5>k=Uuyg z{rXDZ{$UT_-^w>>2TGbtDaFXh$QI{(CywJ206=bErgTP)jEp!+ zsSh~kZ!az`7K3)5IGi*Zjk!F}-;Cq000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-vl}SWFR7i=v*1e0AR}=>D-^`Bg>IOx34Fr1qV-^IHLJQLvNR`CTLQ{nlx=Msu-O-t`xX&=J>+WV& z7Z1GfzVAKfdComw_tv`It^s8YHef8@lemM2gBUjkSl@%)*c_7KtWAgPCVs&cyqpWD zHqVZ}!BK2O8_xsOGpNOp5e(rE9K%n864h}WhtNW^sy{=wYCMXi_z_3YnUAP}Gx$~s zOJ^4FxuhE>$8ZtftAw&XL-_~nR}#Ds64C9%c7L$?i8YNtJ9=DgPa4^+LBxsjkH!5sYRqchS$$9y6+Bk)#uB4W;8Z;h7S`ktj`7 z-k)Px-k<6BP7_P=Oa-qNoayLp!kPv)DkWLReO!&<*SHbG?Kr1Qh22Vmr|=aX;4b#Y z{xR-hC$CFcX6J4Ei_hcG6a1$P;bEnL4>#h$WIX6Zp&g=jJYJ5EvOb+>DE}q=t%P)3$#*Ll zlek?E8ZTnp8#kSbjp)6IZYP+x@UWMoE8d)Yiy`%3zyA@`QVy-* zkPLjj&p}cP*0Er}7On}LQj*y-cpDPII2BCHe(;@D4!%d;?%*3&n)f^N9DFZv5GRzT z9o4VA*>+f68;#A0V7zuw8RT-ZRoU5mmy^0O9Ts#ssmc;%a1L_a`dR6rS>^wTs`5@3 Z$X5;W-Yf1x`lbK?002ovPDHLkV1m1pZ|?vA literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/android_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/android_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..1ccda8f96f5ef2417d678e054b07f9f126ad2d5d GIT binary patch literal 1282 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/programs_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/programs_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..4e598a52906a13223d5694bb2bc0913fee9b1abd GIT binary patch literal 925 zcmV;O17iG%P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-w7fD1xR7i=X);ow@RTKu`@7%|XlbJ9HGZXQFA_^jkqF9I) zmeFZcEY!xt#zHF-pCE{Zs0l> z^l=zJ$65$j#PzYxR%9VsXIt?IKF(T_eEYnVNwpN*PjNYJ#ho~TZ#2Qrycs8-)$t9a zWSXFH-F7LvmJ1hb#$C8Z3iQ{(v@6!Dco|noiIc5(E9SF-xg7_yphc}LDJ<)S@J`G> zNU02Ga2dXh{dDkUSFQ#2!Jbs{H{yIj&<)ey#I_K26g$JxUVvmpCqlp$!*M$w*b7x% z*LR1xbA?qM{3c~i2I=5RDf0$FI~T&10=Nprx&_W@Jkbk(PPSaP8k!uC3b4W*cnQ1l zQ_w#X!k-PkS?q~0HN zK{p**Zq_75x1j4uF>2!vuw2!3y?_s;E8w3N(V6%vseZQMWYDc)J_P)!iP5Dk1&-sv z9LQt1&2W2}l3M?Jadtailwy`+^fa!(3&Ass*J54?jAK~JF*<}DBi!~YzKDGtRvp#E z=us*2K8yV(yizFJ3GDykazrY^TyS}Gi}j=wqp9L7x10<-qiI3Yfq8`Crg}f#my)BF ze18(Z2ha?zl^X52pt(8}IHBnt*GaXvMbT8-_t6`8Qu7Yz2NTULJ5_ih7jCw)mb$?_ z_FLzg5LUb^U3{nfzl(2PD)gO-i?3ZfD^gPImog{EEPtcG%b3gt?+&ep$~cdcnH+yLyxZ^%Kz?E+00000NkvXXu0mjf7-XYD literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/programs_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/programs_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..eee51c278c00ec30732906024990ef6c034e1c1d GIT binary patch literal 1580 zcmV+{2GjY8P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-yrb$FWR7i=XR$XWu*A@QGnS1AFXFU6(wM&%l+ve`JmtlZ6bgNmWV=B^YDMKzsyZ(%b!rlt zLZQ$Gue9r7cV=hr&OLqbtXL&-Q0RTTbMHOheBXD^xramqhZ$$ioM|3Cdh{u4Z5;rZ zx%2Sh!}ssqyVpLA{UG?-!R6UD2ifAL_7c>qTF$u9j)~Pt@Uq-Xk&SK zdGwiq78e)4X^gp^rs=7{U|@|g18eOF!1w?$v(j4ozVCCTQu&+K`i$QcZ5IR;xcLLE5hCR+w2$NX4VkC@qS@ z0Qdx2`9n5Ik~V;AwOVZlz^k8NbmhvG`N3fDR=eHq20@^sDB57=e^_fZ05G#L#>^#2 z@|DqOWJ+dxeoc}CfT^jen&)}X-MMq;9ROeen4O(+VSxMbR^9nw~Vq zbjK1fbCjm(bid#KlJEOr7>4ggQREWQ4@aZXyUc8hqIea+7p%3{nOQ`n#>~Iy^?Eg9 zOqylc$ta4R0kEb3z*;+(W!b)4QZiGX=PB296*Dstky7gKtE;Q`0pP-g3y(zPbDNu+ ze+7VZ=gw7p-WIWG%lbM@JDLopE{siDz zV@!1X_;JVgeQC8?3IH8DcFYZeKw7O$;iaI5`06^?LQ9D0CdhZ6YFTEpg zH<%ekQN+yrIuTU?6nLCo9)SA3Jeo`k0G5dUwYeQ*A*=)Xs1M-ZCs6#~gL5tQ}MMNlNsfb7+A|VlR>8Aq#M5KsFd7f9D zROay#&vUQe?;kyK!icjxoh|@z97p-S|B>T3{}mAuk*Fw&FFTI&ArWN&Y*7?n z6cJx3^L^T3zaNIyWZw@Z@A`YimSA&&P3mv(ae8W6vgiI{;+QlSZQv$8mgMiIfc68=>H0000000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-w2}wjjR7i=X)=y|$RTKvB-#n8{HU4R>qoRl?Zmj=M5OJdm z1+@^=MQOx^Er=WGqHYBD3Svszh^`C@)qopaDP1XAUAQS471NrenrLEXP8avQ z&P$wRrg-2n^WMGZ`_4W0yXV|iL>SRJxD|Wz{S3ax!YIyTBaH9Iqqsdu+BvqCWZ&Xb z9LL6XK&>5C^dw%yUFhPU1gafc8OSbNgs<@`J{*;(!s~br>sV>d-!ix9Jc$Xsg%{A< ziD(RO*qFQnQnFGpL>-j%l36(LpPE9PeW> zqif?5Ea7Z^805>4Q9MZSNfLoT2(TRvJB4QyTmLlT#2$AoKh`EU9MZ|IxJJuNgD6tk2yHjDG zBFV0z!eJ|cTW~La%RT)Ak6=8st?Y;Vz1!wJsM|=l5l|>1If##I zG0Z9bWYXrEwyf;IEFQ{lD@uuJKCAkbz9yMW%sHH|4C_kMYBwgTey)*rrWT;VNan z4{0>Mtp|2PQQ1sJUGG^PO7p{q<>bx;-|2Ev;TsotIceHB9y8i? l>l39t476cHP5WOL$a5E8mWAd;-tYhb002ovPDHLkV1oB$r>y`0 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/ps.com_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Suite/ps.com_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..102dfd39c80eeb3992a5b8e43490916293325549 GIT binary patch literal 1497 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 Ac>n+a literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/3D_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/3D_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..35d6b7603170d2e18690e746e4d0092804b17458 GIT binary patch literal 1652 zcmV-)28;QLP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-y?ny*JR7i=XmQ8G2R~5(4x$oZhF>n0de0V|@SICfP?>WB#0iXuo5 zA?>1FG!Z7_`OLgG@7<5XqBA8fcIApAz16+<|GVeibN}}s5y4L4(4j-arBZ3HF(wZH zz!+=XyLa#Q+S*!eC+qQ}K;?3o6Vanm%HvYXeOl`x5jg+=h?rQGwIPJKC4~4RBEC_n zRMf`?mCNNRDdn?K6dmaGdPYjwGsY+Y7%V`>7#BjguIsW)CUa8=@nWS?`NNJt6B856 zah&JlIDVqtZl_YpsGk9DB|v=vAw(t!0^9SvSCS<8{_^s&*%mZ9I?D6;{4ZLq)@-}o zt^q ztJSIjz-%s;+W>&?{ZB?GPMr91uh%CHXgBU+wy(?Cg=Q5h`3Hfdz4aN zjN|yz-EKGWegC~oCi5Fa1R{cd=0rp;B7RD1ef0kQ`z0x*DwRraM^W_HrAwDm4giqN zW{-8d-Tk(0>wG@{S{%neSXx?=gWaAydGhDBZJ$NNX8_>F#fukzwcT0G&CTs`9OuW4 zM&r>aiuU`ye+&SYIRJpxdOS%Ik(_sB=gyrUj*pKY zS4w3N5s8SVr>CEmQhp8qx{l-AR!aSLadGjzBS(%roy+AGI-Sml)_NQOmf6V2$goms zpE1S|(cjADvOhUFIT1zCnR>mxmx#V~;J|@B^nR=}#yIrvl2Ynur_=dbtJV5yr_*_X zG4|@{=%|17>QzZZFEPfnlycwU!-t1?p-|YHBuQRM*^Hv-SemA90zif__D(LBdlwO3 zPt){Y)6>(RH^zL%81v75g^@8PmQuEqQk^78006!)G&J-j09Z(p zM3g5YhlorRMIHcTIp^7YKL7irrKN8I0GvL3I+Ld96TM!qNJN`#1`!9BnbI^hp67kC zKh#9T4iR|(kmnC9Ajfesh-e#QWSXX*otm2ZwPjh??%uuo(zR>XzA-sDIm8(I#8yQ> zM8FtBL>v^6*Y`yO0KfpC0RXAzd2SE{ukG5k>$xBZ{@m;J9$sHxpG=bEr@MFW9wQ>1 zB*~&>Spxp+cMJe5BC>=K8Q=GNhh*g4Hd|d?tqCD+5fL)Ro;-N)pjE9_-*g=3RH0D#86rNuw6t_%e0t2HDdn3|fJh@$8ft+ft< z;1cKjg-WGzbFlMrxjdqjdam7Wk1@vnV%zppmSurbN+F^_MDl%KXssXCT7M-;l2eUF zBOMwV%KET!ZfUBBh>S72f7r$tlfwH?2J``&T)$s+)UPlD z09Y&*H<>CMOk7x4SoA#aTo{JMzIcy_Vj@ZqaqvtGvQQuX5K$wd0RRYspy+wtxdCJo z2mqkjY@Q9nuo4782>{sO_1sDHEs6y}PzuAa(rh-*J~+M!w6e0I5b;b91TPl~g+K_A z=?iQN9E=MgGKE4R2!h~c#@Lyam6gp7vYp1v%*?b>>e(oY_V2Jc`8((Q#rgU9>Q;Im y*>26u%y0nMQM&~IZ_LlnfBbgq!}0$%kpBVM6;-D4lEW(i0000KO9? literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/APP-info_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/APP-info_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..e22e99ad626e99ebf189e99d533753451fa1ae70 GIT binary patch literal 988 zcmV<210(#2P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-wR!KxbR7i=X)?18TQxpgA-*@Jl(V1bYYABwBG*QxuxWAAH zrGz1pAt6Y_i=+u5E{TX}A~K0v+6P{U7n*2@QnwHy=|cr6T0HR93N5{NI&Ei`hrNzD z)6Pu4#!7Zh&fa_d*KPmT-mQqxp$y_Y%+LS7@iVq{qTKFaeHpID1!?4jTpLScKjCAn z!{M2LTC+rSD;~oVjN?E8)e5b2WDdHp5zph@P7PIf0T19H_D!SLgT6Edhw|Hv*YGeV zW;4{r>ljwjGSL95H_pZHcqhO8xCYl{!~7_#f3`h z9!kA2>`X^Trf5b)J#LAJ(TLa@5nJ-Rwei0zBHoXPfrwZW5r-mTWkjrxh(9CZ;)qxl z5xXPekHi|P@#~0s@OXL@8A)?gIX{9&aa*SLbNq-?@HW1~R~hA)a+rFWsavX?uDbAT zrLYq@Dr~`a+?+;g2iw?>vv4K8Rw%G9F_+eW6t2{#WDb78a)qP=%IUj1*LpI#3hS|` zfzy|f)H0FSYpVo1AETM3ZiVp`p1@VOAD5@%_c*Cxtfla16dRQ8F`o0Ii9J}QNAq*B zmKH9ZsSIcQ@b)g_MtA z4{ppfuE}Wkrn3`?J#VI7*PUs23NPVYyrR@+1s3AN1Rl+FeTj3h%hCMQ#tx-`CpMz$ zOGC?*(^PkA_%$OK#y?68FTw5{O_EoMy`zoI33OV+&|X}Nrt69 zqBPwjJ4sh!Z*D8?W)m(_ib*NrLcFOo$zd!`#b*?vKACe&lDsLAj%~uWI+yEA&1>C2 z7bx60BiFl>RQBR@$CfIw{{#O-xlj5V8$MMoyXSBCF4_o5Gita!3xCBy_KGWcMi7z_aPlSi?w5q0OBN7mvD+UQ`IWGr^iya~*w?Z*8Tn z2NS#o8^kK*`Y@fLHr`N*zrCS&EUEWZO2=4@d(Cq39mYNB&0K{~(HPSisOS4rXH{ZM zd8l;qI9aTuYqrNpg&!Q}iC6&qvvH!Sy5n0000< KMNUMnLSTYIEzlbP literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/APP-info_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/APP-info_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..ef71e010709563ecfebd9615b4e9757e35af81ef GIT binary patch literal 1693 zcmV;O24eY%P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-z7fD1xR7i=XmS1Qb#~sIiGdr_8yVB0y>2#`9+0?f^)02;zC6z>i0A+S5JI|^Wz{+7A92qA zP6&BtZf;J0ZqW4f^z%xoGjSXrNYm6PrBY*z1^@&AKtw_*Wt?;2x-RuR@1LCW*XHKt z{_;ei(%07)c%F9`0IsEJ`U&UUV~icivh16!R!e)H z=a)*QH^VUe{?gLYMkv{4Y7hj!EFf!z{~iPo5q#edq?A{(EPF)=@fFu~zX1TB8e?8| z9OoI^wqLK;>xK|AQ!16}0PyqPdD?ra)oLfwG(8nXQT-7Rv~9c3_x+{Yw{O49Isc8; z`V9bZ5OD?(-!;b68Dl^4ecy?qC`{Az)a2yki7lXsi3!^n^HLN=-NG-~_D~@NbUK~i z9z1yPOcX_v?RLAK=lN2arvD1VFv#=#(%rjvZ*$JywJghtqNt0AFHKBL*c+h!{{H8Z zB-yW&iU}d$I1ZCiGAX5zQkozLsONeA>2|woN~!O(+wBHPL^eHk|g{4`}?2UxFciCu_Q@MkzJ1Gc^})h{Zp;=pk-OU);jZj|AkhoC5$mP zKFA;%hT$#G^F|3F+!zChD2y>_FI-8I7$L+l0JuTN$HxbiQu~xrX_3WTDfKa9jPBU6 z14OtJ*<>M&iRKzh<-#w&N(g4Fd;+|$MFY3h*3n$2_Zx&l`5t7jgOBH z(t&}2y?LIOi(>3uKCx~4Yf7nw%aQ*L@XC=<)Icq2ysuJK23e!ujG0DH$uq1 zJ$v>XU0q#0TB%fiz&ZaRBDS+EJCSACd!9wi9?4D{Y)wKA!F>TGcz+6 zjWJ?uZ0rT4)CZK(-S_U@`@QSBEKSq>TI(*QbPI)2$}G!jG#ZUNba{Dst!VWE{@0mv z&iT{Em^ZFmxpG!({kmmYU)EahZZ?~*UcGwt93n0a4-bzKLVys0+rw34rQn=@w7k5$ zMho)WuItiG4HgUCL$kB94r6S%7z>sVV)*3AlY%iegoyCCdFHwpriPx>p(++|lS4y2* zUtfPlYuzoPhlofjl}bqnaq9Z@>kC^z006aG?N_Z<>%};Z*M$%c0OUm&NueGApf}J6 z09aX;DWz0ad?O-)lyXo?dGXq{Ya3%?OC2?v&GY4Qc@Pn2qA02Z06wB59x_4*^!lHa zvJwQrn~g@}{N{hQ1bA_AQ4>ODgCMwAsZ^wG+isx(i|l&n>8aqHdjkUlQc8J|QaZc1 zxVU9e`OM{HYHDgyYkek;w n0)Ths=jT8Fy0zW@-v#o&{+(&Dn@!p300000NkvXXu0mjfC!#R% literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/Base_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/Base_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..b45728c57d33fa8ffba9f51582fd5ec17de76f85 GIT binary patch literal 752 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/Control-Panel1_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/Control-Panel1_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..32dfa26c6cd435bd3032ddddea2eb8ff6d8e4f28 GIT binary patch literal 849 zcmV-X1FrmuP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-v%Sl8*R7i=X)=!MxQxpgA&wKOwrc~4zwIE?55iM;Z5wVf5 zDP8!t5i2BuL?}(98;PVMh=f?of&~&mMMOn1M67j-bjlLj>VK1(>bz@l&QI_A<@d(x z^dvX$o%=iYd;Z>YZm*PLO4@>(FrWNU{DLFX93D*ZeHZS*&8cKIzpbRQL--bpI5!EX zw}wX#VlQ@J6@MpCbD)=oY{U$H!W;Np@EmsIcU*yA)5v*|>np__>QvgtanT_A z)qXGc{=#+X)tTzdKez$!<7<3{cX4eRS>vzZ_yC7RySdu=kPY!0p2hd+{+;Q~Fy-db zv+t7MBQ9y3f|E_jBzKvuU%cskZ0Q+oHW3P2u&>vMBil6UGE_F+X&Eo~&o^T_pzJW2(W|Zwa3h zMX?}U-;@B&>H=?86Rw5C7<;Hp^ElZqJX`B=(ii1^L64J~HsD^{r`L=R35J<7U00000NkvXXu0mjfqra4k literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/Control-Panel1_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/Control-Panel1_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..e8b36ef9de530319281293552cc6d3102fcd2c0a GIT binary patch literal 1407 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 YKSU`Jx%u&Lm;e9(07*qoM6N<$g5d5_r2qf` literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/Desktop_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/Desktop_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..0c25d7cc15924b9d400e1da6e906c98cf67a6390 GIT binary patch literal 1197 zcmV;e1XBBnP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-xCrLy>R7i=fmQ8HjL=?yWZ|t$x_GTRKZhD}cTU9DT0u<#I zrGly<%~y|H5S5Thx%65=PY7|OCoYxB1vs+#ASh~4qU3<0oIq5nir~Zrsow8huh(PG zaHt!$B?+6tU-HR2@8|#9H}5^tT4NMVPEJ-PCMM1*r2+t8j5QuVe*9>Ee?J`MJRJvG zUS2k})^ABE-;`3G%d)JjwYC9(hz5pX)Hvr4Ip;qR(fw+*nw}W6yu5r_N_iuSqF3TL zR#M7XDU||vdVm;XCg;3RC={6My1#JFZ&$0;??wV$x^#)zw*6_p-+!;&ZYNU8D0e`I z1<-i_&bcduupGzvaxfTtw7I#djs#6lPn$sye9>yPuC&|jIskPP;0PcSLX>>p|F&MQ zU*Fx`JxHZF{A1tuKgl5>06NU^F(LrE)oO(Ru8fb5*8tr7hogmsg}FG6@78LyCK185 z?J*+Kc=Df&;z|>dF>`S(YW`ayhVV`|A4o`o;lhW@g6nJn#E349`d@`@Zj6j^li- zl-f;_g#8i;7yJFb0szJsQ%e2#A`k!w z!|-Ru*q=mX#Br>YQWpV$O-)Tzq?G5RlyP2R8UTAyP_bAvfG5{MN*PNj&rMBDRamK1 zI-6x#kY7e1ueKKjX{`^=E2Yvb%Yq;X&N8iakhhhQ>-c0`Z374nO;KLf|Eo+QY7o%? zfQKipbdn@;adGi75nWeGeZID~c7N1>j4_pE+0ZxB06@d6*Xxgj5DmuIDW#MIAc?3X zrF^&3>Ac~2o;y1`+tFH6p8rEdM9ehJRv3nV1VNDHP}4AsMx)VqWbW!Rr4>{+r z#&MhgFc@PNfK*D^Z@1fLY}-DxBM(b!O=DwYIDPu`hrM1e)mkgdvRuyj!@a$|(9FsA z9LISlj$=qEQ^PQ3Ez8>SegAhUWpwbrswC@{v@Js@wY-EMcw z^SlSWUhj;QGU{|Xueq*UAflf*=OdLn5oJk|oJ!Mly4UMvmSwrF>ptjqyIa6eQ=Olm zpBoGYcWbp;6M!}h!!``#BxO%ZsWeT~J^+-<gwvjn0V$MHJi;_zVBCs5EJ=3O+*;w$stS#G2#1uwb^Xm8jk%8 zXlG|9C8BFWh&!cHNpQ|xo$E*oxj5%;sZ000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-vO-V#SR7i=f)<0`hQ4j_2-)=U>m_kC5RwdnBX%XOVNaVjOxpz9TRu?NC9m6er&(n27QnhmLFiv5%O0)$}MEWj> z;5LNo%as#%LpCJR{}7s`bcaQDEubGi@g6^N-mTRVYcjF_#%N0D+b5*Ei~D$t&o-~O zcD9n(8lvL&3NN+^Pd?!p_G2G*i#qDYnu)m=V-1Xpl&s+`=CLE^JB7|4tgV?=R<184 z$pm&K_IN{N$AFOWqbSw`>CIC-%9E`xg;usCviBgKi{u)>@OteBg>2Vz^kRcTiFYb0 zG(_+ht)}nkoD*Jjlh(^3=JP@}iS@l!6vY_sh**_`eLZ+m+V31&MQOaoiMqHlUgbi~ z>Q&O~=u503zpwD64Dg(gsrb*Mp4e@#pkD8}(%N1@P0_RllBDDQ-iD->SeFueO>NBL zDn=_CdLfY*R}&Mh8{bXQ_`d3`@r{bcch&}tZwY5GgY81+YH(YDmt!dR%p}H|he{`p zlYPRojUFd;QKVfxPO8?AqdI$TJrIT3(l#Ti+CM!Y{{S0<-1~nm(I5Z-002ovPDHLk FV1l000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-x2uVaiR7i=fmO*F~R~X0t-<$V#=1r2f?wa*f5V2GPDaA`j z=|Li`h-oD2q4#={p7dCXr_!@t+KXT>p1Z+R4B8svr6HFd8jzfdr4%8X-OXf}+1WQU zUk}cvQA`|7KX@?kz4!h2zW2Rv{>02EV^dR8~3`#?-6T>Q9|c z=c^}Ap6r%V?%iCiR=+JE?IM0D2(X)R9t1%fz~v)Hj%)$=dgvF!k4u*>&G!5KD?t!! zy)EQbUJwLZ{eJ(-+}zykOQ4yVnM$7L*MlHP_=PzDD$Fd3l9YP`1q=Wev98a|%v5$k zqobqe;y9ih3Bvwj2^L;<8R4VFS(z4b@aU4&Mj*gxKiaW~l{CpHeIT1Ny zV`JOKn5DsBu;Y2&u^=Jvo*p;GOr&WVODQ!G z{Y6C2<2YU;qB8&{iRgU*{jv}t1cVUQS{qwyC#I*T$7Q`mAjw&DB!-vIJA0g6mg*L5usP4s%blWCgPYPH%a$;>rocJn-U9LM=5Ns{j? zmC975QaQuSzhznWtJXSBlEgU(;5ZJSIB_Cvx7)KysZW9+_#MCp09*jI-FL*yoMoA} zv$OO3!Gi~P0o*NHs=d~1HoYv%j;Cq*EYJTdf+V6YfW&bel2W44Xnb+;;>CoSQM7s4 z4qzcfPDJBU%5~RuPdbhR011Gu>~uOC#+WXEV__Jc4#V(tnx+Sq=?!Lkyo7BWp64m0p02L0wgmtPAs%Y21rhQ8 zxwO_o2=NdoCPNs8kG0n8N-3Yq{&Ej6W@e?7ueDwe!|?GgXnA>gKtwl?%lh0f9Mcp>h*dz_WEA}t*or1M0C{{bGu%zo8g@u1RVO6QhvQ&H^!LT zLWrv?D=RMvm3_s@{QUe}nx@yHD4HxOPS&NAw-y!_7GD?dK)E$PKQ954l3M^CEi5d& gz1(`$4l5x41^j+RFg%v9#Q*>R07*qoM6N<$g4ZV;I{*Lx literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/HDD_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/HDD_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..05aadee33337bc55bf1516c77342c1aff693caaa GIT binary patch literal 648 zcmV;30(bq1P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-v0!c(cR7i=v*0D|$Q4|K?Z^02@ndVq!-^Y_!x$DzsC41C8QCAQB1^cZD5`d&V6$yX)*O@g$SX%)RIT?>+ZF z=bl=g=PKGfE?_pkckvxNRh+X5Y3}!UR5J6>qB&)$tsU(857^e%IWxa|2U&fyZbMBFgX*ccrkjdw}<|JQg{NH+ZNN z%6ix2XIPOAco-5fw;jGKfz=r-?dTR>V=q=W3`yAv-x=J)Mww^|TatVa#vmz^H6;08 zN2>_klBBMaAQ2b`fw@HIjFt_5CRNDVfi06Veo@MkA~(84GK?KbX)zg?iXGvYDprP)}@vaNos+$8ra9ewSjfal^jMP5g6-%iQX6AE9v6000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-wo=HSOR7i=fmceTqM-;}tnVpfeLYno;R*R248G{Rj1|xbg zirZjtZKV7M%_;Ph+*(R5Ej=fvUIJiT>e&T{ixULeI7-T)mlf^ zS_5FTfpN}-lroh{rFc4>{#Q!*tWv4`H5F)MV}mD?$zQ`T{4NNBzSg=otblze0SyyK zDbq@+gzLJ$$8r4A?(VL=7PPjuCVb!j?fm@weh>sL0QNe-H9)SE%6XpmXRFoves6DY ze3at-pFPj}We7PP=AQ}zj4QT55S#+IKQ}jb2H?k0oR2=Xx3@Q=D0&bC!P%^ktGplx z&Y~!Ku(h?dc?nc378BOm$3YOpc-QQkK*lft6a+y`M30NbVqy%+WHNWdFkI1E_onU1 zL=t06YuyXOa3zz;+#Q3gwfDj>v_!;+2p?&&Fbu7=_8tI;LZPsrlv*~%MCo*z0T9NR zn^wgD7{_rmV@&q@{YY!QTqqP4L@t+GilWE|z_Z!xTOq{TIF3O?{Qt6E5i!PyF_y_@ zv$>0li%_K= zbCOch`ue)(IF63vc&3UR$Dzf=#lc`ONLp)K$z+mo&d0BTV2rf^M2s<|wf>AT_H!J^ z4raXKgTVmD$HzoO)a`aViA3Vd;RTKWv_-4cI#Nott+k)D+wCs^+_Bb9&N^A6UReNE z2+?l0+ef_FY@SLf4}}mZV@zzV?E$#W3W+E(#>7GhS4w%wU)9Q>9cA!?)@- z8~{uymE@d1t=H@QF$e%^wc1P9bzdl@=7&Yy1V%&zrPRFZx-WKic3zGGmu98Y={)f~ zucDO76A_=~80nq3QY!CxUZvCNJb6EU3Djsb3}ft}QtEjwms6vjO#+VMQp$8Lms3iq z=bZD0jYi{=QMuNfluD&7W6YyoueUO#IXMtQJgZi#wGZW+XtzqGk^nH3-2(8sTCL7* ex32282J%11c}WC4hSt#l0000iSv8_ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/HW_info_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/HW_info_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..13caf5ea6159186ec3aedd4550d4a86b041a72f6 GIT binary patch literal 1016 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 ft-HtnDT%= literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/LOCK_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/LOCK_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..7ff44d4f533fdc3e473c9fbbc07d2496fc35a5a8 GIT binary patch literal 840 zcmV-O1GoH%P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-v!bwCyR7i=X*1L;eRS*a8&%OKG#LXH*i2FyF_-KSwVkKxG z7%L+P(Lxce6vf6`5J9UnHi|*SN=1l9YX+GxMFtnKLs@L>Ng+xC;mJ`!des;uzt{i2WmY7FV)5xejXUc%-qMH9S>$Ca>b zCU~R)doZ88|KQpH&jEadr&XcspV6B*jz207LJ3cUZ}3C@y9W;>##-)gD#>vim+<1$ z_lRyi8WGncVkIJ$tLNp2_%$LPs(8C~I3mtQ#A;7wC9#fmyj|#a;cF#*JL@`+CQ4#_ zhga}qhUingmNH){3DKQPipXp^p#LKz&enedD z$u1}6(TLEd1xNIq?s6z*QX1y$k7OpEeWQM7i;Y5~K@Rmx_znoA2{j zs6ZB!B#}IOaHR@)lbDCFG{He7B{wRNCS(3OzRZ6g;H+}DI>o=``zfs8x%8|vbR)43 zPOx7oD|P6a1o}`ZG4O4!A^IM_<9X97Au)Gj|4>|Ox_z7dn)c4xY_X~w?vT=c$(cn% zylrBywm7Gho4Fl;j-|Q8KG!NG;}<21`W1F`v)V#-A+axZ;W}+NbZZ0uwxYEGWo=^r zS5(g^{iG{Flr(+@%cd23D_U35xUS@jiFt-w+r%*?omVT%?nq;{3t^+&nZJ^^QLfDs z_@u80-o^{2bHGlrPG!&%PO93(P~&?~X?&MVLorrKi#wIZ_mryf^%GznC(@dIN}Quw zL*U(7Oqr93am%1GW;nT5@od&`(&8sO98PMQ$0Np#Tc0a)#2{^_sHXolK>iED?s?!U Sy%WR$0000pLLP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-xnMp)JR7i=XR!xW;MHGJTRo8U)Os8h2XBGtUnk5)7D$C*} zY;Z#`yPKH=1o5IlA$ZUnL=efvA3S);$xA@bia4_~u7pIgOhB^6V*+8liegC5&(2PF zPfzt!dD!lCcidSfONd15pg6}8qT001IJjIkEy{2}N37eu^OtybeF7OGS#%TmfK zK@hw!7z~t@a-fuo0U#wH5gD9w%d#xWX0!J>=hv#$>Q7S%ojrS&Ow;@#48ym3z1~nt z8Kkxo4yyqGIOka*M8>x5Z=)#sTnVq44$g_V$Hduh#|ug@~xN)`&=k zVc3Ys6P}FYIM7<}*#H0uA>4dE|6{w|e(%nmJA0ut_N(Ue`Ogv&4-wOYXwJFmI1Xkq znP0Wm_qEoFh@O{HzS8ga*>E@v6MNO`^*jK$Ff%jL0)UVI=h5ow>bb#S@J*}L>LQ}v zFXFmxJCn(LSgX}G_8;ux#fvWwhr?^FR_nPaibC8~(^_jR7K<~cXu zsD!6E=h;%J^oQ^JuWf8>3<&_hah%g(7@iyx0mCpX#@O$P$QwZreCm1Lv!3TY$-DM6cv}G|k%y^ZQ&bcV8(rOoTZA{E3LLyuAEfHkq1gi_P<~t@k>|LM< zM9^9TV=OmmeH^A~I!CP&B6bilg2PM9q_T4u4&^6%cc|TNZ!yL?L}VOd_*5VwgE7|W zbUItKxw+{jrQXtG6*j%pX)tb^JX(u${%~`1)1yTBrfu6aMugF56u^{_Qu^a!wrvv; z-2_OAYQNvVoy+AO_`ZKUZ3|LL$ryWUX=&+ir4&C(got7QaN{`Ei8GpWp0#cJLBHSM zeI9AFR#sNdMNza@R1pyvW5*CNy}L-FAE+l1EoNwN;owj_io2_dept*z~~i39i2?RKx`^ZBX}VpeNS0H6^OrumYPkq}}w zpU+pj-R{)`;obk!Y&K&=yex#c?z*nvoM)3zOw7J?opYXbT~`Ppt`pJaX0v%98Wty{tGPi Vpbg}MXHEbB002ovPDHLkV1gYhYu*3= literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/SW-info_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/SW-info_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..31c57000b7a7e2d2238bd4e4e291a66003c12525 GIT binary patch literal 884 zcmV-)1B?8LP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-v?ny*JR7i=X);oxtRTKyC-^|Wt-5t?{bs|^@BKSxo;)7VI zXs2$W5d>5DXl$&ahG=1}BAP}KZH$$~LJQ4mu(Oa@iK6j=ji>>$=Fud(nXF!mbH3#6 z=j>#H2QJ)?^PR{2pZ`7Qc1kHGlmTwUe10Fp4_KPSxHo}*0r%sk3^J3tGa2kVe1=7= zuIH#T=0p!;4{pZaSV>2XK_?Tr1XK71ui&Fe19kB_p285P(|Ko|gc{u(HsBpRgMY>a z>fv2HioeouZk+&aSr%|!f&F+=1!cQNuVN>T3P`@jdt*)`b*pK2ry$49Omx?|ze*|1 zdZ?7LTuM1oO8F!AFID;rt=*-RvuS%I?RPZ#=0qFtd>*~QykI)@Z{d!FrIT0OkC_;Rgw!b>Hu34mT^UIOJA_-E<7%}#IJY}m*GJA--bThAK&6Z6?uAsX=en3#+|C&tA@B%)Z`6ux|8XAub}x#`aaRaVbO&*j|kK_?_;BY zVO2mig;`PC9&W|$xF&5*i~D&DhkK%Be4jrKtz}*V?aR1MT*N^pbUYI{gfCNn3;wJU zoK4?L&4pbQ6m3fr^gynwL|vw_FJYA+>w@(bdr3^4pR#H_iC6y_GjR8gKyL*pTcX_j`B&Q9_7z! zwX{hdC)@HA;~pnn(G4!@aZ<~)VAmwitxp9}M#_Z()$+d{kpBX|4>7sdOx)D~0000< KMNUMnLSTZcVwYq9 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/SW-info_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/SW-info_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..d9b30606a4cee1ed7361cbb12a69e5e6a25f9796 GIT binary patch literal 1472 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 AnE(I) literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/apps4_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/apps4_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..3120915c8bf3fa32e028d2088eeb88746f2a0666 GIT binary patch literal 1295 zcmV+q1@QWbP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-xiAh93R7i=XRy}MKR}lW@y?wX0=kuQL$B7h)Dh0Acnn*$J zEF%XFfx+i4Wr!l76cLn3M1`UhX{eAQOQfO3h6@;Qgk_{iC)yw(nkb5t%J%)NFT1yX zyKgA&_PASYV#IX2^Jc#JX6DTsVrCpgPM$njnVz0LZj31cfDod!y}kYN*|TRmN3o~3 z0o7_Xi5vlv2MF(Z=fPYV^)PwOZ}G*7}O?`=9iB zJ)^bm8Dk;c;Bo>TgE^s#dGQw(TE-Ao$YrynU^;KVU!y zIpBc!^4LU&7nYZb8}X)SiITkbe28OYcjJ*0}v4o$^tVp5ee6I zONBz=PP5tk=IPU?!&F+MhYN+m^#RDXQYt5<%qD&S5CGO%dqgBG%bHB-5Jk~{p66`? zSe}}i+6D048;mYoxNxr5>)qPf*=c7o8QXQ;KWy9H)LLf-Obh^Le}Dfg0G@5zx4AC_ z0G4HGt#z&4ZqGzfv|lclr)=B4RIk_X4;jtR&u1nkCa!v(7Xn}@rNhkY^?LnwIz`oL zbvcgXe;zz|a5Jr2SXlT-O8KeQI`lj*tW+vj=jZ1)Ha9o-1pwsp`BOmzUcv*@`HYO2^|kE)Fi^s8KQj zkl-IXcFbmGi-=V6kNN@t$Ye5VG*)9w6vuI~SS%i=YPEVk48!Z4PA8Wf5<<}ASRw?zO(P-=>`F-p-PTKK%Gjbe92q7L1 zBj|R!PaMa2u9V7+uzKSj0sZbeZn z`F#Fw01ab|LO)f8h$J&F0FXqqVT{p4B+&0j4dAnGxBGDvMNzq2p2}vkm+sxWcYh2B z04`p<_><>(UwfXnEv2-D5V>?Z;yB&|04e1p#)XVAK^(_D*L9~|*Il`L_wMkS80)ll zyM3)#ELH$4d!Dx&$8j5}!Y66dT6-xV1|VG5{h&}N+-bF1*G83N4Y0Mf6%o;8*L7D) zrIM?ZN*M9zC`tea-wc42Qn^y8(H102^y-Ywx~prR9AW$X9;bX(LJA53~RP002ovPDHLk FV1hRtR15$B literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/apps9_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/apps9_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..845c3dfec10243e11dfda6846f920503134919b4 GIT binary patch literal 1007 zcmV000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-wX-PyuR7i=XmQQF^R}jX3_a!fhiTWB7Ef)WPb)h0nTik?p zQH0v6h!F)9Dk?&YbRq4gbWteME{f2uic%;QN|7vDtBd*vHzFu56#SERq1%MQON<($ zM)Ul-nD6?I7kxbGfy=$;o|$jv%zQKFWRhrd%mtPMJ)VyN{{Yoylv|rvUk7{$thAAK zuT9z5b>JlM7cl)Ipsc};HUVD%eLxL(XrNpnvm+fq3vdPa4mjGZp%U;t@G1Ro+ zBz+}mG|_(`X&}eXjkHO+AnCTGVM$dl=<^sRl+sAq8{C>rWo&s+9yT?FdHrVam<^@c$>oUxrs=46Fg}IlQL{a`ad(4`0dHFWr{rd){uHsxgL*xgqTgr-<{U%bq;3ck{jen#0hOc--q8bbCJA zq0PhIWz19X>@hI_93jXdqBw5=XNklwb`JlrBU^0zCQ(bPfj6m>p&Qr^{8=;v@B{EE z^?N{vcQ$E&7J|YVaF<}`49h$uNCR=d_!0Ol2Y%kccbG`-s68*9sxKNMLfK0YV;2n$ zzG+~my{S;oS$e`2!PA^nthOw@y$m_?I@6 dj{kLm{14K;LlNti;i3Ql002ovPDHLkV1mcixDo&W literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/apps9_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/apps9_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..9b78feb2c0025ee2a9df51e612cc8e4bc48c2664 GIT binary patch literal 1736 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 YFUgSb2O^VgJpcdz07*qoM6N<$f-`i1CjbBd literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/back_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/back_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..e138d73ac1000d1ef4d9230b347574055602fe5e GIT binary patch literal 1412 zcmV-~1$+95P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-x{z*hZR7i=XmQQFLRUF5Ezn6KLKf8ImGueO$f?f=TdTrBF zX-P|xCSkUv6$KBiASI`QCy^ek*sDE=3YGRCC|Hu+CMJZow4`_ly$H2fs$N7rbvL`& z&d$F#^L`$jt-G5|iTH!Z!0)~Je&+Y)y)Qo`BG^kDIB=jeHa0e{l(GQ;7-Nm6PoF+{ z@ZdphFYn`vK;?2-Bcfwc%1J5ZzBEloiAVrlzKtuIrx!L2$O! zYQ<7YKdS%-2~Z}$Ik$um!=`CokD}HP8N&BIskmI zqoVow`4eFnUaQyZO+=)A2!5N=Za)Kyf%aI$G3q{oKmR%Ib5_kt0Wj zbGh7FtyX(oO6hlP7ZDMdrYQ=A!fycZ84-nyF;6LVY(6X$zS65fRTU%RO=A3h-)QKcXD676F5D}%6 zeh>uv^ZEQy000I6pp-fu1VQ&HAtFK{#Hiyqcj7pH^Tv%Ee*yrwuDjrQ-t~IDo=cJ> zAtEFq=pLO2f1uIrbUmX^Nk7Fl0ke+U2%cc}Np^z`&=nx?%A04mee0l@A*nvkYxN<I5mgw55h706w*AVfQ>V@?E-wBK08lEG#?PEN z^U=)A%y1mX0b^{(-XUVDl(OPDR{y3j0)Pe{Jb17qg!sDAXp9q)gs!_&EEfOboWED8 zRDJ{ia9#IUk|bX=n@uMSLyxhZ0y|)(lnOG+ux;B-w~9+dmtIp`~f+E2Vs;RFFM=rBn!+5pd28&iUib&CMDE z0AP&WGEKAl^AHg+j^lQ{Ue|*l_^MnkzXbrWxVZRhyWMt$5I+nL59>sS*j1dtVbRTvL`X`tWVysXo zRGQ7^#qRkY(8k6_f{5pZ5LX??5u9@?6WA5lndh8aj^hX+#8t-F`HhW@o->W}~1K>iKU!wa{c Sh#lSl0000000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-v_en%SR7i=X);)|>RS*a8-@Ci8;4axExQQPLok77sX<=bu zq0*?8iG?4HF)o}FU-FdoLe>0~a~Hq+UU_zI_R zV-!$lOhk|4C=Q{AjeNES9n4@yKEKD?_-tB74c^6b=;CUA-#KL8W);Oew&NIHMt_{6 zSscd`3N8HvT*3!9nGy7`h!rJw>y`68_!Q5osf>tPS0dtiL|jPyEh1JU;(SEhKd@Is zoQQ~DBVw(xxsVtu_1@a((TG@&h>N-TVmf&~BIY9Ewuo4Yh=qvQ6%mUOac4vvjEHa2 zS#7%>5s$U_Ep^-RwNk!UGtt}d3!cQTr0b+o6fNI7@D%RDo4DK(l{q_y2heSD;UT5E zS|{?^OMM+b<6GQ~+f(;ut_CZrlURomTkGhsfhwsCHgOk@;1&Fyd%LMo;S5SYu{BE7 z98fB!Gs569UR0{`{fuIgbQ1FbmK*F>O0qY`poazJhx`aXDfyYyzj}$izrk*$tqh~C zcJ>z@#2pHSvqn?aNUo8hae10a?6ZwBPtGV!b5e5uRQljPyk=`;43kLAGgxiuI%PO@ zQEA5(Rd3(~zEi4k)B&5s{s;WDGEe3QjQaV$sN`fxq2m!etx(wR8$95AVxDGe!giH^ zQ$00000NkvXXu0mjfm9e1z literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/bat1_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/bat1_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..2e53d9d2c0ba01a2368a15dc1d4ce9610a6f705b GIT binary patch literal 1486 zcmV;<1u^=GP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-yNJ&INR7i=XR!xW;#})owRo8TPO>fW4&PXV%Z;m8{lv6;g z5JbpPjM!+UoxLQ-BqSsx7o7q@7~6y;ArS0S5-`{%kek>YY2&c6jR)zHjYL2YfukHk zFbD;-Gp*^K>A&i(%0WHydbKO9$%DQ$@2jug`|ACWF$VjwlP6Dh4jedeRBPP=0LEDG z=+UG5w{PFx+7F(dN7U_hEo02Llv3xEQpd`&Y#U>203f1_b3PD4d@6+an20`FTU#r> zG*P$Py`Yr39LMq3(lph1o~K&t5`YFk0EjWhYqgr=I1ZCi{zC}y_S)LopZ7&{{``4n z+xAM5B;OCiFjq>&L06G(R#1f`}=nPg@uLh5Yac% zG!wsQ04%|Fe}%{4on zPU^aD!8xZmj@fWH^ycQ~W^LR4?O-rCQWQl##kSk+rfu6lSYKcN;3?7BvuA7ddi^h3 zTU$peO^Ap@v)TOY;lqbNJbd`@OdQ8Wy1=PoF;h zvj-0zyy1D?77=N!bq+vHU*JwG03=DGwbri!0Gpqm?iqzQbl`XOEU;+0t6?TGgC$(pnee@wk5Q;K4WV-o5*t zl=9y~2;01XO>140W!Y-AT1S~Nrd73-JwZeSrPP=)cINo;<6qHQzb>V;0I(Nund$-=w73sc=5m7)y8J_g7JtNBVJSofao2O2ldI`W`08IdT z7g={eDFYC&;c$4La~?3ptmk;6(y7yKw|{>9`t=nl<$pNmw$^&j+%d*1&Up|7!F{&5 zxw%!fdgn#rCP@j)t}-Q3*VViog;uIuimm)Z7_ zF~&qu1k18szj5QnRVn4)q?Gl&F6g>0V~l+WRE0Jkk3Vr;_nr_!PC-Nj&bd)a8P2(H z+jhfooCW}16vc(b#l`RDdA=fq0G`aKozY0wb?=SG<4=I9d-wbOd~tE{E#LRw9SjCZ zMW!vw@_pZj<2ZjX#vB4r0x+C&yH=~ot5>gn3;+uY3vc4{@-P6%_kEi&_Ex{&&w(BD z=+dQ2zY4?fN7FGOrF4DY--zS*{qcAVBAT`=13-A5$LjU^%Sx%sK@iy01cvYX9pCrg zxpwW^(=qXdm-hJa0v5j+3%17Z_s~Y}~OrtA02I5M#^|LQI#FdzNLr-Rt$%cRTO7>(lT2IdcEG4U$=JJ|GPl`53?ckbH-^WYybcN07*qoM6N<$g7E#{TmS$7 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/expand2_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/expand2_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..cb84ce74bd7438cd6f04fd223c83ccdc02d74b94 GIT binary patch literal 986 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/expand3_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/expand3_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..c6332c2ed5fa7eb77c8d8c8b2f6311a1c2f6d4a6 GIT binary patch literal 986 zcmV<0110>4P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-wR7pfZR7i=X);o+m%kUD$w280pGSlIG&(@jrN6Bgv&Q;0i7l;U#?6{7oboN^&5{nIywW&L`PXd;Moc zl3$aIB-xl`L6U(atCJi`a<0zypEHFyltiyASf#ORq^yYv8p9pfhr7z-_izN?;7_c? zK`iKaG*XzWa7ED?lUUMOcjGU-Tkk_!l83bV`VmiS9VMf92rm@qn`PxYW#tzocUfcI zVr;Gb;R@kcJxj2Buq>H1DRdX`M14C`@0-iYt@Zn9?T=~sc(nfij>pQ_@xop-Rj-?i zkF1D7m>N!aZ1? zpREY>zxN9JbPq?%+8G@K#}?JSvxVVbEAbR$u;xnW4!L#d%(O3*D?H|)zwn%4za9q zcDW8_c0#`LaR`&^x;n^M$Ww{(I0ALN(%Zf4W@QUCw|07*qo IM6N<$f>;95ssI20 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/expand3_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/expand3_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..3f5a095d3402adfc74ec962b64a32e7ae5193271 GIT binary patch literal 1709 zcmV;e22%NnP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-zCrLy>R7i=XR!wLf*A+hZ&fNKXqZ!SNWMf>4TS#pOcN1Ep zwhLD#KfZRAU!`?2YPn(IP?c zB6Uq^B3F8E-W$!Ezx#8#nJ1o{9~64G!}-2B-#Onohae*C=bb!xa%6OL^r%uQ005wr z##>ukcW&Rly}h4!@>xVPGc!6OKE^qJlyiPuN*N)d2>?I{DK$-NF~;6!jQyDqa$|me zUVLt%nVFgIaL!-Ovh1rxQ7F!Np_CE;&<`M#Qk^koS(Zf|$605LU7DYt|Kq-hCMG7R zX_|9+oI}#y0bmWl7;`+&Gi=-bZCRGDT)TEneJatZQ>XMG2!7q|c4w0$ zX(OU~kbn>Z{g}Z|H6ispFZ6xC*>1O=zj^cKu9W&9i0}Ka*CbnvF-y}lXHY7oR4#mO1{l57LO?C|h#3jlunv5cmsrk*T{;_X(e)nSYop66{?mUT-A z!2kd#r8{L=eyysi)23-Q4a4XPA-+*n)x%kqRh;vppCKZWD2j$n)4Z^>wDcYT00jUT zA0IcAQWujXDG?C~A+`|WAB&5NZ!Rw{&n+)6&jG*+A><)M)CnPf4}##$m6espeBb{; z6h;5GZQC0t1J+m<$H&KwT_V?YPv?1lf^(h`LI@(FQp)H@oj-s6pkWyArfK@cEX(3N z&tKWx-2BVL#Kb$Aru|0<@r3XDf3+-Y2oZr0LOADHp64fA*FC*Uq?CF*&+|Q9(tqd9 zo%`~wTetoT0Iv@X4FMsAG(8J2B65rIdOc z0Dz8-jg4^5kJlQLem4<9k~3${JR+sMF*Y{#TC>^wz3aL^3d7LUG)+fDSrkRL)oO9h z`L7(u@ik5Rxoz7{jX^l)1?T+u*x1+z4a4xLlrpHz*e_%1^^(Xtaf&G98J?MuCK5E$uNu$2_br|l#o&eK@c3Jh#1sk z1^d}3rOK+RzM1Fw7dYoxr_+g(Bza+WcJ?RDX0zF7G+qjVK-V-)BZNR%mc6Q~zK)0r z06w6U8nt>@V+ZuXnjj*WrfD07@s{H_zq2f>0RY(TcH7-<_l4Qn*|}!3dBrr%i;m-% zwMCRt%5`10p_J+Yz{jSDP6&w!AteAb2Fz&*AvP$bn}%ULQxpZ%WGw)Ac5-r33LzXJ zgsfH2G)?Q=zkfeDeE6_mXVx!O2>>x|x7&9#O^Yd|yHi34p)AY#_Pu-e)-B8WXi$o7 zw;Q+H?F-#*_q#<=l!%D7ZM(XzuO2#dsDX$NAz}ppKq=KVO^f3=zC+j6*0$?WZ`Ec6 zAw*9~`9u^&4PDnS`My6402C1c5uqrGURjp8QVLAdYz2my>FQO>&P1E!UAx15g*=RJP zD2iH!VLW~C;K5NL#EV&$rF|URwkf6b`mSNqG+nW6dxJ6N^s~zIJW11ZYI=HlZed~J z4d3^t!Z5rZ1i{wu@NgQ2;Rj(DzJ-Y2qLdb#^FMSt9j9*-#+YN<_C}hfD*yvSb#ij@ z$+9fpZnat+LdfpK9vT|*UDv(M82j1XyLbPll(K{nc2N}Zv17*?jIpQ6vV5`A={QwY zW%U{%Q4|eZmUUrqaq+!9L;wJ1&z}8hk|aM&l4N^e5`$qF4coSvo6sv6Dnd`C(t`n$^Wyb;gyE?>QRb$3nd*+-pD=hYwxMgU+oNs<--C_)ISs;XC2 z6`_=vF^Dc*B==Ez>8v+oK zODTI&%2X+p*WCsEnuKBKd7gKfQu^HL>gt|DFMc7A;imBmYvw=ak8Q7`lW@1 zg{4oz`^(g literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/help_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/help_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..504891275c2f71cfc92bca39a8eba082d31c1c28 GIT binary patch literal 856 zcmV-e1E>6nP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-v(n&-?R7i=X*3XNTWfTYS&%JX;i<^~>2JTu!)=?wuNMUh6%;0qj9xw740K86EIfNLdD0Zpett?Ikn_fqyiVhugf9(<1Z6t0y_ z;eK4jmE6zZUR+aRSo62A9tZJFt!NE?QquQELufkRKg5^#J-HvW0QJ`t*uo2Hr%o@!=~_azTby8^Z6*AtN3QEEdEwvZo{Sywkm;L z8e-8krJfEdaomu~FXGz@@G+(4nzWSITRTd2tTo(qOL#b~?d9{7;=&8b^DcIzQB9BZ z5_|n>y{?6Sa&?p<-j6vvh!5}*uCIclt<=qemBrhnuF^Q?a{n<7HK2grkh>x1iIBy{xJ3#b;JF)mqVC z_)3|!PbE`@iVGJE24a(k(ru38t^SW;gYSe=D}TDX!M9Nv ze6JZZ_!jYMTJwNG%<2Kx1n;kI${bIOWfzr6E+;#bla0Hav~k9NyqwfDjTcOI-TGc> iRYPetMK%4e3*^7Qy)SrU?Z7Jl0000000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-x*hxe|R7i=XR?lx6MHGHBvtxU`&f06c962CCR45V`N-nfY zg{z9xiQQf}z@e3ps!Em05usi{s2n)-LJw4eKLE*g6556YwMq_ER4zqCs#*zw#HCUk zd$V5eui2T$W!>6N98&RayEE_m=9_uH2qMB^?D+BH`<002s9cYAyL$-{>a z+lTQd2NBilbqx_KLWmE95J#nyB}7aE01!e##@G(${4wYJS3<~Iv)PPany6l{pA|w} z^*rzGAPAHYB2Y@j05EVMlv0gzp2=h~G@H%-!8yOtY&L&B6w#S8XJ|T|{@VBb3y$MN zLI^KWK=uQ`1b}m%HBB?6>-vvj7=E#`vZ5vuojiF`vn=c8?(Xh6$8kCUpe7MaAf%>g z7W4UhqtoeJ-q_f9ewEtr=6pW?RYKBE@X06+FhU4RzGZTdfnWjv%5j`F0Guln3OfMs z`5r~{^Ye2-5d5&SvttuNa6p2HNGWByu1|5!dz8{HA~L0v6-ALA1c8f)a!5HMA}N(h zg>*W7ad~<9_H&}y+1Zp~7Tl~U?7005ntnJEh) zjtU`y@d)FbQvi4X0C3{O2_uf<%iG)AhU>c1nx>r^I@B{l$Vgx%ssbUz(V3ZZ1l+v;+ zYg$7@D=8~`N<YIMQzu>yA`(JrY2_aoVNC+>Ib6?|} zX9*#zckkYPmi+q8ah#8A+wLKvn&3|o?5@`7be@=|*`<`ef{0=g5h6-N%$+}f{(ax~ zi%}H4)9dxx!^yoz1*IBetlRB&pU} zB1w`q!#RJvxw+Y<3G=G1>+}FMkWQzk2q8BcjmB&c1od<}-KCTs_{O@fQ%dP7000F5 za9#JFuIpQz^XvhtC}Zqz0D#ri)u)WH{=k2NnyjwtTdwQg0~ji*)oOJv48uJ|bzqD! zme1#RQ>oOVQtD0Db>Hjv`{9I;CZ$rTkjZ2&E-fwH9w7n%SXfxN?l{h;`?LuF0Hl;^ znx;)DrJ^{F`vb9KBw(6m*)+{ti;IiT+r-En+qQkpvaB)yoO2v!2SytoQA)`$4DIA9 zN0baTzEVD)Z*;reYs2d!cf7v79uq2F(*Z=?k literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/home2_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/home2_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..7bee766fea4a2874e0d0259d5fc89e77d846cc3f GIT binary patch literal 868 zcmV-q1DpJbP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-v-bqA3R7i=X*1L<`RTKyC&;Dkz4>uB5vzW#{4~hSU(cmLu zp*B7cY(zvG#X=BCArY<8Xc56ethA8TXm72e5fM?)q}gah*=%;RJJ;fz%lzh-$>bM2 z@ME}h?)jegId`szjAyh$*>tQug~vsLtCEu6Ui^(m@np*Wk)A(`uhOga z#5gs9TuQ0m!=;qXQp$x=%K6ss`BKV1rIepaDMwrP?=7W#*gC(K@>O=Tlyai-t4H&A zRa8=qd5!5l{DKGYUCYKVGZ(`ahL-G>D5m*#=#Gi%+UO`*!8dpiKf9LJjq^~ks-YW+ zd92MmZd@f*$?f9&=2yvYryNP|c5qVfJ4&AnxX|H#HYE#~p-;!|zi0SYK?n(@a zxqy{vv#y9(cYEw0-o}OG-H8|QYfG+4;L9B&3`M7JiM({1v`zc*8(vJnGwE5|opH+uFc7)bG|wS z=<1C75_665_&6&{`jF`8kr*8Z#9G)9$zK$GH_ZPJh(4=E4qBcqC+1lu*Te~YB#J|V zUrCT!Q3K=Bofmyl3uq)lRdc<9C-7-k5xk4%Mcx{d1yT~M{ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/home2_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/home2_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..db6e95275e385bd0a94a6daad362a183d28ae1d0 GIT binary patch literal 1436 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 R&2j($002ovPDHLkV1kw#33LDe literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/info3_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/info3_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..9ccca9cd20ea26595b3e4094d2e38fbf7a6c7177 GIT binary patch literal 820 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/keyboard2_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/keyboard2_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..94d55a63d8f9d8608c448f89acddb6dce4661bf4 GIT binary patch literal 806 zcmV+>1KIqEP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-vph-kQR7i=X);n)pRS*a8-(K5sj1f^V76KtaAriv8luv*} z1(A3a2vZ3tZ{&(hdBEpoiis!JB?|)$nx27?kpJM+kUc(FNWHI;l)7h{19yib%2h^F6 z(L1<^mvM-_1ZoXB8OU+W;U`?iH`6+5@F~vY06Vq*kZx_fjAQr=7to*NXda*AJ*6!D z5#Zw_GRPHtjdQ9}Hbcr+u&x~NEKa0uKW*0&Yp_{m^cKFtwo-!mjIyJgQCB&Sx&-^V z)&|^B%Ds=1cpu-^j*j66g}!^ZiQDO{kB9Iuepe1Y^7ko);=AdrizjeeVdoZJ!GVYn z5pP7qort&@5&uNQtGV9E-!l<$X=tqz5!WK((R^>8HzVTT#JZE%cT+xVz>>)H+yAO^ z)N7F$41bIDx%LxVqkQqtXZoFdhDp*GO^k86?cQ!;uQpgyD0x^Z?;N$YQ)N`k*iMjg znAmIc3Og1JO4q{&crn+zcm`+iCl-{lEht^1JHb&uF;0%^b)l5==~U|Bait`4`Lrdw ziofrX70N+wD`j~wBUr!&eysFP;ayyx2DFkUv9}v+D(z;jQg~pKKco0VIj@$YkKq@Shh-N} z;#os2sBWrn<4c7c$J0qGy#!gBBBO~-wUrHgY;X^lWlS(A`Km(wPuh)9gYOGv@ZI+R z2Hzvf;QPpg!Pmow8O;fW)?qyB>b>Q(xtbV9+S4?blb4jtCS6V%{A|X{Ni7R_-E`Nj k?@Z`>_i|LreO(~`16gAr));*jg#Z8m07*qoM6N<$f_Eo)7ytkO literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/keyboard2_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/keyboard2_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..ed55b66871cddb72d97e0cfb062093b5df2ada9d GIT binary patch literal 1251 zcmV<91RVQ`P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-xT}ebiR7i=XR!wXhMHGJT?T)=`yF2kuBoHd9kRYlW;8yuo zr3z70626iB`1F3*p8!J z+dI4SIAquP!3mD|POF`n_s#p6?>%H@=m)oN-!2Re4i0Ipvj6}@RNvp<-`U#Qs`hgp zFC!|K%O*3wr<591O5F^@Fwe|M002bn7>02mgxD5B{EUb%DwRrbWukJqJfW0&3p)hysR%Ix^w4_nayUuK0G|U-)uH(0H7}-xPXux$H_@4 zf2h@JAFZ#icSC8O-Ylhj5|LCd^P(3J5t&&>XYUUT3>*N!$N%zZa&q$hPN(zj!NEZT z5d|WehzQYo$jkvECSz_shEGHm01zDK4w>24TKoBYeju4lK3H5_{IN?kGBT1#r_(=G ztJSvv&_85%oJUci0FC{1TUGn1ptJIN^AX^>$-0sVxmwe zymVdn-skj+A-;h$KlgZ?#OG``ZQ8>6%D!pS_*3{hG+>_X&YuB#f z#KgpxdwYAIZES4(9fxRibo8DOV%GD#qgJamoXKSF0>Cl>0BEhp+U<6?O0?GgsRRQe z`daHw^beRBn$0FNvr45>#zlE+wOU$hJq7?k#bU9bl)9;uY6C!=d^&v~3RkbfK&>^M z`$utcD5cs;shh=Ou|T<8ZYT`Htkyb+!xF!p7{2ej%VT#J2Nx$R}cguN}V90Tb}2s3z?3ip9Fxc*<(cm zz+eyruQPKZ48wqkUS(zk00RJw=$m}s|7Lf0w{Zzk7bYUs5wQaRX#iluFcL>cM_;Y1 zto#yh8XFtCA*C$O&CPw^kI_@W$abA-wc3th7(Aj^jA9MD%cNZSBmUa^Y}NDwQUKAb8|? z-f*A8$#14000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-v)k#D_R7i=X*1e0AR}=>D-^|YJu5Q#Ut45LtR!UY$Nd5t_ zQ$a$~Xo`F_0TC4hNtZqd7K*SWLeeB^AqtCMl~^T3ny681EK){gC4Q_syE|iX&YO96 z7{{5-fm_`7-t(NV=bZOeTCJ8oWgXtbMD8EqE*|uwT{D_ z?8u%OE3C8_~FK`|2B*4Geh@1Elmogh$a1@Wzv1VdV zS4GEf#cX=pLR~cEJxpafe@&w|FfAJObe^5Y9~osm9j+wiR;;UGQc!ZSbfJ;}AL4vQ zaiXIZ&CLHoI0Oo7LuzV}O!l%<*2M;4MMdcXQ3>*`ai{AWB!M38u|y7mr9!EBAH5oc*Fkburr-*o0q1Efy>t0L7%3 z!%Qtx@(Ak_xai=~^tgqmqT6?9Py9u!PJ=_a3PZ(I8A|LsH8C>&!bho8Pw#%mhLZ6y zLErLlY~ogFKP&obMc!MH*bfTtE{lFBls^|mzi+U~&=6@}DNi_PuEQ&x-&6002ovPDHLkV1nxmeP#dv literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/keyboard_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/keyboard_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..725948867813a800b64b7c287fc8c3f601b48c00 GIT binary patch literal 1389 zcmV-z1(N!SP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-x=Sf6CR7i=XmQ83~MHI*XbLP%{Z{ADp`%FYd-DpFh#a#%B zgchyEG$pA8QQTNmYBv@^M5HTm<-)E6DUDw{7rxL~4Q**jK?vEnu(VbM5nMGd@B4ne zxijOUH|3>G+C&fB)!cJ_^FQa@a}TrDVmmfIK3*Le85uLilmLK;nyag;H&<3x>f7;W z_XEw&&N|lG7nD-ZE2Va8tt-~r3;;03V$S)R5aNaq;u2%*Vy#w7b_|-Gojs(KIvE7P z-YANUQYtdWBmmYO7!f%_h-@~SrCcues}SOJtycSCTcCpn4^k$R`6LX(H#(h8Unv!& z3fN`=Y#Klak@Gyyl~R5g$MHvti;HGU(B$N#Q!14{Z@1e=I-O1ffY}PL1&}gwSZk9Vssa%` z83X|*qHMKV{oVKdm#$p7(sux0XlQ7E5CnVr{eDZ{wy%W{t6J-ai71mKNzZYdTnYwb zj2mMV5oNU2J^^S2f{F1?~=Y!>Yq4{ z-_=?lBBCM@y~!AR%yr#oT-O~3FeZd}5kQqO_BQ9dYOS5@_xm4MYr6p201!oyF~%GK z0GgPXs4As)E2W}=4s+u;R!Nfl*>1PbGRDGgxBHzjW<_iLa}-5Can7&bx^?Rt0AZ)o z`6@}0UzAeHS}Ri3Oeqy9rFKtDOjMn6xjYufaVh;6F;J5rilV(z%5RlYT1xq;QVP~u zo5^HY7>1@;EIykgiFRFgE(ikcI8Jx4Ta7V^*1A+GmBz?gTS~{uJtHEDBCfUWwA=01 zv)Sx#yM+KdjIkI%eiK#3_kBS`v&NYB9LHH{ zHk*QT&a>HUUn%uCfU~~u2LLnx+T^k^fTq)EG;VsH*Ce7*V~he|8Do}+GK?`7fQ{qW z7ec(OwSI1Rc-ToJ7y!e*@5kwdIT7)+Mg{~RNhw3Eb(b+Ft+iGNkrhJRSYBSP zJ1O~sl=8JGijX9U0r0BU`jYFqe?REQNJQ&7f-xqx)*kKm`w~Dbr6eM{0Hi~;*Xv!* z=kwQm-`}N_^4sn96OQAY*ra9;GN!dwN~zFw-Mp0YTCdl;3=9m_>FMdIIF8qcs>Od8 zsHs^1tWv2Iv)SyibLY;T2L`%iVPWCClyc7Vyh@r1%NWBB9}57U=T)SXbL)@|AOL8! zTBizyLe2BM5o;~k2Nh^g#%&|d^F|7VLao(mofL1>oZR{QS<>t-J02E|C8M(GA#5_HQqA00000NkvXXu0mjfRQrgT literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/loading_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/loading_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..684a670a190a00e580f7acf920303d9e7aada98a GIT binary patch literal 936 zcmV;Z16TZsP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-wB1uF+R7i=X)=i9_QxpgA-}^E1n(1g$W5mbOLfQ&tiG*0u z5RphMkq8YoYEd>8b{2GHK_VnJwerzqO4vxO1!;>2izX9fS~XMCc0RAgId`6?V>;f6 zlicKao_p{A-2XZM=bYOqr5Mttum_X*eilDqc9_lmA?6R@0o((jG@jDa)mlnH*B6^u`k&yB$KgZRTASM zzQV^fA2PNtC)k=u@Ge{<6nCQ##Uwt**LX1VG{A_ksLq+6aCWx$Y(A0J}GWjEFdYi(m77JJuD_zFzWFF||apPAbxn<5mulB1JYXK|`hJt-tC z7f%b3d@9s8jE#wcdP3x-G^+p!G+`EiBah;}^b`yKO zGK`A4v`74K15qKC@rMw|eoYVRYh*u{-*+ZX4c!jWf$zmqWw9ih)<9EU&gc6vJcOBK zHjAH<$%LpLALR3*CO?D3Txv6_b_CCBDtJ$*@@L#3itKCnLKN3kP01P8l(8wig%>OE zW{vNCQ3%iE#@enI5^z4BZ^-#x?yUv&T2Y{%)M|X2welX`uz4%5hpFLhTf3FNq^XZr zbX2WgPHxMSZ*@88;(Ob?oV0C3G`L}|TgQb;H?{wA)VBY1f&2$TH%;EJ`dY~V0000< KMNUMnLSTZq?y}2P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-ytVu*cR7i=XR!xW(m`}Hg9|r`GcXM3qPt&ECXdW84+2V)jmQK-X2ckT zQON68uj{?KRdsLOdt7wAkTgzD2hXY~IOn_PeBZs_VMGK+iBqReEgw5}?6`9-1pq+A z?7@QvcW>RgH9kr{I}B)JV?z+pSBx=VHpV<_t$m7!d;kE(Sj{=#l~Uf3Qoh3&dwY9( zyLn=ujg5`38Dm~hO085?<%}_vbFQH_ficDqQAjC+AP6vuqW7efuWoN||LI6T=g*%< z-}hfG%ksNGwXCZ5QgCL_od3vL zo44H(0Jt{ya=+i-1%RI{YUASL(xpoms;au0=lO1XLg9Jd%sKb{;c)m%0QfEE{OPr| zwa;9+awX!NKTAXw02BaJ0Ki)6AkXvNs;aJDym;}#W1~BJ_N>?Gblw_|$IlpJ3MpkE zrR)Sjpo1XzVYl1;%VaY7nNsS4=Xw7@#CcuUpDv1`27m<@oQQxi21Gv;Y8zQ_psiPkzU%Q90+bs1wl=bUDY z0RZrYSi&&0P1B$;h8bg2S(Yc_IDQTQh6n)QoLeo+(g6T?o);nFn}fk%vnZM-{(`_HN#04*^qdf4 zlZZGGeJsdgd{Ro$@Au#DcDos4jPL&@9{|$FiZI3`BHr8F+xpL5Q~ zh`5mZ!w`(Ij4@U-#yZBBTq*VKbLY-|sjlm%wbrxtA|6iAJ_u;7>*;j*MItgp)Bpf7 z#%ch_a594tpYkBG=LP167XLqx$j&$2ALi#t0z z}2^DH6)-}i%VxBFTYMRyRgA)-&*zkmM=0PrayBF_1uwS$NR`xh3iwT*M`^F(wE04xzf7>0<5Hvrm4 zbv~cJ+v#*}7e(=mF{a4#{IgY6z1cKP6UXttrIh!|vRo;O0$Vk4BB~J)<2cR$0O#|0 zcRHP(1c1glXFbo0!Z5r&pU>X~Xdl(lXrviquOvz00|08R^=vkq6Ok8&;cz${ej^Bi z4}}n6k|g6aO+OGqa3Ms;^Ssx6-~YXovSY2)t!=O*Nqj_nWi%RTfCGNCwzl^3JkP(k zunEpNkK;Jwod2V)>(5zh`$>}gqAbf15p64_Y!pRv0AOWVM%G#f0FWffa*`y!xpwW^ zLz{TakEYY|1%a+x4O-dYyCr z;?~xdJrrmW>+9V3N9b8Us3n5+|3|6L&e3pH#=5_5(z-T(jq07*qoM6N<$f@<{SIsgCw literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/memory_card_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/memory_card_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..bc053921ae77c7c1bea1e4e8140b800ad751b41d GIT binary patch literal 875 zcmV-x1C;!UP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-vFI(5Z#En5CtLX(v@2)wyqUauxhN5G&9Z2xH#uFH*eky zQ#>%d%)R%V=bY!BkJ}rM$EK7e9KmA#{}Vsr@-)h`Q|zC_gSaa}=5nu}U_an1tYT{~ zL%j(RJ%-nC4~E!GLq(yNjvT-YF5pdkHZ4$tb9f#Dtk>sTXKUqo?8m!!1*1tovv?n; z1T9U6@fu{9-(G$jLGLGcRz+p|j^4rweov)!L0KDYgoC&x&lIqcNRAc!ftR}?dITS1 zO>lk%Po(0$7T5?Ig5pzYR25kdhwvmmuOr%z*F`233O4W?&f-p7tAGxQEIXa+PYJ4P z8v7!dRxv0*Cq#CwwLCw7<=nekt@m&o3wSOKKc3E&{q@v4fiIfeIH{E-6<|L>Hml!8 z()B7{N(zT|%P4JYM8z+svAr^^Erp&<+@1zUE&X2FT*gv^qar1{JnE9VVEec&z3$mr zSJLJpj?Rkgn6sO@NgxY({vSMmM@2G>1WQFmY5P#UIF0l~hQ5Ihaaa`P8GIwUL#H$% z)A}t>CY>MRQ@n_u@t)`=--#@3pYLOB7MDcWx7tZxSGO&7vWQ>sFn$#UKG&f$leRB4 zqVg|_B5WTV=lXnp%Y_d_FZ)T{(S0HVyL2z&a-nP0Zt7<6x9H;ci_TG6(N&SH-{KwH z>D`tlZC`IeUyFHiL{#)O(J;>?HCwo&GWKseaZF_1U*axG9gUNP3u*g0&_E2Wk3`j% zyI9G{B=~yjoW{KgHWWkhn4qud&ZW%(yXVo{c)|8NV6Q=UQ$|om$U-_&y2}#I+ha_W z2tTmh`rB=#fYlTghf3E!EC$~*s=?PzfGs?o-rOvB9#_AvC=1|x>YPs-J02?2JWlS; z$R<5b8hq~tA1Af!!$YQfZhdLzaJ(U)TK?Aq@;{Kv^R@?b1?K<&002ovPDHLkV1mz5 BiVOe% literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/memory_card_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/memory_card_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..2ad7cf6eb9b233ce8dcc6a5eed111cded25448e7 GIT binary patch literal 1464 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

  • a+@0sh?#>R#OfK#no0B~=6d;9CJTPNlJT_FDl;6+?X@tV!~00000NkvXX Hu0mjfoAK{u literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/reload_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/reload_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..047e63a879470e855ad1bfd96f5d1f4a7e0e1903 GIT binary patch literal 974 zcmV;<12O!GP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-wNJ&INR7i=X)=i9EV;BeU-@W(DOlNLsswqNz#7EE)p^@kU z5fRm-L`0NsYT=_hVNoIx3l`#gRcx>k^$|o25*FP^EE*NG-AORjX;r1}+%Yrez83Fu z%;}kHdc~WZ%(-*k=l_46|MR^6a~dfn1FqG$1gqlr5$wa^L4u0`o^QkkTpA=J@oXl@ zzQd;&$6x;j)L5dT+pry%V;+A7P#MsOM3$k2Z}2qUAC#zx=W!oqF;(4P+glB8V;HaE zA@r6aD)1Walx6Al0k0D^D)&uU-krEdMapI^@EL5D8(b$@YHCJfZ!cmu2Ug#TZpB+T z+9y+TFUBwzfWz^30()>Hrb}F`#9jEHN;HgJ^7u~GNE%pyy?7g6ql*i03$Dg`Jb^pV ziMX~r{?}nvN=Zs-Q%b3uQkqC99f)fpu1-qn#gtMz_SUZrDW$QL(qn;9jqe8bKRw#0 zHYKrE;5|GTmEMcb@ufU87t3d;iAJEj z?1|^i0Gx|zAC0U>V}B=zTNR96#I8J%*R|wB*NMssS?X?pF2l$85$j|>ob3lx$meDT z%WGA&@ddU;=JT=dS=^2x{31I*2k*xJszl9*Iog!Z$B|me<)$f2;-K8i=Ws?OaR?6t z$@RFw;vTgEdv76I#`n0gl1({1)e3h7!4-H1AK^EgCr@Cq*il9U`*3-V#w|3v`WooQ z{R_A%_C19+a13|LJvzsN{nS+%r@sXql>0RtVB7IH&c<&1BoDzwxKQrFOdlndt5{Io zRCmffnZ%h<`g8z|1wj#2&&X1j0Hq?GkoXi8Q?0%xKEw{3B_G0l@PDE5)|LX(tZ;@_Xi=O6A_y7O^07*qoM6N<$g1_6tD*ylh literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/reload_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/reload_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..dba70ce33fbc341a548f2f5217a054bd3e6a1ad7 GIT binary patch literal 1646 zcmV-!29f!RP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-y=t)FDR7i=XmR)EZ*A>VA_s-n;+?~n7PVHptC9B3$DO&S4;`76;uwdXx0&Joe{(+WIfoGup2UtHKR!7%HFa2P9RUF6 ze6YE>d1rlnz4s*N+2cU%cH1PPZz!csDy5E;W!WSm8vqz%nPC`PLWmE95Z4)F*E*d} z@u@-Wc6(MS^}3YuSem9bUIg`2-Iq|xNY0N zOp@f4IF56rl&m~pj}o9tKnURlL14MA`*xOP7gkqS^(TT(oH$`dQS{sG?d^p)j{5-g zCjkz?Pz&gz2=-VA%vrpN&)CN zj(Y$WCMG7f0KD-rkLKp)UP{yS;?~yIkTEtcN<;+1FdWOWT+=iaV@#K2Y2|sYg%BG- z5d1?*IkU5~lU91H*=$bOw*Bhz^76_<(9Fz?<@^3$dcEEkl~QsnTm*pmz8`p=cSi`( z(OSPxM3Qs(V3e!Z{{Wd)M~XC zrIbgNQp0fw5g`o2dc9u%1Aw1(yInaJwsio1YPZ`bhr?k%ilTdrF%$S-;V7kKk|alK zwc3jSR!soVTAxaiWM7pK5j@WeYPH&xZnyg*062H<+_#FNSg2$6G zK&#cNA1sn2NwniQrvR*))6>(FK@c2KN~Pl!#uzhP*X=8%egXjPcKglIX!N}-%TySK zeM8xdJjN(O*yt<`WiG%U;dJ^*H#W{oi>lv2I2EVmhB#{LYD4ItWgj~-!0 z6%y(DehNS+r6xzCk(5$y`@V0xuKQQhG(Sqy^vgw294U%IJ?f5g#@K){mSO+pgkc!I z>$>kY8jY{pwtXs&<1@qI@I)Af9oKbj%d+ZW820l#f9>kks~3b2TZ}R5fIh3V2WG$D zzY_$(fOGy75vje<5fRJtTwc0#=>Y(=TCEovjmBbmSxX!&fjB<{TqNwM9(Ruo|95$MNwqqO_+$Z5W*jCK@Xei z*|TR~%ChY3t*xyGM6}5{|BPW6j_>K z!P&p7wf;zJofwAk*&qm>4a4xygTdgsDDdo3!c6L;jWglv-?=!~0 z81u${P7_g9!Jo2i`}6gBU3i{%(J+h)moHx~9}C*E`T6;?MNxc5O8J#EO)1aw2U_bs z5$){|9_PGaS=N-}IL!0B_e|6L&C=4+@}u+~yKc?T&zk`D)~zpz}4+UI%b(X=&-xuUiN0|6L&e3m73whZr775dZ)H07*qoM6N<$g7Kjr2mk;8 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/rotate_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/rotate_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..f118b16b57fb6557fe949ba03872ecae6c0271cc GIT binary patch literal 898 zcmV-|1AY97P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-v{7FPXR7i=X);ow@RTKu`@1FaZiKBU#OcW785hO8c5lCSZ z6d^i@k4mvo8xgEDg}t2wO_N3&ZA7$5AxyNeu=7z!jEVRt#2^|bnna9o?#;|ivDVJ) zxpOnQAqzH~bN1Q)TKnJsT5Gq4!=VXn7CW#t-~Yl7SeRsSXM*`TJc?cEWGd$t)7kg< z6!W-vC7{+iJ9-+g;{hz;{{$)vS{cYR+Bk|gad=Wk4c^8}=;M6-|H!}f;u-YtE?&d( zdX74H56=i%mahO_c5|_MA7+qS@ey8BQQ3@u9Kf^UfD6Dl>)})am48|p*g|3)s29|Z zp2W-fV>`d~F&G&$_!1uoCEk!h)qyP})>8$%P}jp3LcWXm6GsxLEFKC$Y!(We!FKGy zUU8N+jWa_2d(kiQ-Y3*`CY}C`yYu^nYS&Bn9J_I&ko?E^9naz4ipKMaxeuQd>gKFg zNuh2a&Y_G!()oCT+=n-C3_qb;?OtNe5oa`udo%L-@LSf3p_RMZjJt3y8F(09<7TV# z>_TGCHrOd7xn!-4%jV*2AgaW-_y@n?P(Bw%mJ)ksgDtsW*?8*+O4>P^>bWgc_p_ky z_5?0i%Za_^YPD_}-z3P!jPO_$@la5=8+QmX4UEaZPEIZg6^-tyjgx}sdxX6Ec*ts6 zd-xUa;E@clREkBMX>dZ6o3`=R&4pbn6m~~OC!K8{380|Gud_Ph$uf}?P`u{yRHl5 YB`J*RAcSQR2LJ#707*qoM6N<$f_CMh1ONa4 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/rotate_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/rotate_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..9dbdbb7635bd7541c9558b01920686de05dd0728 GIT binary patch literal 1546 zcmV+l2KD)gP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-ygh@m}R7i=XR?mwZ#})owRabZQkL~%fyCR1;kU%VpC}0wh z7eb=QI7W#hX-5Yia*7SPX+z+(Y&uOhswQalVoC^Seh-%LHSP1cv5aLfnbbD)S%Y0#? z(P;Ezt@SHqS$?ysDyy}wthENf;sPZLr-8?ANODWIbOTn8Y8h|)Cm!!UfiuItxs-n?o5C(+rnXT8B-@Y^iQF6Vi^55OKl z;GAxfdDWr~&rD;0s^?L8_@9+Qo?%lfwq4bs!dcEGSvn;!uW!YXwK+ZW35tbba z!_eoP|F^2D)EMIt(L%A!^L!7$<$k|E2Jp+zDY|&^;tN$(T^WzZQy~PCQd$5_(=?>D zhLjSVb1=qwQp!L3zQ3cCdUZOTHpZB;6HW`otE;R1AP8Q*apT5&2Sn%2o%7>3{=?qh z-jl|drr+;>nk30B=iJ(KI;Em0FdPnD9LH4<1pVoB`o}N~ZSC*#`TR$B?%ZiS07#PL*|IE8H%&9;ocoNieXaG^@;ra8X_}HThS_WeYi;ZM z{@pZ9pKh8avDTgo2JQ&q7c^F?{Uumnk319bM6-Rwbqr^ z`qak8#u^(AhbP;%9dyNbWSJ}<0A#IgjWL=r=6jy^0q1sVvLBE~TuJBxz=|*>~%@c1y|QCrR=z&-1Qu&c6>p zc39M5PrUv8{fB9qP8ee+thIVsk#i1pT??g@EQ&%n=h`p~xl&3frQA}YctH^OQ52mh zioz{L#N(V#CX>lSwzIRd*R}eE7XaXV-xom;M8+6ttrc+``(YSHM8t^5Ei&@Z@s}}# z5K;*7(az4!o(BMov0Gsn{-mm^g&Hn|xIG*W|5+5p$5P5CIOl&MqFrMQ0q~u3&2qnW z&RMPXc#&}c5QZURjNJmdrdkxm`*9rKpU>w{YOO0{%$J&`d4_XNQp#N+#0jnSI)I)r z<|_aK&+`rdiAXTUBx7vR>zwcVQ5c5zi=ucRSZb;lE?jt_uInq~@p#G@BhGoqIgfh1 z-YqHRZe7<;bRec}+eeBU0GCpJYOVd-d_Mn0mSz6x>S`*beEItI>+d~61OS&VUHVO) z=RfPl1c->maa{Sn|H+|jJe<97&cPV7qLexjhT&?Orf*%lcI{wHJW@x~>Gbu%V6X<@ za-Qd7=bW9-=dvuzlb=IAf(QUsR#wtpulMd`GI{+G=MInZ(P+f2wQrPV`P12Kb}-6u zL=i4H0KoISC{0s8ilTRf5U*XmdbNEl(ZV)2H!m1tUMb7+^f8x{`<~~$xxKx8<0!nx wu3MX%n;w8;ty=(YZ*OmZ@pbF4{l5$3XA0Ocx>s}K_W%F@07*qoM6N<$g7`G{G5`Po literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/save_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/save_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..8bc74925f6701442a8728d1cfdd18889709f8bb4 GIT binary patch literal 839 zcmV-N1GxN&P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-v!AV3xR7i=f);*6EWfTYS-`qRw)df+4OJWCB@{(Zu1Oy9^ zMlFoeVWY8B3r+k4#%M<(6l#Z5Y$93Y6PQ?GBA8eZ3maKs0|_j{nttHv7_z_Fkm;_W! z@#sx_f}_~P!vrb{RT}aXhWG`aBs zngoAbBCF2cy|{>XbwW9wqc89d{=(DgU6a;LBCB#=mHTcb#^3m`&!gAzJytM}%Q%Z2 zA_v1BvI4##!u&zvJis2D#$wl_IeaQAsS%a+Gk(Ie_$EEv7WedIRfOptUcp-;uWO>1 zmatxkPKfGS(Z;)!@e4SXMvW5<6L4P=6`d-{jwbdGgIqY(15zri%Ku$zQE6+~Wx7}UZ7=bXpFgJP3=(^##tqSK_Dvz$CECi1sYsl?n<9Vr zC+H0m`^G@blj~{iq&721;AilhwquX-w@;eHypH9Pqb2{YsRT7FZUsk;d>Or2FcN}V#Zb|&Ukwl~!`a6uGDlLU`C zVJNMs(RS-*Y;7)eDq~Hx8?HrsEjk6!jfd%Vt(~ZIw$Gos^Ay9LPpriP-Z%KZ6NB%T zh<_=BlJxEdr4TVtdn4Ol3(+Lmy@pSz-!v;)`BQ&BCN~W>(&)*j-HsPEC1;N`468q-2xM` Riwgh%002ovPDHLkV1f{@h$jF5 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/save_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/save_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..325de0c61e5b4e8c0c137b7b88108395d446aea4 GIT binary patch literal 1371 zcmV-h1*H0kP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-x)k#D_R7i=nR!whHM-)AG=8fNn?f2ruX?Cr;fl%lUp)9D7 zQHvtcgcyk*02PZ?EXuM%Y+9jiS#{A$@DJiZiWEKs5~~Q>O$|jzNI+3naboA$c^@9n zOcy+dd^l-P)hmtkq&MfBd*_bMTr$RBFLC6^k@D#1=zgtr2>=*l&84NK=Z_veYU~A1 zy9rgRRm&Ljg_QDhDdhpB)QB<01^^;TIp@nlh-X5Gdqi}%R;%^iTc}#CekrB=Hj1K8 zlO)kn%0z431JDN$W6TmlIF92m&-3a+h^w_)?bkgCO-@cS+qSR7aeOum!>*Jv$||5i z1STU8LU_LK=Umslo~G%gg@pyZqtLNq$E;GR^wa9<>gg~HSBx=c2mV2VAR_X8e>ez& z*_D-*Zyr8;xPFw@#?3(x{E&$(*|zNnA$WFF>R)s?07xly7=}v#P7e(YEd%&&TSe2; z(w9tF_uV~B{Plu;bVhYE$laR3Vp0JPR8;yB(!0)R3y0MN#mfh+sB3Db`_ zjW=T$uP%pl5V#fZ|z-HRU)N4FflPv zwuXm?_or!E(pvWhUFF-iZ~uMp;K8Y}u`#Zc+LQ(7oL;|vt?Ko9x()a?$(~ZGR4SGB zTgI4DW-B{-(bK0-2NLZeOvYUrcxC^Ou!yKhL@9tgcBqPoP^nZt%;j=U-*OmZl%{F& z;K75xb}?qkxSQ6>%F1)!_nVBd4~#K#(C+c^@w{!@*W)<;*cj6#B11$u$8lbbkB?6S zSQ~_6j9HxXX0zFR&K4IJ8=2LwXPd?Pw-AD*X=+O;3rZ*kGCR9oKcY_G`VmdcB_J^LeXSEPh`um#2K+|HHB@8-RNG@?|mz0|2h; zGRD{)AajOJr*l7_&p%mPTiYk4jEpfo0Q=6IIrCAw-4;iW9`%Tb0eDp|mtVYj^Ckqq zj4|x+;ltyTlaq0=Sd>JxFT)xkgy*{MlTN2|AJ|~3Q&UqX(=@%dyu92ZBICNQ;GFj} zG`(JrIOm2jX1d)jOVgBu5XQD`gUk_>QX-CHX^f$fk&z+Can9YmdGppLApkga>eP>6 z7@iNqu#ug&m5~^{bp^_nCL)vJ*@is|0DRvs`@a9njT<-CpNUOIRHjP3P7AK@_m0a2!dLx)w;Zqdz-gat5vSGz7j>z*><~~cDvnH zCe|nC*;a*jhU(;UxuIgQXnUS_opXL^c6L_nD%6jenVG3xuh$<=l$5fql#1}~wdI_1 zPY6+T9EW?JSGO$d>fGGi{2;zv$E}%}84Eyv-1000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-vV@X6oR7i=X);nlaQ4j{;Z*QIw9|=jo)<XJJoj3hx!Id_-R#C6F6{1|^Zzqv z|Cw_td7f(#!`Oqt`2HQAFx$%F&KBN};so}ENKd?52(gcNgGns^i>T71qO-V$16aX) z5ETn5kw`B(Fom0V)v8d2+qjHH{4B@U#g-TMp&R#c71d@!op^+E(za9^kpByLBsqxZ zxTLg|SzYigj7fiRJ0c>s8f(XbtM;-~(P=!xTpQ$#kca31&SShR)QxwNeScw#_NpmR zkxcU&nU$4`&#WEV&Xv6@R<29b{_Ty%O9bndFWhbq!XB{)lTA z)!-gzlzAQj8Ft~iH5L!j2)He%~9g7~A$8J2p5or`HZh$`v?zs#z(zxls5_aGa zKI4=$j^0{-(ih0pW?)Bf&t%fbn8qfxEqjQgQZKxaj)|!jg%+e;$%AtmvqhGZxDcP` zu^lg^et3efkw8Zifx^+Zlm3}Msdb!1CDdLBMYkZZc!NK=fa@sc=JNSmAgYTjy2j8+} zio4h*?Q?FeW$Vd{r!Usr4URPzl~yh%`=!d7T~0E5(B|c&j4qti+I8!-^dB|EdO~IV b*9Gzq5<000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-xG)Y83R7i=XmQQG0MI6V!Gw;prn|;f?{TCq@^JZ!4wVQc6t?hr_JaIt~DY5NQ}jgE97qG4?Yd!N8=HQYkfH zjM=$d?vGxt_s-VVmS+M$GMPNx>-A%+7^QM}>eMOgSd@Pi5JHGj%2i5D<@5O*&15nshr?kyEJlQ|FMdzF`zp1PMgo$Gz=rSaNz=#QoiE* zera-Ya)mMWF@WEW0RsR~LP(1cA~6bA6GF&?2M?s@d9QNLztLKM<+|=`zVCa-@F$^n zi#D6h$A)3FD5a*>T4}9cE*6V#Rw|W0pFDZ;o?#dl6N$txrfC`x&2_jyDK!nlXti3c z$L99-c71Vi@eyO}4Jl=(-|sWavc6tfS^4Dt{rg)0)&Q&#LTDt4)*eO=N;AeR#@M6n z?d`f5l5ca)-J^ z;GFMtyWP9Mfu_2&w6rLtTx~QOZ9<3+(*TSfOr-k>e-%Rj$Y!%C%d#%rx^-(E7!?-) zpjxf2bIwLI`n_QhKFUs~s9t z#ttXT%gal??_cfr`!f-TlO5AEuU9IS>ht_wIBqR3FPi`&javZjR4SFDk6X{`{|=D< Y03#t*b>;=Y5dZ)H07*qoM6N<$g8c_ES^xk5 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/sett-big_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/sett-big_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..a3438fb1ec68ded790b18948d3645404b51914b5 GIT binary patch literal 927 zcmV;Q17Q4#P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-w8A(JzR7i=X)?bLGQyd5I&-2W?Gh=tHw%rlsT6RZkxs+({ zn3_pICCC#ICY4Ei?PaEIU6Jzw^v{-nVzg zXiq&o=XuUK-{1Lu&+pG^BEkmS6n0@p`Ch>HIKGj^y$y`d;6_|oj7*fVI9|acSXs|d z53l16Da%R)9u*4}yL!Bp@*c#!Dk?X0OFIR)@xD)T!jK=YV^rX&6PoB|S=^w_E_z6GaF?@j^ z@Is|f$9!2j(>RC-5iuJPrz7HML>!BV-y&imB5p6^dn2MP{rYJmVq57y6%i-P`eOy_ zbirO_G-J?9x`Vx^hG`gaCDOBe4p z+LZs(m};?Gy5zYssVUDdc)0@Gins9rKEiAISt9Tfey=bT%pKU>O7ED^m*zt00DEP6 z>DqqWCS7|Gcgxh&wZqth&nspt1$+CbT-V@lEDimiC_C?-2AhWFoGdJc<4Y^!W?A3W zmvEEJU6)sL-@&KyOfQxa&Q;^n(rK@Grkk;fZcmnk2P>d?%;GK?i2Ex* zctCpTn8AQwz>%Iz8QO$tLmV8Ir2;*rFKgg}f_=P`>yW{`*T{%| zw-^~;0~{_b@6SezwFP@M*Nsd4ca>c=Wru&@MOm9p;8lEFKxT2DEQoXEdqO`000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-yqDe$SR7i=XR!wXiSrPu~^?Nft)8p>x@kBu=H(--Ui8v$* zX0?#SWG%yF#&)C#1VTXg(F$?c3kQVugb>%2klue*zbyS?MZS!G3?`n`IuzE{;%UllPkUPP{3xzap!>eSgR%Ul2uLJXcg zd-n9vqer_ha-Tj5XklSNGV`li>l<3@^J$t+GIJRKh$u1)qo14^l?ZQG?vrSiKdihjDbww65?=<3z0(skWm?d|Q|@;t8( zAR7Z<00cnh>tt-N02H=uHyp>g+wb>(xV5!)6iSIPaUADoImm8qpO_g$1ZJjEsl=5^ zWe)%aK~Rn3_=6W8p3gkb+XZl|Ua$86{G`x};-k~)w8AjF<9S}MaDs@0Qpy5AN-5j6 z?SzOH%H{HH$8n&PvXxS0(==@&5(S{=dA%?U@3hT`TLcXmA3(4Zf@?YNs@e%h)P+Oy&FZ*H$2Y+=c1IVHk-|V zjYgxdJbd^tmH<$z)uw&lzo4}q5)m;oDwT>Vm&-q1U0v;VI-QHFtE=xZb6UJ`d3pH{ zMD)k$>1pf1g9rPwv$MKXD*Y%7!+jzmt+gKn!G&6_HVt4+0zj5!GeHm>%MxZLW_}3( zR#sMaaDp&%24Mf%wQH4$iHVofG>ymgK@eo7Y0dyx6H`-DO|A8Lt#z1Z7&9}N*%CsW z9=}LLXti2jym|BH=g0R)qfyAr|27PxnrAWRUWHog^HWn(P0?sH&ZcSV=EVpiqFSv+ zj^n%^MbU2xV>fQxsC7D>x8gW{JBp&a?RNW@moHx~1Hj|Qk6CNISg+TgS(XLlDW7Fo zlBTKay6#!Q%x+FA%*>Ed)-21q@4D_Q>+9?96+otGE*u;j%=LP`y#4sg!!My}i9F@tAj2?3yULkJ;DrIM8-Ni2k@I*#-HU@&-PVq&7Cl=|CXFqlk|p7;H+HUVZnN>$S|*|Mzv03hG@KN$o8OR!76(@D0~>n*eTkp4Y=+<15r0MG?hu{HfevT>SVPtZ00bj^o@N z3p`T2PX;DyF50Qb7x?#CauJ}m$5 a0Qp~{e000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-vzDYzuR7i=X)=!94brc8i&%N`Ur;HWj%&de~L1dA*aVxmd zgs^mxt*T8Bt!mSvb&Kim#u0U+3#D3w1Ht63KOnUVipoXng3u6SMxCegUW;?CbG`iD z@T>zrxR>8K-}C>RUo{$yOh^lO3Um4YH?HE^B*MK3?vLOwo=GMByjxFYzu+=faBmz? zwS`A7;vMY82JR$KBT%Iw+cAZou!u{ODys1@UdI4yZT=2#TX+W3IE%M2+)7ao=kSsU z%dh}Gjz($Z96rZuTA{2v%pc%{Nbtibk-Wo{J&{q=p&3g2C7?q=~a zmfMP^@vSJ|wJ}O+JSOtCDsnOuMWQ1!%KNK0fI$5?*_pp>6{ecUjiN8rh?iLgd6Z^|vGCz&m1;*`Z^_!xaHn1Px z;U@Ma&-xgzZYTCajXf=pF4Y-=KSd7T#}A@8Pv-YNQDKi1BTX8jmJ~@Zz80B;S-VTK}U9* z=%wSe7#Y8|!qKLt%kPLPo5c&sze|MlGM-G!yRtiy_gd3OD|n^gO(l}t!x{V|LNu2^ zxALx3u}w5qm}~?!UiL-K*6?V4-!y(M7Dv!PB)6YJ?GRRZ1~!{|HI+2?T_sgwEvDQ9 zYhoFvG2ii|OIxjuMrJ;-mhTG{7TE?xCt|2b~ O0000000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-y0!c(cR7i=XmQQRHRUF5Ezc=%C-^?y=yW93+hzAo(NNS=U zNYloU5{po5+4e;ABr$}@1-z&+TtH%?Ccwo5BzQ%G-AyaffMqSQrlCh05zmB}wCrxD z(>F7HJMZU#Y29xBq{QE8lK0;4^L~HccYa7jup2vY;6O)bXXid+OdbG$F;-hxSa|&K z;lstlzJ@;L!-40jWG=XSUZ4>F`IKPgb>Vi-9I?zS4ySQPrCvgIdX)h)9Fh=5PaZy z-m2DGB@y6O4k&TJId`R$DaUcXi=ycB$;nBxE$HCEgLXcj|8{9PHVAJXlYq-Ml%M%Uw($i;4eTK>*exHlF7#0>EfnTiY`L_-t*Rt$hp+ z4<8G|@TBK?&$fXO5kZoH=I>2B&-0#zVR&+AXz17mP=9}a${2Ib^SlV27kd+gF~(fi z&AG1Y0042$9ox3k$^K>{0swiQ7ZK69{{H?HK$5y_HhV}Z)vdLzx737)2mye*uB%+v zy$Apu*=+U`0QeaIT+j2m!Z3`Rk0ByztyK^N-PvsR5CBZt0073A!$A;i=#n)PLRdlw zlg(zW@$vC%M5ISYN1xVeweN)x9qDxXb{K{!0MMCjs5*II|o z(GU?>mX(%L{w;(UM#NJ9V2&O=`sTvI!c3)7@lvVOOPNeYxUQ>PyEBO@)LQTF>FMcU zg+gIp9LM?OF}7CLLPSMG|CGz+--^ZJg;XjvmCxsYKYsl9*K>1obD2!$txP6!RS2=C zwK|aQ|CBN#u)SI*x1+)uIma!Bt%SGmL(Wtw6e0|7mLOB0pQCZ z2m(ahRyY|V)(|mjEo1_-h-lA=6DMAonwt94w(W0(5MMZs^ObGemuF^X=Bw3eiHOE+ z+jf%FZGx^^J{< zT__fd@3ghGbrDg!F(%#=1!J~lS+!cN_L$Ai&MqcWFQ}!OL_|s{rj!aBjmFZzz(CvH zy?c+{xpU{QzP`S^*7}<7`#&x(FTWbcan#&+L`0l(!8w04J3G5*C*-@1rIg}`7~>Y&>o^W$jNJuDl)?A?`gsBvUa!B5h!zn&5kj0HA}fj_k1^IrF4X)6iF58cjx+E3{(XQ%>nfGX zDk5H%Ql^sw8?*}%k%+W0CL|(MO05Jz;3b*fq>BK6Qpz-A>~f`2SzQMK08C6w+;$x2 zhLo~>O`$jC;y*C#^dFQ`wmXh}2%Zn3S?J zm&=vv_4@hd^$nou>FEX{o|aNxFBA%rbM7V%wgs-ObI#pDp&+G{*BN7{r>CbkNZPi; zNwHWQYBU;Wl~Uci98TtK+rCmRmnXLJx8t}~EEa75*wwfN0Qbt}@{5mKt@eKh$bSJC W(aSXxI7VIo0000000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-wDoI2^R7i=X)=OxdRTKyC-%OK9YfVdN;zAUBfGBFav5T&X zAgJB=0I|C91r>CqNOfUXZWKYG8U;7HQ*mKeRdnM@D=Mhiiin^>d=N|0N2qx?$HhHg zbLVTCj(B1CX68HRf1dwyZYLrPd8Tk3w&m~R_#U&vD31*Beh+TL4QXU7-z}!G@9-fG zW9586opmC*3r}MQ{=we~)F^b)k&W1ZZ}0-%AJ$M8FJT{+uu#jlWNYQk=-~}KiT-+q zM(`%?RnpS0z$3qp=l`c$#v`5FhIjFhDwW-qhc9BUQsB0ckp$m|XH&OhFqQq(-J4iz zMsx?>!Cd8i^Kuju_zBnIDtx6h#!01y?Z_u^9}d+K_3(_+No^zJIECl&O9D*dbG(|e zn^L~kT~wN>R~x!j>8=HX1>b@%aWf9!Or~%QGuWS*_#GG3nM$l3iG9}49)n#H>E(~O z8^7W?T$2DNa0?#65!|EHZ`5EX_7huIVf^*!Z4*r=l@4GY2dy^1rhGT9wDRLPhF5TL zE2=YzJ=KYb-FQuD%OoH9v940wu~zDO z_#xA9dxG@yc?B*@xutY)w^Fm2G*qW<3=`*@b)EE-!uUGxOO;IBnXv5K>2Wr+xdg4r zyMjye`?ncM`!ub*tjxKwjIJK6-Nc^jDuq1W0$ap(T#5HmW~)`MG?7f=V|<}d;PRHC z4T*iMtBj1JR!K);`WA)63wS`83R6l=8`6G)M>DdgQm?^iC~_3DO^psGSba|7{uDf@ zbk@TP30Lr`GO{SGy-T4&U88Pd6A>b!7ZIOD#C$}|M8t3T{39YxN5tz9adpbppPdnL zC?Xaro#r{8n7xP?7^-*TZRZZvPS)oHzE)bes|?l~6)K!cj9O=4sJ8df%L>zHTZ)vz zZnV1omzAyCUqf~Z(|Do*UTg8ar7XU`4DO^0oo4Y(DvR$y>ny$%r75PBbTwqHTe=P2 zd^V@fbYcu#RED{nY*!*%?{d;ri2a`~C-oUsX5BE?tq+vCt$8kFs6PMe0{JhBXi;F* S<%2!|0000000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-ysYygZR7i=XR!fT<*A+hJR^58s?y2goYAwPnoJEvKSlJjf z3?xAwV;c?9^mI$vB-oe;3?h)=M>a+{Sp*ScFg9KoY(e}7r0yAw1j9Ho8D%plAz4_l zEwC}hpoD1pRjR3~+qe6kET(E)BR?3Ev+Bn=-*?aZAQ8bqWNvP*ap=&YA84)X004}! z!M%I;?%cX{Yx^Mf_)SFZcH1PPCzMi;E2WN3r_+##Yybd6l!jsSIOiX7&i{;v?{>T0 z$+sqIx7(+cQqLtx^2034v{EY5T2BC=FhItb$vJl%$6-Q<_c`aUce~wd2O>Io@+7lu z`(m1=zlfq}tdvS}4}gep&kzv+fC_ugx$r#Ca$WZwDdmOr^>zKVL?=$1FzfaDo1@X_ zOcX_Z0MM8t0st|_(6;R=5s{QK&TY$#%=5g!_x(=4-~Z*!n>Y7DX_i@i-~WA1vYq3X zK@8V*@4K#hL2Dfn(Ti!C5@U>Z9Yh2G9YxVL0Gz4SYCQmWslaB%hi0>RD$BBSQ55w` zBt%5S7~_uP)NR|=>+9>6cXoExon7$(z@RU}f`|xF6!o$!JGZp7bZQ^b!oq^3wSGQ| zA_=?6E=a(2-D;!JxL>Q)UaMBCpC3PdyjH1H8lLCt zEG$@iMAd5bu{2GODWwwpBFi9zmH78S7Y)NmP17_C!>~-#ynF51wciRM zeij75e{9>n(kEz5fSIy@qPaj(=?yDeEIU{&1Un$ zcs%}Izu!-!l#!J3(N?SVbhq36n{C_A_`V-A#>`R}Ax%@QwSE!+fX&a(Heg;6CuQZwbn)) z$A`4mJPgAzBAytJ#|9$a7z_p+5p^CJtkr6L%d%c%L{!hm3Kh9wj9CEiF%gm0`iUe- z3;@tlN@F-2J`_dK>~uN>t+mRsEHF*;$2V@=_%{*VWsH?uhH~uszCJ1m0)Wglh1Qx% zmgABRX{|wPU4(3s|NbRmh&Vt*SymvT2>^Tt0Dv*}FWa__ub7Dh0BBj3VvOBBa^#4O zhyf8z%MZ@62dv-k-!TkhP`HeUptY7->xUN?7au~zZlzNB$Z;G`YfXh{t)Wt>ghGhF ztgWs6e!s^Ea+sx$;gqN$qy~k;!E8 zn>daa;y8{9j@%pJy6){bj^6_)t%;?jrBhPMKlOUOVct(zB;0jf&$jKzG|l(5)^`z+ zA>wzHQV(ZYW@TA+|A9e_VHnmN$2oWP>ecJ}hyVbVmzVz#MbWbltO+6_Kt#hZ3@48Q z5s{isrxJE|);?X&^BSJ#U0PjT-CGm;`e-;DzFe=@8vt-7ilSZ)QiNSkCX=L8w}4;X zS50ZJOrmD=RB&UxoLL=T@uLG6CQ~=N16GyRx$K h?a!?T<^Me({|EjuLw-;;*7X1Y002ovPDHLkV1f)~0J8u9 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/sim_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/sim_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..06120825bead13c18d038dc709e6c7bb87025012 GIT binary patch literal 696 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 AE&u=k literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/skaner-1_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/skaner-1_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..baf70020564cfdd59dd74f92fc7e9c619d028028 GIT binary patch literal 1238 zcmV;{1S$K8P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-xP)S5VR7i=fR!wUhM-YA0GriNjyYBU_EP_eSF$U*qbTcxE zF*q`kkGaK{IDvqDN<#1{gyd$EgL5!({y|n)F$gDs+_#kOl8tu-h<~`Qp&sCZui%Tgf3scETSm-Hciuy<2W8!Ym@Q@bQl4b z1X9YnF{Y-q{yER{ua}pX{gFZ!E?fxP?e@Lx?d@xE9QOeDqXdo+6vmiNtJV6Y*Xw=u z?Af!urwqrFTdmeNrN~CfKamKqcVi#N@dkivCr_T-1n^b0E-G;K>eVY*mR*nIc=Na- z2le7O-psP>`rO>ym3>09v$Hkt{jE5TbL zsgyEd7=BT!)qYn>O^0FlU9DE@Dy2?KDepy5^plkGL}jovO}+R25&(#qnVD18+OyW$ ztb7szzA%9tspf7|7$J!Bl?`^et95b`Su1NsEVb>%mzx%qk z5F!kMpx^KJUx~G~wT-gXtLn7OER<63FmuSvUMcl90L9FOl=3uyCNn!B#9IIiGdm)h z0?=XRqC5~wDV3D+<=WcXMp!C8)>?m*=Q)VTCrP5c_dn)&9(eCZ0Dc&aMnO>&F*ASf zoD;T59s^}(7z_qa8;!<`;c)n_wKj3i(az3J zjfgw|-r3oyVYid>U@#cRVOa=291iy|Geb&Q*IK_A3=A0AOip>5ba?&9L& z(qVjW9Jl7@=R*J!javYoEG{k{f8074|8;=;3zUzKsjyrGegFUf07*qoM6N<$f)-Us AQ2+n{ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/skaner_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/skaner_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..dafa465afa34eff1541dae0eced6a83c47d5d0b1 GIT binary patch literal 783 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/tools_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/tools_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..e7eef2743eeda3c9002a500aaf39d27149968309 GIT binary patch literal 1451 zcmV;c1yuTpP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-yB}qgFI5VKegsOz3ce_m_9aj$g;FSSV?Ib&iy`7e@TFh_!KV@^^dXy> z&Ft>%%-lQo_QBmWiEfPaJfCxZ=XbtQDFu6x2qfn`kWvZ&=ola&M5mM{lgT7WrBZ)VN^h6T<(WMJ<@0%B7{>Kht99Pbkx!j$^MQh1R|z1P5WnRYU;bWxw(s$Wlg72DeEO8fdHU9 z&kL1OR|f|N6Pu|^r_-l=-#^SbuK@rWhM`Q;{7Xu?F9?DU&YU^(gi`vclyb~4jCXwB z-wy!1D-t4d&iz)abvT_)p8|k+0stVTJl$%wHoL?y3@W9(oJ=Nf5<>ceAb3O9^|Q0H zvmPQg5s~ahsUxjcOG+tE0|1bLfq`Dm`614E&@QNo<2Y%W=4-2~s}q)G{bpI#oRsq0 zd_Lc27{-2G*NJ*r{+_W4IOm531_pZdY&Lr!3`1K=DcYTeQ4|GAsp|(19=tv=F>wJA zH2{c}QcxPf!%bX}(*ONUx zJvycIJ|gz&y3U0V7iMQ?Yo$`@NEn7cxvtwMgx~-`q?E0lph_vQEXy|xW2{@Qk#ion zuG@4RXSiCe9&sG!JwnJYqobp}<#PE6A>`v+F86mfn_abSdxbHUK|~$?TT$DDAfk(i z;ZFLUmBTr23L#p)@4K~H?Whpq*J82QKQlA4vbMH1T&YxsE0sz!T>8NlNL;($Z3uw2>>OY3^kzTup=I?ASL z5<*A?puK_`jm87hG?yu*sohv1A_yT`K@hwfuIy?(4#s~wG^ zNCJSOl%`D6Ty8WP4>o}o78W8zyu}zZ+EMR1jP-imYcv{{3WdT~0PwyLA`!>2AIEXf ziHR|05JGM(EG$F-JMPiBbLVb&o_BG}ndrKq5m8Gd5000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-w9Z5t%R7i=X)=OwzRTKu`@1ES;q(;$8jdtKf5Nlg)1rAU{?FoDObsI39^iaC?#GP*G7@KV0rm~v z#!*~cNl|MRj~>Q8Y{3F%Ls2Qv3PVOQgp+s%Zwv}l;CVcWc}!RNYrIwAF?4VUd$G70 zP#Z7f5jiX+bF1=Av6?^&IlQl9mr5v$8uI}>Dkr!E>7a{C!jQ{i)jev3%v9(&u#!hR z@EXol6b$2cyn;{hC$7QcxJS;-Tn((GE*`_1*`$=DlsYM;6Dg(hDWzXiN~hyHlTz9p zJk>QC{6D0WW>ZQRQcBbD{W)aM2Tv!Zv=qAge!0>PV<+Cj zrJ-v}=w9lh?P^sb_sb+sH2~dz77_Y&E+(R8XA0^#_ zcN+}24eRB+wL<46jJL5-F3E+8K*HZxhnH|&fPE&1W?n9iI&GD!b2fk$LifhDTpc6& zLpOxKa0Vyvqg>KE0{9F3Qv+#XTg4lpa|GR{yDrIH{yv_roqdk0aXXITWBd_&>v3~L zVi^^3-^}T6-XVO@z~99Uco5Iw3S5itaa_)8wTX++eXcE6)mdB>t`=eChYdh?#@R2i zCMsty%6Y7MG!(i|74nraS+QmmU*bEtAJ$d`x8aip1J>Yf{gs-HXESpUQeLjHkU1DS`W`BS zJWe*to~`ycDe$%b_&BN3Fdi`2bL%b56*&-4mHyWQ@?Q^0LF~}&5EB3Z002ovPDHLk FV1nEGrB(m{ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/windows_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/System/windows_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..e2585a5db37a54edff632512cc090a98a7080052 GIT binary patch literal 1562 zcmV+#2IcvQP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-ylu1NER7i=XmR*P(RThBHxpi+_%~A zhz+|Klg-XfW=t{@A_+_ckCN}I@t7w$vVx#xWM+kNYHErT(O;yLJEfGHl~O}QWB~vmVr&>jTL^JY2=Or@ zel$Hjo&I9b)YR0|Qp%TtAb2E-A}ytiwALvAtSBI3j0+)b+qPM;So}r^acp{e`rMj8 zV`F2?vaHv_FnreYyhKVFWFFw%3{Yl32vKxh*DMqY@5XU_bar-D-xIWL+csXS)&9A> zyu8ozyd?n0FUD*V0MH;f12Wfj>y=97)Y8(@iMTLPOV%nADx+*`B&caa=C1cj*gz|^?K`~D7rsMl9VxqoO4o2b)zU^ zLWtt<@bE&v-ygqt@nXUO07|9OjvxrONGZFyvuCDh_O#ZY4hF!^ojV(rW!+Rt{mnGZ zXVNs?!Wi>8=l_YK=&wqtr;{YNpUmXtE|eP0ehKx_SEk|YWI7=4u4 zuHEsDRwSlr7CGm0Cr_SyeL(!x{{8#!-h4ER z+Cj6x5V3=Zac&o2nx=t>{~cUBGBQ%JEbHM`tMyDA$H$4NB82#@*7}C;`=2YN3i*?{ z?I^|o(BVrw5tB9sn+^$i~OV-;`3C z01&Kt!5B9TqtoehuCw|1`Nb^N+eAc$Vc3RYe0~1>`GwKZQD@h#U9}ZO+qR$5T7NOP zfkvZIP)aqDBnej{mxxFRVGALy&Cky-@{Igpp-?y!MG*jiR!ZrKiHWxnaYQL)O-xLD z$2ot`ah!*`-R}E?pnARjyEu*?&{{|N`zaI(j4}2hK$cW}-@o8EPOIPVZpU-OVm^_5Efg04>Yn<#M^tIsXI^ztvh-0pJf&6#c%}>*>rE5fKgz4OMO1e(ubf zGc$L9008#x-TQ{;dC%v{L_SW5h#;$~PL?SsP18gv6+u?JhzMNQ9d=#!#Oc$gSIfj5 z@2K1DzEZ2zh5=xo=Xq@a(7CjPhzLZa;yCv5df9(~+l6naQmLHkbULr(*RcG@+}vD> zh%dOVd!k;iyF!Q}Wn<9r%FH|^Aw;oWue+}6o?wiN8-5&!@I M07*qoM6N<$f`p;*jsO4v literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/add_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/add_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..ba108fff3a3ddc290e1b0f412e52f32a2f20bd60 GIT binary patch literal 897 zcmV-{1AhF8P))pT#-Xx%10!cIUule)rz+|KL0Ph|Ak47;baFghM!pyVJ;Q$6h+$@T*_ON77t*rgs>)|8&aLQ9OwkL>G~~BV04D*9}A#uFSb7nrWL( ztPD7h&noFipNCEoZ8S@wO`BocEQ$}JH{FO(ifR=Div)- zrI*!fyILCHGi;V;_(aT;vDrr1rbb}4xd7i1zQ?Cb-+L8riJn(HZ_`Bdwg+UkKvVa)*gJ<;scRUXI+UyBi^0Bwtd&f z4FZa1OsDhAJR-7g86T!V!K`@GGsURRu7b%fyo;x5BV7^I4!nrNqSa4CgDk~acuIfk z3*g_t`xg9jQqyiR+7IAP(I871Y=~k!gU`itt##;F$WWmHZpA&~|AI8~Eq?BbpiTb) X%Xir;BELij00000NkvXXu0mjfu+*KY literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/add_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/add_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..b86014d22fe6adff4a2f07c3e7e67011ccfcd3cd GIT binary patch literal 1483 zcmV;+1vL7JP)=~yT19GA6{$_g1(j4lr6#8eRiw%Zae+(KA4O^*h*n5pmz`P9?yTb(yNAq%$&e8G zBuit@^ZVZWp5L>P)*7Bc@X3=WpI=*Bdnt;dJOBX3nD5%P>(BG&&))-pXeR^cX+SeG zGuazAZoJ|9exDGcM@m^xN>Km+!!SZZh|3uJ+ceFk?(XiNCMPG|{|kgqoH+4ztyUZJ zeSg0YB9c-HrBnz2?F|THY!E^iV~kpsb=Ps6Z|3Iaz5@WYBhZyAS2FYS^PhX3_b%tW zC8Z1i01!fGE01(+fDn?&<#O3Vp|H@~+k1L^eB9p_Xm)niyng-qY^72;!a08g06GoO z)=%TcfXKG(&SJ5+bnxK8q4Du?zClqEba8R2fxkrCRGWod_WWob#&d zy8Y#H`Pe3)iHQk|bN&(MycK)-L_RRa)HKb93kwTp78VxHn5J357}K;~doSm_;d$PN zV`F254WN~kmDd`L#(pVfYrCYwdOll;d9am3?Xbcy6pcn>PqkV-(gwmo5WL!IwRS8z z06?DSA81i@jNx1^rvU&MW7u&V1dk6Cl2Vdpvl+B) zD5WAPWxmm993W8?IdNN25Z9Gynr2s5*QK7Go*$%?I*K9$0LU;5Stt}V0KmR|``(YD zhys8%3`0{&(em>0;Ogq?u^g5MhixoSvRO3ji=OGICZ3 zQPNt62qBFz#z7FgEQAn=6kv?8Gz`NdrfL38DRnW%d98H_01!n{SgX|vob%V)I}k!0 z`F#Gq@B8Nf0GiF_E3WJA)>^N%b;2-gX{{y1hX`YAP)ci=Oy)N{Jw1J&Qu-Gmgz3kP z4{5E#wY4=rIie`?F~)!~hA4{s^#9mV1h9T=DW!}twmdU4^DhQ~D4WeLF~**#a)i*P z0RY;zZEf4OZquClzezHg3^7e}5dahh04NrV*DTArn~G{naU4fGj`LKVIGT)QS{sZ<8yYa$J%2_c4Qnjru{5CkL)!zitzwFcX^i=|TO($%Y1PeWYr z$@@t4_V#{UEEbn++b+iKB}oyIQbzT9oz&}fBBk5}qSpo4wq5M%>blm~*Y_zT@2hl5 zrlzKHw{G3~s#dGL<@Jtm l(b4h8g$oz{*(!px{0HCy&&q;5f>Hng002ovPDHLkV1jhZra}M! literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/appearance_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/appearance_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..e103a71258ce788cbb76f5385564f484cb5bd797 GIT binary patch literal 911 zcmV;A191F_P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-w2}wjjR7i=XmQ9G2WfaGM_l`58-D(hLS`<-1i-b&S<43`) zBulJZRjU-jN>{mQ7qlyc#6SXr3=-6p1(7XWWE$m4O3n6-N{um^<4kk2`MG$`+njml z-sxHg9`1e5$N!w?JpbpTq0*y_04sqN@%=k+0T}Nkcu5cTXMv5tqmg7VY%`JU9PkzJ zC2+GFP-Br9Z2{f_Rs(+ne+Ez$(1=2o0)4;_zaUK2He_kry|8@Q4EYrZ+S1q=ZD zfnC7tVu_Xj2Y?qTZJF%=-c5`mR{%$VZKPHg(|ggV^;W3x)-_@O$P z9H!NSYAfu+>gQ@(9gERczfkW9pF7k8wPcfl4eE&cjXIu^e5y7Rz)AI2^*MDY#wPWW z`n`H*n%&1K*?3@&ppL5N)ywKt^=oxm3fyXu+`?+CQD@cHl5S8vu3ihw^Xh0b*fALF zngVtJ(`iwk1kM7dSSY7~Gr;*1m#2Z1>g`1 z4^=3PYlZHwq?5wRcIf`~P_1MSu#>rWK)#El`^DF&eUAY9fHy10P8Z)NloR<1|Lx)% zrkwO!S>)oo3A_^33{l!8^Dn000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-y)Ja4^R7i=XR$XiyR~7!wow++R`!lmYwg9P?%0p`fB?tkv z7b#Md3LA&6?cF*dqNoq88Wf5Ut;!3a3MzyuAt4nB@jy_6iue&k%-Y75V^>7>3r;8x z{Hbc6`cMc`*51w7J2Q9g-nl$<*L9YbG6Va}ZUefP|q`R+$rYaAygCMHHkM@Prg zG%W!DW2}AW&Yd@I-MZB}&U$)3qDG@(YOSZFl%JJSo={3vwAK~?5RotpV~2D8I_LaV zBHHkMzxRQO8jVIxO8HC}hNt2fJ= z%*+h4EbIGG6g?3HK_aCL`yJ4G0q8ye=RE7WZpLw(t3rrxudS`6M-rVmbH*%{Nyxzl_;hH~L_`JvqhGGH z)(U_oqCv-L5Ckm%j~0u?9RT0_pN{6{<{pXT_~o6QoemM{{xeNPER)IPGnoub)7&MZ zcE5w7QmP_^K$0Z;TI)ggT5C;}N~LI7)|1Q2%PR*&XV0F^MBbN*f5_x}U{)6>%*pP8AN?{Dxm-}l!6 ztS>AqJY-qc3qcTkYJY#fO+=7VhEWuq%;)nD16VTwAWhThD2melD?y=9C>4vvMJeU8 zzVCPE=jSV?Y5q8u%S}ls@ARi^^!)krf9&;oUu`yDJ4%PT7@-BYJdIi_j;62L@~B#*b-?a5ZFH7SJn zlGgeYhGG1sTCL{R*Vm)v<>jY6&%0JA6iNUfrHrMNC#u!zh*>U|$Au6jrBu(h?QEe? z_=}YC>o;%SOaWkQY^pSynj`u3qAy*@QH^;j;Kd$m%jd;!2!tu^N6=AJDS z3inAVKN&?)q?9U^N~Lk8wJ!B#g>2i7k|cR z3_}o+CL#f#O_P(8Bd+WIqTOzfE2R?KwsVzAbX#;~=u^&bGZc=2K-j^n4|IKC7FK_*F(JtAUSYwb7=V~ni>M@tZCtut282Or?~TQif@o$|1F-E`QulGzCh9{3{PX1w<=1a|HbNRjS-q&u`>va>rvFsLrjb^j?!R^*?{J#eB Yze{IW-&5Cwk^lez07*qoM6N<$f|pk%rvLx| literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/cancel_disable.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/cancel_disable.png similarity index 100% rename from src/main/resources/assets/gregtech/textures/gui/terminal/cancel_disable.png rename to src/main/resources/assets/gregtech/textures/gui/terminal/icon/cancel_disable.png diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/cancel_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/cancel_hover.png similarity index 100% rename from src/main/resources/assets/gregtech/textures/gui/terminal/cancel_hover.png rename to src/main/resources/assets/gregtech/textures/gui/terminal/icon/cancel_hover.png diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/cancel_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/cancel_normal.png similarity index 100% rename from src/main/resources/assets/gregtech/textures/gui/terminal/cancel_normal.png rename to src/main/resources/assets/gregtech/textures/gui/terminal/icon/cancel_normal.png diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/default_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/default_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..ca7242d48d40b57be2c440e9c25561a085421498 GIT binary patch literal 1835 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 FV1i{*Coup3 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/default_press.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/default_press.png new file mode 100644 index 0000000000000000000000000000000000000000..f020b07e2d45b0b83c862b1193dbf0afc4fd183b GIT binary patch literal 1810 zcmV+t2krQYP)`9!13?1yLXqjCb``U34vf+UINl|jPhp0DPtwAR0b_r8EuClF+Pzp35dddcop*PHO1 zJqY-i1)q;#!ZrawtfnH!h+95II_+v zdiX(pYZ#1b?Vu|6+xEJHHNmkHM~Q_gejYJ2Mrwjo0I7((l9rwX2b#icDSkF`s%4v1 zo|{dLC+RrX%-n|;MLy(A2p(#^3k=k+Ht+x9cu}Y8SRY+w?zpn<{q~OZm+woX%rM9X zVkjIy_V&3;m@IK5F66&8qE6y9GOnfaw;R z(+C!iVZ-WY&9vUxeuoiXdC#gC5n|In+o&8qKfb=JHf3jeDl<^@Pfc;#EEyQ8FDn?0 zbL6R)Rq3Xs;=B14o3Gj|89qOGlru7iK0^DEc4Fze7KX zhuS-NBl}5vY3%prK11g-yBpNB**~*e2i)q(h2pD*&iLycR5z>-j?GG=97X#e(OYxv z`_g#&%qFwwT03iWozcak#bfP#d zOihr2O1`H<4~5hOfxI9Yj!TOGJ;mSqVbTU9ivI$3Ctsle{nq=Z0VEterSN<@1>rWj zq@oA$iHjOa2sEjPUy0D^HyEK5PBcy;37`51TPm*k3??kupu(P{1@QfctOER=rbk^x50B>uv=Siur}4t zqgURy%FCoTlUB|qdnB; z1*!S@GoonEapp$j96=BQbZ&kM?*u9Y27;XK81*l0Q}fRM$~PmF#V@;J)Gk` z!A-bDvSM>v^kfr@rKG*EfZ8#6>Vfn*skZql; z%9s;-;(MiH>I1|1z;S6hdR{Hr^5b;p!UC~F*9eB&smz}r*?eq+ zRWv%61pz}urJ(B^)qW^{ok9F+*+mO<(p(E3C*qC`1(p2E`LG< zUYxI$hBB!N_?glbqxSGQ_592gb~6o@;0uuf(4EWMzLNB*N6pmNDnx~qNu{CjpeMQL zxctTOIG5;Kdwm8Y{00*YgA!e%z;QWyy`9wsPrF-`>hL&h!L-P2#N7+}H!Y~>ZSek2 z&73b!6s1||d@bOkSQq3X(0kkCNJUGJLql69J9i#cdl%Q(9e3{ZUf^U51Fj{HUVq-q zm^=>CXJDWpmLO4gOhsPY(z_zvYuwW>%>N?(1+7)gAn`p=^#A|>07*qoM6N<$f^pw- ADgXcg literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/down_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/down_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..e59d07fa7e8ccddba7911c33cf91faaaf5c98313 GIT binary patch literal 2307 zcmb7G3s4kg96wPc!DrEnn%r3=A>7;DyS>-Osd#4`$srvSh)%h;``z8f-R`lwatCSw zMT(3=jXFN2CL=X7LrOE$#4w>TRK}VbE42Yl#vTY|F==Yw!f|OsubtW5@A2E;|M!1< z|JmBS+^h-lN%0zuW)O*yr^ojRrG_l|F z1w~4cGlyoyfR^DzH_(OyL5S99GG>K?3|j&e#0|W>U_~z-ID{fRXGIGQPQn?q0Uz(E zkU)M#ZUI|S!df_V)=VTLOhbYIP#7c}@Cz~>wxWZ)G#snTIEoBHloBhNsTxFzoOy^% zlmKGT8Znlnbco5KC5?ndN6kQV1Zlzv6He+ef}{x}t+ybN3x(Ds&O^KGk3?+2nHBXZ zN|46!P$;Ag>9wNd#Yv0Bf)hGir^6rulgkB#31fnsJj`GRGAr>xg%<@xWn|pq62*!_ zr9&ByQj)VyY3=cCwoYWGkOM^g;jpBk!B>$jsj>Ul=1c0E(5KBg}L7%9IvQPXQ z>ge_@24HBN&ZvzMwFClD6S6Y547w2s$cSjUpgah07m&pz5)0;*L7B;_H$mDa0Y(v} z0#Wo2Cn|4PGGenKsfE12i6J@dCOEJ&3b3L&LPuhR86&9zosQO#w4O>Q%rrp^L7gJU zd&)M2@px&;aghGP`wU%?zpdqgR~KzI27;{|w7@S;dGh_p@gixM;p)#-0u&$ij} zB+8=$i7_)Kqsc?E6f`uLFWN4$OVk2TzaKgaoXA3sKjrBS1_Mhn7L4Qw7URs6 z0dwmqIQ6hbH=xW0hNOns=1V+0j*S0iR#g=T8OyAo9JWDq8127s67AqXfYcJ~&t(TQAJb@JTC(k#1&-QvUmUM1 z1c`Bdod@-^KJHIxH>IXco)h0;thEb^5_9pz`3Y0f63LamJHFhu9J7})dxF#V`0|DL zo=K_2V>eFTpYC#XBu&q{cKq~RJ^N1RL%r9IckbSIdg+rbJumkx>y+zu>=>U`e{R7} z=cOCn-bMGdmn*T?lEV|O_9YrOuU7{8?tZ2<)Lgl*adunfs5-c4J0^e4yqMEvnfI`(Bc`1=dHykN&8hKA``a}K z*ak5AeYtjFbBU!qrRS=9>*eChcvtMPr(gX9{jGCt^R&Hvjul-q%4$=-UK`r|{8t>+ z)>67DOBjx!(Y9=)@p<;UDR&-8BJcKf_v3x9v&{qL)PU9|;~t79&KZ|b+rP6*^? zS8VW<#;)#Knvr(TnPW}2@4OM$nNWRw!w(l8{-Ll=IGFm%6mtBlDS$6eNGLs&@j`un zOY`yrv*S-*SW{i!(fhi-yKk literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/down_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/down_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..37081b918f41d70b2de09e9dbe1cbea652fdfccc GIT binary patch literal 2770 zcmb7G3se(V8Xi4Jqf|GZYNcXj2pkH<$z<}LDN!)t6%ArU1?p>PY++?i*sa(Nr`nr@7YHv_<|X4gHXBxsfw08AUu z#m3Qbs^u6#rEzf$l}K_eX+{PO0KrQvMx00`X)uvY(ivo&!E=oqP^Xb`){0a-l~GP6 z>msvFKsB5ti@{(E#t@{DG!9zQ^ae9#k#Rx5%NI^%019hZqE8wi;;M0vXJ{6ATK{Oqg^=T1Oc` z7bBiXWzaGXqjb!LG~*<#!8{%&CSb4yH^K;)=W=Njs39hC#tf5w)VPL#Nj;fH8fY_v zMJBPvWQwND$P%z;nANd-=mG7g`|MF-8lFVLMne(@ zoD3o+r}UJGG0dnFJUt&Jm&ceWtxnG@nAH(W!Kg5~7(vBih|fhv<*HOzl)+5n27-)I z$T&=BxH_E%(@M2yA`jt1h=5N*e4Y@8@I;b?v|=eL5r{;jM1oH2S5QQTs{ma4$IgO= zA{dUJ%h^{ z!EnNLBxD@IRSTqsGd`_*PCR~>3==~-hA6F zB1ZB>5!>FK`BFki?#mx2S^rwrG%Y=RK};y?e$&hos9#O7f7;6bNI-kZk%ghQt3?HZ zh3(lFoYGA@?`39rRetxUzVgBH!I5&S|1Q?KyxQ8@ok1n7x#r{UKuBOgP4U{gb!SaE zl7Wl71KACW=kK^dS32Oh)S)+1eHGsUKyFb!a{40L7#_I((#gC3{-ejd2T%M{g!Ah> ziN%o}bX8YRT&ms7eF0co9HXplLFX-Htze~hI_m{NK|zkpu#Z3b2s~y_+UI9Q3;UZB zj(SWx=ncFKRG4S)_yEow{?gOgJ>qm+2{{m6ePfk!Tk@H&cYZ7VRFJ<3@R|PkKi>-2 zy*0GC_3iJwpI-LiwdY#+CN>8BlrGkbuhdDll?JwUV+Hu%@9+tqKW zZhDPzbjv5hU}68vnyVMJr_eL+gecxCFFzWe3LEtLV2!P_hTUc@P`BRy@B&)uMfd@m z-pZ?R-WeVqR{1p3M>|{NP85`WCA^+wdvs2}mhHxN`>bx4#RCWiZe0s^10q=6)x~AS z>NU)7xlglab+P&dsRN$cgt`MojuB_Vz^kPo=SD?ND0}m@6#L`9R2?{f{``sHcGy3P z!%lAj5(erMY|&GiP)sI!vGzqT`FMU3Lu z+-u6L*`bOv4GpSOi*mMkuB>$Iw0Es|NFRJr(Y)Ji$bYzgePsK|_Uw zkDTrvtf#vl)CTO{aPNv25gl0bH&9fpZgtcki);QxoxDNv$JzaAOJXi+Qo3Z^AB(~$k32JXmGa*8-rk>L0y7c<=W-Hf z4VAH`Y|k$&bocf3?W>gKteN`Ya&>jYo~>u?_8+vUe|AU_dunG&h8qwQSTZ+t@JOhF z^|^7gUVqnd^XAR0Rz+RM;(`Oo3xLAr^!kh!udO$!B6~D z9eF~P4LLN}KApHcw57_!$6#t}jE|2WsrCNmi$2@_{jW5tYZsW>RId>J$Lu-m6Y2nA z{s}R0cZb7T+ArO}4nJ za0`Jj-xajStUWI!r{^V3So z6N^$A98>a>QWe}Xi&D$;i?WLqoP*6??Ag@Az`*G3>EamT(Ybfp#;n5z0&V*{@+ukZ z+vY3nmOrqYTlO=P+yx;oe zyDd`31^GoC_||;oxWJrlyRDdeO`1dW0+vlPOW7W*XpH4pab<#K1NRMvYWWLc_Vt0x zSHAI2Wncdq55-T`@7~3wlgm?*f7lfm~ryhZw=?5$3nY|4(wozV|td) zv*N)0+2&77_A;sa&*sq(x$g7*;<>7Nz73~EgTiW3)Blz?+_k#0c3Q9nihy=?$q1o_P+k`#0N7)62e9xy79; z&F92HRwm6Eh6&brN+r){geY%Z8&PJtvM^?UjKTzic@xAoePrPCn4$K)l8dFt!Dp+P mxW{7sB~|u}?<-;y>KSMpUXO@geCx5!@X<( literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/equipment_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/equipment_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..b8900825bd5d896d695c6d885670b9ab0fb4d9c1 GIT binary patch literal 1140 zcmV-)1dIELP)|X zFEKMBLSCx?0010xMObuGZ)S9NVRB^vL1b@YWgtdra%FdKa%*!SLsK^Byt0e{00YcP zL_t(YiLI8uZzDw%$KRXTS?}1Ju}w|_0Tm}AE-CUS#L{sgL=Y#DB7rCl3JN47bX-Xd zG=M;KG$$HBij&BW2uT#3l8A$?CktDN<9t(t*os0*4kNP%nf7AHEV5=hsM5WYtp-|Z4oWE76RH9CtbtelUK5Roy5piTl z$1x(3*7~$wufJ%m{j@uN0V5m zXl`yUNYnJT);exC_z#4Lh%v_V`FxViW@7;0gJ1vvTI;4U=Dkv>Gr z3wkzGuPbZq^Ru(FPqQ!#C#|(b=iER?a6b3gIj1KkCIkR*BC-Hrp#P=;008G)YOO5@ zAtsq~PPLB}H*5?5z!+n^`*|3o!y+Q#oXhpKJwzjaSG{74u_huK7%=Nc6hp*>F{YU@ z=AP$y^`5aj9?JQl`*)+!xW{&PcYpUh?-$SW0vh#l8bL%vLWn>JaeQ!a@FxQR;GEwL zfE!7&d$Oh2woRL{3?Xl<(%(S zDwSkVuc4rBl}e>&thIj~9Ua-Jsj27SeC+!0@bHgO>i+@wa_t&r@bi!W0000Kjs{jB19CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-vOi4sRR7i=f*2`{9Q5XmC-`+jdN>fQw$2-*hEvN|wE-`VL z5F?S$SI{6~g2adrhQuZ6A%rM>0|`|kap~=xW3bk4m(zVN)$^a6v)ASSU*BbY-^v<| zhAvUXc8tXD@A!z>ZZ=ms%x}Uz9Ec*L7>IKVn8OFWz-uhEBFfrWbO;mJgF6187XL$z zK5RyYx4435-3nE373boqe-&$69H<}|5MKeK^c~lwOjEB zr;h~LFBiw@%Dv?}bvIy01vlc4%m732|%)?;`g~=~%=h9taJtsCPAN z6H3vrwF%P@F6BrfRut7uk#m`Ut9OQ*IFHZCSRKDhL<&;z^jY#<#VuS|A#ZAY72L-W zAxSzlyaH+CtKuEAPiOoE6-%o>o49JGi7Nwyho~na~I)g!WO>{&A8EfuF>a zQo;`Jx&fhujAMuL=hn24SyMt%m70$>BPPV}e3asU7T07*qoM6N<$ Ef{#5vCIA2c literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/file_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/file_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..68c2577aef531a9f48163e8e4a2d1f14e3ed8d19 GIT binary patch literal 1306 zcmV+#1?BpQP)Kjs{jB19CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-xlu1NER7i=fmQ8OHXAsB#GrLcAv)H@q*vVG_Dtbk5fv7-< zgaUE$2@1Wmy_8#N)m}=a_ENP{4^>h74H83;+VIjy&IQD&Qc;2ST&Nny_CCS(#?S6f z53EC838?&~x$Hik-;C$knIRFuUOIB*2mn+@Mn?9FNC^OlsMTyXAKkrsx3Q-K0JIe} zIXQ{z*RKNr#>dBpipAnvS(d$Rj5&~|X-Pz!9JFRxR!b@MfSGSSvs9g>^RPs zTI(}Ol0400<8rxN+_!Jvg<7rlGXQY4T7`(%Ns@fHy1Lp2kZo{e1woLwuKU5&t5<&o zuma#QfWLEltdwerNQ;ODe=7mVwARKLb8&il+5!MuL_kERy4~&}V@zvMaS_4L&``m$ ztnX%LXKw?*;^N}A;+!~f0wQ8sovM`UQS>dg!_?E2VDVyLS&vL=cf%p6A_HN_ktdB4&Q!wP$7_qI8FB zJkRrfXXaY~VApCjOifK0+qS;tsjRN9TJ3h*kD{o!gZb@t z+wXR}0|@!PUkQR>E{@|*fGzWApwp*MBS{ifC=@RDdcAkF*6}Nja>sSupQ0%Gv|g`o zsx1T0#y9}nxN!she%}E2$aUQdl}hEWFbqqMJ0YEc`4Gmw2 QMF0Q*07*qoM6N<$f{Kt^c>n+a literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/folder_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/folder_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..af9a70aaee8be5b5a4c974cebf04a7294485658a GIT binary patch literal 708 zcmV;#0z3VQP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-vK1oDDR7i=n)=x{7K@T1MaV}eio;3ESwC++FCgKfH#=M#&$%FE)iY8O`Jdzzk;X@ zXv9JGq7UzI3oq+BDsUIqv5wX9{>t7mcnEv&05{O;=BOVJaZyf7s{{FVmg0~jc#dmI zsVpj+Z(~Zn;7(32?5{W)lvQ>oNE@<9&f#)I(~P}CviwhCy)ExaSzXHk?!!0C#k^4h&*5?90G}et z2^^ABxEh?3cqOGIrF1W)w31T#oKjj$DSb~VJ&Cp5j2D4j46c>nR>&`Y0zWJFQWZ)a zD`OhLIf1bPizUZy+jmm}ZsxF0ZLl(s}4$65>rO}DJJ%$1^9UNO4l{(GIaXGSX%}IgxcG;Yi qZ2)J~YqwtO^7eLeRJOlrApZdM@&%XJ6K>-G0000000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-w)Ja4^R7i=Xmd|S&M-<23%BCE!r#sfS8f^$(I_BcFsXJ;Y#K`X5-9WU<=a@ssBD z;FXab%a+nF>}lq`&&-?I?>t6CFo_ly7xS~TvvXQ&4*-C3-aa`wIX*ZzXigH(ZUdFe zWs`_LL&Q%JaegouYZGMRiUgm_V@RQ{X@R4f*`Wm!LkVfanA+dW6bAl?DHDFMX^ zgb+z7Wx{csS4ycLc6N63SkThalIeNgFK1_GkGtJ&3jp*uz!)HxQf6J({iD@teYd~A ze_2X%bh7KZKgN(|oc}t6i0DReJYRRa-6jA$o|&0B1%U70+0okC+M_6n)=y7QJB%^9 zzS|*4Tqp%2XQj11S4#B&fDadw%jIS)%X(6))iy6d%gf7&R4TRAY&P#9V!#*!#+b=D zcSb3kb1Rd{99fq2v(}mu5hM}`rIh;I_x&%!Fl++AfQUc{k<91w|MYsjmA$>aa}xj{ zolZXpf?xp=JM2O{lgYF!%lcbu&4(p43?pe6#%`@v`+al)D=RDidY+duO>^G&eHQ>U zA_id?E~L}x2LP~R0sv^OABJJ5<3j+$Fp`NxqQ1So{q0TXaa~(mTWteC^YY+sV z^!xoD06-Xq+P3Y70Ihip=IAg5M7*p_mrMgQj&fVs% zR_oX>j5g=oyfbV{an4P{Fxu^Q`}E@Oy@gb=n6;;7MRG|ia& z+Hst(lv2Ywj4_JMb()We2&9xb$8pw&kSibnfKI3L+;!cGlya7c zINk70j1ygmODShv*R6Cqo#&(DS3vc8z0VkXDy4jx&1R(#A{i$b3mlFMA(Gi_R!S*f za?YRD>-8(Qc5HJ}DwS6I{r geY-p+rk!JDOaK4?07*qoM6N<$f-I2w$N&HU literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/graphics_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/graphics_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..290c34a2f8072d2199e9bdb760769da60f05696f GIT binary patch literal 978 zcmV;@11000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-wOi4sRR7i=X)=P+%WfTYS-&`DL7_-b7vyF=gD!U17qJnCX zUFf>Wf*@;AP_5duYtgEZqDV<1vQ=Rr*`h3?AfZAqy4ht@i-N*TCbV%JozH)Z_k7Je zA2Tx6fy4K`&w0-OJeU7D=jlsgkur{pu(G}n;RhUCjPu|k?6=@1Tv9=nmTkI%?Z^9g z4>Jn^^_^lzci{ow|#^X47 zsz8I-h7FoyIXMsbLXukKN^HjiT1VO6GkFv4(OhslNP2$flfLpfSQwk;7+X8K18?9j z&AE@X=1rB-?0WeE!8$lvJ6VByv9ld$2%l)^JAkk70e;6C+<;3pg!mP&w04owVO)&s zv8saoh--0N5=m}Lax}@2BrhacQsZ46O0p@*Op@I_wq9M6WP4#v7PhYOr2^U8a(Fh$ z{v=P;cYl&^lYE+_uf`rrvMtHxB#$InR^v;O>`BroY?6%E;PE6|lZ+<0HOYxIGF_{b z)Te1IMv;u-LJ*7&C%pIHMT&U;&KcVT{$hUg-wz;Jg}}z>&gS(XMqdo88B81zyKq zY{o_ntyj+zs2%V`{U0f;&?M}Hra+G1RXmD4I3Ks;c@4cgcn3?&CT_nb9R_NV$24i8 z{KquMJ28mwHRa|4e2zEqi{`!t%66cfdlPlKfTr*Vp2nAD+n~v_t08hRhWS#{n68Y*|n-e+#n9ndg%sQiYt zN>IC~-l?JVL|yVw{dP1g?Dm&#!<$b!W~=_3qS|f~JF(Slu1wWMPuGguJD6EOyNeks ztesu(`5NDA8pizTzcs!wP2=0>6pe2N_hSpr)Z|85Iv;pfN6TkRVa$1`Eaq`?nPz9F zdYts*8>jg=Y0DDaY;n)6U1rPAX$NY{|9U|F1503v2XR}AW&i*H07*qoM6N<$g3Ha& Ac>n+a literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/graphics_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/graphics_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..35d6b7603170d2e18690e746e4d0092804b17458 GIT binary patch literal 1652 zcmV-)28;QLP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-y?ny*JR7i=XmQ8G2R~5(4x$oZhF>n0de0V|@SICfP?>WB#0iXuo5 zA?>1FG!Z7_`OLgG@7<5XqBA8fcIApAz16+<|GVeibN}}s5y4L4(4j-arBZ3HF(wZH zz!+=XyLa#Q+S*!eC+qQ}K;?3o6Vanm%HvYXeOl`x5jg+=h?rQGwIPJKC4~4RBEC_n zRMf`?mCNNRDdn?K6dmaGdPYjwGsY+Y7%V`>7#BjguIsW)CUa8=@nWS?`NNJt6B856 zah&JlIDVqtZl_YpsGk9DB|v=vAw(t!0^9SvSCS<8{_^s&*%mZ9I?D6;{4ZLq)@-}o zt^q ztJSIjz-%s;+W>&?{ZB?GPMr91uh%CHXgBU+wy(?Cg=Q5h`3Hfdz4aN zjN|yz-EKGWegC~oCi5Fa1R{cd=0rp;B7RD1ef0kQ`z0x*DwRraM^W_HrAwDm4giqN zW{-8d-Tk(0>wG@{S{%neSXx?=gWaAydGhDBZJ$NNX8_>F#fukzwcT0G&CTs`9OuW4 zM&r>aiuU`ye+&SYIRJpxdOS%Ik(_sB=gyrUj*pKY zS4w3N5s8SVr>CEmQhp8qx{l-AR!aSLadGjzBS(%roy+AGI-Sml)_NQOmf6V2$goms zpE1S|(cjADvOhUFIT1zCnR>mxmx#V~;J|@B^nR=}#yIrvl2Ynur_=dbtJV5yr_*_X zG4|@{=%|17>QzZZFEPfnlycwU!-t1?p-|YHBuQRM*^Hv-SemA90zif__D(LBdlwO3 zPt){Y)6>(RH^zL%81v75g^@8PmQuEqQk^78006!)G&J-j09Z(p zM3g5YhlorRMIHcTIp^7YKL7irrKN8I0GvL3I+Ld96TM!qNJN`#1`!9BnbI^hp67kC zKh#9T4iR|(kmnC9Ajfesh-e#QWSXX*otm2ZwPjh??%uuo(zR>XzA-sDIm8(I#8yQ> zM8FtBL>v^6*Y`yO0KfpC0RXAzd2SE{ukG5k>$xBZ{@m;J9$sHxpG=bEr@MFW9wQ>1 zB*~&>Spxp+cMJe5BC>=K8Q=GNhh*g4Hd|d?tqCD+5fL)Ro;-N)pjE9_-*g=3RH0D#86rNuw6t_%e0t2HDdn3|fJh@$8ft+ft< z;1cKjg-WGzbFlMrxjdqjdam7Wk1@vnV%zppmSurbN+F^_MDl%KXssXCT7M-;l2eUF zBOMwV%KET!ZfUBBh>S72f7r$tlfwH?2J``&T)$s+)UPlD z09Y&*H<>CMOk7x4SoA#aTo{JMzIcy_Vj@ZqaqvtGvQQuX5K$wd0RRYspy+wtxdCJo z2mqkjY@Q9nuo4782>{sO_1sDHEs6y}PzuAa(rh-*J~+M!w6e0I5b;b91TPl~g+K_A z=?iQN9E=MgGKE4R2!h~c#@Lyam6gp7vYp1v%*?b>>e(oY_V2Jc`8((Q#rgU9>Q;Im y*>26u%y0nMQM&~IZ_LlnfBbgq!}0$%kpBVM6;-D4lEW(i0000KO9? literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/guide_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/guide_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..21560907b769b787011f9c5c88038fed4d94e082 GIT binary patch literal 955 zcmV;s14R6ZP)nFsl9}i4JiwQsK%cVD;7dnu(Kc}NW@Ai z5s7G6h%_N#V`IU>t|}E`LnkUTt-OXe)9K8yxaZFN`udwUbCR3i{oV8bp6@xoUne4L zldi?BxFX-r;b;7@9p#BF_)|ETYZf!uk-Qb0!7um*U#9a`>Ws+og3~WJEE?+h!{r1d_GwR_x+^E!~S&z#UG~KSC?3IlCO$CKNV3z`v_4w1~Jnq1t zn~ZxDbd5TxL7cz>4&ybvp8JL5^+t3$O8suay-*z;#0BlNrl1LaS3t6ud&ygC(S!52 zn*!x)lxAFN$wr><&*;9#oq2u|H{%u?=xfVrAFk`-Hs!9zWi*5P8xBt9ehz!aWVD+6 z16>8SQ)7fFwR_mbwdms!{5wW(O_>^(cgF}-s#h?J2O8&xlq+4f`P5jaZbr0X0~nQR zr|(cQ>EQX4o5BkjaW7?>4coMT9)k(|gtIQLQ>0K=L07%j89bDZcBXDMcth^%*rI^# z431CWPi3^sDveo%_TW{#-H3EDvsz90+N2%4l=6#>U~3QlRmaKUh*-+;aVjFtMZ~ej zxM{AbTy4B#sax#~bF{6`y4?|RJR%k&;&ep(77=?lF*a`PP2JNGaW*1;jEH_jtbbt# zcncq7z2Jy4=e9&tkKpU6#&QNK@qp8qK1LLx){GG}l(h)q`bkdellb*zj$}n9~ro)AX z)2>p(em+m&4Se2aY@8#?2kky()bCe%YchGuN;95N{t>>)vsT*5QIoD$ejs<{`#;JL dG)>2~ z)+e>rFQsW(A)*2RaL%<5VoNEtDunnO5iQ=haijZxgJx!CrjjIiCkTQgQ50ob>&O_B z0_Zz1&bg3MT9#!g+qSAP9ciZnqg z&j&%!8T>=-c6$@R*ntBFJ_7LeHxx}zPfvtl_;It@++vJT4gnF7<2a>CrSezTbuV1G za-|0V=g*&ad%fPJR;x801VJ|k^<7Y{R!1DixzK1d{`3@d`t)f_O1ZeXx%oY<%gf6h z4giHh;k7Ufj|@X{P?3o4Ei5cF4;?x*8;0QrVHkceIyySLu&~f1qI-<7;*bwZ(=-ah z@UZXurvQKhfH7t~48sh&n_-N(`R@l(%12VlM*tq=L0tf5H^(T7be3hW0RTI8?ASre zvi|V+@#DiplpxOjhJV&eM%Fh4*4`Ps8)pHGtHFRfPVY0(TRlhtbV zD^QQXimSxREQS^e=I^IpquyM|LmocW17sh}Qw)w^d^^>cstFI`fzAJ=y?(W^YFR!n!k8f;joUGMqW4`ZS_B^lrG#x~wl(Ljk zD|hbP`L_fBA;f2vWxWx{F#wQl+g_;Qmm+mdsB3;la(x7$m$ZGS1Hv;auQaW;}9d2hE_wYIjV@87?#hu4V+Ns_$h zIL-zDsg$y9+g?eMf5&c z^G2gFzXJpS^?LpClP6Dp)NZ$%LI`U=WjmybvMh^y-yiXP|C2_e@vHvcj(H@de79UK zR{@Om2Osiru^$fpJNRzKas2BYiihuEdV1PojQzIT?Y`ORbb4u;M!@!myO#<8P)a$z z?^}-Jd({UE=$m^!PR^Y>_f{Oo7s4<+97T~%(=;;1WZ3yQkxD7cwryeC_DZ2p zxOnyI)f>CTd**X%YHF&)7<)a-vRAd%FQjQ&CL)z9Or(@8rPPX2>b4MKX>M*V*(=sF zL4$Vc)TwVtDStpjB>>=@Kk0V6_m-EJzuu4ke*kMG&D2wDiY@>E002ovPDHLkV1iQh B_(A{x literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/help_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/help_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..e7e98ffdcffb1f643e3ac3a5d14c8e71c4cfdce7 GIT binary patch literal 903 zcmV;219<$2P) z&(dLAv})**u*G* zw~B8P9iWdNaSX3+7pRAq@f6naZxy)7N`L{DaSDf$SS!#1UdKWFmF(L9n!q~Pix2T| z4K@vQ9M9nQYOIeXA=`BD9r^#9iKK8P-oTShKnF$Ie`kxoOa@Bydb38 zs(kn0X}neg4e$wW5Z|Q8wF~dyaqZT_S3F0~PE$7fhfmPNKjQCB~h$Te;M;U2u%!!@E9*Bcg> z082vu^VOPCTb&k=lGRPPu7}%_SyM(OK$+`Tf&1of{Y_ks13l~(yK7d>l<_m7_3X%J z9bFSSr)?_A1Csb*YzAHAwS`Xid zB5nIlwUthA3U`Qd7$%8LmrCCga(~^$ucFo0TeruQNg=j~pK%vPC8IUGl+Jb2 ztZjf7@t}#+Z6KYTKO&Ec>0{y*Jc>W6EQ)nS)~mQ%90g5B2V8{{c(zPT0}b((XtIA+ z?8>4gQGox5Z&VW*Cz(BX7mtap-3U~`PT-LYxZaRmQx>J^p2TyeN@dpN$v0QCGwKUBOYj-4tvV5OMH5AX@#+qCxg^?t&=B6>&#+KgSwv9#C!9iwoqgd_OBL dkgMBq{vQ1>8(KgAV35oJbL0q`#$`oRu8@1AxU-%+j0a{h zGv}V~e&>AWo{K~T2eGlSu}2Gq!c)eWJ^%njY-p`-FE20uagg=6AJEyeXKk(ZM3N-W zCrNTlYh5BD8vuYYmROcm6GE(8mh}@6U0+yOX#8)WGiT1sv|6pV!!R6CN~KAXC}WHU zfP4Wm#w^aclu`=Ub?-Qi^X1j6SHC+D(A?Y{2Y`>lFnlct0+l352mpYH*ew8M0XXNf zx3{;aP$>M6rs;*n#YMFz(A3nFa2)6BTCFx61i?nO`>p`H@$z`S?++A<#Z}9)UN4u+ zQSQLoy@e1TWFXa?fNk4c2;l)h+690C0K{?J&{`V+pdbjU0C2LeukRB8c4gUiHM-Tzkk5< zyz}$(^WQ%JI(6!l+J1f28UQmHh*w6yf*UO5{c9_B+sLqBhAZ4Cf` zh75^wE(Zn%{tClzqEe}B^DI5%&1Q2XNs_HyMb|`h=-jz;hpW}MNu^D`~D;VlsN!^F=ir)qK+CMBBW^=HJi<+@7}$;YK(D} zQcjwt1OVXsz9*$D-MV$__wn)ZuA)&&C7$Pv13;OdIC0_;Ddn*|WxISSiXx1n$O8Za z0AZePB1#c4I&$O)b_2;-X|0b=OiVn+3x&dnQmSN(NxQU4j;*tIkp)HAQ7p!B+_iRD zrc$kSQA#<&jWK?9tmKO7W@y_sc%HX~hzSu{Qc8x1G3We&3cFzukub*e@I4$ljEKN- z9NTf63#C%&*ZcSHL%m)%H*ellqobn-ioqCT4Ma>JYref0WlwPV^5rm&WAr@Fot~cV z9~>Nf1^|5cH@zM45wXP>3wW#5TH~D87-JgL>T763qBU*9FA)TmObNkne5*+kem zIXY6G9lBeMM&mcOva<3g=X{-WF6qCAQwjhO$FW`)DYVA=D$ zJ7E|OYOU2CBOxgki|^aEUEkc?e8L!`y7;uSab4G4YqeUd0GR+PmCCjd;&b2kd)gRu z7$Q2gTJ6K*$B)0FwO(h8$$i+P@B7lStdEzLmK4CQc{DdS_f@@Kf4OZ;V75c>JdgGC z^!&m(zZXT(vq2CX>eA#yMBw}WA>a4EnV+A(nE&YL0nYh5#bU7^08ZwE4|j~RaXyBK zJWbOk5$X06XF|#c-(noc?{#Ekx6o#1XC)$j)@U?d+TPx7YOV8HbZkAx$dxLD@O7?VQh<%A0%r0cqt>$+>UZGU>@ z%9Vv~@%FuL&CJXc5b=dHO`l7Wm5UZADEtkvX)?Tsp1!}j+ w$;rn#=T8z*0RVt8R&O*Kw=0#(y@Ra(2STr#^cHvOU;qFB07*qoM6N<$f_3Di5C8xG literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/items_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/items_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..ce332485503254bf1add7667bde60503601afddd GIT binary patch literal 897 zcmV-{1AhF8P)|X zFEKMBLSCx?0010xMObuGZ)S9NVRB^vL1b@YWgtdra%FdKa%*!SLsK^Byt0e{00P-b zL_t(YiIvt%tesO72k_r{w9YA2k5+^$F{nqVk;KGIB%~yi0TL1-BsCC;i7~;Tk%&o0 z6(NX-n7C;>BW9*mi5Rp==`H2pUXQl-aSYblIp5v=?mfpp`Enj>?fqYC?e$;#>x{=^ zGvYejhAZ;-628N!Sr+%F*tcSDKDXm4T#~kBjPN~<;)^72MQ4+Y9>puzgH`;SpKE1p z20FkN{D8Oc-mFA@yp3mZ4*xVZZbR8%fXna^UdX^UB-)A(un)gw^qt(SL_f}_mw_xd zd^*^PBY3PyRujF0{rIKIqL0(~3d8*WPuzn!tW??U!iRXKjc8w{{d*(2v8ewp%;QSj zoWx&dMvvocOJ-N&IlSK_8sKZ}7H87TKLnljn3U`XexxUJ5kX5)Fi>1Bq z7u_|o{?LawhBs`C!SXy-26n`C8=lGQDk>*Efg_&TFbMzn-8cojF|sk9%! z$^5>QzO~j?MFZ{W<8q;&waT$Xw9xqPBwlkd7ECJA)XSRa+Dp4Fiwb&J6b&*Bqx9`< z2CzIIX=Zhnbwqytq%AS&ebxe-NFh)@~Eo9BC3Q3SE>r zHWnHfiuN2%d5X`f$xt2Ob$M0P*TlPcQcUC0F(VguWQ{c;`l82ca1bvRhni@JPsETt zD{4ONy`o?xNp|9MF+nbDL{!KQ;tBjE6wmale48lOA-trL#bz%jPvd1V>X(ynrLl2W zWIW8z<9O3#=&r+NM6ewXim8387?4}ic3zxc>8yF}SH(<3P23<}Ah+l5Kg6v&lh*zN XI=kOSMyvVN00000NkvXXu0mjfSOcOZ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/items_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/items_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..14ae9e95d8675fff8ed0a12858030f95a6ba6a22 GIT binary patch literal 1483 zcmV;+1vL7JP)|X zFEKMBLSCx?0010xMObuGZ)S9NVRB^vL1b@YWgtdra%FdKa%*!SLsK^Byt0e{00kpS zL_t(YiIrAOh#b`x{?57gc2!MR*R&IPdH#Srqo`Q~5f`pPFuo*abb1n!C|M}tF5p51 zL0pQ6;twjkh49`(gty3RCYeb@hKbSv7cN|7;rJLG$-=}5ot~cRny%`;x9)W@)sLQb zCXQ!SRDIw1&N=smU5wGg7Mlv)x(eC?e3a&B%e`O`wjj~}1v_xmq*yWPE6mgQRO z%vx&z3<$)`LQ3iTzORBH_{sCUPtKh?_n#dJO;1lt0B?7@-RI*t&a~Fu0d|{U9RNrv z{Ys@$4#V)jd7i&=;lhP%TcM*zk1EgeK5e(#Psee56M!Qk0^p>SQYqyFumxObtutec zF8nwE6h+alYPEVv2=PL_UQY+U<*=$!>a9Ygx#52!5N1}DO69sz>Kkiq0Dy=nHpc94 zx7&AFYt0~_IF6eDo){k=e;>e^fo~o>)M~Y-(lmWOj^mpH5dcmIA% z5aMYm<#Z4PfAc)=$8x!RhY&&*B_tw39LLS|_4SjrTJ70Qr8{!uh%cr5ve|6jtF=yv zh@5i}Lda^hdMyZo^8o(moV!zNT?Rl(sg||&7a_#MX_`*8+wD8^JU2uH=bV#L`nz`R zy58+}4>cN%js$>GsdR9CeSNRidbKD41_!K^`hIqH_Wf-x0st&bPEOt@rMx%K^8`g& z#+WQk(>+lX9R^UB0AQ^>l%{Du>Vb&*p65lUPoI9%81wDfvuD2;{(kDzsYxm2W1iNf;sMG%a`*-`k|9Pv`+T)xv1CVphg<&}EdESd*7=Gt@-U|T!;+&f+ zF31#s8@*od-${}@+UxcHnIy^Da7BnnPE1Vv?3{Z}hGDoj%d*?7wfPVR*l0+tl4uQ8<2gv_yHHuP}33@P{XWbZLd(m`Z6aFTLWqf|&&)CR`~5{JWt*A*4=N5@FmrQhY02OZY-wr9 zFmscc#qdZghVE*TB;WJG!ooEv<&u=rcS9&<7DTkNrROb-h*m~|bxJ8;DYba{^5qo< z03pOzzVEAHq7Xtb^YxtyG4pjH#HP{(K_HoV0VvKTj^p_t2!0yQiin)G_UcZBthHB( z$PHx^1VOOa@AoeO#q@488l76L_E8i?pR`)73>#N8XXfC{nKSCjl`8_b*hl;J?aP@t z0FW14ilWFDLcDkJ;>8RY*+jI-QQn z^V~*JbbAy<|C*hheQki*w2!2euU4zo2>?&TaolXT+a+ec8=ISOOD$`y2H>J7y1iPh zUg-6DZ)^gLuJT%~<`dC}Ns^rCbUN!=>uhL0ZDkGslu~0+6!~LgW1j(d{rvg!o7!UA zpOa(9j-BrHdM~AEx+lvrZH&pRwSzMNHb#_GO8G$$h#&|SOQq5WGcz-DTc&)g->s>s zsgQ`C%=7$lt@ZuJn5uJ50UIksO1Y|(T2xA15<<+^>-FEQiX90J+u_59@0LADyX#Bbp{%@klfjqYIuS);`002ovPDHLkV1jPZ#=ign literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/left_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/left_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..8f5e09ebf89d06ab591d676231d4386c118781be GIT binary patch literal 2307 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/logout_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/logout_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..2f772da7064b0ac08973d1f55cb1a9421d0b9fa4 GIT binary patch literal 1472 zcmV;x1wZh-IxdevyHh5gu(BS#+degA1=Ob-A6A~v+vcNP~H|JaW|?gcbGJzdaRk1C~JQc4}x zS|701761SUA&OF3<(%K8l>Th3y*58T-}ui!r%s)kXti2z$8kI)rOcF4(io!wpzVN! z5Xu;HUDxG8h~FH?Ie+=`=)bL0=e#Hz=iV%*@Or?M2qP zlXL!I4zh-bfQW>1UP43y4^y_?Fw3%3YaIiCjiP7`0FL$a^n3~cZ|z`IE|@8b4V$*iT95Lh=|6RP0sn0QtC@7tWp zZJM*Th=^KinIy@fAPB|)V1@wz7-L40B*}IpACYERrs6oRHk-|8JCG0}qm-@y0BNVP zb6rZQJkL7{05fD{WaLq$)M2GmvResv`;Ca)^SpcYdi_lR*r1e_I>FkkwAKToqoYp{ z-}i^K)(4C+I~V}~yRg75pT@B3k~SoA2R&-eHDUszpT{apz0i|2Wz&UP`z zWLoQxb3Vk3F+naX2DS!FbrK|%$l|KTAHQ>V+=|u*{xf*;_>nE(?W<# zX_^igW74*}wU!%Wie!7>|6vvp!S{WMh`ODH?ZyZp4MbD`AfQWA5<(zN)4JBWtdz2F z|KiU8fE7XnLWre-fq~^XjxQ!j@@$r6wT`X@=&70GMgM&{dNiwp%GIP=0Y&06T$lpn2mk=3^e5MKc{dD1uJgZy`<754N!1 zUQy+8*+s<98;!=R^?JRT-&vlit-_J}S^xmfxfcY1>v`U{0Py~mD_6F(%C3)-si~>g z(=?hd^S5fJKrtdp3kj`i3uMOPh?s4qEc!= zYaLo^c}}mz7~ABWuW-(9P)ZkPW@cKu#o807)5gZe4l>3Dt+hS?03oE-Xf*CrDwV(Y a!*L18!5Jd!rB}KayNt*<2mPj&N)vf zBCG-xp2Bu)PTn<~!ymXk%D~u&{RzB@U3fm7tjoOtuHbi^!ne5|j))jWRYdHIh@T_k zMnqhXh^rAX6A`mXGs&Beh<-$zi-`THdymb|kkqZmXLt__xRI&(7vs3zh<1P;x*6#t zzQKW%UooPIh&UM$HzVRwL|n*|pNWXqB4Roswj@m_?@Y>Eh=_}+`+Y?8nzpNk&kl}Z zH)gPyybdBGTfohvI@)N-&ER!>&XWD6qrG@P1#8F6Lv)jB)a$k!%wi8dXgiw3M|sL< zDL*Lc$mVevQ%y&2V4L!z|BI8Rvp$~1TeYJ~sgsdK_YfFhC%P4$REn{0ZKA1BN3|7C zS9nRO_*-k}q{eM*!iyCi#UsjfUTZ8WMZTdLCAn6pFsJ;q|HEme6!+B%zu_Oti?NMR z(hwtfZHy@${nrYADy@F~DwM_>>v8uVGm$pWlO1E%O znLTq!J$#sZZTXHepN^*NvYYk=zQ&e@0?Yf>k%s({pX_zX|EV*P1qj3Qs&8Q z<8+aSTBr0b%70z3G`DJ*DSU@_EluO0qr9gKtvyQa`;EN~_$j|%m1#*#7`G_hG3?K|1&f+htXvlW}Ct9d&8l6_n00000NkvXXu0mjfpqY^8 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/modify_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/modify_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..454147eb5b1723ee4044c885c2d75242b708eefa GIT binary patch literal 1365 zcmV-b1*-aqP)nj32>E5+Niyns~?z(QH_S zu*&3^LCHZE7bTm$1RW&?OimIcGvpM=VRQ0}1;t&|TXsHD-P2uN-Ss?d&p0I6Y@+)= z7XNxbUcGwtiXb99glM^3ej*IRXW}@{002-*`L=D_ex0A6Uj=}8vjF5lpoN8n(Hl2z zyyCiUF$jX~Q50pBQY-;QjIoYk7{6PVb-hq1d|#{8I*$sXM~@zTt=(=nmZ%qAbhug%IJcUAsb9UkokF@(Cd-@elw& z&iNVuOx?P5>k|N|^pBDDDWy_rf2Y%Vopat=-!rHMAR>w5SVKfQv__M)fiD39=X|Zx z>Fh6+N^cH|4ggTCR&CDt4Cg!m033$=2N3`O&bim^cHf6E=N+}gfDKnnu?WA!Wr;}&po^IY6meQ3{DZ06LYeY3ofe)A&LI@oZ*?@w`gb?~hendpZm|+;k^1{Nx-#P%qqobqO4a3+MhT;7- zNJJdtoF5~Eq>dap@*DtwQYyKWkX(TI z`T2G_o&MZ$9J}uwPO8`IMXu`}Ycv|Ea=Gl4%Vn?GY^Ge-J=W{>qPzXDJ}ykhaXzip zYTf_@08p>jzsh7XR~*O5C#6Dw^$wR(3eNdNv)Me^_ct1ilbrJjDdq49AR>a}IJrzF z^G&^8ztZ;)7gJ46PQJgiw3G#aDb9Hd0FV$uD5cjMW4d~oQ{p@8DrRC&Q{%tC^LRl~;Y=pAtemC8f+LwSH46rIIn$ zHVk7ql}a`D?Add*QmOPdiuFLykhBvgP82xjJCsrmB7&~#osp4|U(TOD|JVI8xLf}K X41tH^eF3!C00000NkvXXu0mjf{E2S_ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/move_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/move_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..8d70c9f1681d7e473c977fe1d661c704c59cf61f GIT binary patch literal 858 zcmV-g1Eu_lP)pF7IZ~ebVG7wVRUJ4ZXi@?ZDjy3G%qkX zFEKSnS1wWj0010xMObuGZ)S9NVRB^vL1b@YWgtdra%FdKa%*!SLsK^Byt0e{00Oc} zL_t(YiN)5xYn^2j2k_6mxrvEsuA0^*I5>ntYrB|D!KDyLQwNcNI4IVk9o!1RKS2U6 zp@R;#=paH{IXmr zzUMq|ttbiyloxOs&3InN5BT{Y&W(T3_u~R4a0l2MyGRt9Si5-0~gfjiQU{FQ<0m1<@q$XX>xmZo$b^V+1?OFDek0%NvYMQ`DA{MsQ%A#KZ# zcqQI_i&1HNtF|>9$GiBdT+slgvDu}P8hY@dM2ziN_jIu>0&6<3_X15y^lf!;EHH!{ zSioTX7UJEI_W6~AwE}aJb{|bh)U5`nNoTQ(-*F8uhyFV}2wf8!9d=_Uux~anQmH0q zHyF=10`PL^a#N0m{u4ZhH%nVqt!ku>Gg8OzmMUpt1yi^fKn4Dg`eQ5BMd&Vu?MnFO zWOoDmOkLXJUi=-(AT^P3qDiZfi4e1LyHI z#-%=4lxA9)T}8ZG44d)rIUg7qe;XSOEJ;&%SYk;{x&ls0M7Sl9p^j&?$?$o`{+}=CyjdcPvs`=#q*>m&otY>^SF*nS#e|+-~V=%m*vnu kPRep5pIcS=Palwv0Vf~!efy?m^#A|>07*qoM6N<$f_WNxZ~y=R literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/move_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/move_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..3d7bb6c9f948d77039457d0b63570d1203b0792f GIT binary patch literal 1353 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 KMNUMnLSTZdTJO04 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/next_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/next_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..3c6aeabab484b15a6f7a3ec5022a5ad887476233 GIT binary patch literal 986 zcmV<0110>4P)H5l#qt@ z-2|Km8i8Kmg?)!iVHL0rXacqXAAsw?8{0oaTqMPRp`@&&R!Lta-IvrTsa#SU@~^-r9d^X zA9xQu2mS)nDM^A0ko=5dmj8A)3ueUj7^ zMJq~w;qF;4@Uei^KWtnE+yD;Z3PC1e{WS2|uF4)?3AhT<0KCLijik#t1>6QYaN#cl z+6}rQ1v(CN0=34N1yF?Tm|_KTrp_Yl(Yi}3>wDv2>60K#|j@%X zdJTAFd-A|dpgCcE0Q|OfIUg8Vv#=B`Ujn=i69Ff1XHZ4qYM%$z02hHnrf3W}gFCCZ z2v}v~aUVDW3Cp z-I4|kIvhr?~`g)4a+XWKhys714mB%~|ubU+&qkP3{@tKPy6STy7D0Xklzk zf+^Mymu0q$Pb;aW_sL1c4L z{q4e~ez#?1YKbfa^udw%4`Jah^FQVu!iy^_0+?ig62?Wzf4x4lc2)*o6aWAK07*qo IM6N<$f_YY(!vFvP literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/next_press.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/next_press.png new file mode 100644 index 0000000000000000000000000000000000000000..1d8f93e1a603cccabf5ba0592490ea9235dbbcbf GIT binary patch literal 1479 zcmV;&1vvVNP)#QmlIYzC{p>NsNH|+b${!^NJl;R~eiDWpx36E?eVt{8B6;Mq9D`+Z0~N^)W|#q5hX)>a&+69@tVC?Mn%ntmN$ zc$nDQt4J+H;zp5|C+h~T4?N$e(bf}WW_%mDbB@i~?c$N~B4nhNwM$?B0 z#7@%MeTlg{3+x^(Jsx;*KqI!Ukq5V4$IKo@IdKqKz%KjL#3%>QKt&MpA->QF+WSwD zNu+pgWC?UB@LaFPnhlL4ZoGw=d*4+=p$4StK&!z%Ab=4(LFY4H@o*wltyC_W|FRC+ zdP6+8^_mAWJ(%zw1xmTQsl4~4yX8G5ki*Kq%hc!_v^*W+*L913umWuD^)Y*AD`xhn zw|&-9RRV-xAPj-@3xw{0sRy=!0%qaX?gnOI5SAQ8G)1`3EQC3}$6Kii0{)hj?>*r1r*3+1C&PRzZ#Bl-iW+ zO=M>y{J9fJuu;10%IO4AeNd`^Lf{k?g-M6;PctOW6#l=y)F#uBB~zBbC~ zpqOqT*eE4>0IxR&sdSL~DxJKdFy-*~@hsCn7C?dY3wl3_()5ClB_*`D9KerLGSCcU z-4g!4mI8@wg48YCQjp7=B9K8rphM%S_ae0I3xEKps2KY=P4b-S+0}L;3FMKwgbQ zhe4(Rt&U1SDg14&y;D%!F2gd_%4*c1flT5L4`b#m78RxL+r*x@N+CT=$=nBGzRJ<7 zLnXQU^#b{c5}Cg&W`8PTXVePH0M&rz`+=seYs}rXq566n9SV@TKS*}&TTnsVu3yu< z4dLFw8mN*&*=3V@ccdR7=83c&B-(L_fwLx5pURorMOu3<;tQPs0-pNv)(SWOMOTqi zEW_$4Q-A^J_#&UvvSEaoF|+)!0^B>Hn7xyuqyH2}@Jk?sdzn@pbs=0AA!<$|RdxZu zhcEOQ?Hj*mdMw9F_bT~$WW>0fSuNZmck3l-GrRjg}2zX2zc0}X2u(@~Ak-|7nwv+f h0Qr=|&TFd<@-OquR9s=Cy>S2l002ovPDHLkV1i6*oFf1L literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/ok_disable.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/ok_disable.png similarity index 100% rename from src/main/resources/assets/gregtech/textures/gui/terminal/ok_disable.png rename to src/main/resources/assets/gregtech/textures/gui/terminal/icon/ok_disable.png diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/ok_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/ok_hover.png similarity index 100% rename from src/main/resources/assets/gregtech/textures/gui/terminal/ok_hover.png rename to src/main/resources/assets/gregtech/textures/gui/terminal/icon/ok_hover.png diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/ok_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/ok_normal.png similarity index 100% rename from src/main/resources/assets/gregtech/textures/gui/terminal/ok_normal.png rename to src/main/resources/assets/gregtech/textures/gui/terminal/icon/ok_normal.png diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/option_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/option_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..07ce91319f9e13bf014fe6a9832eecebbff4c1ca GIT binary patch literal 1022 zcmVl?t$A8~t#>W_pOSx{;aN7_kAwsf6n=zbDlRPi4n?lU_LOx zzkdO5fR7_NoUO244XpOD0GJ4j^0fgV54;2J19u&~tfYqVXgzQQXaEL*UVj$DSvNEX zQ~~dSR^ZA=fwI6^U^`F%dLqT;Bq+!MV}a|yJ~wPgplaY6&=1Cr-@gKzfu|9zjqa6z-#{}kE(TiV z*7snXJOOqAr-8#*4J`)xT}cem;^!{-ToL1|0Mr9(VxZM-5pKy2;G2hIGSKB=86QQW z7C7o2v{F7{`hk^TsXP@c#)5Ae#E8F%@w3Q5_PMotfWF9+)BYSxfCR7R05h||LM$c! zL>u}su9o=wc3=#!8{?_NmA4K75@Zml0~*p8S=E#(K7bXYaLD)6cvv3;mnwkZI;w!0 zWF5s4if|He5lh#+ueJHy#01EY{VeNN4`88DbRd9S01hU+-HUNG0PM#&6V_DYgh*qd z@5%zNfbW!e8V&^DIF<hSd-0r)`Uh{t|&uu4cAIP)*EjFTm2jO|KjV#TK#pmFvT!MNQtW+tYy_< z9b-!jQqH4Twqf179xKcOr8)~nX0Rw^Fyc=Fx5`>n;lHjHSc|p#xo&Zluk~T!4Vl&E sb7iFxP%N{sAIMt&{(=2Kc8uikUzwcq6cZ_(5C8xG07*qoM6N<$f@nCw@Bjb+ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/option_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/option_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..94de36dfe67a2af394045cf7d3acd21439e9f78e GIT binary patch literal 1705 zcmV;a23GlrP)FMda9mly>YwZI7AYxKg)w`>!tN*%_{dhaj+}xZ| zRn>z^sV^v{K2=rK6cHH!0E{ukIgg~2?{Ut5MMQ6`tgIyeH)v*N=4e@#r_watpXYh4 zl*+Z%6#$GkAY+URAuP+Xq;1>po2L27;^N}Z?g-TFb_D=@H%-$M{eC}JN~MShh=|)I zpiu%Lgyp(!({Y^nx~`wOc=2MsBk0JHBhoa@SEDF;IF92FrIbtv;S@!YXszp=U;sc` zYXku1`~FlA1eZDIU+eXH**JhrMoTHrMp5)|zu&*fIhVfg|IPRPAGKPoT1qKt8=Z-W z5RrMFXF85EOp@foFbp54s_Lc5xLcr3r}M=u%TB~`d{YQv5|OU!`d&o*t8LpST-U7- zk!|H5A`gO~*=#nSa~$UlAw)Bdz zV=ODn^2IO=ha>ynGEAQ5s;=w%0RZse!GpUj%lhfY#>PG(ssMn55YlzsigW%K&iSWJ z(|mJbVd0sXnVIj!aeR`93d1m7;GCyrS)L8UFx$?Rh$vdE)<1~oQQt$J{MNyoMq9`MxZLP1huB)mFEX&%@ zwAS8etmui8AOPsPu7~3)iOBFg&z_&3e}Z%V2g5La7)4R0wXP@S+R7p#skLrywd+>v zVh{u^-}hhd^?E1IojVr+04y#p{*rV4y61TTd~^yJ^=`+($rxh^A}ZK?d5MV7_x+ad z`>!o5ES#RK_W1GRk1Z}Pp7MSFC#_a%SEJDgY}@t`QEa)?3=vDlSj>0t-d%9cAIkH* zHIk12U|h*22mrwK>(|c|Me*YK^XG$W*RGx3yLWGei1Up`6>1h#Dp#@Hno_a%P$J^< z{eJ(eNs_Q~bt1pp63Q4}KLJw%iu;#LU2 z|0W1S#QTV-)>;pJ-@hvef{R5_Jhv%$>s!|8bSy-CIZ2W)#c@2W>pCAvwc}GhGEu|x zJgd=YoCAPwE-fupw*`&Yv17-+TolEVS(fd~^ITO`m5;{F()Ir3D>bm~CQtA^`RRu&OM-`Srh)_zoCZ)X0IbZGddgV^JZVQ@R zhYlUOM+osrB60u#7-Rh;N#4D3<;s8VWdDBwmZU|-9|-Av00000NkvXXu0mjfzyUL0 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/prev_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/prev_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..67fd8ce96017953333ff7672d527049062f3c331 GIT binary patch literal 1618 zcmV-Y2CeytP)jo) zJtkJ~>T2em|L>i1&pqc5Gh?HRPi!Od$^_*S0Ki1BVbzL9zumA1-3piF<2?I+V~=R)$Bt^j7oN2Kf!F&0mFAzxlb`bY~%bzqD+*3{(R<++=R@M`_Z0J~v9chmRSg0O1jYLl7?I zGHnkDfB}%2r2dk*eqoOqxYJnyv>%TW*jAEo@esrIb$HeVra`(wdh}_nUAk}U1OU?tsT*jMH1-0vgjP1vy0Ecdcl$pr06~xJ_naU8CJ_FJBw3_966<}H01%T<25ADp;i4t4v_wKo1FTmX5`k0ZWYL;S z$D;Vm%Qe`TnKS4u2MX@JzYoYC5fJ|Bci0gcRzzZk+@2+l7OkLt=YisFbs_Y>0m!vM zAOa`MX3?5Ue~aQXzpWvQnAx!2a-iVsc(zDF=4ZQlsYt3b2>R>v@MIpsq-nHU{1gxi zIkeM|0I?E!`sEt3hyj4SL4oc~m0Mb(rk&yh;<^FyO2aq4O?B_>r{l18!e;RSfU0Xf z6#$zS^zyNg&4Lw`-8!9mH)3W&D;rlA`9Mhhp;H+-X{%GIKxcdU{C>yOW*!LZ*WLtk z89=;N01Pld3Lr^f3y=Uf%{#}6R^<>Vbc5TTaVnz|`0>9YptC*AO(wd3+bQh?ujZbw zN}#r%f_O!o-?Am10-+cGm$|)QL;Na%$ zvI_Vq_nWN?F-b4zGT5Fiq+&G26ks zgS6}HdLxDeH~_@Fb_##=hjzYYYqM4H$i?+XjOFltG%VGo9ez4@eoxd~IApEa2j<=` zLlm{%E=hoDLaGVJtNg{;wEfHM`h|vk{K~C|sP+oq_2CchbRbp9%zwAr#El27HM`l` zVE}&aX+$Jugj8pgQ=D)rqbDI`HJtrV?Ej?ERrr>Ju=!|+bl+A5H_&KY4>+pzuuU}p z5XqFh(h_WJ$}I{#g&9-sdI2H|eY{(UP6zapT${D+LWInT83zZ(|$AK2Q};I@`L Q=>Px#07*qoM6N<$g8yys2mk;8 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/prev_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/prev_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..83924b7bad38b86f9556ed53584ac8676fbc06bc GIT binary patch literal 1006 zcmVNO8L@@F0KwE8p25arxW8ZVy5-Zuc=bp3A`u19T?e#l}B>vJ8KpEE) zvbqTZf>nS96oRk*) zcLi_&SOh!*ZUWDN9}aB<<^!vNxxg*pIPf^Npg&DgJQ7KDk~$^5k#ts4i=?TNN|K6_ z3Ott-Z@?a` z)Q2+)s_4bC7FY^g^@18m&8Y(>0cU_;zz$$AT{MYr`V&bjeARg=n% zCmdD+x`ER<3mgG{0=+5B5g@0XTq#-;e|C1@>Y`B>^@8 z2Z34m%5y9Mru+3^8rX+*{dv?zJ%TmsE5Lq-4gp($BfxA%0b$0fJs|V zxEUM^xR2@CZoeL(_J{=N6|4m=0j`mKZcD&UOqB0bpG0cW>;Qkz5T{z0DBIIPoQNggl=aF;_nWNKbkhI(g2HC57PhaJ*50vtoP zdU`K<*AL)gG)j^hJay+};@#;!YV>rxkEn&%N7PD8MS8K1sLx&~O~4$i^qVntIF>4s zn(EC1rolx_Xxp%^KQq*uKmUTAvmW3sqiU1scsyWrp8r;`_7~dOAl4B2Q*+03I8k5> c|L0Hr-)|kTsy`LuxBvhE07*qoM6N<$g4Fx7_5c6? literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/prev_press.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/prev_press.png new file mode 100644 index 0000000000000000000000000000000000000000..2742ebcf89b009801ca47b44811dd743bbe5ca1f GIT binary patch literal 1488 zcmV;>1uy!EP)lsBfBROpK32u@Ugbok9u$xuhLhXs0vNxt%k6`*3E;v>gO>C6k;<)>_~G z*Is+?CB_(T+5Xrlxb1=+6#)D)l(L!!j^1(-xhe3#TA`!Q#!W`ZPk2;v33SZ{K-oTS zGEZAqfl}5ddpTg!>3>XkW8ja=g!E7pT}zR@ypihc7HYvdjP3@I4-7BERLHIM+%bx#Gx1}sEPVL5w=b$mv5 z|6wN1l-P8tc5~qG8!Qs(b}}P7@ry5GbSFpwXaviG9E}7v7!OeyBHsHfUGo*$OEWxl zavpR(@W7x&XJ3l36EEVIUIEHL^#-5@Oq#wSEVo4@{x0dEkGXbkhRvgMP&F62uTSW@ zGtT(P&N{4Ehsk1?G2u_wzvsX*x5#SoHLjd~nx55hep)dXc^%k25M^@oA*#if>On#4 z@)?8JprV2}f<&e6)=(&b4+K;TySaL91Kq15^MMD41fx@wW_E$@Y*N+&=78NUEPW!% zz#fm}IvW+0CZ!E%1*3Z@PCtvXk{nno0O5H`Ew{OLeq-2;Qed$)lnHi1k$%!;U{4a; zQ^fi#PP~wrgP;m;D-vMo`E0D(l_h(*H&h6%mvzWWFnM@sn9ht+9u# zz%{hLf!S*wf81MC#M%{=Tq3+dWI?0Ul{ra8dWTE@o)9KBWWFnM_MJTCF^#U6y2^z> z0rAm#8RcApSi7>Z9MClfh;sb~XYoYRYu>+)k_CGkGtIQs)yTap<>eH+sYJB zLD@b*6-8-A<0kVcH3r6+A1Hze41P|N`KHX-w?n82AiX_K|LY#^GS%W7Hq3yr5j9RU zk*7SP75DuK@g)V6a}=-^7eNH$8-ko>ya}oULwb9hzUSKztGOZz&Bn5i<8>9d=l6OE z{i08_Z6B!VIg+_;=NZ_ zzMz5Tm6x!2e1oa9g4uveB>o}Y0|%KLtuzu`2R?cUCPs@aUGp`O_`Bf>=Vq4$Un}*-p1skCVS({L zO%aKIMDO4i2i!JiB6n%YYb-aYEEMmVKN^+c2r+hf!9R z%*hImjkQdC^Fet38liKgP1JLkz3NfUCD4HrMq2@HGEbtrK&4P+>O#Q7r~cz0+{%7i qFT_#`#|{7MnxQylxbM&{C;1y=q*evUa{R#n0000pF7IZ~ebVG7wVRUJ4ZXi@?ZDjy3G%qkX zFEKSnS1wWj0010xMObuGZ)S9NVRB^vL1b@YWgtdra%FdKa%*!SLsK^Byt0e{00K=( zL_t(YiLKVZZ;fFT2k_5r-*S~UC<($wh#!N=AZATjio_t2CStK#`~zY@Vlpt0iY5lJ z5IT#&OeG>FQW8JYMqB#h8qV{iuiLA={qaq1-n{pD&-tG7Jl}K9Q>oQzn#4Bj#rpI< ziZ}SsjB&BR`YQCK-#%=_>a;eA?|6$rJWk{dQJE*BlemQan8tW|&ScvZXccXEhwHf8 zEKz|QIEM+0l^i!hc2LDS4B$cv?7u{-a1XusmZJY3K_kKnHsKjgm&sb{KE8$%__9b6 z>DyYe?Z(Z27E2lRinM=}qFV~GZ5Pg?zf4rcbL zz%CqP_KbQkwE_h7_=BT_l(&dtoG^Q!6|`HppzARub|w3mz;0|Wa6nXi&L|h+OMF6W zlO)sFii0Iz)7XIh1v*9jWI1=>A^H}XO~xIZ676V4bd9z3b+i&_D5e6xM1yP>dpjz` zF=**qmz!&g5X4A<*P=-CIn~nhkmZY^5FP$ifsdlq?@N*7)W_!fX&PC*RSe;CKBGY) zh?Pcxr_8pXPP`CPG}qH|P!nhV9!D^qGaA8FF;8;Z%ORabL`nY_Jp( z*o@nFlo#p;-x@p+P4=tBjfQ(Pd2n=$?ihPSM>Ate4c00000NkvXXu0mjf!j?~$ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/remove_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/remove_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..b69a612b704d34e89207fb4070e7604bdccfd711 GIT binary patch literal 1131 zcmV-x1eE)UP)pF7IZ~ebVG7wVRUJ4ZXi@?ZDjy3G%qkX zFEKSnS1wWj0010xMObuGZ)S9NVRB^vL1b@YWgtdra%FdKa%*!SLsK^Byt0e{00YBG zL_t(YiLI8;Ya~S!$KR{2np7n-?IgS49=rw7&B2TJFu0n;iDr^uKs>m3^dO>pT0Dyv ze;|SfZ;K$p4oN1Fm?2T-AMk1xmc^5@LN+^Accyx~s_S`3&oGHQv&pPqsMD+W{qSDb zt7;@7IFBlo%9UcV_@ejz82|u8jGc3Ln$6~)=gG%mptZHNf^%-pTKk%{_NsGkl86cb z0E{sk1VLK}aW@EpUy11Ft*x#2!l2dF)ul8|Kk9TkGf9$U*4o5-?*O2ifQ+$#b1tQn zLMe4`Y;5eCjg5^T&IMXtUgiMsS*O#vuC-3AwH*KeM8wA#P;S6Em!(o^qF5~6&a&*| z?d|PkAgEfcim|b=@7nG5n_BA!06>EP1ArKY;iYo9ydMO?d-ZzVbmOdlvk>Cb9CC<= z=Z17EMnuwDAGX`=SDkZT^v8RkTCMhmG3L6~`a$l0ZpaxPXsr*AkB`@Cwc6XKKnn{C zGRv|XTI&Q(KK3Y(9t;3LYkh33{jgH0lzN~-p>WL@Gh?ka7irf(5+XY15@XDC7>4sb zkoSJh7?bsHCZds6zmg=eS(aS`0KnPV*=MDc-yag~x?L-kN?a-R8vxuVB1S|*+nJwG4**w;F)u|?WOH!l zoGVKyXSnx1%&!$sL@0zPNh!B>c6Q#sNHtwmtJQCfF*R##oO=rI{RDer=Kmzl7>g0n z0)Rq9a?V9blFU`B)eRW2b03Zm0 zU!;`cY{Dq3UrH&?7~2EL2Ucs{R7&0BoJ%@8bt8y~NC=^nQU__8?)N~gRx1)hd>w}2 zM0fAgaNy**kU+!;%7qZ) zVHnEs@$p*#aC38W(+vf6wX(AE&Z9?^*FzwzgtU7OGQL{JOp2!dw4UQY*k4F&aU xet!Nr&iM;OR0IHEjQtbG@tszyb^kp1{{ldXHip*t8=U|E002ovPDHLkV1kyq{sI61 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/right_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/right_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..1ce563e4838b60398255152e74bacc767bbba750 GIT binary patch literal 2300 zcmb7G4Nw%<9ltpENl;Ou)rc(XC*t0I+;PWlya2f)-l0bjh=R$0d%N$r&3){$yLg9* zZNzb^rU|B6ZH=NqgS9r)LDoHC5e(tCR2$ON24a1n743Tv_lfRGrRlt zz2E!&fB%p7pIw)iJ3nsJsu3><6IIEwT^RIdfi z(hMR+&OF2_$^c2zn=plO}?ujB^o+Ak8>o#z_N4kPKmB3^WqCP-so&-Aumi z>4+`(WkEfvDls@73)0R|gTI9ZTXK@1=o zBkK|?R0|4~_PgMhqO<`e5+)chJj6;ksV6j-`hYwa#Yq*iug^Ho;lKy{AfPG`OGdGh zM^r_{BmMw&bol`TFtko*)W)D%{Qjs3Ma^Cg-G~HaP_$B5DFHkmC}M@of$Zf_<}}S4 ziLuInRYkc_6nz7U${Uc3SgpwHB|?A~gG$PMaA0FqU_mK@A~7NzBaMX=#ZV+;Fs2ge z3_;8LIrMWR7utfEhpp<$@b zaR0o+YR!{Hx8Q>dO8)$(5J$GvMA9Y`M(N2uxlSkJ2q-EW;DEzsL1Ae0g1|E%9T0Ak z;xSV?Nn;#mG-K&3X~fbEZWG}mc;Mz-1N&_vSD_Vvw!i-@@FE8}zL!TEIKoA{X^bRc zfx3awg}KaWZj9ng>9mPA@@AeMV0%Uu;BjPq_p@rMc*tntfRS?305hk%2#hltDX7W~ zM--a|fRQ#qQmyFw>WHxm3e0e25o)NzjZ})t3g% zZ~d!d-zJbSytiXv*niOLnY3y8!P(;s(j>>(nd4&HtE$j=w07s3rvGGk3NF=UcG-WO zH#YF+P1E1^e7;!B!(vC~A4>V`Z%r43@-yL;|GoX;?_MAM=+)+{l^xeDM~{5oyuDlU zhrfF9(OZ|!{4-9Pl+m4V#L-))w%Kk_PqyUF4KFPb z6S~xc)fKmgCWSi>W?H7Sy;0PfasC*VGW-Vl%J`5u@wxGyVJF@hv*p~K2Hnz^6Me^m zp@v~SuQlI|FZoMS<4E*kV%?RgFD*^=?pzs4E&XHM6Sc#R_c)eG@qc3PIkW5PtCM>7 z|K5>!O81L!@}dLB+gCO4zbz|i2|S+?e`h0VZZhL!ub>-cX7u1}DcV?VEe{T=@OFZTn zUi@bEK9ePD)f=yfxnFF2d+~L_@#)HmAD@Wbd*}3R(wLC8W8%h_&Ts9k?l^Z^wm028 z*ZYT41&2F*6IOpYeP8jtCi|()?K@A(Pm^&YKHQSKWA6IDA8(vmI_kYrV`WZtm0B(i zX-=LT)2KhmHg`KE43}4>)X_mMT}R!BMpqp!@63Bf7;euIyPy;#5(fZF}o(5uxab)M(>YrLx^&QNqNA&;z literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/right_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/right_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..b990d329762e6eb8d7a115bf07e7167144f9da15 GIT binary patch literal 2788 zcmb7G3se(V8XgrD5m;C~l=29}lpYXGGLwXmjHXHmH30({siG^|VKRXskBONO9%8X> zR%4~;S`b^rTGq&-2U}$kmGY?dfGvU#9-{bI*CJIs+DZZO)t&IF?y--Zb7tn=x!?W% z@Ba6@|Cz1vv5VbYd|Utka8t--D(3CuxSgjl&+_Oct;}nNQNEG}0Qb|5ds5+CcV7UQ z+D9fNniG{vP@K|pFg2A-a5D8q1`PlU7G@eTTuYe2WFmz$NT3Hb^$nR=apMl&VQ2rtUC9iO=nI07+iB~XMT zAeg9(2O}vH0fupeY#b5rz;H1K5yE1gU>?YWk#H^?&PDia7(rnn$`^xU7sNy}sWqrd z_V!pTrYC_?&1NIY3X5=Cq*s-J$pcF~aOXvta zVKCDS7MZ{rQzCuA83u8N?k zbQ4ZQSs0mbI96jsBTWQmrc4PGr5oR<_;JZ#WF#1}f;6b940_HBa6*Qe2?@l5c?cU8 zu@ON6kB9OQlrNYIi%=LIg(@jEsmXd3lplujMK3`a!>BPc_Pby;j%p~A9%GhE>ai4p zYc!-l;6xJ9NJ>YUn81uW{)^ugk&*ExN<-?H0a~?K3M!%^g@{-vWb-)4h+L%-RTyY9 zX21!BOad{f;gF;n4Z}4eLZgA%I1#R96UhP%TZ|)Owk8?TsF@xtf`#MrWfY$7Fo0wJ z=vh!xIK%OaJdFS&!o)bAjjQ>|>~LIwu*EQASD{8A=D`}KnT(IK#hFOvIAXdNSskj> z3}dnYW2S_Kv3X${%yE{~Yz)W4*L_QRMD%1zvS8fU-(!`@Knr@LNK+J3ptj;byT6z4dMRpUX6^sP_f40Oc``E zC+aWLnW*4|fuS}r^_i!9`V#;+eX5W}B*?cG?rNcYqh>eUINRD))7PSDOSI>d9CY#7 zI%`F|fAmKlg`y7;w)2Hjml;8CITh{*ZMDq|*b?n0+8F<)`{ysQ=U{>C^fMKA*oV zy8KT&gI@o;O0!B!R)hiP5wJkD1-X6laI@rGP4T&2Zbw?xgC~=fadCX$kwCGtQtDh@ z6$=2)f$H$-U6uxKdiu0!E)gD2cMzAiY}>Z&XmF~@w6nK=`18Jj$J?Z~bf96)M%JP~ zZ@y`q9W^)q)|bfq`Nfu>{`DlKbvRgm#wTz;B@a%PI=cjR-W_<{-?;l+%|Q1)(}^6O zvaM2T8#tCbdFWw;bD*nd^>#9Vrq|qvwwf}*Wl8S zlZo@ZezujS?x5Fn&6GO_HhO=2;Lc6hwW&Iy^U4u{vhs;rh}|7Btf|X6vGh1MfEF`>#Kfe(fLEE?hm=m$UkWDQe0h zHz2JrnrI(-Mw6fHx+rLgnNw`ro&K$l#tTBp0`>E-m5t-y33(Y2&~o(xraZ;9&FF^yl}s*!_)JdAAT@?mvw!ZxdJja0>FW?vU)}_ zx4KD|@-YZa0=i4Smw+CdF~s$2>UMAM!n+}sc2E4Clrb;n?bR*0$GTI0xqa5AA*&Tj z%qvY@s(rSu`uY1y*KmrGq-ToO`PH}Ugw=V-QMYcofNp&TyC&Tjs-LoP+oi)v-Ah9y z0l{UlCD~OSX|=@%?qGB5!bZ7PKW%dv9;%-s(@9d+Ls758ORvcs`h8P%4#E ztvg;jI&XcfcEf4!S%DC>_@CZ*@t*#7T8BTlC5ox6tgPv5s@rFHJs==A4;gfVn4i>w ni*NfiRZ~}w|Cq6G@aM@a@BBU2cdrd_{D&%{Vr7S=?{4}p7K1LJ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/run_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/run_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..4027d0278b165a835f10332c9d87dd1241a3c952 GIT binary patch literal 864 zcmV-m1E2hfP)pF7IZ~ebVG7wVRUJ4ZXi@?ZDjy3G%qkX zFEKSnS1wWj0010xMObuGZ)S9NVRB^vL1b@YWgtdra%FdKa%*!SLsK^Byt0e{00Ov4 zL_t(YiKW)hisT=WTSm zT|>%xyos06{XJa5)nSZV1N0-9NWZtR7AumjgWI@_3pkg+tJ3Hb(Jp+0Etto{bbXR- zlcQ}c#}ypGiD7|S_#XQ)iwDKQHOU9GF^WkXN{%fFG=h`ZiCfA0r2uMx4UFLz>@LBY zJuiQUPjKToL8N!P$#xt+mdX-nC%#B8mWB;cgY5MnFt~}&u=lAVrLK)Xuu;^cjHHA6 zcwN+Nws2r6>83NUV>|BVh{i>C^@6O%uh@pK@VDU6=zs_t$)Qd7fQ8geV6I}YOmJle zNAWK9;bL;)MGGmefj-9j8R!*3##!}rly&UjG*5%3$-!i7ibL{)h#}Kd)TG0c^z&>8$MB6Vb6R^z!Kc$c#vBH3Kct zx*e=Cm?t$E#X%9(s|ip7Y>I}s+rnSCqko-hvRn}IOKcXCy9CLB+{T|xToa?dy+lN{ zXCLEtQIic~Ee*(E7_4Vm%=({1O2!I< zEb}RfVL;&J@G3E*?lAb581JrtX9G8yDf?8mRHUnNG+ zG3+TpY7v#P4~NC5?}#RuD?poKkgiPEX?%+_wZr-W5v$-sG3qyq0_Sb}NRTmi)>L{{ ql|ewIY!DxitJD3A_<+1VjPZY?7RN;YXZMo;0000pF7IZ~ebVG7wVRUJ4ZXi@?ZDjy3G%qkX zFEKSnS1wWj0010xMObuGZ)S9NVRB^vL1b@YWgtdra%FdKa%*!SLsK^Byt0e{00f^& zL_t(YiItYkZyQAvz~9Wy*t_e^X46=ue4VNa8i^BEP#sE>5S2KMF)awuq6!HlJ_MDJ zD$a-tABRdDIDk+k4kf9Z1cagl+WrCMNGg>cK_KPB9&dKXGqdwJ)DBJ?C+3}2^Y*>p zym|B98-j??kCaNKLqQNcX{{Xu03d|K#+chnOG|(DV^8)1RjbvUF=k9_eL`z})EF~_ zh&ccNN~v}nr_MRQ<2cT*i1_ou!b1GNK{GQmQ%b21k|Y_CQf69fX{|K?&@mvCQin0- zx~|JT&%2w?=P%W2weR}^O;1lV0QfXXlCwexskKf300<#uHwV~uz!-A}1_la25d4s3 z*@ugZi?SzZa&nUA^ZBpq_4h=2b#+c8$_1mCwxqLEB)3ZW|^|pTk_wqpqAq)|>k7*ws2qD(C zwzjI}a{0^-(8R=qn`PMrA%yHW?-&L_pbi{3upWltAY;ty14sY>gb-U=>-S5g(!e$- zm&+Yb({w~@opz235rK0a_`ZMr;K73@qA0ppEEfNWqG*tFUf2sr2qDH8nWpLCFbv1H zLDt%_G)=Sn4Jf4!B5q#3e7RAp)xIqh3KLNjyy=97Y2Wu>mr_n7Niry-=wKg-xM6TsNC_c|QYx5IYLzior<4vMqUjef zIy%atD0)RH^;VK3N8&h+t+m|{XgA%>IF5g(%gf7uF~;sN#@rrt@xWT8QaM>D6n<(n z8lSDLtvxD)*g!kGLwbl?q4ppnwr<79fq-i?Y zY&NMWT|&s0aU8$YY&N%y zF|rNYbCh$={V)t&-}k=*fQ#3zUE5JAJs&5hPMvzS)oQ()rs-iRr8dS$Yi$NQA191+ z?s}f*c%HYK%jLefdiCnUZvOUsZcR;11%!|nvMhT}YkkBR6ComRN2nNMo1F7i&iRVt zI7_p$v%A*EzMyUyA0K~=G4=!^1^@t*(ncJ|w{P6I@pnJ={{kKuj-1|@UmpMf002ov JPDHLkV1f{FWy=5n literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/skills_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/skills_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..660157ecfb91031a4b2ac3cbc0559a9482688415 GIT binary patch literal 863 zcmV-l1EBngP)8IJA;U@ z2RVd0bH0VOc@-DtIP(Zj;u!Al0A0rS_zFMW)=EUo8V^Op*@*ZpBDNypT0~rlh(B^% z$+fMBSdEB}BjV^RdxIIFdjW6b2-a~c*9Vy7e28e~OSq0@oaq`I_JF*C4=~1`9gx6{ z9Fc1h{A&JxAFp+db{Rd74{;4UjUj1xqXFKB13hPkxCbxcY#-2r_$HZbHw;=Pix}nq zt#sx<&)LPa`2;R79lF<*oOD4Z2{OWuIFHY8DV^HLGp){F>A-TA(Zl#Q6{6$aMjAYg zw;IRx<6S(J?7GYb$?OC!R7OuKRWtE#kcIUAlxf+-8%jRq*;aRgyVCYQp*x0~m8I## zFDN%aErM3om6G0<`z_c&NyB3m=%CW^H+w*8j>dKq+{!2&sm5C{O0Mq1(onfl_BV7} zkg9wTck}=qPW|YduLTn6%(#ZGE#VeKt{+OUt}Hb`OoL4|^-!sp%^WRAOMi?PlX;bU z@v_oOHGf@Zo5}9RP)X>|3EBl2=ln8`5rsl{*+ zUn@!9Nv~>;%qweoemiX(#+TL6_O3gnbos4ZUsFC4^U7-K43&udj(6&23v^MrQfkkv zrf2iYX6lTTl3&IzeL(P$a#0?!hlfWa>$n?l;`4T+?{V^;-3xKAatW{ETz6yEn}HI7 p?L7i5m=W&V0sW`a_c-}qq?PV&X5KfyH#_g0 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/theme_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/theme_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..4a8b9bb2c368c13af68d773d42aca62f5e648186 GIT binary patch literal 978 zcmV;@119syotHBsFAiv(k`qhY5W4|-j*t8bs=~|5H~K|xbYjfQE;W8 zAfixE6gL*_QpL-{osA$$s;y0{ZLL;KTXQ)s=8Spr&8}Ns5B*y{Vikp(RjNkD+PT-?7-jfFUAbJ=tU>2*mn%}i5n~siP z2tVLuytQ3JUA%&)aScli#l5I17{LUN;n{R-OGCqW2S;%!y>A+b#yqy*-G)!_NYhxS z<=sno2p3vLBFAtd?&g18uZSaM598IX5FJg}m$&eC2n#rwYctrdBt6H0p56hD=`HVr6=bZ0vA ze~gaw@TyItiK513E!XiHEtu_Mr;@6@YNn%P+e(h%L{?F*C^72hyscv`<;UA~)Z8$d z3Knxdp5N;^RvT-JX|Tp|6Ls)UdQ*)?3M}A3%;8>qnTjh-;ArjEI8~p)sZ-Vj&`a&2cIs_O|xSrR=%Xbs-|Yh=@HM{Gzn_ zk@RFxX(K0Xq%%q)4CVLh1c+0Ropf-ig%SJd(r0Wq94@)pG*`_q;YJ%_^v898jC8Yi4I{g*YVzM3#+|usR5W$=PdIj3a*}j=d|-v_{>vUDfq+P>(!X&kFgS zny&YLzxQ25%#25o)2B~=qtR%b2q7E>03sTD@88?l*!bj8?CD`d7cN|=dGEW%f03afo1;7=6lu|dF%|new zQ)Gor@a++3$#ufH%D4Bom=bmq(%Eu~!F z+1Yv8IhXIR2N6X|sZU0u(ch+0&4&*k?t1T!GPB=bHz}p=bUOddvaGwgxp_xa-Yw>N zzA%eqLgbvg#mqqn5ep$=0PMZLMMPqTK6&qLp6ADsBw4y&qYy$j&+~G>!L$e=VrC9i zO}HX853{k>y0R=60YIEOb?S(7?&LwyRE{_y#0jnS;~|7Rgpg~kj|d@7gb>^;n@LpO z`)9h{?l)zl(O9t7wnGTz0XzT@oO6e?)@R~4{;&di(m59c@R(|xeGZo1`ssrah&~S?9Le*%RuqMuRRSS|7!#30)ff|!cDw!WBuRd9{P^+b zn$6~NyWM`r7*l6vFf)uX^>(}cuOvxUDxDv-+wBi(wVLKHXFw29A%sX}Q50KJ%ApXV zT`f&vjA0?f%WG?E|EvtQmX?-Y(pvx3T3ZJIW6Y>5%NMU+z4}q5^Uk?*=Uz6(yj2v1 zU}mnC?ib_n_+4@B+O_{kDYvDR8uxZv1Yl=08ofIm`o_k_#{fPApa3XlzO}x-{?W8f znxm-|zo;Z*T8~JkO6=Yn}Jr zh7d|T_&AYDDQ%32j4@laTJ4RC7cX9(h4;|s*7@`28$|S-vMir<&OPJ3Z!xo~A}pko zUnr%vlv3BDDB4(ET`dm6dMMGfEG;d4OGCGoaoiEyyyVhkk=2<8qLI%ke}u9fPy%HOYoV|D<9ONh`^iCSq2+n^IL#h zNGp)QjDpM@t{{)2c{F7bGBLzJ0xwWlB;@t@WF}-ryLcHmR;O_k>4GSEW^}S@5V6~) zBNkBth(T+_I8sj`$+VU<5;UbxLMVbv#))K{)L{h45JpBvBasV*)+FA^WLqDL*n(eX z)U7Cf2FHWJpf;$}ijoT_X`03f3a2OxA}~4Mr?4T+CnxkUSb@w*f?p9tAEGj{4snrU zMxoMf7rg!`txt}G2?h)gv3{J?5~@pGK%R@@{EH+{mvNrMfd_bjPmv*(jAH$6Q4wXg z_z%?4<=YIv(AsQK8@+1rdZQ*}C3P`$BNC8a(Q;0{AK=+Q78gkzNL>tNCaB){8H)s1 zMU-+x(bJQt={=GWiv>xXCHQzTD384b4y>#K%qT@rBu1DpQlCRn3`H_J{dmH}5JWfB zCh~$azc;APz!19Ips-+gR$>1W%yW!Wl)Nl-SMahffct$e6p03rv4|c~f`*|w-L3QK z7Rz)=bP680AZJgVf~2Qfj3jL|Vw9Hbl54Xu={{LueH=))no$@Utsw9Wp!EjY;7G<; zqh5~zo!*JjEO25*9nhO}tj=fvT+e>1$SqO}K;7Sc7I=|^9Dm8%69!J)5E32xChm6K#Bkyn|1B_%L4{+)!jMno;Os``J z6YC@mCYDl*zN?OyG(mN* zQPmY(?LyrN!T+ACuC-e_Ru3GuL3J4Izwjg4!GRA_ORzr!VkMu|K4x^_?pf{6u6w&`s9Bo$s_yC5{Zn_fynZo0ysdwQBmTX>z{8*4WX8Rb;@5}` zgR(ErY@VS))$X-voAChK(OC)*QqJ0CvBclP}vBu%HxTEccXO8SkIdFLR z=+yY7?qvv3}LB%NWOny-8Dl%wP47h+Sd5}+)JF@5if<31Lf4(}THRwGn{y^}=icvr|M&m* zyMK1%yxF4|6BqyhjM9dy_4Ip!_ZdEn{@)cbw~l`KI>MKb0N{7r`wYqt_6r1nq3!0V z#nfWmTm&O*eAGx7aDKAQL8Ad+#;jxqidk@qWx(Uib_M5d)wdj$*{I+|hw4C`Lxsni z!&9C3!qjp~v270f*HCp)3kcm^UD6 zu`ZIOBAhrYlrQFCkVwdq$oP;LlnF&4EFlO<1fWC!!8{N`KrsT#SbaYZ9nEPpA$s-O zeX-~-1t*@O9Ed=Wl$69zg876qP5{YdG65(Q2!%Wv!6Q@b6q?MllT-Q`)HsPb%?`>; z*jZji)IcOq3J$HbHwBwxfYwg-m5DBxAQ^QCAU^0#sRwAp25^o9r?n@z5fk86+=kmJ zlEy*(=G#QoRzy*4oBodq$ zu1Tb2PVr{rKvYf~r3hyfL0J0_DzaZPOQmAH5pA{`i6oNy92{4p6t3V1K_SEgr94O! zB@`k;2!TbxpcDbYUZ{>RnoTJ$gTi720$+gAhB2ZP`lnzchL{Ma4W-jH+t4^%;IPMW zSOY~wRD_jq(t&Ap@bmLpl`7Inn9Npsfz;1dva}kN7?O#_JRu+Ik*m`oT02Rhb`005 z6&$)We6!hzh)}Uf8j7Mk7^5vEhD1`H43?O9B1nuHK?y8|VPXG%HGw5~4dC71dl!rZ zMsxgE9%?Y4m{@A!g$i+$7aA&pcm@+H<4MFuOa#MHi4>Fdv(0y!>FbDEpJ(-|GSZAv zi3u_oFfk7lVj`Xx6d8C1kyyxsjZy;&OQd3x5%ikA$45xGnWRrRrSBRo#FzJttY%h^ zbr2NuUI_&U^Lha{a{8vtFR900irlw9DITXu|G*`^(MiHYC816{ERL?-pLkI4d(ufX z@sEZ7wS(+c^fKWuc=rDn-d7SV9<|5ebZ-@Kyr~GhU8wg!1pj+hJ!{W(tbRD%2ED_9 z{!4!hba32GQ#ctLFq4>u!n58NS@9uLXtusvPol>Y&V=s9@8+ z`xlEYqy+uL??CgGd)mW4KI}UDxUx@q{m;9D1n9X?wU}aKFEYS5ZA>u~F&NG$!%gfI`y`qF+xNT3x z_<1NlNKb3^Y2ZlPs*=3=43hsv-rR`FNj~2Nju3nO>m%hDYc|G%Cd=|jroIE!g2qyp_ zJm~wbIi>YHb=tqL)qd^?+*$o~Siqr%*Vvi20@#@ujfEEXu^Hvna~?3`b5qX7i@pS| zcD#4TRszS>&DcEkKzeD-vVayS#aS!;TjR;n+! z^J-yHQRD5zu8(VLYu#y^Kk9f(8D5+xjM(LWs`Wur#I7}Y^?yIND0(FD6Z6bX3K7)S z)vaz)W`1^3r1PiKI+jyZ#bvNJUAuNI{aa^iPWJZe8yaK$+hdf&_cn^ph!lnRh2sYz zH{qwtV|Z0lnqwom_~+0ga}qme`=|N(&eyTQNd@agI@oes3jhcN-7l|rbZ@wXsad~C z?^(3FVRBXbInS~=N5Ssm$Tv=)oXXvsDjr=wfBt;f4@~(6d+FZdF_otESvzJ%+$=5QnvRve}%*Q1$ZjWD0baeExv6{PPx9pa+ zn6J5BeP#9G4O0v1LNxbl^qiH7w|Vz)asfo0m|+m zpYML^+PxMWd4)G_ZBc--{;uH6?gYkXb)@O&-LZD4pDbAirWgl zihA>mc0*cJ**Qt-wv6hT9RP4CaN=lf<9H2OutT)h%7;&*HouI{u?0-)GR{yogeH)?>rArZCT$o%6}M zCl+&Ik))=4Plfr8wPj%)^VQ`+;~5_x4Z?2y+TERo=)YQ9P*4!JKcs5QmpArykDIq< zrK?3%Tbk!DZMz#15|Rex5-n|wyB6+LGgnVP)Y;s4aYtRHkh8i{b&6>LYwo-fcJC9& zlwz~lNQq~?vRazn{di+cJ9fECdT=9!Z0*R;&!5$~;hF#CngyBT#*uWY0HD>(Q+t%} GfA}B%<0Qra literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_add.png b/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_add.png deleted file mode 100644 index dfaabb5e2c2f77b84aa60c6b7331f074505ac6b0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2273 zcmb_e3v3f*9KSI#$9Oo9Fd!Qo2Pz=fd$xByS0=QBb<#0Mb@M^wdiS-fYkTGH)^?K+ z#AS*&C37OrC4(%A;G)7nT?BaqjAM~8oDXCg$V>>3DFnyEfM2_=jyD>cdw$>Ve*fS9 z|NXx2>x#mHxx>@Ory&S3+@5DEg7@_3nVJHx6E9pB;cZAT?^z8&hCUQMlaO^A#v(|{ zPOq~>FLBHhB*kwKWyJ*y5q}V(5hOb&5)`E}prbC}@dhkdPs<(*^~x5k*ytb~K`SWr z=2fa-L1lqcsw|VtGL|zF&5j6=zz=j0jre^5O^8^q7_R`Iqs;_{#vpo`1)CKOh?Y1C zQLCZ?)Mzl_62;OeXEsnK(oC~6P@1GTg5(H_!AVLWO#)*^<39{WQ)RbMWSbL@1>Y=K zsjdeFf(VDhhA?ALR1ZO!&1Qn637W3r31(T}D9R zyvS0x#IqdkVr3pTag32+NY2c$rvC43ic}soK=k{*xgaYNJDBF?g`%mRi6 zG7tI_zg0LZ7~w(nd-mT8kC#L$6$2gs*H!}i@2T9MC;K$sl*+Bs@Bd1Lh%Tso-Xd82n1l2RJheNWL?{jAW7|Z+bkzv)A-KbK*tm5)q85r z^3^9-P5iu6Gk)eho$^N=z`}C^8A3ncjo~{p6qfh?*To4==sq2|cqS_4?*PU)e`@KhoT(j>=VRRiT!)r?$TP;OnROj8WB- zcK75I=bvc#?v+#gfyMLck}C>7qBBQiNr&5(4LhG(_QjW7`FnFSwXPmw;rHN^l5I&d zma&d$V^;ESN#mr|*z%$`rr1CBum7pDa~JDaS+J$9X{4>HcVmIWc8TlCnvh>RrS`qn zO~?_S>BZ2?mdnE0C4*8n28uUzbZouaP1|dO$6m5$9-3&Ahkf09T1S>#V-C3fDA$y? z+wvRJZ1Y2*rU@x~vwrCvS2HKOtLtF-iL~F_$4V&~8QtxX>}x0XIU1T*cWmGO^O&v) znJAX?+8TSAV~exs!sQo`ldVtIpX=G&oPvJ7+fZluc0=#glGV*u-dy`>D{`?iYZ*C= zOZukXgUo21J*{~}>i+cOJJ+_kBlU+iKj(iqqk2-9Gm!^Z;hpP}k;c(YXO2ETGiA+R z3o|awY^h24@zEXU5u~-d_OyOwP$X^JwngcK&zi>XN=AIgmtH*c*>7y>AY>`B{`7*MjtN;K2 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_close.png b/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_close.png deleted file mode 100644 index c534c30097b038fe7d5b7b5ca85ae88f843c7d08..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1798 zcmb7FTWB0r7#^XOCK`}hs5CL1Ohj7k%$&LG&c&>4vYU3dcGIxg(o{h_J9Bn-*x5Pb z%xreEeF-AoPzY8iiP9=GQcA54qEr-HrG1Fjil~U_Q(pv&6cSKGu%6kQX`5bL=5pqo z?|lFFU(UZTkB{x@>E6^$QB+SVnaGg$ec`?CZt~o`d=-*cmzzA`Q`9~8hxc97{96xD z)Y{8db~2bu@6ioh=Aemlh^v)df~KgU?KKw~B^1y(RIr>FbLEpW3~iY)W`86N(rz3T ztz_Lp6ZNsIQ7;*q$!vd|9;)etpo{`Y*UGlz>$Mou;MK`EoaPz20SQVmW;irRPo~G| zIQ9@7;i9Y|$Re$1oDc{wy5Nn>9*E5NoEnDO(#uS6V z)p@>Jt#Va~!(M?GG)?1y$crLN5UfA#1hB?B{$QISfqcWW+`z&P9Wufkt^_fLC~dk> zc006=-wG267+-@fFK{4qsR1;N4$iH3cEh-7@W@7G?z5mpdl>V04PO(F(|_Xg@pcB0htBT=5JvIz?m-hTgb(+(R(HUKV4!ov87) zWI7(Fx9qnZ6IcDME8r*r0~BLKAPOu{SP5hWphr|4sE-2j1Wjlfn^u1MMyRYu$R%6@ zB?V)`0NxgC8hRdkWk}q$%CLZV*C{Y`Cy06++t?$9i8^WJd@3Fv_i)~_$%3ERHA1IG z<55A2Mp=;)8gkQVJ>~cTbPSYA#26A9&azBhg&Go&f>m#T8(5yy26KDsF@J{`dl^ER&=a3oV3Ak*y+FI zqtn5WL#RE{pTGLy<9A7K|2&l#&Z@7SpIGcUN8j6rA3Qy?Vg1wAi;paQ@!_$<8+HsF z+PmZ7fumpVE-kKK(xjQ$bG?6m`rAK$QTrC=zP<3m`4hYM{jMFd`$yhhhTN}vHlNAN z){|Q!4;_B*Qt!@9>!_2LyQx=&rM{Qmc>R}G-v9CV32MfgKYiuk=yyHb!qDLHMRedv z`{$3I`fP6FvHHcifi)MGFVy?Hp74_ItnDitnWtukGT?(#KMntRsnYw{8s}hX%fi{% kwj<1!?pfuJtKS6Ftn%jb-1lAm;XhSsbS!adBorXm!31pK3PSh(tMKetQwz`k3DIBo{Ty(t@cj4HF9P8RCZakS2a()_@ z+@aY3kIfF}t=TC{x4CWiv;B308mQn1vGq#X3ype;YuGhtJMQK=wgHKzQrtl7ke$el zuxS!tHknX>1!a*{^#oJ|U6i-7q5xH1PUZSlB_E7*%diiI7lUm_6+OXLcsJHwYa zpsCH}IzCqAQmJ%Ygi&UihS5sMs^~C3<70jlhol-5XUXkfpB!k zAe+sk6{sr;5EHOLHMi&H5NcTzquA{Vo@9a&?^)i$13O=kY&XNxFG956EzVivSK+XDIrI(+SVQp zT)G@ldAZe?l}#+;;1Un^m1^eQT8x(SIB)lh&3iZplE&>(*$ z>LHrGI&lr@7-AIz=%@nF961SSF%hkVY|B^@v8~~D;FlAZjU>HcTeJV3cq=7V33)|K z_g0?!@1b0uCYu~rgmU@v`@cfr;|;Z`EqX*CUIdEj~Ai7666drH;(@_z4^~O)_ytn#fin<&$qsP^yksvQpbP%V`1Rf_VZ`HIq`ni z?mhb!7c%D;*Uo>|?cCej#hm@&_kHl3eo|iOd--UV`?~u5tuGxv_{PQ8UR?i3X47sn zZ%%&l=!NY!Sf^fn(>;Cm_AUK`+8Jio)EZ_lJfM~azTJPi`q;)v@9@&nPI7S`yztE4 R{LS$(o6QWHM+TqR^EcG+g&hC@ diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_down.png b/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_down.png deleted file mode 100644 index 99441b8e0b17caad32ce466214a4bb227350a699..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1903 zcmb_dONbmr817YA)|H6F91<@!or8+jbX9jxzsMwRdS7@!-LW;NupAoFoRkC^-tjpx`ZN^}O6{HV?(7AJtV~{r~s> z_5D@vHyfu8EIzv^Nz#G(N_ACypDvz-dGUVkkH4_^Jdv!N$t3B?XNqS|`uLN>k~IHi z*jmrm{a0PWqY|dP%}RqP5ok#|c4ClVvcYn>%{pORQGWaC8$}LjMLAvep`UoH8?J1p zY;C*IBHJ6pp~{Kl^09#{3`8u)@*wKPnLDT`BfG9>7u~8Nk0AL*MOi8w%Ikhp_IS$V za>)b)8JcW4C1gTJGhUW8h%6OaD$)T&E;L=;ktdfTyrnd7SF6htU*fN#bn`rMRkh#m zm->2%ryUhJj-x_N)ifXwARERx9)LJII<-(`8A-z=4|yyX7IB+z<`qRS9fuGlGqZ6v zNs~yJI>3pFO0WoN1f*n!OE%Nq$T=k{>#>N%c_y%EhE2LW=UJEE$MkIYE(apDzCZJ^ zFPA8qxybU`mIz~#kbTivYnU)~m1TT0C9Jk3XdW%1Nn9^wIOl1L^WJo!np4WM=gBXe z4r9vu*^9g2tcr71Q8cI_04<=y7J_cscA@n1wXU1_pK@TEuK?M0b!w9CJFq%E@LS zfMWi*7APme#y|8N9oodO+ki3)1FRWsU}Itdi&_xc79=PjQ){oKp(sb(+ikUAMTJF6 z(~%8z9keObfz1pZIBlB&&Co2Wi`%xeLi8gYxhr8NR(Lomqc!%{q}2=Mk#t;4ijt@( zq|gGR%A`BoCm)aGc{0D>Wy0tKR5JFS@gVQxlr42c?jE8+^?uYdy!Bw>Hg*_d76T}- zpjbnr3>-r&f?*icV7kVr&8C6hOWbhF;zm=={(It+l#nitJ521Ys`B4Mc{ELqIqnJN z-tzmuLQ#tib*wFQuk1!+yEb33h@&pCqZiHDQ6he3hY^cKmQr!lT(u8eZ!| z{lT@hvy0!tg&)2kzuvj{;hoP8?fkfN9{lp&#dn)m9=r6^@`bnMcb@+`yY0>O&)xX0 zHvIGE>o=~?*{he242~aMs42fUUTIvFsu#{)_OH!<4{rZ-_@na&Z=FjX&%7%?-@3GX Qq&O1mwMO;xlW*?)4IT?w2mk;8 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_export.png b/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_export.png deleted file mode 100644 index 9d7c511d2c87e3a2dd82bdf013b83ef42c734685..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1934 zcmb_dO>Epm6n2WJ+Mq%O7uriL2O%Pu^^E`4Hd)eSH#7@uh_)*dqzV|%jCW0TJ;wHC zH$fo&4pgWpq8tEms1OKIK@SL!C@L+Ss=^U*;Kl`sQ!9bE!g&AK()0&}C6C85-@Ny| zH{Y8%y1aB~&*c6|Ns{)I7fV&~-J89;c8d1EZ+~L(*&QuDo=DOycVzE`^v=6?O480R zg4$}jT6x4Jyp_Y0do0&&MFK5JGqc?YlQovg9;*joLAm(VSw#+LL0K^?uo4wnBUs#w z+2PHl8rfVU4pn9!kY~ECFwkNtmb4t$Bfg3?IS$W_%& zr<3dGIUd(l4$<)w7i6tZsqBP*4oLR&kZ>I%CFztuXibiI` zWRND2Ftv*#73E+SQV&SU2p6^EX3se#Dr>S93)4hk(Fhwgc*>Iozl!P6^koi2YAcnI zk8QcMS|b-py09+77$js{bW+=hm|A5CZ^wi!tP7e`Su~Mbj2TXOT;ses+^FRtWw}_C z?^y{#$~(#Q7@U=G$_k1GH3VQD=&**MYuYZf?}eg;eQ1T#z~2~$+5n-Nrn`pen&xFt zAsC8Nd|faluFvBZ7U2dhTxV(&))je_M7PMBJQj`xJAHh-Tr4if+z*;!BB>slm&*%9 z3pthrv>fWutyJ7{n4~x)tXwK6A~m@npswX$+p=v4eABQ1@9RtVm48X9#fM=QnXcSS~vvr)ewV|~~<3N-nZjM{c zSW#ioU>d~+#-fZI3K%mq;1SOPG;dkH&LGwZ%S7MPk-HcqVuv>dWptQ5Gw3w~xhEYL zldL2P3dyv`R}3J zm?p0bW!v)mzd}*71GTR$^`Elq&5a$tViS8q;zZB7qpL*xj4mSh&jop7=$dy6yMX6E9{rW_e+$bZY*o Gm;M6umTA`j diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_home.png b/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_home.png deleted file mode 100644 index a4a74bab595dd6dd2e4683d912a457fcaeb365dd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1496 zcmbVMONbmr7;Xs(ny?a+gA#lcy#x}qyQ+JhU2JFB?b+-Mq}R=6AnQR$O?S;qv)x^7 zcW-8932_Z*SWp7uMe!ouBIrHA2Z)e^Ac&ZYLGb2DAs!?|*1zY`Y#t^g1@->w`yciH z|JL%-;?&+ldnHMlYSe2hFz?U$lY3x%>E8YsxdLl{t4rcuc>ElnHlce1Tyyj}U zYM-Ev2vp{Z7FYX01ZYW`ne9i+S>q{c@s1ao@}F0~k&)+`^68RI?8xF>uf7rUQyWW7 zXJgGVTzU2wn(0#@2zbg+Kk&nZ_Dy-nOJSWIV;K!0>6$6eWdhNvy^Jgob5v5xilY^E zR54VoObosFD$?6&Dj?f6(0>`b|vrV+)s*Xyahf-2$; z)(peIM8~?W076LyVaobSm`qO?YCLgbFG@WTqKuKX#CmGVpy|kjAj)aOWb7tz81AzO zYbwc18UkG>$3^S0KNRjdnEO27VVVF|%dt^cq$25x|Dn#W?+^g4we4KSeRT8RL^s%Q7*KN5_1(ojEbTeMOSGVRZS_iT5hr8kfK5I_ch_HX8|yI?>^%D z*J2M6kok|zlci-AIkfI2@TY@u;+*1dj#s{ihQUIalO=&EJK67ZR~{dGkL`gGZLiCL z^Z{`(f+eDz_E^m4I^eB`L>&gzah9wjEAZV04)1m(_5=>qB3tHV3O0G6;~`YH7|Ph^ zFK=Ch66iN-bIt1e&h72(*x8xf?lg-^9efIA*diSlbU;OI5Pycw^etP=Yv*h>h ze*5vp{K*q<;4`~^{pHG$bC<75-*0}oh@GjT``67|)}bq#>Ym$!e-6BJ>6v|iy>;pN mpRS!he*K4Up;iAb9F*#pkG}BX%m>%A+S^!Is(mqk=E8r|X5H`r diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_import.png b/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_import.png deleted file mode 100644 index 8cf830a620070de2c84a7ef559f223ff00f3611d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1929 zcmb_dONbmr81A5kO~RU>NF*ROy(kH$rmG**)7@l@o9WH&NM;>&M|Ojkt*NS>X?CWo z?e5)~T^9_|g9$`MJ!uYJRqzrL0(($$5IsuJvmoSPh%R{Z5dC{zZp`MPI848)zWV;} ze^s5U&Q6c-J+xPnr1A2MHwVuH*)_Hs?$7@ICxOSFXy$YxN&BA6u3gf{7oV1--B*Iz zV!Bv4VeVIB;IsT%2tm^_no2NwXwp(H1c8f}n*M;|NSXJa6Bwa2llbJzzu~L;wBIa^F zXCbPYx?FH_nuQ(RJSyv0E2y}jY6ilZi!Il1s&+b^ zT*t_XxS?u} zCJ30?C6TJ-aOP4E$mj?ct;DUKaYj|%;%y$L31GDmHfoAgBu#M->e2Ka1|YPR%E-o! zTH5WAi6os`1vdr(*%6)8)*`OX@kFe|luxaK%!$mK$SuX3q#~{f(HbVII+QGzO7h`_ zAY`JG9N7lv9!Yso(Xp-}TtEh{Y1qx%F1BC5aL0XUMX{o7kF(^Ay-@hJ0??h#1U9wqX`*2iK`(g6v-Q-B;oO+L5%jvu3Io zFq&Lv#3TgT$YF?cQ%7}Lw-75>mTz!Objq`$?=#H=31oO}&_?t8^}$;!kb9-$5}LI{ zQK4BaaHb4~gB{}WP?iVlJ53Ix_oY zk}q&nw@n`r2NDTMq!4^x^L?n>zM{K@=Ur^L1|F98zZX7WrcDwyIP9&e^50!~xSG7% zl^xsf|8hmmHq?G?ssAjy-rTm$7n0Z;f*n139UUd`F*=NR2vLgRsJZq17cv}EYh`b; zW?#7c;pX_)c+7k6@IL*>#0Sq`8M`t6>D9M?-t+jW&(D9idGZJ8SNX@w-ZMWPcy%j$ z^p<<*jjjDJc^fzX_~zv^Prd)nqP&$~UA}~le*1*~+PUea8{?myH>6$FM^0BSEV0{X t4|cC_ynE*QTfa1~U3~1LOTO5c*?;ZkbIzL!pQPDgS)Q8pzC5vX_AkO)X!rmC diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_menu.png b/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_menu.png deleted file mode 100644 index 3a2c78e329fbef69538d22bcf820558000b9b9ff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2798 zcmeHJO^@3|81^EHXi+85N~l5{EEkDZF!qe?*cq#)Y@MYE!pmwKX_pgBX2yxNvB%i6 zn`AFYy&!HJxPU5g;(&yJdk>U9fVgphUjRbAaYT&sVYcn|gA~CdcLh`Peso@qekDndGk~CI9qhzt2FJo_4>D_eR1o8rk(jC z?eEFG_?>`?%p^<KAhzAtbsHkzg1&_u08s$Fz`^?RW2k5)OM;!wTgzDLEi^__7J+3=CKGew zn4%n72xDwP+p=w-5TKgnl1xEfU0gAActy*!kg3S^nvo2|fea0$ba8~NXlV0lX_GR{ znv%joCajM%2Qu2=ii2`I56-B?$2{Y?tP~bC*kUB4s7B%;)Xnle0hG0I+{8FhOO`bu zD!F;6j*G&cvj; zd<@PzMDozEp^X6afsOmfu5$*x*I+wPmObjA17NrWT)H%oJdr`DqiXg|d(nnOuB1|O`IUyzA7%J}`Q-jvSq*vtd(ZZiBkqbo+2*1B(|GV&| zC3HmcAy>WCGU}sPbr)JB#JWFM^R;6gYXw(rupT!3SG_bHoac(VRQ(xDc3;-Cr@!uX zHu}?BfByXA**oz0JKw+Z+uy(b_2mn{zkj*Ae&O!tvlqYn>6f*SNS~d4PaQaQ;M9Tt d$pN```_(faUt0g{tNI^lZ*!~j?X?eX{sU(co-zOc diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_minimum.png b/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_minimum.png deleted file mode 100644 index 12f30a4c85399253c917b847a2d7df143aeb021c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1672 zcmb7FONit|7|tRN>+Z}lAc%O`kVaY2N-F7e9>r#d+4MNmV8&*)VaMB4S5>;hbW+(Q zGu<->5xuymhrNn7?}9f$L|hMo7s0zA2y^iuxL2jO(w&a8yR)xAl1kNA-~auO`g6Ox zy}5GXwF{CYt#r29JL0`s-shLZ^YXnZ7O$7mt@m?Dy7+Q=pOe1$@>NNC@vo@2TkHn! zBEn-8Q{HFlBu)idlCG{zQcU()A@|uJN<8K7?|x9^h?jk*1BuV|CnAc{b2= z*L5{$Xodj<0^~nB| zDlA=^0V%0*=|MJ{8K*>JBNnry$OTrfvFVT(JRkDMP}j>37!aWig4)KJTH?4ikrx|> z!i_2*XQK1oQOdL(mh*#*u#H0@vr&4JB0poe;8~CJ(IQdZg=E?H+#o=mBrkA6 zSf}kNA~b3gQDlb1?PF#ETQ>=?ZPNhQ4IN;(m_o;KEW-&G``erxlm$@kpPvQFiQxEO zp6j%1$0Y<1(;~oSrV091-vOi*I)-f+2BiH3+k06gjw2qOW-V1w!D#7(wrosGEjloX z$$;Bz5@5BQkiw>Ius$h^epW|lE6PQNkE&yIgWak|qez~W4#K275}rcJT3}SErlT|B z@l2Mh{o^4Mq)(`lx%Hff#TaL7eIR1@lp53?Cq2i9PZs`ciJU8XRQN+R`~1SIkdPrx z22Au;O(|W`$}Tidi1u)V27 zf2Y&67heDHw(|Q|OWmKPSLmfiqw&qHU(SE}!MEp5PEMvj-M#zCZ~y)Ak+= kym9B^(zVsimAySly7%WQ`Ti37r~FrRHn!VeU*G%aKEp8%ZvX%Q diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_new_page.png b/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_new_page.png deleted file mode 100644 index 6e35218d5bbd9b0e441dd2da11f11c1725394bbf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1902 zcmb_dONbmr7;Xuy$;x8Di+V6^M>4)$#Wp&2v zTXcJqx`A@|8Trrv3xb#xL>|Q5B*%lQGUCPJyKL4Jc?2motIBd2P~K>+$sW&`Y^gS& zx{2h9tLip%k@>WYpkC2nMbixcbqsB6xboyuM6@gj@p|pqNi6YKRXRnHVomG!`)c1% zdDhl+*L5|BG=zXafP9z~WB`(U|CFJ|a+*bH5%EMW8Hvw(MO6_>$0@|=j5f(9WfBF` z1|-#V6_zQDfB~K1(q7gb1rMmkx-4c%kqfLo!=@cx@VvusLp|%hDS#+#vpI{gqn0?H zg~*HgmPlh#kR8!^YnU=^o#nijQC8m)GWVC+q}an&tp!@;I;6I2)`AO*QA zIG{M>SxiK_QB2xQOOv)D&x(jW-sPDHEYunE?G4Xc%Xk=dMMu7V^oZQ3d$#V{HbAOA zlG|+JMv@mKp{!A>Dxx%M6a`pEHlw;>0|!D1T-!8&OQ{c-Zm}S&7|`{}bbO7|UTJ`G z{CF({oC=P=<>|g{I<9X4%b*ZIWLAK0IuuwsvwRyt8&P-4_CgkkqzqFl`IaI%b!vDYSF-AEo;2NPN@iK;?N zFR(zFG)FtskQ<%T-;miABEjr!&`UonZJCb6TJpR=Px{LBs`mWV24;;4D`Gq@^_sh1nI<(6~i z>igd;O7d>c`t8Om7r(!J`PB8#KYk*9ec{s&zpZT+FV(g_xpd(C(jRBfzSBGY?pu$2 zu;*v_ZSbpl<;sN@cRl&T@VmWVUwC8RxoZc{U3=uG$CrO^*H0fu=AUQoKYjH<{3U#D QS9u~f>Z`Rcj+}b)FDtrSZU6uP diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_searching.png b/src/main/resources/assets/gregtech/textures/gui/terminal/terminal_searching.png deleted file mode 100644 index 7e0b19abdd2037b4c22ff2a270f503de4de6baab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1939 zcmb_dONbmr7@mlUd5~SULJlsN(G z|L_0n`>W1X=1(5n|M31)Ds`|lS6CG7;pE-BM|>Z3o2A>$K%i5pH89YIk_Ik z0alb&tCenL(mbpws%2RUL<&McAVAddW6}nGbZlUuz#>T zC`%3$8$TQP!p(X6=g6o zuxi`{6@qa{OzsMHD0X?+BqCg|Noq_9{F*EclZf-Y!9(F#u*-~&m-6{a$X%}?CZffY zvr?&;*Huf`0ZOY~y5%x1`B6-K%1VWtEK-y9JO^u<5T=Q;fSAw%Sy!XLq_zr>sadv7 zvYMvbgY^YY*Af9F>wC4}a4Ky4O;59sVLJ{2gb@fFqPf7%Y8l{Y%+M?gy0%LP))qof zlp|@3T1{9v2`h%gVnRe2Sq@-KL%^oC4je<*-3)^SQI?3lt0O$;MPi3L{W4l&FZX*5 zPwGks6PlDnPNs<#m?QUxy`A!LFP{7BTXiOk-a#cj?-6(7775u*P2}z_8dPpaJtFIO zCQguMSQdhSWDN#vQ>30)$P_zaQOz)2)pdn#dyH-+p2aYOGjO2Ue^0z`nbwJ4W8!R8 zkt^Bu@0CJG@H7&+sy0zQ|H2u9|Ok z`>MF6UM&@7s^(jty;B?8 z$pKnUaNq*HP;o<4;!+8OdMH%%fIC^um<@mM!p+)CN; zt)&*-TBFF<4!xot9AHThF+tQp)QdAbsA@xAEXVn@uBk(aSgUHa+@QMJTvk1vGPPWC z05xn=by3N1ATsR(stFBOhpui|02&xN*h1>~(xkQ25AaI;=-8J0s%l*!60Ga}e!tYW zN<8i820}=Orf!-*B0#no3o-z4wr|2vXBkbyM1(w6b4JqU>!PYjr6U)jq@aznahPPl z^Z`k9qXcu8hCrVdxMV%;4UPL$XFV3NSY#4w6xgK81<$(t4%Ef+O$KCWo6W+;u3Dm~ zFp-J*4e7=>AiJWo)@H)=6_)Y!l(P8^DRW=$O@h6Y5y8_I=eBv8%CtV^d#2@g7g5VX4mAIp6TS<&+0uPcCFD3rEz(yyqCmae!GehH{%t z+=w$lV#*rzswP8I3PT?g({>RuAs}U!fp*0X06}I25QeDjRstgkM()b}bxzmw0?7A| z&VtXWL)#CNsP_K1Rpc+v8C$REMR53C)j0Rik+= zFkc%_hr7h%zATUT_q$Az-la-L)-xW6K1o@vBV%`u8r1J3JtG@;7k+<<94We8_$@X2 z|Ami3Lc1jHFxgvmEq6uFyU-{h`mMPduI=bp6S!=H`LO7}@}ubBESA)%?9cf8mA$gJ zuQlqmR^`L*ue~;XNqv0J)lYtfFa7iWA4f0mf2aMqI4nM1&|dBT&^Y(mb$#l}jq>4B z=M|tn@Wsi~A8CKSaQ)=WS3lQk)2F|jTb&Bd{`T;h+2=3T=k_R1e|zDV*{i26{J6LK jr1H}n-lYTE@1A`wJ7ySP|Gqt&|5F{5IihvtwAF&Gw847O(sss9 zZ7+Ao_B!#XGW)cAe29dBm=#za#{DEm!@4rEi$uHZRuy>!Dc0-CTe{teV{MD6SQKU#!2ZKRv zVAOclRW;A^RH&=E4g><^TS2yt4OP4Y>a zM8eb|PF1Z2%aBGuN-A8sk@ZK;DN$LU#Vjdufz>K(+T#V!d;BJ*tKsV$h}5=Pm5)8S z#Bt>!FBUdM7?XtTiOxG)DO1}l=NlPe3!8%Gu`-$zH8O?^o^?3yPZw%sN?C3+Wyg zTQDUkx6f9P2(ux(=Kz_hUk9K+NB4u}p&Xjq}kEUGybo0C~2$`SW>S}j>oVbReI z&4q>m0tyY_GSdKF;4+|_x3~vH1HdVo5&J(rP+T^e3BB6z&Gxw2SW*0yD`R+dtSs!0I_x=NGQZbL(7w+pE@y)Yey?*G2M_)U9`PVDw zzr8Cx>BCRITfFqbx%1z@NiSYrf9BdxKOP Date: Mon, 16 Aug 2021 21:33:17 +0800 Subject: [PATCH 53/58] serialization + deserialization --- ...inalBuilder.java => TerminalRegistry.java} | 2 +- .../api/terminal/app/AbstractApplication.java | 2 - .../app/recipechart/RecipeChartApp.java | 13 +- .../app/recipechart/widget/PhantomWidget.java | 1 - .../app/recipechart/widget/RGContainer.java | 68 +++-- .../app/recipechart/widget/RGLine.java | 23 +- .../app/recipechart/widget/RGNode.java | 257 +++++++++++++----- .../DraggableScrollableWidgetGroup.java | 5 - .../terminal/os/TerminalDesktopWidget.java | 2 - .../api/terminal/os/TerminalOSWidget.java | 6 +- .../terminal/os/menu/TerminalMenuWidget.java | 1 - .../api/terminal/util/GuideJsonLoader.java | 10 +- .../java/gregtech/common/CommonProxy.java | 4 +- 13 files changed, 267 insertions(+), 127 deletions(-) rename src/main/java/gregtech/api/terminal/{TerminalBuilder.java => TerminalRegistry.java} (98%) diff --git a/src/main/java/gregtech/api/terminal/TerminalBuilder.java b/src/main/java/gregtech/api/terminal/TerminalRegistry.java similarity index 98% rename from src/main/java/gregtech/api/terminal/TerminalBuilder.java rename to src/main/java/gregtech/api/terminal/TerminalRegistry.java index 5ff653ade00..9ac79f39d7e 100644 --- a/src/main/java/gregtech/api/terminal/TerminalBuilder.java +++ b/src/main/java/gregtech/api/terminal/TerminalRegistry.java @@ -11,7 +11,7 @@ import java.util.*; -public class TerminalBuilder { +public class TerminalRegistry { private static final Map appRegister = new HashMap<>(); private static final List defaultApps = new ArrayList<>(); diff --git a/src/main/java/gregtech/api/terminal/app/AbstractApplication.java b/src/main/java/gregtech/api/terminal/app/AbstractApplication.java index 48868392bfa..9398957458d 100644 --- a/src/main/java/gregtech/api/terminal/app/AbstractApplication.java +++ b/src/main/java/gregtech/api/terminal/app/AbstractApplication.java @@ -6,9 +6,7 @@ import gregtech.api.terminal.os.menu.component.IMenuComponent; import gregtech.api.util.Position; import gregtech.api.util.Size; -import net.minecraft.client.resources.I18n; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.Items; import net.minecraft.nbt.NBTTagCompound; import java.util.Collections; diff --git a/src/main/java/gregtech/api/terminal/app/recipechart/RecipeChartApp.java b/src/main/java/gregtech/api/terminal/app/recipechart/RecipeChartApp.java index cc96a00a73f..9633e2475c4 100644 --- a/src/main/java/gregtech/api/terminal/app/recipechart/RecipeChartApp.java +++ b/src/main/java/gregtech/api/terminal/app/recipechart/RecipeChartApp.java @@ -54,6 +54,7 @@ private void addTab(String name) { } } + NBTTagCompound testnbt; @Override public List getMenuComponents() { ClickComponent newPage = new ClickComponent().setIcon(GuiTextures.ICON_NEW_PAGE).setHoverText("New Page").setClickConsumer(cd->{ @@ -64,7 +65,17 @@ public List getMenuComponents() { ((RGContainer) tabGroup.getCurrentTag()).addNode(50, 100); } }); - return Arrays.asList(newPage, importPage); + ClickComponent save = new ClickComponent().setIcon(GuiTextures.ICON_ADD).setHoverText("save test").setClickConsumer(cd->{ + if (tabGroup != null && tabGroup.getCurrentTag() instanceof RGContainer) { + testnbt = ((RGContainer) tabGroup.getCurrentTag()).saveAsNBT(); + } + }); + ClickComponent load = new ClickComponent().setIcon(GuiTextures.ICON_ADD).setHoverText("load test").setClickConsumer(cd->{ + if (tabGroup != null && tabGroup.getCurrentTag() instanceof RGContainer) { + ((RGContainer) tabGroup.getCurrentTag()).loadFromNBT(testnbt); + } + }); + return Arrays.asList(newPage, importPage, save, load); } @Override diff --git a/src/main/java/gregtech/api/terminal/app/recipechart/widget/PhantomWidget.java b/src/main/java/gregtech/api/terminal/app/recipechart/widget/PhantomWidget.java index 5d6fc4d9176..22271b16d20 100644 --- a/src/main/java/gregtech/api/terminal/app/recipechart/widget/PhantomWidget.java +++ b/src/main/java/gregtech/api/terminal/app/recipechart/widget/PhantomWidget.java @@ -8,7 +8,6 @@ import gregtech.api.terminal.os.TerminalTheme; import gregtech.common.inventory.handlers.SingleItemStackHandler; import mezz.jei.api.gui.IGhostIngredientHandler; -import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.items.IItemHandlerModifiable; diff --git a/src/main/java/gregtech/api/terminal/app/recipechart/widget/RGContainer.java b/src/main/java/gregtech/api/terminal/app/recipechart/widget/RGContainer.java index 5a92028e39b..c17c2693f9d 100644 --- a/src/main/java/gregtech/api/terminal/app/recipechart/widget/RGContainer.java +++ b/src/main/java/gregtech/api/terminal/app/recipechart/widget/RGContainer.java @@ -3,16 +3,16 @@ import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; +import gregtech.api.terminal.os.TerminalDialogWidget; import gregtech.api.terminal.os.TerminalOSWidget; import gregtech.api.terminal.os.TerminalTheme; -import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTBase; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraftforge.common.util.Constants; -import net.minecraftforge.fluids.FluidStack; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import java.util.Optional; @@ -20,8 +20,8 @@ public class RGContainer extends DraggableScrollableWidgetGroup { protected TerminalOSWidget os; private RGNode selectedNode; private RGLine selectedLine; - private final List nodes; - private final List lines; + protected final List nodes; + protected final List lines; public RGContainer(int x, int y, int width, int height, TerminalOSWidget os) { super(x, y, width, height); @@ -82,14 +82,10 @@ public void removeNode(RGNode node) { this.waitToRemoved(node); } - public void updateLine(RGNode parent, RGNode child) { - this.addLine(parent, child, null); - } - - public void addLine(RGNode parent, RGNode child, ItemStack catalyst) { + public void addOrUpdateLine(RGNode parent, RGNode child) { Optional optional = lines.stream().filter(line -> line.getParent() == parent && line.getChild() == child).findFirst(); if (!optional.isPresent()) { - RGLine line = new RGLine(parent, child, this, catalyst); + RGLine line = new RGLine(parent, child, this); lines.add(line); this.addWidget(0, line); } else { @@ -112,30 +108,46 @@ public void removeLine(RGNode parent, RGNode child) { }); } - public void loadNBT(NBTTagCompound nbt) { - this.nodes.clear(); - NBTTagList nodesList = nbt.getTagList("nodes", Constants.NBT.TAG_COMPOUND); - for (NBTBase node : nodesList) { // build nodes - NBTTagCompound nodeTag = (NBTTagCompound)node; - NBTTagCompound headTag = nodeTag.getCompoundTag("head"); - byte type = headTag.getByte("type"); // 0-null 1-itemstack 2-fluidstack - Object head = null; - if (type == 1) { - head = new ItemStack(headTag.getCompoundTag("nbt")); - } else if (type == 2) { - head = FluidStack.loadFluidStackFromNBT(headTag.getCompoundTag("nbt")); + public void loadFromNBT(NBTTagCompound nbt) { + try { + this.clearAllWidgets(); + this.nodes.clear(); + this.lines.clear(); + NBTTagList nodesList = nbt.getTagList("nodes", Constants.NBT.TAG_COMPOUND); + for (NBTBase node : nodesList) { // build nodes + nodes.add(RGNode.deserializeNodeNBT((NBTTagCompound)node, this)); + } + Iterator iterator = nodesList.iterator(); // build relations + for (RGNode node : nodes) { + NBTTagCompound nodeTag = (NBTTagCompound)iterator.next(); + node.deserializeRelationNBT(nodeTag.getTagList("parents", Constants.NBT.TAG_INT_ARRAY), + nodeTag.getTagList("children", Constants.NBT.TAG_INT_ARRAY)); + this.addWidget(node); } - if (nodeTag.getBoolean("phantom")) { - this.nodes.add(new RGNode(nodeTag.getInteger("x"), nodeTag.getInteger("y"), this, head, true)); - } else { - this.nodes.add(new RGNode(nodeTag.getInteger("x"), nodeTag.getInteger("y"), this, head, false)); + NBTTagList linesList = nbt.getTagList("lines", Constants.NBT.TAG_COMPOUND); + for (NBTBase node : linesList) { // build nodes + RGLine line = RGLine.deserializeLineNBT((NBTTagCompound)node, this); + lines.add(line); + this.addWidget(0, line); } + } catch (Exception e) { + TerminalDialogWidget.showInfoDialog(os, "ERROR", e.getMessage()).setClientSide().open(); } } public NBTTagCompound saveAsNBT() { - - return null; + NBTTagCompound nbt = new NBTTagCompound(); + NBTTagList nodesTag = new NBTTagList(); + for (RGNode node : nodes) { + nodesTag.appendTag(node.serializeNodeNBT()); + } + nbt.setTag("nodes", nodesTag); + NBTTagList linesTag = new NBTTagList(); + for (RGLine line : lines) { + nodesTag.appendTag(line.serializeLineNBT()); + } + nbt.setTag("lines", linesTag); + return nbt; } @Override diff --git a/src/main/java/gregtech/api/terminal/app/recipechart/widget/RGLine.java b/src/main/java/gregtech/api/terminal/app/recipechart/widget/RGLine.java index ac12200850c..4e2db3025b3 100644 --- a/src/main/java/gregtech/api/terminal/app/recipechart/widget/RGLine.java +++ b/src/main/java/gregtech/api/terminal/app/recipechart/widget/RGLine.java @@ -8,13 +8,12 @@ import gregtech.api.gui.widgets.WidgetGroup; import gregtech.api.terminal.gui.widgets.CircleButtonWidget; import gregtech.api.terminal.os.TerminalDialogWidget; -import gregtech.api.terminal.os.TerminalOSWidget; import gregtech.api.terminal.os.TerminalTheme; import gregtech.api.util.Position; import gregtech.api.util.Size; import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.math.Vec2f; -import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.items.ItemStackHandler; import java.util.ArrayList; @@ -31,13 +30,13 @@ public class RGLine extends WidgetGroup { private final WidgetGroup infoGroup; private final WidgetGroup toolGroup; - public RGLine(RGNode parent, RGNode child, RGContainer container, ItemStack catalyst) { + public RGLine(RGNode parent, RGNode child, RGContainer container) { super(0, 0, 0, 0); this.parent = parent; this.child = child; this.container = container; this.points = new ArrayList<>(); - this.catalyst = catalyst; + this.catalyst = parent.catalyst; infoGroup = new WidgetGroup(0, 0, 0, 0); if (catalyst != null) { @@ -63,7 +62,7 @@ public RGLine(RGNode parent, RGNode child, RGContainer container, ItemStack cata .setColors(0, TerminalTheme.COLOR_7.getColor(), 0) .setIcon(GuiTextures.ICON_CALCULATOR) .setHoverText("Ratio") - .setClickListener(cd -> TerminalDialogWidget.showTextFieldDialog(container.os, "Demand", s->{ + .setClickListener(cd -> TerminalDialogWidget.showTextFieldDialog(container.os, "Ratio", s->{ try { return Integer.parseInt(s) > 0; } catch (Exception ignored){ @@ -82,6 +81,20 @@ public RGLine(RGNode parent, RGNode child, RGContainer container, ItemStack cata updateLine(); } + public static RGLine deserializeLineNBT(NBTTagCompound nbt, RGContainer container) { + RGLine line = new RGLine(container.nodes.get(nbt.getInteger("parent")), container.nodes.get(nbt.getInteger("child")), container); + line.ratio = nbt.getInteger("ratio"); + return line; + } + + public NBTTagCompound serializeLineNBT() { + NBTTagCompound nbt = new NBTTagCompound(); + nbt.setInteger("parent", container.nodes.indexOf(parent)); + nbt.setInteger("child", container.nodes.indexOf(child)); + nbt.setInteger("ratio", ratio); + return nbt; + } + public RGNode getParent() { return parent; } diff --git a/src/main/java/gregtech/api/terminal/app/recipechart/widget/RGNode.java b/src/main/java/gregtech/api/terminal/app/recipechart/widget/RGNode.java index 5f14d453745..6ebae440c4d 100644 --- a/src/main/java/gregtech/api/terminal/app/recipechart/widget/RGNode.java +++ b/src/main/java/gregtech/api/terminal/app/recipechart/widget/RGNode.java @@ -28,7 +28,12 @@ import mezz.jei.gui.recipes.RecipeLayout; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTBase; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagIntArray; +import net.minecraft.nbt.NBTTagList; import net.minecraft.util.math.MathHelper; +import net.minecraftforge.common.util.Constants; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.FluidTank; import net.minecraftforge.fml.common.ObfuscationReflectionHelper; @@ -36,10 +41,12 @@ import java.util.*; import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; public class RGNode extends WidgetGroup implements IDraggable { protected Object head; protected int recipePer; + protected ItemStack catalyst; private boolean isSelected; private WidgetGroup toolGroup; private WidgetGroup inputsGroup; @@ -123,7 +130,7 @@ private void init(RGContainer container) { toolGroup.setVisible(false); toolGroup.setActive(false); parentNodes = new HashMap<>(); - children = new HashMap<>(); + children = new LinkedHashMap<>(); // important } public int getHeadDemand() { @@ -169,7 +176,8 @@ public void mergeNode(RGNode node) { for (Set value : parentNode.children.values()) { if (value.remove(node)) { value.add(this); - addParent(parentNode, container.getLine(parentNode, node).getCatalyst()); + addParent(parentNode); + parentNode.updateDemand(parentNode.getHeadDemand()); break; } } @@ -206,8 +214,8 @@ public Position getNodePosition(RGNode child) { return this.getPosition(); } - public void addParent(RGNode parent, ItemStack catalyst) { - container.addLine(parent, this, catalyst); + public void addParent(RGNode parent) { + container.addOrUpdateLine(parent, this); this.parentNodes.put(parent, parent.getChildDemand(this)); updateDemand(parentNodes.values().stream().mapToInt(it->it).sum()); } @@ -255,11 +263,11 @@ public void onChildRemoved(RGNode child) { protected void onPositionUpdate() { super.onPositionUpdate(); for (RGNode parentNode : parentNodes.keySet()) { - container.updateLine(parentNode, this); + container.addOrUpdateLine(parentNode, this); } for (Set childs : children.values()) { for (RGNode child : childs) { - container.updateLine(this, child); + container.addOrUpdateLine(this, child); } } } @@ -279,75 +287,51 @@ public boolean transferRecipe(ModularUIContainer x, IRecipeLayout recipeLayout, return false; } if (!doTransfer) return true; - inputsGroup.clearAllWidgets(); - for (Set childs : children.values()) { - for (RGNode child : childs) { - child.removeParent(this); - } - } - children.clear(); - AtomicInteger y = new AtomicInteger(-20); - recipeLayout.getItemStacks().getGuiIngredients().values().stream().filter(it -> it.getDisplayedIngredient() != null && it.isInput()).forEach(it -> { - ItemStackHandler handler = new ItemStackHandler(1); - handler.setStackInSlot(0, it.getDisplayedIngredient()); - Widget widget = new SlotWidget(handler, 0, 0, y.addAndGet(20), false, false) { - @Override - public boolean mouseClicked(int mouseX, int mouseY, int button) { - return RGNode.this.handleTipsSlotClick(mouseX, mouseY, recipeLayout,this, handler.getStackInSlot(0).copy()); + RGNode.this.recipePer = 0; + + // items + List itemInputs = new ArrayList<>(); + recipeLayout.getItemStacks().getGuiIngredients().values().forEach(it->{ + if (it.isInput() && it.getDisplayedIngredient()!= null) { + ItemStack input = it.getDisplayedIngredient(); + for (ItemStack itemInput : itemInputs) { + if (itemInput.isItemEqual(input)) { + itemInput.setCount(itemInput.getCount() + input.getCount()); + return; + } } - }.setBackgroundTexture(TerminalTheme.COLOR_B_2); - inputsGroup.addWidget(widget); - children.put(widget, new HashSet<>()); - }); - recipeLayout.getFluidStacks().getGuiIngredients().values().stream().filter(it -> it.getDisplayedIngredient() != null && it.isInput()).forEach(it -> { - FluidTank tank = new FluidTank(it.getDisplayedIngredient(), Integer.MAX_VALUE); - Widget widget = new TankWidget(tank, 0, y.addAndGet(20), 18, 18) { - @Override - public boolean mouseClicked(int mouseX, int mouseY, int button) { - return RGNode.this.handleTipsSlotClick(mouseX, mouseY, recipeLayout,this, tank.getFluid().copy()); + itemInputs.add(input.copy()); + } else if (head instanceof ItemStack && !it.isInput()) { + for (ItemStack ingredient : it.getAllIngredients()) { + if (((ItemStack) head).isItemEqual(ingredient)) { + RGNode.this.recipePer += ingredient.getCount(); + break; + } } - }.setAlwaysShowFull(true).setBackgroundTexture(TerminalTheme.COLOR_B_2); - inputsGroup.addWidget(widget); - children.put(widget, new HashSet<>()); + } }); - inputsGroup.setSelfPosition(new Position(25, -(inputsGroup.widgets.size() * 20) / 2 + 8)); - if (head instanceof ItemStack) { - recipeLayout.getItemStacks().getGuiIngredients().values().stream().anyMatch(it->{ - if (!it.isInput()) { - for (ItemStack ingredient : it.getAllIngredients()) { - if (((ItemStack) head).isItemEqual(ingredient)) { - RGNode.this.recipePer = ingredient.getCount(); - return true; - } + + // fluids + List fluidInputs = new ArrayList<>(); + recipeLayout.getFluidStacks().getGuiIngredients().values().forEach(it->{ + if (it.isInput() && it.getDisplayedIngredient()!= null) { + FluidStack input = it.getDisplayedIngredient(); + for (FluidStack fluidInput : fluidInputs) { + if (fluidInput.isFluidEqual(input)) { + fluidInput.amount += input.amount; + return; } } - return false; - }); - } else if (head instanceof FluidStack) { - recipeLayout.getFluidStacks().getGuiIngredients().values().stream().anyMatch(it->{ - if (!it.isInput()) { - for (FluidStack ingredient : it.getAllIngredients()) { - if (((FluidStack) head).isFluidEqual(ingredient)) { - RGNode.this.recipePer = ingredient.amount; - return true; - } + fluidInputs.add(input.copy()); + } else if (head instanceof FluidStack && !it.isInput()) { + for (FluidStack ingredient : it.getAllIngredients()) { + if (((FluidStack) head).isFluidEqual(ingredient)) { + RGNode.this.recipePer += ingredient.amount; + break; } } - return false; - }); - } - return true; - } - return false; - } - - private boolean handleTipsSlotClick(int mouseX, int mouseY, IRecipeLayout recipeLayout, Widget slot, Object object){ - if (slot.isMouseOverElement(mouseX, mouseY)) { - Position position = inputsGroup.getSelfPosition(); - RGNode child = container.addNode(RGNode.this.getSelfPosition().x + 50, RGNode.this.getSelfPosition().y + position.y + slot.getSelfPosition().y, object); - Set childs = RGNode.this.children.get(slot); - childs.add(child); - + } + }); // CHECK GTCE RECIPES Recipe recipe = null; if (recipeLayout instanceof RecipeLayout) { @@ -383,8 +367,141 @@ private boolean handleTipsSlotClick(int mouseX, int mouseY, IRecipeLayout recipe } } } + setRecipe(itemInputs, fluidInputs, catalyst, recipePer); + return true; + } + return false; + } + + public void deserializeRelationNBT(NBTTagList parentsTag, NBTTagList childrenTag) { + for (NBTBase nbtBase : parentsTag) { + int[] nbt = ((NBTTagIntArray) nbtBase).getIntArray(); + parentNodes.put(container.nodes.get(nbt[0]), nbt[1]); + } + Iterator iterator = children.keySet().iterator(); + for (NBTBase nbtBase : childrenTag) { + int[] nbt = ((NBTTagIntArray) nbtBase).getIntArray(); + children.get(iterator.next()).addAll(Arrays.stream(nbt).mapToObj(it->container.nodes.get(it)).collect(Collectors.toList())); + } + } + + public static RGNode deserializeNodeNBT(NBTTagCompound nodeTag, RGContainer container) { + byte type = nodeTag.getByte("type"); // 0-null 1-itemstack 2-fluidstack + Object head = null; + if (type == 1) { + head = new ItemStack(nodeTag.getCompoundTag("nbt")); + ((ItemStack)head).setCount(nodeTag.getInteger("count")); + } else if (type == 2) { + head = FluidStack.loadFluidStackFromNBT(nodeTag.getCompoundTag("nbt")); + assert head != null; + ((FluidStack)head).amount = nodeTag.getInteger("count"); + } + RGNode node; + if (nodeTag.getBoolean("phantom")) { + node = new RGNode(nodeTag.getInteger("x"), nodeTag.getInteger("y"), container, head, true); + } else { + node = new RGNode(nodeTag.getInteger("x"), nodeTag.getInteger("y"), container, head, false); + } + NBTTagList itemsList = nodeTag.getTagList("items", Constants.NBT.TAG_COMPOUND); + NBTTagList fluidsList = nodeTag.getTagList("fluids", Constants.NBT.TAG_COMPOUND); + node.setRecipe(itemsList.tagList.stream().map(it->new ItemStack((NBTTagCompound) it)).collect(Collectors.toList()), + fluidsList.tagList.stream().map(it->FluidStack.loadFluidStackFromNBT((NBTTagCompound) it)).collect(Collectors.toList()), + nodeTag.hasKey("catalyst") ? new ItemStack(nodeTag.getCompoundTag("catalyst")) : null, + nodeTag.getInteger("per")); + return node; + } + + public NBTTagCompound serializeNodeNBT() { + //head + NBTTagCompound nbt = new NBTTagCompound(); + nbt.setInteger("x", getSelfPosition().x); + nbt.setInteger("y", getSelfPosition().y); + nbt.setByte("type", head instanceof ItemStack ? (byte)1 : head instanceof FluidStack ? (byte)2 : 0); + if (head instanceof ItemStack) { + nbt.setTag("nbt", ((ItemStack) head).serializeNBT()); + nbt.setInteger("count", ((ItemStack) head).getCount()); + } else if (head instanceof FluidStack) { + nbt.setTag("nbt", ((FluidStack) head).writeToNBT(new NBTTagCompound())); + nbt.setInteger("count", ((FluidStack) head).amount); + } + nbt.setBoolean("phantom", widgets.stream().anyMatch(it->it instanceof PhantomWidget)); + // recipe + children + NBTTagList itemsList = new NBTTagList(); + NBTTagList fluidsList = new NBTTagList(); + NBTTagList childrenList = new NBTTagList(); + for (Map.Entry> entry : children.entrySet()) { + Widget widget = entry.getKey(); + if (widget instanceof SlotWidget) { + itemsList.appendTag(((SlotWidget) widget).getHandle().getStack().serializeNBT()); + } else if (widget instanceof TankWidget) { + fluidsList.appendTag(((TankWidget) widget).fluidTank.getFluid().writeToNBT(new NBTTagCompound())); + } else { + continue; + } + NBTTagIntArray childList = new NBTTagIntArray(entry.getValue().stream().mapToInt(it->container.nodes.indexOf(it)).toArray()); + childrenList.appendTag(childList); + } + nbt.setTag("items", itemsList); + nbt.setTag("fluids", fluidsList); + nbt.setTag("children", childrenList); + if (catalyst != null) { + nbt.setTag("catalyst", catalyst.serializeNBT()); + } + nbt.setInteger("per", recipePer); + // parent + NBTTagList parentsList = new NBTTagList(); + for (Map.Entry entry : parentNodes.entrySet()) { + parentsList.appendTag(new NBTTagIntArray(new int[]{container.nodes.indexOf(entry.getKey()), entry.getValue()})); + } + nbt.setTag("parents", parentsList); + return nbt; + } + + private void setRecipe(List itemInputs, List fluidInputs, ItemStack catalyst, int recipePer) { + this.recipePer = recipePer; + this.catalyst = catalyst; + inputsGroup.clearAllWidgets(); + for (Set childs : children.values()) { + for (RGNode child : childs) { + child.removeParent(this); + } + } + children.clear(); + AtomicInteger y = new AtomicInteger(-20); + for (ItemStack itemInput : itemInputs) { + ItemStackHandler handler = new ItemStackHandler(1); + handler.setStackInSlot(0, itemInput); + Widget widget = new SlotWidget(handler, 0, 0, y.addAndGet(20), false, false) { + @Override + public boolean mouseClicked(int mouseX, int mouseY, int button) { + return RGNode.this.handleTipsSlotClick(mouseX, mouseY,this, handler.getStackInSlot(0).copy()); + } + }.setBackgroundTexture(TerminalTheme.COLOR_B_2); + inputsGroup.addWidget(widget); + children.put(widget, new HashSet<>()); + } + for (FluidStack fluidInput : fluidInputs) { + FluidTank tank = new FluidTank(fluidInput, Integer.MAX_VALUE); + Widget widget = new TankWidget(tank, 0, y.addAndGet(20), 18, 18) { + @Override + public boolean mouseClicked(int mouseX, int mouseY, int button) { + return RGNode.this.handleTipsSlotClick(mouseX, mouseY,this, tank.getFluid().copy()); + } + }.setAlwaysShowFull(true).setBackgroundTexture(TerminalTheme.COLOR_B_2); + inputsGroup.addWidget(widget); + children.put(widget, new HashSet<>()); + } + inputsGroup.setSelfPosition(new Position(25, -(inputsGroup.widgets.size() * 20) / 2 + 8)); + } + + private boolean handleTipsSlotClick(int mouseX, int mouseY, Widget slot, Object object){ + if (slot.isMouseOverElement(mouseX, mouseY)) { + Position position = inputsGroup.getSelfPosition(); + RGNode child = container.addNode(RGNode.this.getSelfPosition().x + 50, RGNode.this.getSelfPosition().y + position.y + slot.getSelfPosition().y, object); + Set childs = RGNode.this.children.get(slot); + childs.add(child); - child.addParent(RGNode.this, catalyst); + child.addParent(RGNode.this); RGNode.this.updateDemand(RGNode.this.getHeadDemand()); return true; } @@ -404,7 +521,7 @@ public void updateSelected(boolean selected) { inputsGroup.setActive(false); inputsGroup.setVisible(false); } - children.forEach((widget, rgNode) -> rgNode.forEach(child -> container.updateLine(RGNode.this, child))); + children.forEach((widget, rgNode) -> rgNode.forEach(child -> container.addOrUpdateLine(RGNode.this, child))); } @Override diff --git a/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java b/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java index 677352b0ff6..6d28f4efb82 100644 --- a/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java +++ b/src/main/java/gregtech/api/terminal/gui/widgets/DraggableScrollableWidgetGroup.java @@ -8,13 +8,8 @@ import gregtech.api.util.Position; import gregtech.api.util.RenderUtil; import gregtech.api.util.Size; -import net.minecraft.client.renderer.GlStateManager; import net.minecraft.util.math.MathHelper; -import static gregtech.api.gui.impl.ModularUIGui.bColorForOverlay; -import static gregtech.api.gui.impl.ModularUIGui.gColorForOverlay; -import static gregtech.api.gui.impl.ModularUIGui.rColorForOverlay; - public class DraggableScrollableWidgetGroup extends WidgetGroup { protected int scrollXOffset; protected int scrollYOffset; diff --git a/src/main/java/gregtech/api/terminal/os/TerminalDesktopWidget.java b/src/main/java/gregtech/api/terminal/os/TerminalDesktopWidget.java index caecc8b6fb9..0cd106e3bc6 100644 --- a/src/main/java/gregtech/api/terminal/os/TerminalDesktopWidget.java +++ b/src/main/java/gregtech/api/terminal/os/TerminalDesktopWidget.java @@ -6,8 +6,6 @@ import gregtech.api.util.Position; import gregtech.api.util.Size; -import java.awt.*; - public class TerminalDesktopWidget extends WidgetGroup { private final TerminalOSWidget os; private final WidgetGroup appDiv; diff --git a/src/main/java/gregtech/api/terminal/os/TerminalOSWidget.java b/src/main/java/gregtech/api/terminal/os/TerminalOSWidget.java index 72bddbeab37..2151b87ff0e 100644 --- a/src/main/java/gregtech/api/terminal/os/TerminalOSWidget.java +++ b/src/main/java/gregtech/api/terminal/os/TerminalOSWidget.java @@ -4,7 +4,7 @@ import gregtech.api.gui.ModularUI; import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.widgets.AbstractWidgetGroup; -import gregtech.api.terminal.TerminalBuilder; +import gregtech.api.terminal.TerminalRegistry; import gregtech.api.terminal.app.AbstractApplication; import gregtech.api.terminal.os.menu.TerminalMenuWidget; import gregtech.api.util.Position; @@ -34,11 +34,11 @@ public TerminalOSWidget(int xPosition, int yPosition, int width, int height, NBT this.addWidget(desktop); this.addWidget(menu); this.tabletNBT = tabletNBT; - TerminalBuilder.getDefaultApps().forEach(name-> installApplication(TerminalBuilder.getApplication(name))); + TerminalRegistry.getDefaultApps().forEach(name-> installApplication(TerminalRegistry.getApplication(name))); NBTTagList installed = tabletNBT.getTagList("installed", 8); for (NBTBase nbtBase : installed) { if (nbtBase instanceof NBTTagString) { - AbstractApplication app = TerminalBuilder.getApplication(((NBTTagString) nbtBase).getString()); + AbstractApplication app = TerminalRegistry.getApplication(((NBTTagString) nbtBase).getString()); if (app != null) { installApplication(app); } diff --git a/src/main/java/gregtech/api/terminal/os/menu/TerminalMenuWidget.java b/src/main/java/gregtech/api/terminal/os/menu/TerminalMenuWidget.java index c1e6c653425..5824a033bf3 100644 --- a/src/main/java/gregtech/api/terminal/os/menu/TerminalMenuWidget.java +++ b/src/main/java/gregtech/api/terminal/os/menu/TerminalMenuWidget.java @@ -6,7 +6,6 @@ import gregtech.api.gui.widgets.WidgetGroup; import gregtech.api.terminal.app.AbstractApplication; import gregtech.api.terminal.gui.widgets.CircleButtonWidget; -import gregtech.api.terminal.os.TerminalDialogWidget; import gregtech.api.terminal.os.TerminalOSWidget; import gregtech.api.terminal.os.TerminalTheme; import gregtech.api.terminal.os.menu.component.IMenuComponent; diff --git a/src/main/java/gregtech/api/terminal/util/GuideJsonLoader.java b/src/main/java/gregtech/api/terminal/util/GuideJsonLoader.java index 89326758ed9..298055c4df8 100644 --- a/src/main/java/gregtech/api/terminal/util/GuideJsonLoader.java +++ b/src/main/java/gregtech/api/terminal/util/GuideJsonLoader.java @@ -1,15 +1,13 @@ package gregtech.api.terminal.util; import com.google.gson.JsonObject; -import gregtech.api.terminal.TerminalBuilder; +import gregtech.api.terminal.TerminalRegistry; import gregtech.api.terminal.app.guide.GuideApp; import net.minecraft.client.Minecraft; import net.minecraft.client.resources.IResourceManager; import net.minecraft.client.resources.IResourceManagerReloadListener; -import net.minecraft.client.resources.LanguageManager; import net.minecraftforge.common.crafting.CraftingHelper; import net.minecraftforge.fml.common.Loader; -import net.minecraftforge.fml.common.ObfuscationReflectionHelper; import java.nio.file.Files; import java.util.ArrayList; @@ -22,10 +20,10 @@ public void onResourceManagerReload(IResourceManager manager) { if(Loader.instance().activeModContainer() == null) return; if (Minecraft.getMinecraft().getLanguageManager().getCurrentLanguage() == null) return; String lang = Minecraft.getMinecraft().getLanguageManager().getCurrentLanguage().getLanguageCode(); - for (String appName : TerminalBuilder.getAllApps()) { - if (TerminalBuilder.getApplication(appName) instanceof GuideApp) { + for (String appName : TerminalRegistry.getAllApps()) { + if (TerminalRegistry.getApplication(appName) instanceof GuideApp) { List jsons = new ArrayList<>(); - GuideApp app = (GuideApp) TerminalBuilder.getApplication(appName); + GuideApp app = (GuideApp) TerminalRegistry.getApplication(appName); CraftingHelper.findFiles(Loader.instance().activeModContainer(), "assets/gregtech/terminal/guide/" + appName + "/en_us", Files::exists, (path, file) -> { if(file.toString().endsWith(".json")) { String fileName = file.getFileName().toString(); diff --git a/src/main/java/gregtech/common/CommonProxy.java b/src/main/java/gregtech/common/CommonProxy.java index 36a0105abd3..cc044893efd 100644 --- a/src/main/java/gregtech/common/CommonProxy.java +++ b/src/main/java/gregtech/common/CommonProxy.java @@ -7,7 +7,7 @@ import gregtech.api.recipes.crafttweaker.MetaItemBracketHandler; import gregtech.api.recipes.recipeproperties.BlastTemperatureProperty; import gregtech.api.recipes.recipeproperties.FusionEUToStartProperty; -import gregtech.api.terminal.TerminalBuilder; +import gregtech.api.terminal.TerminalRegistry; import gregtech.api.terminal.util.GuideJsonLoader; import gregtech.api.unification.material.Material; import gregtech.api.unification.material.properties.DustProperty; @@ -272,7 +272,7 @@ public void onLoad() { public void onPostLoad() { WoodMachineRecipes.postInit(); - TerminalBuilder.init(); + TerminalRegistry.init(); new GuideJsonLoader().onResourceManagerReload(null); } } From f7459745e49bd6b139878a8743bb2bd6e39c03e8 Mon Sep 17 00:00:00 2001 From: Yefancy Date: Tue, 17 Aug 2021 01:22:48 +0800 Subject: [PATCH 54/58] sync mechanism --- .../api/terminal/app/AbstractApplication.java | 11 +++ .../api/terminal/app/ThemeSettingApp.java | 3 +- .../api/terminal/app/guide/GuideApp.java | 3 +- .../app/guideeditor/GuideEditorApp.java | 4 +- .../app/recipechart/RecipeChartApp.java | 16 ++++- .../app/recipechart/widget/RGContainer.java | 6 +- .../app/recipechart/widget/RGLine.java | 13 ++++ .../app/recipechart/widget/RGNode.java | 8 ++- .../api/terminal/os/TerminalOSWidget.java | 70 ++++++++++++++++++- 9 files changed, 124 insertions(+), 10 deletions(-) diff --git a/src/main/java/gregtech/api/terminal/app/AbstractApplication.java b/src/main/java/gregtech/api/terminal/app/AbstractApplication.java index 9398957458d..112af08c911 100644 --- a/src/main/java/gregtech/api/terminal/app/AbstractApplication.java +++ b/src/main/java/gregtech/api/terminal/app/AbstractApplication.java @@ -8,9 +8,11 @@ import gregtech.api.util.Size; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.PacketBuffer; import java.util.Collections; import java.util.List; +import java.util.function.Consumer; public abstract class AbstractApplication extends AnimaWidgetGroup { protected final String name; @@ -50,6 +52,8 @@ public boolean isBackgroundApp() { return false; } + public boolean isClientSideApp() {return false;} + public TerminalOSWidget getOs() { return os; } @@ -61,4 +65,11 @@ public List getMenuComponents() { public boolean canPlayerUse(EntityPlayer player) { return true; } + + @Override + protected void writeClientAction(int id, Consumer packetBufferWriter) { + if (!isClientSideApp()) { + super.writeClientAction(id, packetBufferWriter); + } + } } diff --git a/src/main/java/gregtech/api/terminal/app/ThemeSettingApp.java b/src/main/java/gregtech/api/terminal/app/ThemeSettingApp.java index ae60a1f6598..b209f9265ad 100644 --- a/src/main/java/gregtech/api/terminal/app/ThemeSettingApp.java +++ b/src/main/java/gregtech/api/terminal/app/ThemeSettingApp.java @@ -150,6 +150,7 @@ private void addStringSetting(String init, Consumer callback) { } @Override - protected void writeClientAction(int id, Consumer packetBufferWriter) { + public boolean isClientSideApp() { + return true; } } diff --git a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java index b44bfddf8cc..e0fb2cf43bc 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java +++ b/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java @@ -80,7 +80,8 @@ protected void loadPage(TreeNode leaf) { } @Override - protected void writeClientAction(int id, Consumer packetBufferWriter) { + public boolean isClientSideApp() { + return true; } protected IGuiTexture itemIcon(T item) { diff --git a/src/main/java/gregtech/api/terminal/app/guideeditor/GuideEditorApp.java b/src/main/java/gregtech/api/terminal/app/guideeditor/GuideEditorApp.java index c9129d5d5f2..fbe0d0f4875 100644 --- a/src/main/java/gregtech/api/terminal/app/guideeditor/GuideEditorApp.java +++ b/src/main/java/gregtech/api/terminal/app/guideeditor/GuideEditorApp.java @@ -61,6 +61,8 @@ public List getMenuComponents() { } @Override - protected void writeClientAction(int id, Consumer packetBufferWriter) { + public boolean isClientSideApp() { + return true; } + } diff --git a/src/main/java/gregtech/api/terminal/app/recipechart/RecipeChartApp.java b/src/main/java/gregtech/api/terminal/app/recipechart/RecipeChartApp.java index 9633e2475c4..372e665dd54 100644 --- a/src/main/java/gregtech/api/terminal/app/recipechart/RecipeChartApp.java +++ b/src/main/java/gregtech/api/terminal/app/recipechart/RecipeChartApp.java @@ -20,11 +20,9 @@ import mezz.jei.api.gui.IRecipeLayout; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.network.PacketBuffer; import java.util.Arrays; import java.util.List; -import java.util.function.Consumer; public class RecipeChartApp extends AbstractApplication implements IRecipeTransferHandlerWidget { public static final TextureArea ICON = TextureArea.fullImage("textures/gui/terminal/recipe_graph/icon.png"); @@ -43,6 +41,10 @@ public AbstractApplication createApp(TerminalOSWidget os, boolean isClient, NBTT app.tabGroup = new TabGroup(0, 10, new CustomTabListRenderer(TerminalTheme.COLOR_F_2, TerminalTheme.COLOR_B_3, 60, 10)); app.addWidget(app.tabGroup); app.addTab("default"); + if (nbt != null) { + app.testnbt = nbt; + ((RGContainer) app.tabGroup.getCurrentTag()).loadFromNBT(nbt); + } } return app; } @@ -79,8 +81,16 @@ public List getMenuComponents() { } @Override - protected void writeClientAction(int id, Consumer packetBufferWriter) { + public NBTTagCompound closeApp(boolean isClient, NBTTagCompound nbt) { //synced data to server side. + if (isClient && testnbt != null) { + return testnbt; + } + return super.closeApp(isClient, nbt); + } + @Override + public boolean isClientSideApp() { + return true; } @Override diff --git a/src/main/java/gregtech/api/terminal/app/recipechart/widget/RGContainer.java b/src/main/java/gregtech/api/terminal/app/recipechart/widget/RGContainer.java index c17c2693f9d..fdb8fde71d6 100644 --- a/src/main/java/gregtech/api/terminal/app/recipechart/widget/RGContainer.java +++ b/src/main/java/gregtech/api/terminal/app/recipechart/widget/RGContainer.java @@ -124,6 +124,10 @@ public void loadFromNBT(NBTTagCompound nbt) { nodeTag.getTagList("children", Constants.NBT.TAG_INT_ARRAY)); this.addWidget(node); } + for (RGLine line : lines) { + removeWidget(line); + } + lines.clear(); NBTTagList linesList = nbt.getTagList("lines", Constants.NBT.TAG_COMPOUND); for (NBTBase node : linesList) { // build nodes RGLine line = RGLine.deserializeLineNBT((NBTTagCompound)node, this); @@ -144,7 +148,7 @@ public NBTTagCompound saveAsNBT() { nbt.setTag("nodes", nodesTag); NBTTagList linesTag = new NBTTagList(); for (RGLine line : lines) { - nodesTag.appendTag(line.serializeLineNBT()); + linesTag.appendTag(line.serializeLineNBT()); } nbt.setTag("lines", linesTag); return nbt; diff --git a/src/main/java/gregtech/api/terminal/app/recipechart/widget/RGLine.java b/src/main/java/gregtech/api/terminal/app/recipechart/widget/RGLine.java index 4e2db3025b3..c1482eeb4a4 100644 --- a/src/main/java/gregtech/api/terminal/app/recipechart/widget/RGLine.java +++ b/src/main/java/gregtech/api/terminal/app/recipechart/widget/RGLine.java @@ -1,11 +1,16 @@ package gregtech.api.terminal.app.recipechart.widget; +import gregtech.api.GTValues; +import gregtech.api.block.machines.MachineItemBlock; import gregtech.api.gui.GuiTextures; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.resources.ColorRectTexture; +import gregtech.api.gui.widgets.LabelWidget; import gregtech.api.gui.widgets.SimpleTextWidget; import gregtech.api.gui.widgets.SlotWidget; import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.SimpleMachineMetaTileEntity; import gregtech.api.terminal.gui.widgets.CircleButtonWidget; import gregtech.api.terminal.os.TerminalDialogWidget; import gregtech.api.terminal.os.TerminalTheme; @@ -43,6 +48,10 @@ public RGLine(RGNode parent, RGNode child, RGContainer container) { ItemStackHandler handler = new ItemStackHandler(); handler.setStackInSlot(0, catalyst); infoGroup.addWidget(new SlotWidget(handler, 0, 0, 0, false, false).setBackgroundTexture(new ColorRectTexture(0))); + MetaTileEntity mte = MachineItemBlock.getMetaTileEntity(catalyst); + if (mte instanceof SimpleMachineMetaTileEntity) { + infoGroup.addWidget(new LabelWidget(9, -10, "Tier: " + GTValues.VN[((SimpleMachineMetaTileEntity) mte).getTier()], -1).setXCentered(true).setShadow(true)); + } } infoGroup.setVisible(false); @@ -84,6 +93,9 @@ public RGLine(RGNode parent, RGNode child, RGContainer container) { public static RGLine deserializeLineNBT(NBTTagCompound nbt, RGContainer container) { RGLine line = new RGLine(container.nodes.get(nbt.getInteger("parent")), container.nodes.get(nbt.getInteger("child")), container); line.ratio = nbt.getInteger("ratio"); + boolean visible = nbt.getBoolean("visible"); + line.infoGroup.setVisible(visible); + line.infoGroup.setActive(visible); return line; } @@ -92,6 +104,7 @@ public NBTTagCompound serializeLineNBT() { nbt.setInteger("parent", container.nodes.indexOf(parent)); nbt.setInteger("child", container.nodes.indexOf(child)); nbt.setInteger("ratio", ratio); + nbt.setBoolean("visible", infoGroup.isVisible()); return nbt; } diff --git a/src/main/java/gregtech/api/terminal/app/recipechart/widget/RGNode.java b/src/main/java/gregtech/api/terminal/app/recipechart/widget/RGNode.java index 6ebae440c4d..7f5db09e464 100644 --- a/src/main/java/gregtech/api/terminal/app/recipechart/widget/RGNode.java +++ b/src/main/java/gregtech/api/terminal/app/recipechart/widget/RGNode.java @@ -51,6 +51,7 @@ public class RGNode extends WidgetGroup implements IDraggable { private WidgetGroup toolGroup; private WidgetGroup inputsGroup; private RGContainer container; + private SimpleTextWidget textWidget; protected Map parentNodes; protected Map> children; @@ -89,7 +90,7 @@ public RGNode(int x, int y, RGContainer container, Object head, boolean isPhanto private void init(RGContainer container) { this.container = container; - SimpleTextWidget textWidget = new SimpleTextWidget(9, -5, "", -1, () -> { + textWidget = new SimpleTextWidget(9, -5, "", -1, () -> { if (head instanceof ItemStack) { return ((ItemStack) head).getDisplayName(); } else if (head instanceof FluidStack) { @@ -98,6 +99,7 @@ private void init(RGContainer container) { return "Drag ingredients into slot."; }, true).setShadow(true); textWidget.setVisible(false); + textWidget.setActive(false); this.addWidget(textWidget); inputsGroup = new WidgetGroup(0, 0, 0, 0); this.addWidget(inputsGroup); @@ -408,6 +410,9 @@ public static RGNode deserializeNodeNBT(NBTTagCompound nodeTag, RGContainer cont fluidsList.tagList.stream().map(it->FluidStack.loadFluidStackFromNBT((NBTTagCompound) it)).collect(Collectors.toList()), nodeTag.hasKey("catalyst") ? new ItemStack(nodeTag.getCompoundTag("catalyst")) : null, nodeTag.getInteger("per")); + boolean visible = nodeTag.getBoolean("visible"); + node.textWidget.setVisible(visible); + node.textWidget.setActive(visible); return node; } @@ -454,6 +459,7 @@ public NBTTagCompound serializeNodeNBT() { parentsList.appendTag(new NBTTagIntArray(new int[]{container.nodes.indexOf(entry.getKey()), entry.getValue()})); } nbt.setTag("parents", parentsList); + nbt.setBoolean("visible", textWidget.isVisible()); return nbt; } diff --git a/src/main/java/gregtech/api/terminal/os/TerminalOSWidget.java b/src/main/java/gregtech/api/terminal/os/TerminalOSWidget.java index 2151b87ff0e..fe9931bc7e8 100644 --- a/src/main/java/gregtech/api/terminal/os/TerminalOSWidget.java +++ b/src/main/java/gregtech/api/terminal/os/TerminalOSWidget.java @@ -14,7 +14,11 @@ import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.nbt.NBTTagString; +import net.minecraft.network.PacketBuffer; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -24,7 +28,7 @@ public class TerminalOSWidget extends AbstractWidgetGroup { public AbstractApplication focusApp; public final TerminalMenuWidget menu; public final TerminalDesktopWidget desktop; - private NBTTagCompound tabletNBT; + private final NBTTagCompound tabletNBT; public TerminalOSWidget(int xPosition, int yPosition, int width, int height, NBTTagCompound tabletNBT) { super(new Position(xPosition, yPosition), new Size(width, height)); @@ -106,7 +110,7 @@ public void minimizeApplication(AbstractApplication application, boolean isClien } } - public void closeApplication(AbstractApplication application, boolean isClient) { + public NBTTagCompound closeApplication(AbstractApplication application, boolean isClient) { if (application != null) { NBTTagCompound nbt = application.closeApp(isClient, tabletNBT.getCompoundTag(application.getRegistryName())); if (nbt != null) { @@ -123,7 +127,9 @@ public void closeApplication(AbstractApplication application, boolean isClient) } menu.removeComponents(); desktop.showDesktop(); + return nbt; } + return null; } public void homeTrigger(boolean isClient) { @@ -136,6 +142,22 @@ public void homeTrigger(boolean isClient) { } } + @SideOnly(Side.CLIENT) + private void shutdown() { + NBTTagCompound nbt = new NBTTagCompound(); + for (AbstractApplication openedApp : openedApps) { + String appName = openedApp.getRegistryName(); + NBTTagCompound synced = openedApp.closeApp(true, tabletNBT.getCompoundTag(appName)); + if (synced != null) { + tabletNBT.setTag(appName, synced); + if (openedApp.isClientSideApp()) {//if its a clientSideApp and the nbt not null, meaning this nbt should be synced to the server side. + nbt.setTag(appName, synced); + } + } + } + writeClientAction(-1, buffer -> buffer.writeCompoundTag(nbt)); + } + protected TerminalDialogWidget openDialog(TerminalDialogWidget widget) { if (isRemote()) { widget.maximizeWidget(null); @@ -155,6 +177,29 @@ protected TerminalDialogWidget closeDialog(TerminalDialogWidget widget) { return widget; } + @Override + public void handleClientAction(int id, PacketBuffer buffer) { + if (id == -1) { //shutdown + NBTTagCompound nbt = null; + try { + nbt = buffer.readCompoundTag(); + } catch (IOException e) { + e.printStackTrace(); + } + for (AbstractApplication openedApp : openedApps) { + String appName = openedApp.getRegistryName(); + NBTTagCompound data = openedApp.closeApp(true, tabletNBT.getCompoundTag(appName)); + if (data != null) { + tabletNBT.setTag(appName, data); + } else if (nbt != null && openedApp.isClientSideApp() && nbt.hasKey(appName)) { + tabletNBT.setTag(appName, nbt.getCompoundTag(appName)); + } + } + this.getModularUI().entityPlayer.closeScreen(); // must close tablet from server side. + } + super.handleClientAction(id, buffer); + } + @Override public void updateScreen() { super.updateScreen(); @@ -177,4 +222,25 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender }); } + boolean waitShutdown; + @Override + public boolean keyTyped(char charTyped, int keyCode) { + if (keyCode == 1) { // hook esc + if (waitShutdown) { + shutdown(); + } else { + waitShutdown = true; + TerminalDialogWidget.showConfirmDialog(this, "Notice", "Confirm the shutdown? (Click ESC again to see ok)", result->{ + if (result) { + shutdown(); + } else { + waitShutdown = false; + } + }).setClientSide().open(); + } + return true; + } + waitShutdown = false; + return super.keyTyped(charTyped, keyCode); + } } From 366a00cfd498483bab07988fd16b75b2e020711c Mon Sep 17 00:00:00 2001 From: Yefancy Date: Tue, 17 Aug 2021 14:02:06 +0800 Subject: [PATCH 55/58] clean up --- src/main/java/gregtech/api/GregTechAPI.java | 6 --- .../gregtech/api/gui/widgets/LabelWidget.java | 43 ++++++++++++++++--- .../api/terminal/TerminalRegistry.java | 13 +++--- .../api/terminal/app/AbstractApplication.java | 2 +- .../api/terminal/os/TerminalDialogWidget.java | 5 ++- .../menu/{component => }/IMenuComponent.java | 2 +- .../terminal/os/menu/TerminalMenuWidget.java | 1 - .../api/terminal/util/GuideJsonLoader.java | 2 +- .../terminal/app/ThemeSettingApp.java | 4 +- .../terminal/app/guide/GuideApp.java | 10 ++--- .../terminal/app/guide/ItemGuideApp.java | 2 +- .../app/guide/MultiBlockGuideApp.java | 2 +- .../app/guide/SimpleMachineGuideApp.java | 2 +- .../terminal/app/guide/TutorialGuideApp.java | 2 +- .../terminal/app/guide/widget/CardWidget.java | 6 +-- .../app/guide/widget/GuidePageWidget.java | 2 +- .../app/guide/widget/GuideWidget.java | 10 ++--- .../app/guide/widget/GuideWidgetGroup.java | 10 ++--- .../app/guide/widget/IGuideWidget.java | 2 +- .../app/guide/widget/ImageWidget.java | 8 ++-- .../app/guide/widget/SlotListWidget.java | 4 +- .../app/guide/widget/TankListWidget.java | 4 +- .../app/guide/widget/TextBoxWidget.java | 10 ++--- .../app/guideeditor/GuideEditorApp.java | 12 +++--- .../guideeditor/widget/GuideConfigEditor.java | 8 ++-- .../widget/GuidePageEditorWidget.java | 6 +-- .../configurator/BooleanConfigurator.java | 2 +- .../configurator/ColorConfigurator.java | 2 +- .../configurator/ConfiguratorWidget.java | 2 +- .../configurator/FluidStackConfigurator.java | 4 +- .../configurator/ItemStackConfigurator.java | 4 +- .../configurator/NumberConfigurator.java | 3 +- .../configurator/SelectorConfigurator.java | 2 +- .../configurator/StringConfigurator.java | 3 +- .../configurator/TextListConfigurator.java | 2 +- .../app/recipechart/RecipeChartApp.java | 10 ++--- .../app/recipechart/widget/PhantomWidget.java | 2 +- .../app/recipechart/widget/RGContainer.java | 2 +- .../app/recipechart/widget/RGLine.java | 2 +- .../app/recipechart/widget/RGNode.java | 2 +- .../terminal}/component/ClickComponent.java | 5 ++- .../terminal}/component/SearchComponent.java | 5 ++- .../component/setting/GuiTextureSetter.java | 2 +- .../terminal}/component/setting/ISetting.java | 2 +- .../component/setting/IWidgetSettings.java | 2 +- .../component/setting/SettingComponent.java | 4 +- 46 files changed, 132 insertions(+), 108 deletions(-) rename src/main/java/gregtech/api/terminal/os/menu/{component => }/IMenuComponent.java (88%) rename src/main/java/gregtech/{api => common}/terminal/app/ThemeSettingApp.java (98%) rename src/main/java/gregtech/{api => common}/terminal/app/guide/GuideApp.java (95%) rename src/main/java/gregtech/{api => common}/terminal/app/guide/ItemGuideApp.java (98%) rename src/main/java/gregtech/{api => common}/terminal/app/guide/MultiBlockGuideApp.java (97%) rename src/main/java/gregtech/{api => common}/terminal/app/guide/SimpleMachineGuideApp.java (97%) rename src/main/java/gregtech/{api => common}/terminal/app/guide/TutorialGuideApp.java (94%) rename src/main/java/gregtech/{api => common}/terminal/app/guide/widget/CardWidget.java (94%) rename src/main/java/gregtech/{api => common}/terminal/app/guide/widget/GuidePageWidget.java (99%) rename src/main/java/gregtech/{api => common}/terminal/app/guide/widget/GuideWidget.java (93%) rename src/main/java/gregtech/{api => common}/terminal/app/guide/widget/GuideWidgetGroup.java (94%) rename src/main/java/gregtech/{api => common}/terminal/app/guide/widget/IGuideWidget.java (97%) rename src/main/java/gregtech/{api => common}/terminal/app/guide/widget/ImageWidget.java (91%) rename src/main/java/gregtech/{api => common}/terminal/app/guide/widget/SlotListWidget.java (96%) rename src/main/java/gregtech/{api => common}/terminal/app/guide/widget/TankListWidget.java (96%) rename src/main/java/gregtech/{api => common}/terminal/app/guide/widget/TextBoxWidget.java (92%) rename src/main/java/gregtech/{api => common}/terminal/app/guideeditor/GuideEditorApp.java (84%) rename src/main/java/gregtech/{api => common}/terminal/app/guideeditor/widget/GuideConfigEditor.java (97%) rename src/main/java/gregtech/{api => common}/terminal/app/guideeditor/widget/GuidePageEditorWidget.java (98%) rename src/main/java/gregtech/{api => common}/terminal/app/guideeditor/widget/configurator/BooleanConfigurator.java (95%) rename src/main/java/gregtech/{api => common}/terminal/app/guideeditor/widget/configurator/ColorConfigurator.java (92%) rename src/main/java/gregtech/{api => common}/terminal/app/guideeditor/widget/configurator/ConfiguratorWidget.java (98%) rename src/main/java/gregtech/{api => common}/terminal/app/guideeditor/widget/configurator/FluidStackConfigurator.java (97%) rename src/main/java/gregtech/{api => common}/terminal/app/guideeditor/widget/configurator/ItemStackConfigurator.java (97%) rename src/main/java/gregtech/{api => common}/terminal/app/guideeditor/widget/configurator/NumberConfigurator.java (96%) rename src/main/java/gregtech/{api => common}/terminal/app/guideeditor/widget/configurator/SelectorConfigurator.java (94%) rename src/main/java/gregtech/{api => common}/terminal/app/guideeditor/widget/configurator/StringConfigurator.java (93%) rename src/main/java/gregtech/{api => common}/terminal/app/guideeditor/widget/configurator/TextListConfigurator.java (95%) rename src/main/java/gregtech/{api => common}/terminal/app/recipechart/RecipeChartApp.java (93%) rename src/main/java/gregtech/{api => common}/terminal/app/recipechart/widget/PhantomWidget.java (98%) rename src/main/java/gregtech/{api => common}/terminal/app/recipechart/widget/RGContainer.java (99%) rename src/main/java/gregtech/{api => common}/terminal/app/recipechart/widget/RGLine.java (99%) rename src/main/java/gregtech/{api => common}/terminal/app/recipechart/widget/RGNode.java (99%) rename src/main/java/gregtech/{api/terminal/os/menu => common/terminal}/component/ClickComponent.java (85%) rename src/main/java/gregtech/{api/terminal/os/menu => common/terminal}/component/SearchComponent.java (97%) rename src/main/java/gregtech/{api/terminal/os/menu => common/terminal}/component/setting/GuiTextureSetter.java (92%) rename src/main/java/gregtech/{api/terminal/os/menu => common/terminal}/component/setting/ISetting.java (76%) rename src/main/java/gregtech/{api/terminal/os/menu => common/terminal}/component/setting/IWidgetSettings.java (69%) rename src/main/java/gregtech/{api/terminal/os/menu => common/terminal}/component/setting/SettingComponent.java (89%) diff --git a/src/main/java/gregtech/api/GregTechAPI.java b/src/main/java/gregtech/api/GregTechAPI.java index b79496a2fd1..2b7342f9a81 100644 --- a/src/main/java/gregtech/api/GregTechAPI.java +++ b/src/main/java/gregtech/api/GregTechAPI.java @@ -2,9 +2,6 @@ import gregtech.api.block.machines.BlockMachine; import gregtech.api.metatileentity.MetaTileEntity; -import gregtech.api.metatileentity.multiblock.MultiblockControllerBase; -import gregtech.api.terminal.app.guide.MultiBlockGuideApp; -import gregtech.api.terminal.app.guide.SimpleMachineGuideApp; import gregtech.api.unification.OreDictUnifier; import gregtech.api.unification.material.Material; import gregtech.api.unification.material.Materials; @@ -14,9 +11,6 @@ import gregtech.api.util.GTControlledRegistry; import gregtech.api.util.IBlockOre; import gregtech.common.items.MetaItems; -import gregtech.common.metatileentities.electric.multiblockpart.MetaTileEntityMultiblockPart; -import net.minecraft.client.Minecraft; -import net.minecraft.client.resources.I18n; import net.minecraft.util.ResourceLocation; import java.util.HashMap; diff --git a/src/main/java/gregtech/api/gui/widgets/LabelWidget.java b/src/main/java/gregtech/api/gui/widgets/LabelWidget.java index 206cb6e0103..57a7988549b 100644 --- a/src/main/java/gregtech/api/gui/widgets/LabelWidget.java +++ b/src/main/java/gregtech/api/gui/widgets/LabelWidget.java @@ -11,16 +11,24 @@ import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + import static gregtech.api.gui.impl.ModularUIGui.*; public class LabelWidget extends Widget { - protected boolean xCentered = false; + protected boolean xCentered; + protected boolean yCentered; + protected int width; protected final String text; protected final Object[] formatting; private final int color; private boolean dropShadow; + @SideOnly(Side.CLIENT) + private List texts; public LabelWidget(int xPosition, int yPosition, String text, Object... formatting) { this(xPosition, yPosition, text, 0x404040, formatting); @@ -35,6 +43,9 @@ public LabelWidget(int xPosition, int yPosition, String text, int color, Object[ this.text = text; this.color = color; this.formatting = formatting; + if (isClientSide()) { + texts = Collections.singletonList(getResultText()); + } recomputeSize(); } @@ -43,6 +54,23 @@ public LabelWidget setShadow(boolean dropShadow){ return this; } + public LabelWidget setWidth(int width) { + this.width = width; + if (isClientSide()) { + if (this.width > 0) { + texts = Minecraft.getMinecraft().fontRenderer.listFormattedStringToWidth(getResultText(), width); + } else { + texts = Collections.singletonList(getResultText()); + } + } + return this; + } + + public LabelWidget setYCentered(boolean yCentered) { + this.yCentered = yCentered; + return this; + } + private String getResultText() { return I18n.format(text, formatting); } @@ -66,14 +94,17 @@ public LabelWidget setXCentered(boolean xCentered) { @Override @SideOnly(Side.CLIENT) public void drawInBackground(int mouseX, int mouseY, IRenderContext context) { - String resultText = getResultText(); FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer; Position pos = getPosition(); - if (!xCentered) { - fontRenderer.drawString(resultText, pos.x, pos.y, color, dropShadow); - } else { - fontRenderer.drawString(resultText, pos.x - fontRenderer.getStringWidth(resultText) / 2.0f, pos.y, color, dropShadow); + int height = fontRenderer.FONT_HEIGHT * texts.size(); + for (int i = 0; i < texts.size(); i++) { + String resultText = texts.get(i); + int width = fontRenderer.getStringWidth(resultText);; + float x = pos.x - (xCentered ? width / 2f : 0); + float y = pos.y - (yCentered ? height / 2f : 0) + i * fontRenderer.FONT_HEIGHT; + fontRenderer.drawString(resultText, x, y, color, dropShadow); } + GlStateManager.color(rColorForOverlay, gColorForOverlay, bColorForOverlay, 1.0F); } diff --git a/src/main/java/gregtech/api/terminal/TerminalRegistry.java b/src/main/java/gregtech/api/terminal/TerminalRegistry.java index 9ac79f39d7e..d0f1a7303c9 100644 --- a/src/main/java/gregtech/api/terminal/TerminalRegistry.java +++ b/src/main/java/gregtech/api/terminal/TerminalRegistry.java @@ -2,12 +2,13 @@ import gregtech.api.GTValues; import gregtech.api.terminal.app.*; -import gregtech.api.terminal.app.guide.ItemGuideApp; -import gregtech.api.terminal.app.guide.MultiBlockGuideApp; -import gregtech.api.terminal.app.guide.SimpleMachineGuideApp; -import gregtech.api.terminal.app.guide.TutorialGuideApp; -import gregtech.api.terminal.app.guideeditor.GuideEditorApp; -import gregtech.api.terminal.app.recipechart.RecipeChartApp; +import gregtech.common.terminal.app.ThemeSettingApp; +import gregtech.common.terminal.app.guide.ItemGuideApp; +import gregtech.common.terminal.app.guide.MultiBlockGuideApp; +import gregtech.common.terminal.app.guide.SimpleMachineGuideApp; +import gregtech.common.terminal.app.guide.TutorialGuideApp; +import gregtech.common.terminal.app.guideeditor.GuideEditorApp; +import gregtech.common.terminal.app.recipechart.RecipeChartApp; import java.util.*; diff --git a/src/main/java/gregtech/api/terminal/app/AbstractApplication.java b/src/main/java/gregtech/api/terminal/app/AbstractApplication.java index 112af08c911..843c645e93e 100644 --- a/src/main/java/gregtech/api/terminal/app/AbstractApplication.java +++ b/src/main/java/gregtech/api/terminal/app/AbstractApplication.java @@ -3,7 +3,7 @@ import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.terminal.gui.widgets.AnimaWidgetGroup; import gregtech.api.terminal.os.TerminalOSWidget; -import gregtech.api.terminal.os.menu.component.IMenuComponent; +import gregtech.api.terminal.os.menu.IMenuComponent; import gregtech.api.util.Position; import gregtech.api.util.Size; import net.minecraft.entity.player.EntityPlayer; diff --git a/src/main/java/gregtech/api/terminal/os/TerminalDialogWidget.java b/src/main/java/gregtech/api/terminal/os/TerminalDialogWidget.java index cd9435d2bae..67fa2052fd4 100644 --- a/src/main/java/gregtech/api/terminal/os/TerminalDialogWidget.java +++ b/src/main/java/gregtech/api/terminal/os/TerminalDialogWidget.java @@ -14,6 +14,7 @@ import gregtech.api.terminal.util.FileTree; import gregtech.api.util.Size; import gregtech.api.util.interpolate.Interpolator; +import net.minecraft.client.renderer.GlStateManager; import net.minecraft.inventory.IInventory; import net.minecraft.network.PacketBuffer; @@ -98,7 +99,7 @@ public TerminalDialogWidget addTitle(String title) { } public TerminalDialogWidget addInfo(String info) { - this.addWidget(new LabelWidget(WIDTH / 2, HEIGHT / 2 - 10, info, -1).setXCentered(true)); + this.addWidget(new LabelWidget(WIDTH / 2, HEIGHT / 2, info, -1).setWidth(WIDTH - 10).setYCentered(true).setXCentered(true)); return this; } @@ -237,10 +238,12 @@ public static TerminalDialogWidget showFileDialog(TerminalOSWidget os, String ti @Override public void hookDrawInBackground(int mouseX, int mouseY, float partialTicks, IRenderContext context) { + GlStateManager.translate(0,0,1000); if (background != null) { background.draw(getPosition().x, getPosition().y, getSize().width, getSize().height); } super.hookDrawInBackground(mouseX, mouseY, partialTicks, context); + GlStateManager.translate(0,0,-1000); } @Override diff --git a/src/main/java/gregtech/api/terminal/os/menu/component/IMenuComponent.java b/src/main/java/gregtech/api/terminal/os/menu/IMenuComponent.java similarity index 88% rename from src/main/java/gregtech/api/terminal/os/menu/component/IMenuComponent.java rename to src/main/java/gregtech/api/terminal/os/menu/IMenuComponent.java index 46a7f63fbb8..22c5ef1d47f 100644 --- a/src/main/java/gregtech/api/terminal/os/menu/component/IMenuComponent.java +++ b/src/main/java/gregtech/api/terminal/os/menu/IMenuComponent.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.os.menu.component; +package gregtech.api.terminal.os.menu; import gregtech.api.gui.Widget; import gregtech.api.gui.resources.ColorRectTexture; diff --git a/src/main/java/gregtech/api/terminal/os/menu/TerminalMenuWidget.java b/src/main/java/gregtech/api/terminal/os/menu/TerminalMenuWidget.java index 5824a033bf3..70ad3ce8578 100644 --- a/src/main/java/gregtech/api/terminal/os/menu/TerminalMenuWidget.java +++ b/src/main/java/gregtech/api/terminal/os/menu/TerminalMenuWidget.java @@ -8,7 +8,6 @@ import gregtech.api.terminal.gui.widgets.CircleButtonWidget; import gregtech.api.terminal.os.TerminalOSWidget; import gregtech.api.terminal.os.TerminalTheme; -import gregtech.api.terminal.os.menu.component.IMenuComponent; import gregtech.api.util.Position; import gregtech.api.util.Size; import gregtech.api.util.interpolate.Eases; diff --git a/src/main/java/gregtech/api/terminal/util/GuideJsonLoader.java b/src/main/java/gregtech/api/terminal/util/GuideJsonLoader.java index 298055c4df8..af2ccced8c8 100644 --- a/src/main/java/gregtech/api/terminal/util/GuideJsonLoader.java +++ b/src/main/java/gregtech/api/terminal/util/GuideJsonLoader.java @@ -2,7 +2,7 @@ import com.google.gson.JsonObject; import gregtech.api.terminal.TerminalRegistry; -import gregtech.api.terminal.app.guide.GuideApp; +import gregtech.common.terminal.app.guide.GuideApp; import net.minecraft.client.Minecraft; import net.minecraft.client.resources.IResourceManager; import net.minecraft.client.resources.IResourceManagerReloadListener; diff --git a/src/main/java/gregtech/api/terminal/app/ThemeSettingApp.java b/src/main/java/gregtech/common/terminal/app/ThemeSettingApp.java similarity index 98% rename from src/main/java/gregtech/api/terminal/app/ThemeSettingApp.java rename to src/main/java/gregtech/common/terminal/app/ThemeSettingApp.java index b209f9265ad..eddddc81f56 100644 --- a/src/main/java/gregtech/api/terminal/app/ThemeSettingApp.java +++ b/src/main/java/gregtech/common/terminal/app/ThemeSettingApp.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app; +package gregtech.common.terminal.app; import gregtech.api.gui.GuiTextures; import gregtech.api.gui.resources.*; @@ -6,6 +6,7 @@ import gregtech.api.gui.widgets.LabelWidget; import gregtech.api.gui.widgets.TextFieldWidget; import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.terminal.app.AbstractApplication; import gregtech.api.terminal.gui.widgets.CircleButtonWidget; import gregtech.api.terminal.gui.widgets.ColorWidget; import gregtech.api.terminal.gui.widgets.RectButtonWidget; @@ -14,7 +15,6 @@ import gregtech.api.terminal.os.TerminalOSWidget; import gregtech.api.terminal.os.TerminalTheme; import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.network.PacketBuffer; import net.minecraft.util.ResourceLocation; import java.awt.*; diff --git a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java b/src/main/java/gregtech/common/terminal/app/guide/GuideApp.java similarity index 95% rename from src/main/java/gregtech/api/terminal/app/guide/GuideApp.java rename to src/main/java/gregtech/common/terminal/app/guide/GuideApp.java index e0fb2cf43bc..0d55a95e205 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/GuideApp.java +++ b/src/main/java/gregtech/common/terminal/app/guide/GuideApp.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.guide; +package gregtech.common.terminal.app.guide; import com.google.gson.Gson; import com.google.gson.JsonElement; @@ -7,17 +7,15 @@ import gregtech.api.gui.GuiTextures; import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.terminal.app.AbstractApplication; -import gregtech.api.terminal.app.guide.widget.GuidePageWidget; +import gregtech.common.terminal.app.guide.widget.GuidePageWidget; import gregtech.api.terminal.gui.widgets.TreeListWidget; import gregtech.api.terminal.os.TerminalOSWidget; -import gregtech.api.terminal.os.menu.component.IMenuComponent; -import gregtech.api.terminal.os.menu.component.SearchComponent; +import gregtech.api.terminal.os.menu.IMenuComponent; +import gregtech.common.terminal.component.SearchComponent; import gregtech.api.terminal.util.TreeNode; import net.minecraft.client.Minecraft; import net.minecraft.client.resources.I18n; -import net.minecraft.client.resources.Language; import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.network.PacketBuffer; import net.minecraft.util.ResourceLocation; import net.minecraftforge.fml.common.FMLCommonHandler; diff --git a/src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java b/src/main/java/gregtech/common/terminal/app/guide/ItemGuideApp.java similarity index 98% rename from src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java rename to src/main/java/gregtech/common/terminal/app/guide/ItemGuideApp.java index 1966aa793f0..516cd42e60f 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/ItemGuideApp.java +++ b/src/main/java/gregtech/common/terminal/app/guide/ItemGuideApp.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.guide; +package gregtech.common.terminal.app.guide; import com.google.gson.JsonElement; import com.google.gson.JsonObject; diff --git a/src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java b/src/main/java/gregtech/common/terminal/app/guide/MultiBlockGuideApp.java similarity index 97% rename from src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java rename to src/main/java/gregtech/common/terminal/app/guide/MultiBlockGuideApp.java index bc942a6fd97..c146884be5f 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/MultiBlockGuideApp.java +++ b/src/main/java/gregtech/common/terminal/app/guide/MultiBlockGuideApp.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.guide; +package gregtech.common.terminal.app.guide; import com.google.gson.JsonElement; import com.google.gson.JsonObject; diff --git a/src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java b/src/main/java/gregtech/common/terminal/app/guide/SimpleMachineGuideApp.java similarity index 97% rename from src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java rename to src/main/java/gregtech/common/terminal/app/guide/SimpleMachineGuideApp.java index b584b5c4a73..e0b021ed368 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/SimpleMachineGuideApp.java +++ b/src/main/java/gregtech/common/terminal/app/guide/SimpleMachineGuideApp.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.guide; +package gregtech.common.terminal.app.guide; import com.google.gson.JsonElement; import com.google.gson.JsonObject; diff --git a/src/main/java/gregtech/api/terminal/app/guide/TutorialGuideApp.java b/src/main/java/gregtech/common/terminal/app/guide/TutorialGuideApp.java similarity index 94% rename from src/main/java/gregtech/api/terminal/app/guide/TutorialGuideApp.java rename to src/main/java/gregtech/common/terminal/app/guide/TutorialGuideApp.java index 82f07ba1f1b..4092d7641f7 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/TutorialGuideApp.java +++ b/src/main/java/gregtech/common/terminal/app/guide/TutorialGuideApp.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.guide; +package gregtech.common.terminal.app.guide; import com.google.gson.JsonObject; import gregtech.api.gui.resources.ItemStackTexture; diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/CardWidget.java b/src/main/java/gregtech/common/terminal/app/guide/widget/CardWidget.java similarity index 94% rename from src/main/java/gregtech/api/terminal/app/guide/widget/CardWidget.java rename to src/main/java/gregtech/common/terminal/app/guide/widget/CardWidget.java index a3e8f6a1f76..e2832411242 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/CardWidget.java +++ b/src/main/java/gregtech/common/terminal/app/guide/widget/CardWidget.java @@ -1,11 +1,11 @@ -package gregtech.api.terminal.app.guide.widget; +package gregtech.common.terminal.app.guide.widget; import com.google.gson.JsonObject; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; -import gregtech.api.terminal.app.guideeditor.widget.configurator.BooleanConfigurator; -import gregtech.api.terminal.app.guideeditor.widget.configurator.NumberConfigurator; +import gregtech.common.terminal.app.guideeditor.widget.configurator.BooleanConfigurator; +import gregtech.common.terminal.app.guideeditor.widget.configurator.NumberConfigurator; import gregtech.api.util.Position; import gregtech.api.util.Size; import net.minecraft.client.renderer.BufferBuilder; diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/GuidePageWidget.java b/src/main/java/gregtech/common/terminal/app/guide/widget/GuidePageWidget.java similarity index 99% rename from src/main/java/gregtech/api/terminal/app/guide/widget/GuidePageWidget.java rename to src/main/java/gregtech/common/terminal/app/guide/widget/GuidePageWidget.java index fb3c7c29b4d..ddbd26f5d19 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/GuidePageWidget.java +++ b/src/main/java/gregtech/common/terminal/app/guide/widget/GuidePageWidget.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.guide.widget; +package gregtech.common.terminal.app.guide.widget; import com.google.gson.JsonElement; diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/GuideWidget.java b/src/main/java/gregtech/common/terminal/app/guide/widget/GuideWidget.java similarity index 93% rename from src/main/java/gregtech/api/terminal/app/guide/widget/GuideWidget.java rename to src/main/java/gregtech/common/terminal/app/guide/widget/GuideWidget.java index fda63019391..be8892b28e1 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/GuideWidget.java +++ b/src/main/java/gregtech/common/terminal/app/guide/widget/GuideWidget.java @@ -1,14 +1,14 @@ -package gregtech.api.terminal.app.guide.widget; +package gregtech.common.terminal.app.guide.widget; import com.google.gson.Gson; import com.google.gson.JsonObject; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; -import gregtech.api.terminal.app.guideeditor.widget.configurator.ColorConfigurator; -import gregtech.api.terminal.app.guideeditor.widget.configurator.NumberConfigurator; -import gregtech.api.terminal.app.guideeditor.widget.configurator.StringConfigurator; -import gregtech.api.terminal.app.guideeditor.widget.configurator.TextListConfigurator; +import gregtech.common.terminal.app.guideeditor.widget.configurator.ColorConfigurator; +import gregtech.common.terminal.app.guideeditor.widget.configurator.NumberConfigurator; +import gregtech.common.terminal.app.guideeditor.widget.configurator.StringConfigurator; +import gregtech.common.terminal.app.guideeditor.widget.configurator.TextListConfigurator; import gregtech.api.util.Position; import gregtech.api.util.Size; import net.minecraft.item.ItemStack; diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/GuideWidgetGroup.java b/src/main/java/gregtech/common/terminal/app/guide/widget/GuideWidgetGroup.java similarity index 94% rename from src/main/java/gregtech/api/terminal/app/guide/widget/GuideWidgetGroup.java rename to src/main/java/gregtech/common/terminal/app/guide/widget/GuideWidgetGroup.java index 0ac2f9c3542..4b765ce106f 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/GuideWidgetGroup.java +++ b/src/main/java/gregtech/common/terminal/app/guide/widget/GuideWidgetGroup.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.guide.widget; +package gregtech.common.terminal.app.guide.widget; import com.google.gson.Gson; import com.google.gson.JsonObject; @@ -6,10 +6,10 @@ import gregtech.api.gui.Widget; import gregtech.api.gui.widgets.WidgetGroup; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; -import gregtech.api.terminal.app.guideeditor.widget.configurator.ColorConfigurator; -import gregtech.api.terminal.app.guideeditor.widget.configurator.NumberConfigurator; -import gregtech.api.terminal.app.guideeditor.widget.configurator.StringConfigurator; -import gregtech.api.terminal.app.guideeditor.widget.configurator.TextListConfigurator; +import gregtech.common.terminal.app.guideeditor.widget.configurator.ColorConfigurator; +import gregtech.common.terminal.app.guideeditor.widget.configurator.NumberConfigurator; +import gregtech.common.terminal.app.guideeditor.widget.configurator.StringConfigurator; +import gregtech.common.terminal.app.guideeditor.widget.configurator.TextListConfigurator; import gregtech.api.util.Position; import gregtech.api.util.Size; import net.minecraft.item.ItemStack; diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/IGuideWidget.java b/src/main/java/gregtech/common/terminal/app/guide/widget/IGuideWidget.java similarity index 97% rename from src/main/java/gregtech/api/terminal/app/guide/widget/IGuideWidget.java rename to src/main/java/gregtech/common/terminal/app/guide/widget/IGuideWidget.java index cd6f91be62b..d1c754ef30b 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/IGuideWidget.java +++ b/src/main/java/gregtech/common/terminal/app/guide/widget/IGuideWidget.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.guide.widget; +package gregtech.common.terminal.app.guide.widget; import com.google.gson.Gson; import com.google.gson.JsonElement; diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/ImageWidget.java b/src/main/java/gregtech/common/terminal/app/guide/widget/ImageWidget.java similarity index 91% rename from src/main/java/gregtech/api/terminal/app/guide/widget/ImageWidget.java rename to src/main/java/gregtech/common/terminal/app/guide/widget/ImageWidget.java index 8749aa572be..620fe8bcfe8 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/ImageWidget.java +++ b/src/main/java/gregtech/common/terminal/app/guide/widget/ImageWidget.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.guide.widget; +package gregtech.common.terminal.app.guide.widget; import com.google.gson.JsonObject; import gregtech.api.gui.IRenderContext; @@ -8,9 +8,9 @@ import gregtech.api.gui.resources.TextureArea; import gregtech.api.gui.resources.URLTexture; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; -import gregtech.api.terminal.app.guideeditor.widget.configurator.NumberConfigurator; -import gregtech.api.terminal.app.guideeditor.widget.configurator.SelectorConfigurator; -import gregtech.api.terminal.app.guideeditor.widget.configurator.StringConfigurator; +import gregtech.common.terminal.app.guideeditor.widget.configurator.NumberConfigurator; +import gregtech.common.terminal.app.guideeditor.widget.configurator.SelectorConfigurator; +import gregtech.common.terminal.app.guideeditor.widget.configurator.StringConfigurator; import gregtech.api.util.Position; import gregtech.api.util.Size; import net.minecraft.client.renderer.GlStateManager; diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/SlotListWidget.java b/src/main/java/gregtech/common/terminal/app/guide/widget/SlotListWidget.java similarity index 96% rename from src/main/java/gregtech/api/terminal/app/guide/widget/SlotListWidget.java rename to src/main/java/gregtech/common/terminal/app/guide/widget/SlotListWidget.java index 4b0378ca2e3..7b5e20d5cbf 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/SlotListWidget.java +++ b/src/main/java/gregtech/common/terminal/app/guide/widget/SlotListWidget.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.guide.widget; +package gregtech.common.terminal.app.guide.widget; import com.google.gson.Gson; import com.google.gson.JsonObject; @@ -7,7 +7,7 @@ import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.widgets.SlotWidget; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; -import gregtech.api.terminal.app.guideeditor.widget.configurator.ItemStackConfigurator; +import gregtech.common.terminal.app.guideeditor.widget.configurator.ItemStackConfigurator; import gregtech.api.util.Size; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/TankListWidget.java b/src/main/java/gregtech/common/terminal/app/guide/widget/TankListWidget.java similarity index 96% rename from src/main/java/gregtech/api/terminal/app/guide/widget/TankListWidget.java rename to src/main/java/gregtech/common/terminal/app/guide/widget/TankListWidget.java index 8b67b853137..2d8eeadf282 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/TankListWidget.java +++ b/src/main/java/gregtech/common/terminal/app/guide/widget/TankListWidget.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.guide.widget; +package gregtech.common.terminal.app.guide.widget; import com.google.gson.Gson; import com.google.gson.JsonObject; @@ -7,7 +7,7 @@ import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.widgets.TankWidget; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; -import gregtech.api.terminal.app.guideeditor.widget.configurator.FluidStackConfigurator; +import gregtech.common.terminal.app.guideeditor.widget.configurator.FluidStackConfigurator; import gregtech.api.util.Size; import net.minecraftforge.fluids.Fluid; import net.minecraftforge.fluids.FluidRegistry; diff --git a/src/main/java/gregtech/api/terminal/app/guide/widget/TextBoxWidget.java b/src/main/java/gregtech/common/terminal/app/guide/widget/TextBoxWidget.java similarity index 92% rename from src/main/java/gregtech/api/terminal/app/guide/widget/TextBoxWidget.java rename to src/main/java/gregtech/common/terminal/app/guide/widget/TextBoxWidget.java index 2594280a3b5..8bcf3bd4bca 100644 --- a/src/main/java/gregtech/api/terminal/app/guide/widget/TextBoxWidget.java +++ b/src/main/java/gregtech/common/terminal/app/guide/widget/TextBoxWidget.java @@ -1,14 +1,14 @@ -package gregtech.api.terminal.app.guide.widget; +package gregtech.common.terminal.app.guide.widget; import com.google.gson.Gson; import com.google.gson.JsonObject; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; -import gregtech.api.terminal.app.guideeditor.widget.configurator.BooleanConfigurator; -import gregtech.api.terminal.app.guideeditor.widget.configurator.ColorConfigurator; -import gregtech.api.terminal.app.guideeditor.widget.configurator.NumberConfigurator; -import gregtech.api.terminal.app.guideeditor.widget.configurator.TextListConfigurator; +import gregtech.common.terminal.app.guideeditor.widget.configurator.BooleanConfigurator; +import gregtech.common.terminal.app.guideeditor.widget.configurator.ColorConfigurator; +import gregtech.common.terminal.app.guideeditor.widget.configurator.NumberConfigurator; +import gregtech.common.terminal.app.guideeditor.widget.configurator.TextListConfigurator; import gregtech.api.util.Position; import gregtech.api.util.Size; import net.minecraft.client.Minecraft; diff --git a/src/main/java/gregtech/api/terminal/app/guideeditor/GuideEditorApp.java b/src/main/java/gregtech/common/terminal/app/guideeditor/GuideEditorApp.java similarity index 84% rename from src/main/java/gregtech/api/terminal/app/guideeditor/GuideEditorApp.java rename to src/main/java/gregtech/common/terminal/app/guideeditor/GuideEditorApp.java index fbe0d0f4875..bc4e96fd3a3 100644 --- a/src/main/java/gregtech/api/terminal/app/guideeditor/GuideEditorApp.java +++ b/src/main/java/gregtech/common/terminal/app/guideeditor/GuideEditorApp.java @@ -1,19 +1,17 @@ -package gregtech.api.terminal.app.guideeditor; +package gregtech.common.terminal.app.guideeditor; import gregtech.api.gui.GuiTextures; import gregtech.api.gui.resources.TextureArea; import gregtech.api.terminal.app.AbstractApplication; -import gregtech.api.terminal.app.guideeditor.widget.GuideConfigEditor; -import gregtech.api.terminal.app.guideeditor.widget.GuidePageEditorWidget; +import gregtech.common.terminal.app.guideeditor.widget.GuideConfigEditor; +import gregtech.common.terminal.app.guideeditor.widget.GuidePageEditorWidget; import gregtech.api.terminal.os.TerminalOSWidget; -import gregtech.api.terminal.os.menu.component.ClickComponent; -import gregtech.api.terminal.os.menu.component.IMenuComponent; +import gregtech.common.terminal.component.ClickComponent; +import gregtech.api.terminal.os.menu.IMenuComponent; import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.network.PacketBuffer; import java.util.Arrays; import java.util.List; -import java.util.function.Consumer; public class GuideEditorApp extends AbstractApplication { public static final TextureArea ICON = TextureArea.fullImage("textures/gui/terminal/guide_editor/icon.png"); diff --git a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/GuideConfigEditor.java b/src/main/java/gregtech/common/terminal/app/guideeditor/widget/GuideConfigEditor.java similarity index 97% rename from src/main/java/gregtech/api/terminal/app/guideeditor/widget/GuideConfigEditor.java rename to src/main/java/gregtech/common/terminal/app/guideeditor/widget/GuideConfigEditor.java index d1b635ee92f..5ca2796f8e5 100644 --- a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/GuideConfigEditor.java +++ b/src/main/java/gregtech/common/terminal/app/guideeditor/widget/GuideConfigEditor.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.guideeditor.widget; +package gregtech.common.terminal.app.guideeditor.widget; import com.google.gson.JsonObject; import gregtech.api.gui.GuiTextures; @@ -7,9 +7,9 @@ import gregtech.api.gui.resources.TextTexture; import gregtech.api.gui.widgets.*; import gregtech.api.gui.widgets.tab.IGuiTextureTabInfo; -import gregtech.api.terminal.app.guide.widget.GuidePageWidget; -import gregtech.api.terminal.app.guide.widget.IGuideWidget; -import gregtech.api.terminal.app.guideeditor.GuideEditorApp; +import gregtech.common.terminal.app.guide.widget.GuidePageWidget; +import gregtech.common.terminal.app.guide.widget.IGuideWidget; +import gregtech.common.terminal.app.guideeditor.GuideEditorApp; import gregtech.api.terminal.gui.CustomTabListRenderer; import gregtech.api.terminal.gui.widgets.CircleButtonWidget; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; diff --git a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/GuidePageEditorWidget.java b/src/main/java/gregtech/common/terminal/app/guideeditor/widget/GuidePageEditorWidget.java similarity index 98% rename from src/main/java/gregtech/api/terminal/app/guideeditor/widget/GuidePageEditorWidget.java rename to src/main/java/gregtech/common/terminal/app/guideeditor/widget/GuidePageEditorWidget.java index 1c95327b26e..6112ae4dd15 100644 --- a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/GuidePageEditorWidget.java +++ b/src/main/java/gregtech/common/terminal/app/guideeditor/widget/GuidePageEditorWidget.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.guideeditor.widget; +package gregtech.common.terminal.app.guideeditor.widget; import com.google.gson.JsonArray; @@ -7,8 +7,8 @@ import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; import gregtech.api.gui.widgets.WidgetGroup; -import gregtech.api.terminal.app.guide.widget.GuidePageWidget; -import gregtech.api.terminal.app.guide.widget.IGuideWidget; +import gregtech.common.terminal.app.guide.widget.GuidePageWidget; +import gregtech.common.terminal.app.guide.widget.IGuideWidget; import gregtech.api.terminal.gui.widgets.CircleButtonWidget; import gregtech.api.terminal.gui.widgets.CustomPositionSizeWidget; import gregtech.api.terminal.os.TerminalTheme; diff --git a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/BooleanConfigurator.java b/src/main/java/gregtech/common/terminal/app/guideeditor/widget/configurator/BooleanConfigurator.java similarity index 95% rename from src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/BooleanConfigurator.java rename to src/main/java/gregtech/common/terminal/app/guideeditor/widget/configurator/BooleanConfigurator.java index 250f0e978eb..50b1d7cf2b8 100644 --- a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/BooleanConfigurator.java +++ b/src/main/java/gregtech/common/terminal/app/guideeditor/widget/configurator/BooleanConfigurator.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.guideeditor.widget.configurator; +package gregtech.common.terminal.app.guideeditor.widget.configurator; import com.google.gson.JsonObject; import gregtech.api.gui.resources.ColorRectTexture; diff --git a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/ColorConfigurator.java b/src/main/java/gregtech/common/terminal/app/guideeditor/widget/configurator/ColorConfigurator.java similarity index 92% rename from src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/ColorConfigurator.java rename to src/main/java/gregtech/common/terminal/app/guideeditor/widget/configurator/ColorConfigurator.java index c561275cc46..fa36c712544 100644 --- a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/ColorConfigurator.java +++ b/src/main/java/gregtech/common/terminal/app/guideeditor/widget/configurator/ColorConfigurator.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.guideeditor.widget.configurator; +package gregtech.common.terminal.app.guideeditor.widget.configurator; import com.google.gson.JsonObject; import gregtech.api.terminal.gui.widgets.ColorWidget; diff --git a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/ConfiguratorWidget.java b/src/main/java/gregtech/common/terminal/app/guideeditor/widget/configurator/ConfiguratorWidget.java similarity index 98% rename from src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/ConfiguratorWidget.java rename to src/main/java/gregtech/common/terminal/app/guideeditor/widget/configurator/ConfiguratorWidget.java index 26300ca40ba..2bba4471901 100644 --- a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/ConfiguratorWidget.java +++ b/src/main/java/gregtech/common/terminal/app/guideeditor/widget/configurator/ConfiguratorWidget.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.guideeditor.widget.configurator; +package gregtech.common.terminal.app.guideeditor.widget.configurator; import com.google.gson.Gson; import com.google.gson.JsonObject; diff --git a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/FluidStackConfigurator.java b/src/main/java/gregtech/common/terminal/app/guideeditor/widget/configurator/FluidStackConfigurator.java similarity index 97% rename from src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/FluidStackConfigurator.java rename to src/main/java/gregtech/common/terminal/app/guideeditor/widget/configurator/FluidStackConfigurator.java index f8380b79ca3..7d4f23516eb 100644 --- a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/FluidStackConfigurator.java +++ b/src/main/java/gregtech/common/terminal/app/guideeditor/widget/configurator/FluidStackConfigurator.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.guideeditor.widget.configurator; +package gregtech.common.terminal.app.guideeditor.widget.configurator; import com.google.gson.Gson; import com.google.gson.JsonElement; @@ -8,7 +8,7 @@ import gregtech.api.gui.widgets.*; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; import gregtech.api.terminal.gui.widgets.RectButtonWidget; -import gregtech.api.terminal.app.guide.widget.TankListWidget; +import gregtech.common.terminal.app.guide.widget.TankListWidget; import gregtech.api.terminal.os.TerminalTheme; import java.awt.*; diff --git a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/ItemStackConfigurator.java b/src/main/java/gregtech/common/terminal/app/guideeditor/widget/configurator/ItemStackConfigurator.java similarity index 97% rename from src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/ItemStackConfigurator.java rename to src/main/java/gregtech/common/terminal/app/guideeditor/widget/configurator/ItemStackConfigurator.java index 99b0c7d9f42..5f4c1a10108 100644 --- a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/ItemStackConfigurator.java +++ b/src/main/java/gregtech/common/terminal/app/guideeditor/widget/configurator/ItemStackConfigurator.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.guideeditor.widget.configurator; +package gregtech.common.terminal.app.guideeditor.widget.configurator; import com.google.gson.Gson; import com.google.gson.JsonElement; @@ -11,7 +11,7 @@ import gregtech.api.gui.widgets.WidgetGroup; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; import gregtech.api.terminal.gui.widgets.RectButtonWidget; -import gregtech.api.terminal.app.guide.widget.SlotListWidget; +import gregtech.common.terminal.app.guide.widget.SlotListWidget; import gregtech.api.terminal.os.TerminalTheme; import gregtech.common.inventory.handlers.SingleItemStackHandler; import net.minecraftforge.items.IItemHandlerModifiable; diff --git a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/NumberConfigurator.java b/src/main/java/gregtech/common/terminal/app/guideeditor/widget/configurator/NumberConfigurator.java similarity index 96% rename from src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/NumberConfigurator.java rename to src/main/java/gregtech/common/terminal/app/guideeditor/widget/configurator/NumberConfigurator.java index 2bcb2a0f4eb..1d7fb271d3a 100644 --- a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/NumberConfigurator.java +++ b/src/main/java/gregtech/common/terminal/app/guideeditor/widget/configurator/NumberConfigurator.java @@ -1,8 +1,7 @@ -package gregtech.api.terminal.app.guideeditor.widget.configurator; +package gregtech.common.terminal.app.guideeditor.widget.configurator; import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import gregtech.api.gui.resources.ColorRectTexture; import gregtech.api.gui.resources.TextTexture; import gregtech.api.gui.widgets.ImageWidget; import gregtech.api.gui.widgets.SimpleTextWidget; diff --git a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/SelectorConfigurator.java b/src/main/java/gregtech/common/terminal/app/guideeditor/widget/configurator/SelectorConfigurator.java similarity index 94% rename from src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/SelectorConfigurator.java rename to src/main/java/gregtech/common/terminal/app/guideeditor/widget/configurator/SelectorConfigurator.java index 8a55bf68b78..5b17ebd417f 100644 --- a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/SelectorConfigurator.java +++ b/src/main/java/gregtech/common/terminal/app/guideeditor/widget/configurator/SelectorConfigurator.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.guideeditor.widget.configurator; +package gregtech.common.terminal.app.guideeditor.widget.configurator; import com.google.gson.JsonObject; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; diff --git a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/StringConfigurator.java b/src/main/java/gregtech/common/terminal/app/guideeditor/widget/configurator/StringConfigurator.java similarity index 93% rename from src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/StringConfigurator.java rename to src/main/java/gregtech/common/terminal/app/guideeditor/widget/configurator/StringConfigurator.java index 29724fb1a38..fdbe940aba3 100644 --- a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/StringConfigurator.java +++ b/src/main/java/gregtech/common/terminal/app/guideeditor/widget/configurator/StringConfigurator.java @@ -1,7 +1,6 @@ -package gregtech.api.terminal.app.guideeditor.widget.configurator; +package gregtech.common.terminal.app.guideeditor.widget.configurator; import com.google.gson.JsonObject; -import gregtech.api.gui.resources.ColorRectTexture; import gregtech.api.gui.resources.TextTexture; import gregtech.api.gui.widgets.TextFieldWidget; import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; diff --git a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/TextListConfigurator.java b/src/main/java/gregtech/common/terminal/app/guideeditor/widget/configurator/TextListConfigurator.java similarity index 95% rename from src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/TextListConfigurator.java rename to src/main/java/gregtech/common/terminal/app/guideeditor/widget/configurator/TextListConfigurator.java index ccc30ac3152..1d41381a464 100644 --- a/src/main/java/gregtech/api/terminal/app/guideeditor/widget/configurator/TextListConfigurator.java +++ b/src/main/java/gregtech/common/terminal/app/guideeditor/widget/configurator/TextListConfigurator.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.guideeditor.widget.configurator; +package gregtech.common.terminal.app.guideeditor.widget.configurator; import com.google.gson.*; import gregtech.api.gui.resources.ColorRectTexture; diff --git a/src/main/java/gregtech/api/terminal/app/recipechart/RecipeChartApp.java b/src/main/java/gregtech/common/terminal/app/recipechart/RecipeChartApp.java similarity index 93% rename from src/main/java/gregtech/api/terminal/app/recipechart/RecipeChartApp.java rename to src/main/java/gregtech/common/terminal/app/recipechart/RecipeChartApp.java index 372e665dd54..08ce9d34f8b 100644 --- a/src/main/java/gregtech/api/terminal/app/recipechart/RecipeChartApp.java +++ b/src/main/java/gregtech/common/terminal/app/recipechart/RecipeChartApp.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.recipechart; +package gregtech.common.terminal.app.recipechart; import gregtech.api.gui.GuiTextures; import gregtech.api.gui.Widget; @@ -9,14 +9,14 @@ import gregtech.api.gui.widgets.TabGroup; import gregtech.api.gui.widgets.tab.IGuiTextureTabInfo; import gregtech.api.terminal.app.AbstractApplication; -import gregtech.api.terminal.app.recipechart.widget.RGContainer; -import gregtech.api.terminal.app.recipechart.widget.RGNode; +import gregtech.common.terminal.app.recipechart.widget.RGContainer; +import gregtech.common.terminal.app.recipechart.widget.RGNode; import gregtech.api.terminal.gui.CustomTabListRenderer; import gregtech.api.terminal.os.TerminalDialogWidget; import gregtech.api.terminal.os.TerminalOSWidget; import gregtech.api.terminal.os.TerminalTheme; -import gregtech.api.terminal.os.menu.component.ClickComponent; -import gregtech.api.terminal.os.menu.component.IMenuComponent; +import gregtech.common.terminal.component.ClickComponent; +import gregtech.api.terminal.os.menu.IMenuComponent; import mezz.jei.api.gui.IRecipeLayout; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.nbt.NBTTagCompound; diff --git a/src/main/java/gregtech/api/terminal/app/recipechart/widget/PhantomWidget.java b/src/main/java/gregtech/common/terminal/app/recipechart/widget/PhantomWidget.java similarity index 98% rename from src/main/java/gregtech/api/terminal/app/recipechart/widget/PhantomWidget.java rename to src/main/java/gregtech/common/terminal/app/recipechart/widget/PhantomWidget.java index 22271b16d20..3c82b81b3da 100644 --- a/src/main/java/gregtech/api/terminal/app/recipechart/widget/PhantomWidget.java +++ b/src/main/java/gregtech/common/terminal/app/recipechart/widget/PhantomWidget.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.recipechart.widget; +package gregtech.common.terminal.app.recipechart.widget; import gregtech.api.gui.Widget; import gregtech.api.gui.ingredient.IGhostIngredientTarget; diff --git a/src/main/java/gregtech/api/terminal/app/recipechart/widget/RGContainer.java b/src/main/java/gregtech/common/terminal/app/recipechart/widget/RGContainer.java similarity index 99% rename from src/main/java/gregtech/api/terminal/app/recipechart/widget/RGContainer.java rename to src/main/java/gregtech/common/terminal/app/recipechart/widget/RGContainer.java index fdb8fde71d6..a3d925daf4d 100644 --- a/src/main/java/gregtech/api/terminal/app/recipechart/widget/RGContainer.java +++ b/src/main/java/gregtech/common/terminal/app/recipechart/widget/RGContainer.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.recipechart.widget; +package gregtech.common.terminal.app.recipechart.widget; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; diff --git a/src/main/java/gregtech/api/terminal/app/recipechart/widget/RGLine.java b/src/main/java/gregtech/common/terminal/app/recipechart/widget/RGLine.java similarity index 99% rename from src/main/java/gregtech/api/terminal/app/recipechart/widget/RGLine.java rename to src/main/java/gregtech/common/terminal/app/recipechart/widget/RGLine.java index c1482eeb4a4..712c3748285 100644 --- a/src/main/java/gregtech/api/terminal/app/recipechart/widget/RGLine.java +++ b/src/main/java/gregtech/common/terminal/app/recipechart/widget/RGLine.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.recipechart.widget; +package gregtech.common.terminal.app.recipechart.widget; import gregtech.api.GTValues; import gregtech.api.block.machines.MachineItemBlock; diff --git a/src/main/java/gregtech/api/terminal/app/recipechart/widget/RGNode.java b/src/main/java/gregtech/common/terminal/app/recipechart/widget/RGNode.java similarity index 99% rename from src/main/java/gregtech/api/terminal/app/recipechart/widget/RGNode.java rename to src/main/java/gregtech/common/terminal/app/recipechart/widget/RGNode.java index 7f5db09e464..b924f4f8606 100644 --- a/src/main/java/gregtech/api/terminal/app/recipechart/widget/RGNode.java +++ b/src/main/java/gregtech/common/terminal/app/recipechart/widget/RGNode.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.app.recipechart.widget; +package gregtech.common.terminal.app.recipechart.widget; import gregtech.api.block.machines.MachineItemBlock; import gregtech.api.gui.GuiTextures; diff --git a/src/main/java/gregtech/api/terminal/os/menu/component/ClickComponent.java b/src/main/java/gregtech/common/terminal/component/ClickComponent.java similarity index 85% rename from src/main/java/gregtech/api/terminal/os/menu/component/ClickComponent.java rename to src/main/java/gregtech/common/terminal/component/ClickComponent.java index ae60d32a351..4e41ac96637 100644 --- a/src/main/java/gregtech/api/terminal/os/menu/component/ClickComponent.java +++ b/src/main/java/gregtech/common/terminal/component/ClickComponent.java @@ -1,11 +1,12 @@ -package gregtech.api.terminal.os.menu.component; +package gregtech.common.terminal.component; import gregtech.api.gui.Widget; import gregtech.api.gui.resources.IGuiTexture; +import gregtech.api.terminal.os.menu.IMenuComponent; import java.util.function.Consumer; -public class ClickComponent implements IMenuComponent{ +public class ClickComponent implements IMenuComponent { private IGuiTexture icon; private String hoverText; private Consumer consumer; diff --git a/src/main/java/gregtech/api/terminal/os/menu/component/SearchComponent.java b/src/main/java/gregtech/common/terminal/component/SearchComponent.java similarity index 97% rename from src/main/java/gregtech/api/terminal/os/menu/component/SearchComponent.java rename to src/main/java/gregtech/common/terminal/component/SearchComponent.java index bedffaf158d..2a8ae3bb673 100644 --- a/src/main/java/gregtech/api/terminal/os/menu/component/SearchComponent.java +++ b/src/main/java/gregtech/common/terminal/component/SearchComponent.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.os.menu.component; +package gregtech.common.terminal.component; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.resources.ColorRectTexture; @@ -6,6 +6,7 @@ import gregtech.api.gui.resources.TextureArea; import gregtech.api.gui.widgets.TextFieldWidget; import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.terminal.os.menu.IMenuComponent; import gregtech.api.terminal.util.ISearch; import gregtech.api.terminal.util.SearchEngine; import net.minecraft.client.Minecraft; @@ -16,7 +17,7 @@ import java.util.ArrayList; import java.util.List; -public class SearchComponent extends WidgetGroup implements IMenuComponent{ +public class SearchComponent extends WidgetGroup implements IMenuComponent { private final static TextureArea SEARCHING = TextureArea.fullImage("textures/gui/terminal/icon/network/search_hover.png"); private final static int SIZE = 10; private final SearchEngine engine; diff --git a/src/main/java/gregtech/api/terminal/os/menu/component/setting/GuiTextureSetter.java b/src/main/java/gregtech/common/terminal/component/setting/GuiTextureSetter.java similarity index 92% rename from src/main/java/gregtech/api/terminal/os/menu/component/setting/GuiTextureSetter.java rename to src/main/java/gregtech/common/terminal/component/setting/GuiTextureSetter.java index ad9ca8370db..bd0618ccf28 100644 --- a/src/main/java/gregtech/api/terminal/os/menu/component/setting/GuiTextureSetter.java +++ b/src/main/java/gregtech/common/terminal/component/setting/GuiTextureSetter.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.os.menu.component.setting; +package gregtech.common.terminal.component.setting; import gregtech.api.gui.Widget; import gregtech.api.gui.resources.IGuiTexture; diff --git a/src/main/java/gregtech/api/terminal/os/menu/component/setting/ISetting.java b/src/main/java/gregtech/common/terminal/component/setting/ISetting.java similarity index 76% rename from src/main/java/gregtech/api/terminal/os/menu/component/setting/ISetting.java rename to src/main/java/gregtech/common/terminal/component/setting/ISetting.java index df3878fc96a..db0649d75b0 100644 --- a/src/main/java/gregtech/api/terminal/os/menu/component/setting/ISetting.java +++ b/src/main/java/gregtech/common/terminal/component/setting/ISetting.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.os.menu.component.setting; +package gregtech.common.terminal.component.setting; import gregtech.api.gui.Widget; import gregtech.api.gui.resources.IGuiTexture; diff --git a/src/main/java/gregtech/api/terminal/os/menu/component/setting/IWidgetSettings.java b/src/main/java/gregtech/common/terminal/component/setting/IWidgetSettings.java similarity index 69% rename from src/main/java/gregtech/api/terminal/os/menu/component/setting/IWidgetSettings.java rename to src/main/java/gregtech/common/terminal/component/setting/IWidgetSettings.java index 3b534a5f8b1..94a2f13db4a 100644 --- a/src/main/java/gregtech/api/terminal/os/menu/component/setting/IWidgetSettings.java +++ b/src/main/java/gregtech/common/terminal/component/setting/IWidgetSettings.java @@ -1,4 +1,4 @@ -package gregtech.api.terminal.os.menu.component.setting; +package gregtech.common.terminal.component.setting; import gregtech.api.terminal.util.TreeNode; diff --git a/src/main/java/gregtech/api/terminal/os/menu/component/setting/SettingComponent.java b/src/main/java/gregtech/common/terminal/component/setting/SettingComponent.java similarity index 89% rename from src/main/java/gregtech/api/terminal/os/menu/component/setting/SettingComponent.java rename to src/main/java/gregtech/common/terminal/component/setting/SettingComponent.java index e5cfcfdeded..74397632eae 100644 --- a/src/main/java/gregtech/api/terminal/os/menu/component/setting/SettingComponent.java +++ b/src/main/java/gregtech/common/terminal/component/setting/SettingComponent.java @@ -1,10 +1,10 @@ -package gregtech.api.terminal.os.menu.component.setting; +package gregtech.common.terminal.component.setting; import gregtech.api.gui.GuiTextures; import gregtech.api.gui.Widget; import gregtech.api.gui.widgets.WidgetGroup; import gregtech.api.terminal.gui.widgets.TreeListWidget; -import gregtech.api.terminal.os.menu.component.IMenuComponent; +import gregtech.api.terminal.os.menu.IMenuComponent; public class SettingComponent extends WidgetGroup implements IMenuComponent { private Widget settingWidget; From 52bf46fb917f73a548340289208b5d417716b68e Mon Sep 17 00:00:00 2001 From: Yefancy Date: Wed, 18 Aug 2021 00:23:19 +0800 Subject: [PATCH 56/58] finish recipechart app --- .../gregtech/api/gui/widgets/TabGroup.java | 42 +++--- .../api/gui/widgets/tab/TabListRenderer.java | 2 +- .../api/terminal/os/TerminalDialogWidget.java | 17 ++- .../api/terminal/os/TerminalOSWidget.java | 6 +- .../storage/MetaTileEntityWorkbench.java | 3 +- .../app/guideeditor/GuideEditorApp.java | 4 +- .../guideeditor/widget/GuideConfigEditor.java | 2 +- .../app/recipechart/RecipeChartApp.java | 126 ++++++++++++++---- 8 files changed, 148 insertions(+), 54 deletions(-) diff --git a/src/main/java/gregtech/api/gui/widgets/TabGroup.java b/src/main/java/gregtech/api/gui/widgets/TabGroup.java index 6710345c825..de108f336aa 100644 --- a/src/main/java/gregtech/api/gui/widgets/TabGroup.java +++ b/src/main/java/gregtech/api/gui/widgets/TabGroup.java @@ -16,18 +16,16 @@ import net.minecraft.util.Tuple; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.function.BiConsumer; import java.util.function.Supplier; import static gregtech.api.gui.impl.ModularUIGui.*; -public class TabGroup extends AbstractWidgetGroup { +public class TabGroup extends AbstractWidgetGroup { private final List tabInfos = new ArrayList<>(); - private final Map tabWidgets = new HashMap<>(); + private final List tabWidgets = new ArrayList<>(); protected int selectedTabIndex = 0; private final TabListRenderer tabListRenderer; private BiConsumer onTabChanged; @@ -42,42 +40,54 @@ public TabGroup(TabLocation tabLocation, Position position) { this.tabListRenderer = tabLocation.supplier.get(); } - public TabGroup(TabLocation tabLocation) { - this(tabLocation, Position.ORIGIN); - } - - public TabGroup addTab(ITabInfo tabInfo, AbstractWidgetGroup tabWidget) { + public void addTab(ITabInfo tabInfo, T tabWidget) { this.tabInfos.add(tabInfo); int tabIndex = tabInfos.size() - 1; - this.tabWidgets.put(tabIndex, tabWidget); + this.tabWidgets.add(tabWidget); tabWidget.setVisible(tabIndex == selectedTabIndex); tabWidget.setActive(tabIndex == selectedTabIndex); addWidget(tabWidget); - return this; } - public TabGroup setOnTabChanged(BiConsumer onTabChanged) { + public void removeTab(int index) { + this.tabInfos.remove(index); + T tab = this.tabWidgets.remove(index); + this.removeWidget(tab); + if (selectedTabIndex >= index && selectedTabIndex > 0) { + selectedTabIndex--; + } + for (int i = 0; i < this.tabWidgets.size(); i++) { + tabWidgets.get(i).setActive(i == selectedTabIndex); + tabWidgets.get(i).setVisible(i == selectedTabIndex); + } + } + + public TabGroup setOnTabChanged(BiConsumer onTabChanged) { this.onTabChanged = onTabChanged; return this; } - public AbstractWidgetGroup getCurrentTag() { + public T getCurrentTag() { return tabWidgets.get(selectedTabIndex); } + public List getAllTag() { + return tabWidgets; + } + @Override public List getContainedWidgets(boolean includeHidden) { ArrayList containedWidgets = new ArrayList<>(widgets.size()); if (includeHidden) { - for (Widget widget : tabWidgets.values()) { + for (Widget widget : tabWidgets) { containedWidgets.add(widget); if (widget instanceof AbstractWidgetGroup) containedWidgets.addAll(((AbstractWidgetGroup) widget).getContainedWidgets(true)); } } else { - AbstractWidgetGroup widgetGroup = tabWidgets.get(selectedTabIndex); + T widgetGroup = tabWidgets.get(selectedTabIndex); containedWidgets.add(widgetGroup); containedWidgets.addAll(widgetGroup.getContainedWidgets(false)); } @@ -166,7 +176,7 @@ private static boolean isMouseOverTab(int mouseX, int mouseY, int[] tabSizes) { } public boolean isWidgetVisible(Widget widget) { - return tabWidgets.containsKey(selectedTabIndex) && tabWidgets.get(selectedTabIndex) == widget; + return tabWidgets.get(selectedTabIndex) == widget; } public enum TabLocation { diff --git a/src/main/java/gregtech/api/gui/widgets/tab/TabListRenderer.java b/src/main/java/gregtech/api/gui/widgets/tab/TabListRenderer.java index 381a7ea153f..55cd1ef8360 100644 --- a/src/main/java/gregtech/api/gui/widgets/tab/TabListRenderer.java +++ b/src/main/java/gregtech/api/gui/widgets/tab/TabListRenderer.java @@ -19,6 +19,6 @@ public abstract class TabListRenderer { public abstract void renderTabs(Position offset, List tabInfos, int guiWidth, int guiHeight, int selectedTabIndex); - public abstract int[] getTabPos(int guiWidth, int guiHeight, int tabIndex); + public abstract int[] getTabPos(int tabIndex, int guiWidth, int guiHeight); } diff --git a/src/main/java/gregtech/api/terminal/os/TerminalDialogWidget.java b/src/main/java/gregtech/api/terminal/os/TerminalDialogWidget.java index 67fa2052fd4..f1e5446e17e 100644 --- a/src/main/java/gregtech/api/terminal/os/TerminalDialogWidget.java +++ b/src/main/java/gregtech/api/terminal/os/TerminalDialogWidget.java @@ -18,7 +18,9 @@ import net.minecraft.inventory.IInventory; import net.minecraft.network.PacketBuffer; +import java.awt.*; import java.io.File; +import java.io.IOException; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import java.util.function.Predicate; @@ -230,7 +232,20 @@ public static TerminalDialogWidget showFileDialog(TerminalOSWidget os, String ti .setMaxStringLength(Integer.MAX_VALUE) .setValidator(s->true)); } - + dialog.addWidget(new CircleButtonWidget(x + 17, y + 15, 10, 1, 16) + .setClickListener(cd -> { + File file = selected.get(); + if (file != null) { + try { + Desktop.getDesktop().open(file.isDirectory() ? file : file.getParentFile()); + } catch (IOException e) { + e.printStackTrace(); + } + } + }) + .setColors(0, 0xFFFFFFFF, 0) + .setHoverText("Open Folder") + .setIcon(GuiTextures.ICON_LOAD)); dialog.addWidget(new LabelWidget(x + WIDTH / 2, y + 11, title, -1).setXCentered(true)); os.menu.hideMenu(); return dialog.setClientSide(); diff --git a/src/main/java/gregtech/api/terminal/os/TerminalOSWidget.java b/src/main/java/gregtech/api/terminal/os/TerminalOSWidget.java index fe9931bc7e8..5fb053879fb 100644 --- a/src/main/java/gregtech/api/terminal/os/TerminalOSWidget.java +++ b/src/main/java/gregtech/api/terminal/os/TerminalOSWidget.java @@ -148,7 +148,7 @@ private void shutdown() { for (AbstractApplication openedApp : openedApps) { String appName = openedApp.getRegistryName(); NBTTagCompound synced = openedApp.closeApp(true, tabletNBT.getCompoundTag(appName)); - if (synced != null) { + if (synced != null && !synced.isEmpty()) { tabletNBT.setTag(appName, synced); if (openedApp.isClientSideApp()) {//if its a clientSideApp and the nbt not null, meaning this nbt should be synced to the server side. nbt.setTag(appName, synced); @@ -188,8 +188,8 @@ public void handleClientAction(int id, PacketBuffer buffer) { } for (AbstractApplication openedApp : openedApps) { String appName = openedApp.getRegistryName(); - NBTTagCompound data = openedApp.closeApp(true, tabletNBT.getCompoundTag(appName)); - if (data != null) { + NBTTagCompound data = openedApp.closeApp(false, tabletNBT.getCompoundTag(appName)); + if (data != null && !data.isEmpty()) { tabletNBT.setTag(appName, data); } else if (nbt != null && openedApp.isClientSideApp() && nbt.hasKey(appName)) { tabletNBT.setTag(appName, nbt.getCompoundTag(appName)); diff --git a/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityWorkbench.java b/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityWorkbench.java index c8b71f494dd..0bfb2b42d66 100644 --- a/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityWorkbench.java +++ b/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityWorkbench.java @@ -17,6 +17,7 @@ import gregtech.api.metatileentity.MetaTileEntity; import gregtech.api.metatileentity.MetaTileEntityHolder; import gregtech.api.render.Textures; +import gregtech.api.terminal.app.AbstractApplication; import gregtech.api.unification.material.Materials; import gregtech.api.util.GTUtility; import gregtech.api.util.Position; @@ -199,7 +200,7 @@ protected ModularUI createUI(EntityPlayer entityPlayer) { .bindPlayerInventory(entityPlayer.inventory, 140); builder.label(5, 5, getMetaFullName()); - TabGroup tabGroup = new TabGroup(TabLocation.HORIZONTAL_TOP_LEFT, Position.ORIGIN); + TabGroup tabGroup = new TabGroup<>(TabLocation.HORIZONTAL_TOP_LEFT, Position.ORIGIN); tabGroup.addTab(new ItemTabInfo("gregtech.machine.workbench.tab.workbench", new ItemStack(Blocks.CRAFTING_TABLE)), createWorkbenchTab(getRecipeResolver(), craftingGrid, recipeMemory, toolInventory, internalInventory)); tabGroup.addTab(new ItemTabInfo("gregtech.machine.workbench.tab.item_list", new ItemStack(Blocks.CHEST)), createItemListTab()); builder.widget(tabGroup); diff --git a/src/main/java/gregtech/common/terminal/app/guideeditor/GuideEditorApp.java b/src/main/java/gregtech/common/terminal/app/guideeditor/GuideEditorApp.java index bc4e96fd3a3..7cdcb4cbeef 100644 --- a/src/main/java/gregtech/common/terminal/app/guideeditor/GuideEditorApp.java +++ b/src/main/java/gregtech/common/terminal/app/guideeditor/GuideEditorApp.java @@ -45,12 +45,12 @@ public List getMenuComponents() { configEditor.newPage(cd); } }); - ClickComponent importPage = new ClickComponent().setIcon(GuiTextures.ICON_LOAD).setHoverText("Import Page").setClickConsumer(cd->{ + ClickComponent importPage = new ClickComponent().setIcon(GuiTextures.ICON_LOAD).setHoverText("Load File").setClickConsumer(cd->{ if (configEditor != null) { configEditor.loadJson(cd); } }); - ClickComponent exportPage = new ClickComponent().setIcon(GuiTextures.ICON_SAVE).setHoverText("Export Page").setClickConsumer(cd->{ + ClickComponent exportPage = new ClickComponent().setIcon(GuiTextures.ICON_SAVE).setHoverText("Save File").setClickConsumer(cd->{ if (configEditor != null) { configEditor.saveJson(cd); } diff --git a/src/main/java/gregtech/common/terminal/app/guideeditor/widget/GuideConfigEditor.java b/src/main/java/gregtech/common/terminal/app/guideeditor/widget/GuideConfigEditor.java index 5ca2796f8e5..ff52d6111e8 100644 --- a/src/main/java/gregtech/common/terminal/app/guideeditor/widget/GuideConfigEditor.java +++ b/src/main/java/gregtech/common/terminal/app/guideeditor/widget/GuideConfigEditor.java @@ -25,7 +25,7 @@ import java.util.Map; import java.util.Objects; -public class GuideConfigEditor extends TabGroup { +public class GuideConfigEditor extends TabGroup { public String json; private IGuideWidget selected; private GuidePageEditorWidget pageEditor; diff --git a/src/main/java/gregtech/common/terminal/app/recipechart/RecipeChartApp.java b/src/main/java/gregtech/common/terminal/app/recipechart/RecipeChartApp.java index 08ce9d34f8b..1eac10a1eeb 100644 --- a/src/main/java/gregtech/common/terminal/app/recipechart/RecipeChartApp.java +++ b/src/main/java/gregtech/common/terminal/app/recipechart/RecipeChartApp.java @@ -9,25 +9,34 @@ import gregtech.api.gui.widgets.TabGroup; import gregtech.api.gui.widgets.tab.IGuiTextureTabInfo; import gregtech.api.terminal.app.AbstractApplication; -import gregtech.common.terminal.app.recipechart.widget.RGContainer; -import gregtech.common.terminal.app.recipechart.widget.RGNode; import gregtech.api.terminal.gui.CustomTabListRenderer; import gregtech.api.terminal.os.TerminalDialogWidget; import gregtech.api.terminal.os.TerminalOSWidget; import gregtech.api.terminal.os.TerminalTheme; -import gregtech.common.terminal.component.ClickComponent; import gregtech.api.terminal.os.menu.IMenuComponent; +import gregtech.common.terminal.app.recipechart.widget.RGContainer; +import gregtech.common.terminal.app.recipechart.widget.RGNode; +import gregtech.common.terminal.component.ClickComponent; import mezz.jei.api.gui.IRecipeLayout; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.nbt.CompressedStreamTools; +import net.minecraft.nbt.NBTBase; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraftforge.common.util.Constants; +import java.io.File; +import java.io.IOException; import java.util.Arrays; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; public class RecipeChartApp extends AbstractApplication implements IRecipeTransferHandlerWidget { public static final TextureArea ICON = TextureArea.fullImage("textures/gui/terminal/recipe_graph/icon.png"); - private TabGroup tabGroup; + private TabGroup tabGroup; + private Map containers; public RecipeChartApp() { super("recipe_chart", ICON); @@ -38,54 +47,113 @@ public AbstractApplication createApp(TerminalOSWidget os, boolean isClient, NBTT RecipeChartApp app = new RecipeChartApp(); if (isClient) { app.setOs(os); - app.tabGroup = new TabGroup(0, 10, new CustomTabListRenderer(TerminalTheme.COLOR_F_2, TerminalTheme.COLOR_B_3, 60, 10)); + app.containers = new LinkedHashMap<>(); + app.tabGroup = new TabGroup<>(0, 10, new CustomTabListRenderer(TerminalTheme.COLOR_F_2, TerminalTheme.COLOR_B_3, 60, 10)); app.addWidget(app.tabGroup); - app.addTab("default"); - if (nbt != null) { - app.testnbt = nbt; - ((RGContainer) app.tabGroup.getCurrentTag()).loadFromNBT(nbt); + if (nbt.isEmpty()) { + app.addTab("default"); + } else { + for (NBTBase l : nbt.getTagList("list", Constants.NBT.TAG_COMPOUND)) { + NBTTagCompound container = (NBTTagCompound) l; + app.addTab(container.getString("name")).loadFromNBT((NBTTagCompound) container.getTag("data")); + } } } return app; } - private void addTab(String name) { - if (tabGroup != null && name != null && !name.isEmpty()) { - tabGroup.addTab(new IGuiTextureTabInfo(new TextTexture(name, -1), "Widgets Box"), - new RGContainer(0, 0, 333, 222, getOs()).setBackground(TerminalTheme.COLOR_B_3)); - } + private RGContainer addTab(String name) { + name = name.isEmpty()? "default" : name; + RGContainer container = new RGContainer(0, 0, 333, 222, getOs()); + container.setBackground(TerminalTheme.COLOR_B_3); + tabGroup.addTab(new IGuiTextureTabInfo(new TextTexture(name, -1), "Widgets Box"), container); + containers.put(container, name); + return container; } - NBTTagCompound testnbt; @Override public List getMenuComponents() { ClickComponent newPage = new ClickComponent().setIcon(GuiTextures.ICON_NEW_PAGE).setHoverText("New Page").setClickConsumer(cd->{ - TerminalDialogWidget.showTextFieldDialog(getOs(), "Page Name", s->true, this::addTab).setClientSide().open(); + if (tabGroup == null) return; + if (tabGroup.getAllTag().size() < 5) { + TerminalDialogWidget.showTextFieldDialog(getOs(), "Page Name", s -> true, s -> { + if (s != null) { + addTab(s); + } + }).setClientSide().open(); + } else { + TerminalDialogWidget.showInfoDialog(getOs(), "NOTICE", "Page limit.").setClientSide().open(); + } + }); + ClickComponent deletePage = new ClickComponent().setIcon(GuiTextures.ICON_REMOVE).setHoverText("Delete Page").setClickConsumer(cd->{ + if (tabGroup == null) return; + if (tabGroup.getAllTag().size() > 1) { + TerminalDialogWidget.showConfirmDialog(getOs(), "Delete Page", "Are you sure?", r->{ + if (r) { + containers.remove(tabGroup.getCurrentTag()); + tabGroup.removeTab(tabGroup.getAllTag().indexOf(tabGroup.getCurrentTag())); + } + }).setClientSide().open(); + } else { + TerminalDialogWidget.showInfoDialog(getOs(), "NOTICE", "Page limit.").setClientSide().open(); + } }); - ClickComponent importPage = new ClickComponent().setIcon(GuiTextures.ICON_ADD).setHoverText("Add a Slot").setClickConsumer(cd->{ - if (tabGroup != null && tabGroup.getCurrentTag() instanceof RGContainer) { - ((RGContainer) tabGroup.getCurrentTag()).addNode(50, 100); + ClickComponent addSlot = new ClickComponent().setIcon(GuiTextures.ICON_ADD).setHoverText("Add Root Slot").setClickConsumer(cd->{ + if (tabGroup == null) return; + if (tabGroup.getCurrentTag() != null) { + tabGroup.getCurrentTag().addNode(50, 100); } }); - ClickComponent save = new ClickComponent().setIcon(GuiTextures.ICON_ADD).setHoverText("save test").setClickConsumer(cd->{ - if (tabGroup != null && tabGroup.getCurrentTag() instanceof RGContainer) { - testnbt = ((RGContainer) tabGroup.getCurrentTag()).saveAsNBT(); + ClickComponent importPage = new ClickComponent().setIcon(GuiTextures.ICON_LOAD).setHoverText("Load File").setClickConsumer(cd->{ + if (tabGroup == null) return; + if (tabGroup.getAllTag().size() < 5) { + File file = new File("terminal\\recipe_chart"); + TerminalDialogWidget.showFileDialog(getOs(), "Load File", file, true, result->{ + if (result != null && result.isFile()) { + try { + NBTTagCompound nbt = CompressedStreamTools.read(result); + addTab(result.getName()).loadFromNBT(nbt); + } catch (IOException e) { + TerminalDialogWidget.showInfoDialog(getOs(), "ERROR", "An error occurred while loading the file.").setClientSide().open(); + } + } + }).setClientSide().open(); + } else { + TerminalDialogWidget.showInfoDialog(getOs(), "NOTICE", "Page limit.").setClientSide().open(); } }); - ClickComponent load = new ClickComponent().setIcon(GuiTextures.ICON_ADD).setHoverText("load test").setClickConsumer(cd->{ - if (tabGroup != null && tabGroup.getCurrentTag() instanceof RGContainer) { - ((RGContainer) tabGroup.getCurrentTag()).loadFromNBT(testnbt); + ClickComponent exportPage = new ClickComponent().setIcon(GuiTextures.ICON_SAVE).setHoverText("Save File").setClickConsumer(cd->{ + if (tabGroup == null) return; + if (tabGroup.getCurrentTag() != null) { + File file = new File("terminal\\recipe_chart"); + TerminalDialogWidget.showFileDialog(getOs(), "Save File", file, false, result->{ + if (result != null) { + try { + CompressedStreamTools.safeWrite(tabGroup.getCurrentTag().saveAsNBT(), result); + } catch (IOException e) { + TerminalDialogWidget.showInfoDialog(getOs(), "ERROR", "An error occurred while saving the file.").setClientSide().open(); + } + } + }).setClientSide().open(); } }); - return Arrays.asList(newPage, importPage, save, load); + return Arrays.asList(newPage, deletePage, addSlot, importPage, exportPage); } @Override public NBTTagCompound closeApp(boolean isClient, NBTTagCompound nbt) { //synced data to server side. - if (isClient && testnbt != null) { - return testnbt; + if (isClient) { + NBTTagList list = new NBTTagList(); + for (Map.Entry entry : containers.entrySet()) { + NBTTagCompound container = new NBTTagCompound(); + container.setString("name", entry.getValue()); + container.setTag("data", entry.getKey().saveAsNBT()); + list.appendTag(container); + } + nbt.setTag("list", list); + return nbt; } - return super.closeApp(isClient, nbt); + return super.closeApp(false, nbt); } @Override From 308541f1a2371c3b32ce6a32d425dbe3bdc577bd Mon Sep 17 00:00:00 2001 From: Yefancy Date: Wed, 18 Aug 2021 14:18:31 +0800 Subject: [PATCH 57/58] lang file --- .../api/gui/resources/FileTexture.java | 3 +- .../api/gui/resources/ModifyGuiTexture.java | 2 +- .../api/gui/resources/TextTexture.java | 6 +-- .../api/gui/resources/URLTexture.java | 3 +- .../api/terminal/os/TerminalDialogWidget.java | 7 +-- .../terminal/os/menu/TerminalMenuWidget.java | 6 +-- .../common/terminal/app/ThemeSettingApp.java | 12 ++--- .../app/guide/MultiBlockGuideApp.java | 3 +- .../app/guide/SimpleMachineGuideApp.java | 3 +- .../app/guideeditor/GuideEditorApp.java | 6 +-- .../guideeditor/widget/GuideConfigEditor.java | 20 ++++---- .../widget/GuidePageEditorWidget.java | 6 +-- .../configurator/ConfiguratorWidget.java | 3 +- .../configurator/FluidStackConfigurator.java | 2 +- .../configurator/ItemStackConfigurator.java | 2 +- .../configurator/StringConfigurator.java | 2 +- .../app/recipechart/RecipeChartApp.java | 30 +++++------ .../app/recipechart/widget/RGLine.java | 9 ++-- .../app/recipechart/widget/RGNode.java | 12 ++--- .../terminal/component/SearchComponent.java | 2 +- .../resources/assets/gregtech/lang/en_us.lang | 50 ++++++++++++++++++- .../en_us/steam_boiler_coal_bronze.json | 33 ++++++++++++ .../en_us/electric_blast_furnace.json | 33 ++++++++++++ .../tutorials/en_us/api_0_guidepage.json | 2 +- .../guide/tutorials/en_us/api_1_widget.json | 2 +- .../guide/tutorials/en_us/api_2_textbox.json | 2 +- .../guide/tutorials/en_us/api_3_image.json | 2 +- 27 files changed, 191 insertions(+), 72 deletions(-) create mode 100644 src/main/resources/assets/gregtech/terminal/guide/machines/en_us/steam_boiler_coal_bronze.json create mode 100644 src/main/resources/assets/gregtech/terminal/guide/multiblocks/en_us/electric_blast_furnace.json diff --git a/src/main/java/gregtech/api/gui/resources/FileTexture.java b/src/main/java/gregtech/api/gui/resources/FileTexture.java index 5fdd0336f10..94cac96e4f2 100644 --- a/src/main/java/gregtech/api/gui/resources/FileTexture.java +++ b/src/main/java/gregtech/api/gui/resources/FileTexture.java @@ -8,6 +8,7 @@ import gregtech.api.gui.resources.utils.ImageUtils; import gregtech.api.gui.resources.utils.ProcessedImageData; import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.I18n; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import org.apache.commons.compress.utils.IOUtils; @@ -93,7 +94,7 @@ public void draw(double x, double y, int width, int height) { texture.render((float)x, (float)y, width, height, 0, 1, 1, false, false); } else { if (failed || file == null) { - Minecraft.getMinecraft().fontRenderer.drawString(" Load Failed", (int)x, (int)(y + height / 2.0 - 4), 0xffff0000); + Minecraft.getMinecraft().fontRenderer.drawString(I18n.format("texture.url_texture.fail"), (int)x + 2, (int)(y + height / 2.0 - 4), 0xffff0000); } else { this.loadFile(); int s = (int) Math.floorMod(System.currentTimeMillis() / 200, 24); diff --git a/src/main/java/gregtech/api/gui/resources/ModifyGuiTexture.java b/src/main/java/gregtech/api/gui/resources/ModifyGuiTexture.java index 46628884df3..6df10d314f0 100644 --- a/src/main/java/gregtech/api/gui/resources/ModifyGuiTexture.java +++ b/src/main/java/gregtech/api/gui/resources/ModifyGuiTexture.java @@ -14,7 +14,7 @@ public class ModifyGuiTexture implements IGuiTexture{ public ModifyGuiTexture(IGuiTexture texture) { this.texture = texture; if (texture == null) { - this.texture = new TextTexture("Missing Texture"); + this.texture = new TextTexture("texture.modify_gui_texture.missing"); } } diff --git a/src/main/java/gregtech/api/gui/resources/TextTexture.java b/src/main/java/gregtech/api/gui/resources/TextTexture.java index f7d503740b7..1a7c18fc7f2 100644 --- a/src/main/java/gregtech/api/gui/resources/TextTexture.java +++ b/src/main/java/gregtech/api/gui/resources/TextTexture.java @@ -8,24 +8,22 @@ public class TextTexture implements IGuiTexture{ public final String text; public final int color; - private final int textWidth; public TextTexture(String text) { this.text = text; this.color = 0xff000000; - textWidth = FMLCommonHandler.instance().getSide().isClient()? Minecraft.getMinecraft().fontRenderer.getStringWidth(text):0; } public TextTexture(String text, int color) { this.text = text; this.color = color; - textWidth = FMLCommonHandler.instance().getSide().isClient()? Minecraft.getMinecraft().fontRenderer.getStringWidth(text):0; } @Override public void draw(double x, double y, int width, int height) { FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer; - fontRenderer.drawString(I18n.format(text), (float) (x + (width - textWidth) / 2), (float) (y + (height - fontRenderer.FONT_HEIGHT) / 2 + 2), color, false); + String resultText = I18n.format(text); + fontRenderer.drawString(resultText, (float) (x + (width - fontRenderer.getStringWidth(resultText)) / 2), (float) (y + (height - fontRenderer.FONT_HEIGHT) / 2 + 2), color, false); } } diff --git a/src/main/java/gregtech/api/gui/resources/URLTexture.java b/src/main/java/gregtech/api/gui/resources/URLTexture.java index 1f2a413e83a..4bac1590806 100644 --- a/src/main/java/gregtech/api/gui/resources/URLTexture.java +++ b/src/main/java/gregtech/api/gui/resources/URLTexture.java @@ -4,6 +4,7 @@ import gregtech.api.gui.resources.picturetexture.PictureTexture; import gregtech.api.gui.resources.utils.DownloadThread; import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.I18n; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; @@ -37,7 +38,7 @@ public void draw(double x, double y, int width, int height) { texture.render((float)x, (float)y, width, height, 0, 1, 1, false, false); } else { if (failed || url == null || this.url.equals("")) { - Minecraft.getMinecraft().fontRenderer.drawString(" Load Failed", (int)x, (int)(y + height / 2.0 - 4), 0xffff0000); + Minecraft.getMinecraft().fontRenderer.drawString(I18n.format("texture.url_texture.fail"), (int)x + 2, (int)(y + height / 2.0 - 4), 0xffff0000); } else { this.loadTexture(); int s = (int) Math.floorMod(System.currentTimeMillis() / 200, 24); diff --git a/src/main/java/gregtech/api/terminal/os/TerminalDialogWidget.java b/src/main/java/gregtech/api/terminal/os/TerminalDialogWidget.java index f1e5446e17e..b2793b595b3 100644 --- a/src/main/java/gregtech/api/terminal/os/TerminalDialogWidget.java +++ b/src/main/java/gregtech/api/terminal/os/TerminalDialogWidget.java @@ -15,6 +15,7 @@ import gregtech.api.util.Size; import gregtech.api.util.interpolate.Interpolator; import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.resources.I18n; import net.minecraft.inventory.IInventory; import net.minecraft.network.PacketBuffer; @@ -175,7 +176,7 @@ public static TerminalDialogWidget showFileDialog(TerminalOSWidget os, String ti .setBackground(new ColorRectTexture(0x4f000000)); if (!dir.isDirectory()) { if (!dir.mkdirs()) { - return dialog.addInfo("error file path: " + dir.getPath()).addOkButton(); + return dialog.addInfo(I18n.format("terminal.dialog.error_path") + dir.getPath()).addOkButton(); } } AtomicReference selected = new AtomicReference<>(); @@ -209,7 +210,7 @@ public static TerminalDialogWidget showFileDialog(TerminalOSWidget os, String ti if (selected.get() != null) { return selected.get().toString(); } - return "no file selected"; + return "terminal.dialog.no_file_selected"; }, true)); } else { dialog.addWidget(new TextFieldWidget(x + WIDTH / 2 - 38, y + HEIGHT / 2 - 10, 76, 20, new ColorRectTexture(0x4f000000), null, null) @@ -244,7 +245,7 @@ public static TerminalDialogWidget showFileDialog(TerminalOSWidget os, String ti } }) .setColors(0, 0xFFFFFFFF, 0) - .setHoverText("Open Folder") + .setHoverText("terminal.dialog.folder") .setIcon(GuiTextures.ICON_LOAD)); dialog.addWidget(new LabelWidget(x + WIDTH / 2, y + 11, title, -1).setXCentered(true)); os.menu.hideMenu(); diff --git a/src/main/java/gregtech/api/terminal/os/menu/TerminalMenuWidget.java b/src/main/java/gregtech/api/terminal/os/menu/TerminalMenuWidget.java index 70ad3ce8578..dcca9976041 100644 --- a/src/main/java/gregtech/api/terminal/os/menu/TerminalMenuWidget.java +++ b/src/main/java/gregtech/api/terminal/os/menu/TerminalMenuWidget.java @@ -36,19 +36,19 @@ public TerminalMenuWidget(Position position, Size size, TerminalOSWidget os) { .setColors(new Color(255, 255, 255, 0).getRGB(), TerminalTheme.COLOR_7.getColor(), TerminalTheme.COLOR_3.getColor()) - .setHoverText("close") + .setHoverText("terminal.menu.close") .setClickListener(this::close)); this.addWidget(new CircleButtonWidget(15, 10, 4, 1, 0) .setColors(new Color(255, 255, 255, 0).getRGB(), TerminalTheme.COLOR_7.getColor(), TerminalTheme.COLOR_2.getColor()) - .setHoverText("minimize") + .setHoverText("terminal.menu.minimize") .setClickListener(this::minimize)); this.addWidget(new CircleButtonWidget(25, 10, 4, 1, 0) .setColors(new Color(255, 255, 255, 0).getRGB(), TerminalTheme.COLOR_7.getColor(), TerminalTheme.COLOR_1.getColor()) - .setHoverText("maximize") + .setHoverText("terminal.menu.maximize") .setClickListener(this::maximize)); } diff --git a/src/main/java/gregtech/common/terminal/app/ThemeSettingApp.java b/src/main/java/gregtech/common/terminal/app/ThemeSettingApp.java index eddddc81f56..48b738e9c72 100644 --- a/src/main/java/gregtech/common/terminal/app/ThemeSettingApp.java +++ b/src/main/java/gregtech/common/terminal/app/ThemeSettingApp.java @@ -36,7 +36,7 @@ public AbstractApplication createApp(TerminalOSWidget os, boolean isClient, NBTT float x = 333 * 1.0f / 13; int y = 50; app.addWidget(new ImageWidget(5, 5, 333 - 10, 232 - 10, TerminalTheme.COLOR_B_2)); - app.addWidget(new LabelWidget(333 / 2, 20, "Theme Color Settings", -1).setXCentered(true)); + app.addWidget(new LabelWidget(333 / 2, 20, "terminal.theme_settings.color", -1).setXCentered(true)); app.addColorButton(TerminalTheme.COLOR_1, "COLOR_1", (int) x, y); app.addColorButton(TerminalTheme.COLOR_2, "COLOR_2", (int) (x * 2), y); app.addColorButton(TerminalTheme.COLOR_3, "COLOR_3", (int) (x * 3), y); @@ -49,7 +49,7 @@ public AbstractApplication createApp(TerminalOSWidget os, boolean isClient, NBTT app.addColorButton(TerminalTheme.COLOR_B_1, "COLOR_B_1", (int) (x * 10), y); app.addColorButton(TerminalTheme.COLOR_B_2, "COLOR_B_2", (int) (x * 11), y); app.addColorButton(TerminalTheme.COLOR_B_3, "COLOR_B_3", (int) (x * 12), y); - app.addWidget(new LabelWidget(333 / 2, 85, "Wallpaper Settings", -1).setXCentered(true)); + app.addWidget(new LabelWidget(333 / 2, 85, "terminal.theme_settings.wallpaper", -1).setXCentered(true)); app.addWidget(new ImageWidget((int) x, 105, 150, 105, TerminalTheme.WALL_PAPER).setBorder(2, -1)); app.addWidget(new SelectorWidget((int) (x + 170), 105, 116, 20, Arrays.asList("resource", "url", "color", "file"), -1, TerminalTheme.WALL_PAPER::getTypeName, true) .setIsUp(true) @@ -70,7 +70,7 @@ private void addColorButton(ColorRectTexture texture, String name, int x, int y) buttonWidget.setFill(color); texture.setColor(color); if (!TerminalTheme.saveConfig()) { - TerminalDialogWidget.showInfoDialog(getOs(), "ERROR", "error while saving config").setClientSide().open(); + TerminalDialogWidget.showInfoDialog(getOs(), "terminal.component.error", "terminal.component.save_file.error").setClientSide().open(); } } }).setClientSide().open(); @@ -124,13 +124,13 @@ private void onModifyTextureChanged(String type, AbstractApplication app) { .setColors(TerminalTheme.COLOR_B_1.getColor(), TerminalTheme.COLOR_1.getColor(), new Color(255, 255, 255, 0).getRGB()) - .setClickListener(cd-> TerminalDialogWidget.showFileDialog(app.getOs(), "Image File", new File("terminal"), true, file->{ + .setClickListener(cd-> TerminalDialogWidget.showFileDialog(app.getOs(), "terminal.theme_settings.image", new File("terminal"), true, file->{ if (file != null && file.isFile()) { TerminalTheme.WALL_PAPER.setTexture(new FileTexture(file)); TerminalTheme.saveConfig(); } }).setClientSide().open()) - .setIcon(new TextTexture("Select", -1))); + .setIcon(new TextTexture("terminal.theme_settings.select", -1))); break; } } @@ -146,7 +146,7 @@ private void addStringSetting(String init, Consumer callback) { TerminalTheme.COLOR_1.getColor(), new Color(255, 255, 255, 0).getRGB()) .setClickListener(cd->callback.accept(textFieldWidget.getCurrentString())) - .setIcon(new TextTexture("Update", -1))); + .setIcon(new TextTexture("terminal.guide_editor.update", -1))); } @Override diff --git a/src/main/java/gregtech/common/terminal/app/guide/MultiBlockGuideApp.java b/src/main/java/gregtech/common/terminal/app/guide/MultiBlockGuideApp.java index c146884be5f..edee321db22 100644 --- a/src/main/java/gregtech/common/terminal/app/guide/MultiBlockGuideApp.java +++ b/src/main/java/gregtech/common/terminal/app/guide/MultiBlockGuideApp.java @@ -2,6 +2,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import gregtech.api.GTValues; import gregtech.api.GregTechAPI; import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.resources.ItemStackTexture; @@ -22,7 +23,7 @@ protected MetaTileEntity ofJson(JsonObject json) { for (String valid : valids) { JsonElement id = json.getAsJsonObject().get(valid); if (id != null && id.isJsonPrimitive()) - return GregTechAPI.META_TILE_ENTITY_REGISTRY.getObject(new ResourceLocation(id.getAsString())); + return GregTechAPI.META_TILE_ENTITY_REGISTRY.getObject(new ResourceLocation(GTValues.MODID, id.getAsString())); } } return null; diff --git a/src/main/java/gregtech/common/terminal/app/guide/SimpleMachineGuideApp.java b/src/main/java/gregtech/common/terminal/app/guide/SimpleMachineGuideApp.java index e0b021ed368..c6483b4cff2 100644 --- a/src/main/java/gregtech/common/terminal/app/guide/SimpleMachineGuideApp.java +++ b/src/main/java/gregtech/common/terminal/app/guide/SimpleMachineGuideApp.java @@ -2,6 +2,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import gregtech.api.GTValues; import gregtech.api.GregTechAPI; import gregtech.api.gui.resources.IGuiTexture; import gregtech.api.gui.resources.ItemStackTexture; @@ -37,7 +38,7 @@ protected MetaTileEntity ofJson(JsonObject json) { for (String valid : valids) { JsonElement id = json.getAsJsonObject().get(valid); if (id != null && id.isJsonPrimitive()) - return GregTechAPI.META_TILE_ENTITY_REGISTRY.getObject(new ResourceLocation(id.getAsString())); + return GregTechAPI.META_TILE_ENTITY_REGISTRY.getObject(new ResourceLocation(GTValues.MODID, id.getAsString())); } } return null; diff --git a/src/main/java/gregtech/common/terminal/app/guideeditor/GuideEditorApp.java b/src/main/java/gregtech/common/terminal/app/guideeditor/GuideEditorApp.java index 7cdcb4cbeef..ac84b3cac0c 100644 --- a/src/main/java/gregtech/common/terminal/app/guideeditor/GuideEditorApp.java +++ b/src/main/java/gregtech/common/terminal/app/guideeditor/GuideEditorApp.java @@ -40,17 +40,17 @@ public AbstractApplication createApp(TerminalOSWidget os, boolean isClient, NBTT @Override public List getMenuComponents() { - ClickComponent newPage = new ClickComponent().setIcon(GuiTextures.ICON_NEW_PAGE).setHoverText("New Page").setClickConsumer(cd->{ + ClickComponent newPage = new ClickComponent().setIcon(GuiTextures.ICON_NEW_PAGE).setHoverText("terminal.component.new_page").setClickConsumer(cd->{ if (configEditor != null) { configEditor.newPage(cd); } }); - ClickComponent importPage = new ClickComponent().setIcon(GuiTextures.ICON_LOAD).setHoverText("Load File").setClickConsumer(cd->{ + ClickComponent importPage = new ClickComponent().setIcon(GuiTextures.ICON_LOAD).setHoverText("terminal.component.load_file").setClickConsumer(cd->{ if (configEditor != null) { configEditor.loadJson(cd); } }); - ClickComponent exportPage = new ClickComponent().setIcon(GuiTextures.ICON_SAVE).setHoverText("Save File").setClickConsumer(cd->{ + ClickComponent exportPage = new ClickComponent().setIcon(GuiTextures.ICON_SAVE).setHoverText("terminal.component.save_file").setClickConsumer(cd->{ if (configEditor != null) { configEditor.saveJson(cd); } diff --git a/src/main/java/gregtech/common/terminal/app/guideeditor/widget/GuideConfigEditor.java b/src/main/java/gregtech/common/terminal/app/guideeditor/widget/GuideConfigEditor.java index ff52d6111e8..0bfe6c1aac5 100644 --- a/src/main/java/gregtech/common/terminal/app/guideeditor/widget/GuideConfigEditor.java +++ b/src/main/java/gregtech/common/terminal/app/guideeditor/widget/GuideConfigEditor.java @@ -41,9 +41,9 @@ public GuideConfigEditor(int x, int y, int width, int height, GuideEditorApp app addButton = new CircleButtonWidget[2]; widgetSelector = createWidgetSelector(); widgetConfigurator = createConfigurator(); - this.addTab(new IGuiTextureTabInfo(new TextTexture("P", -1), "Page Config"), createPageConfig()); - this.addTab(new IGuiTextureTabInfo(new TextTexture("W", -1), "Widgets Box"), widgetSelector); - this.addTab(new IGuiTextureTabInfo(new TextTexture("C", -1), "Widget Config"), widgetConfigurator); + this.addTab(new IGuiTextureTabInfo(new TextTexture("P", -1), "terminal.guide_editor.page_config"), createPageConfig()); + this.addTab(new IGuiTextureTabInfo(new TextTexture("W", -1), "terminal.guide_editor.widgets_box"), widgetSelector); + this.addTab(new IGuiTextureTabInfo(new TextTexture("C", -1), "terminal.guide_editor.widget_config"), widgetConfigurator); this.setOnTabChanged((oldIndex, newIndex)->{ if (newIndex == 1) { addButton[0].setVisible(true); @@ -58,14 +58,14 @@ public GuideConfigEditor(int x, int y, int width, int height, GuideEditorApp app TerminalTheme.COLOR_7.getColor(), TerminalTheme.COLOR_4.getColor()) .setIcon(GuiTextures.ICON_ADD) - .setHoverText("add stream") + .setHoverText("terminal.guide_editor.add_stream") .setClickListener(this::addStream); addButton[1] = new CircleButtonWidget(115, 35, 8, 1, 8) .setColors(new Color(255, 255, 255, 0).getRGB(), TerminalTheme.COLOR_7.getColor(), TerminalTheme.COLOR_5.getColor()) .setIcon(GuiTextures.ICON_ADD) - .setHoverText("add fixed") + .setHoverText("terminal.guide_editor.add_fixed") .setClickListener(this::addFixed); addButton[0].setVisible(false); addButton[1].setVisible(false); @@ -146,7 +146,7 @@ public void loadConfigurator(IGuideWidget widget) { } public void newPage(ClickData data) { - TerminalDialogWidget.showConfirmDialog(app.getOs(), "New Page", "New page", res->{ + TerminalDialogWidget.showConfirmDialog(app.getOs(), "terminal.component.new_page", "terminal.component.confirm", res->{ if (res) { pageEditor.loadJsonConfig("{\"section\":\"default\",\"title\":\"Template\",\"stream\":[],\"fixed\":[]}"); getPageEditor().setSection("default"); @@ -158,7 +158,7 @@ public void newPage(ClickData data) { public void loadJson(ClickData data) { if (pageEditor != null) { File file = new File("terminal\\guide_editor"); - TerminalDialogWidget.showFileDialog(app.getOs(), "Load Json", file, true, result->{ + TerminalDialogWidget.showFileDialog(app.getOs(), "terminal.component.load_file", file, true, result->{ if (result != null && result.isFile()) { try { JsonObject config = Objects.requireNonNull(FileUtils.loadJson(result)).getAsJsonObject(); @@ -166,7 +166,7 @@ public void loadJson(ClickData data) { getPageEditor().setSection(config.get("section").getAsString()); updateTitle(config.get("title").getAsString()); } catch (Exception e) { - TerminalDialogWidget.showInfoDialog(app.getOs(), "ERROR", "An error occurred while loading the file.").setClientSide().open(); + TerminalDialogWidget.showInfoDialog(app.getOs(), "terminal.component.error", "terminal.component.load_file.error").setClientSide().open(); } } }).setClientSide().open(); @@ -176,10 +176,10 @@ public void loadJson(ClickData data) { public void saveJson(ClickData data) { if(pageEditor != null) { File file = new File("terminal\\guide_editor"); - TerminalDialogWidget.showFileDialog(app.getOs(), "Save Json", file, false, result->{ + TerminalDialogWidget.showFileDialog(app.getOs(), "terminal.component.save_file", file, false, result->{ if (result != null) { if(!FileUtils.saveJson(result, pageEditor.getJsonConfig())) { - TerminalDialogWidget.showInfoDialog(app.getOs(), "ERROR", "An error occurred while saving the file.").setClientSide().open(); + TerminalDialogWidget.showInfoDialog(app.getOs(), "terminal.component.error", "terminal.component.save_file.error").setClientSide().open(); } } }).setClientSide().open(); diff --git a/src/main/java/gregtech/common/terminal/app/guideeditor/widget/GuidePageEditorWidget.java b/src/main/java/gregtech/common/terminal/app/guideeditor/widget/GuidePageEditorWidget.java index 6112ae4dd15..31e517ea79f 100644 --- a/src/main/java/gregtech/common/terminal/app/guideeditor/widget/GuidePageEditorWidget.java +++ b/src/main/java/gregtech/common/terminal/app/guideeditor/widget/GuidePageEditorWidget.java @@ -43,21 +43,21 @@ public GuidePageEditorWidget(int xPosition, int yPosition, int width, int height TerminalTheme.COLOR_B_2.getColor(), TerminalTheme.COLOR_1.getColor()) .setIcon(GuiTextures.ICON_UP) - .setHoverText("up") + .setHoverText("terminal.guide_editor.up") .setClickListener(this::moveUp)); toolButtons.addWidget(new CircleButtonWidget(0, -4, 8, 1, 12) .setColors(new Color(255, 255, 255, 0).getRGB(), TerminalTheme.COLOR_B_2.getColor(), TerminalTheme.COLOR_2.getColor()) .setIcon(GuiTextures.ICON_DOWN) - .setHoverText("down") + .setHoverText("terminal.guide_editor.down") .setClickListener(this::moveDown)); toolButtons.addWidget(new CircleButtonWidget(20, -4, 8, 1, 12) .setColors(new Color(255, 255, 255, 0).getRGB(), TerminalTheme.COLOR_B_2.getColor(), TerminalTheme.COLOR_3.getColor()) .setIcon(GuiTextures.ICON_REMOVE) - .setHoverText("delete") + .setHoverText("terminal.guide_editor.remove") .setClickListener(this::delete)); addWidget(customPositionSizeWidget); addWidget(toolButtons); diff --git a/src/main/java/gregtech/common/terminal/app/guideeditor/widget/configurator/ConfiguratorWidget.java b/src/main/java/gregtech/common/terminal/app/guideeditor/widget/configurator/ConfiguratorWidget.java index 2bba4471901..706efc8f659 100644 --- a/src/main/java/gregtech/common/terminal/app/guideeditor/widget/configurator/ConfiguratorWidget.java +++ b/src/main/java/gregtech/common/terminal/app/guideeditor/widget/configurator/ConfiguratorWidget.java @@ -8,6 +8,7 @@ import gregtech.api.terminal.gui.widgets.DraggableScrollableWidgetGroup; import gregtech.api.util.Position; import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.I18n; import net.minecraft.item.ItemStack; import java.util.Collections; @@ -73,7 +74,7 @@ public void drawInForeground(int mouseX, int mouseY) { int x = getPosition().x; int y = getPosition().y; if (canDefault && isMouseOver(x + nameWidth + 4, y + 6, 5, 5, mouseX, mouseY)) { - drawHoveringText(ItemStack.EMPTY, Collections.singletonList("default value"), 100, mouseX, mouseY); + drawHoveringText(ItemStack.EMPTY, Collections.singletonList(I18n.format("terminal.guide_editor.default")), 100, mouseX, mouseY); } if (!isDefault) { super.drawInForeground(mouseX, mouseY); diff --git a/src/main/java/gregtech/common/terminal/app/guideeditor/widget/configurator/FluidStackConfigurator.java b/src/main/java/gregtech/common/terminal/app/guideeditor/widget/configurator/FluidStackConfigurator.java index 7d4f23516eb..9ce264b4fe0 100644 --- a/src/main/java/gregtech/common/terminal/app/guideeditor/widget/configurator/FluidStackConfigurator.java +++ b/src/main/java/gregtech/common/terminal/app/guideeditor/widget/configurator/FluidStackConfigurator.java @@ -27,7 +27,7 @@ protected void init() { container = new DraggableScrollableWidgetGroup(0, 27,116, 100); this.addWidget(container); this.addWidget(new RectButtonWidget(0, 15, 116, 10, 1) - .setIcon(new TextTexture("Add Slot", -1)) + .setIcon(new TextTexture("terminal.guide_editor.add_slot", -1)) .setClickListener(cd->{ addSlot(container, new TankListWidget.FluidStackInfo(null, 0)); updateValue(); diff --git a/src/main/java/gregtech/common/terminal/app/guideeditor/widget/configurator/ItemStackConfigurator.java b/src/main/java/gregtech/common/terminal/app/guideeditor/widget/configurator/ItemStackConfigurator.java index 5f4c1a10108..69c773c1507 100644 --- a/src/main/java/gregtech/common/terminal/app/guideeditor/widget/configurator/ItemStackConfigurator.java +++ b/src/main/java/gregtech/common/terminal/app/guideeditor/widget/configurator/ItemStackConfigurator.java @@ -32,7 +32,7 @@ protected void init() { container = new DraggableScrollableWidgetGroup(0, 27,116, 100); this.addWidget(container); this.addWidget(new RectButtonWidget(0, 15, 116, 10, 1) - .setIcon(new TextTexture("Add Slot", -1)) + .setIcon(new TextTexture("terminal.guide_editor.add_slot", -1)) .setClickListener(cd->{ addSlot(container, new SlotListWidget.ItemStackInfo("minecraft:air", 0, 0)); updateValue(); diff --git a/src/main/java/gregtech/common/terminal/app/guideeditor/widget/configurator/StringConfigurator.java b/src/main/java/gregtech/common/terminal/app/guideeditor/widget/configurator/StringConfigurator.java index fdbe940aba3..e0ca118aa56 100644 --- a/src/main/java/gregtech/common/terminal/app/guideeditor/widget/configurator/StringConfigurator.java +++ b/src/main/java/gregtech/common/terminal/app/guideeditor/widget/configurator/StringConfigurator.java @@ -26,7 +26,7 @@ protected void init() { TerminalTheme.COLOR_1.getColor(), new Color(255, 255, 255, 0).getRGB()) .setClickListener(data -> updateString()) - .setIcon(new TextTexture("Update", -1))); + .setIcon(new TextTexture("terminal.guide_editor.update", -1))); textFieldWidget = new TextFieldWidget(0, 15, 76, 20, TerminalTheme.COLOR_B_2, null, null) .setMaxStringLength(Integer.MAX_VALUE) .setValidator(s->true); diff --git a/src/main/java/gregtech/common/terminal/app/recipechart/RecipeChartApp.java b/src/main/java/gregtech/common/terminal/app/recipechart/RecipeChartApp.java index 1eac10a1eeb..b633c0a8dc9 100644 --- a/src/main/java/gregtech/common/terminal/app/recipechart/RecipeChartApp.java +++ b/src/main/java/gregtech/common/terminal/app/recipechart/RecipeChartApp.java @@ -66,72 +66,72 @@ private RGContainer addTab(String name) { name = name.isEmpty()? "default" : name; RGContainer container = new RGContainer(0, 0, 333, 222, getOs()); container.setBackground(TerminalTheme.COLOR_B_3); - tabGroup.addTab(new IGuiTextureTabInfo(new TextTexture(name, -1), "Widgets Box"), container); + tabGroup.addTab(new IGuiTextureTabInfo(new TextTexture(name, -1), name), container); containers.put(container, name); return container; } @Override public List getMenuComponents() { - ClickComponent newPage = new ClickComponent().setIcon(GuiTextures.ICON_NEW_PAGE).setHoverText("New Page").setClickConsumer(cd->{ + ClickComponent newPage = new ClickComponent().setIcon(GuiTextures.ICON_NEW_PAGE).setHoverText("terminal.component.new_page").setClickConsumer(cd->{ if (tabGroup == null) return; if (tabGroup.getAllTag().size() < 5) { - TerminalDialogWidget.showTextFieldDialog(getOs(), "Page Name", s -> true, s -> { + TerminalDialogWidget.showTextFieldDialog(getOs(), "terminal.component.page_name", s -> true, s -> { if (s != null) { addTab(s); } }).setClientSide().open(); } else { - TerminalDialogWidget.showInfoDialog(getOs(), "NOTICE", "Page limit.").setClientSide().open(); + TerminalDialogWidget.showInfoDialog(getOs(), "terminal.component.warning", "terminal.recipe_chart.limit").setClientSide().open(); } }); - ClickComponent deletePage = new ClickComponent().setIcon(GuiTextures.ICON_REMOVE).setHoverText("Delete Page").setClickConsumer(cd->{ + ClickComponent deletePage = new ClickComponent().setIcon(GuiTextures.ICON_REMOVE).setHoverText("terminal.recipe_chart.delete").setClickConsumer(cd->{ if (tabGroup == null) return; if (tabGroup.getAllTag().size() > 1) { - TerminalDialogWidget.showConfirmDialog(getOs(), "Delete Page", "Are you sure?", r->{ + TerminalDialogWidget.showConfirmDialog(getOs(), "terminal.recipe_chart.delete", "terminal.component.confirm", r->{ if (r) { containers.remove(tabGroup.getCurrentTag()); tabGroup.removeTab(tabGroup.getAllTag().indexOf(tabGroup.getCurrentTag())); } }).setClientSide().open(); } else { - TerminalDialogWidget.showInfoDialog(getOs(), "NOTICE", "Page limit.").setClientSide().open(); + TerminalDialogWidget.showInfoDialog(getOs(), "terminal.component.warning", "terminal.recipe_chart.limit").setClientSide().open(); } }); - ClickComponent addSlot = new ClickComponent().setIcon(GuiTextures.ICON_ADD).setHoverText("Add Root Slot").setClickConsumer(cd->{ + ClickComponent addSlot = new ClickComponent().setIcon(GuiTextures.ICON_ADD).setHoverText("terminal.recipe_chart.add_slot").setClickConsumer(cd->{ if (tabGroup == null) return; if (tabGroup.getCurrentTag() != null) { tabGroup.getCurrentTag().addNode(50, 100); } }); - ClickComponent importPage = new ClickComponent().setIcon(GuiTextures.ICON_LOAD).setHoverText("Load File").setClickConsumer(cd->{ + ClickComponent importPage = new ClickComponent().setIcon(GuiTextures.ICON_LOAD).setHoverText("terminal.component.load_file").setClickConsumer(cd->{ if (tabGroup == null) return; if (tabGroup.getAllTag().size() < 5) { File file = new File("terminal\\recipe_chart"); - TerminalDialogWidget.showFileDialog(getOs(), "Load File", file, true, result->{ + TerminalDialogWidget.showFileDialog(getOs(), "terminal.component.load_file", file, true, result->{ if (result != null && result.isFile()) { try { NBTTagCompound nbt = CompressedStreamTools.read(result); addTab(result.getName()).loadFromNBT(nbt); } catch (IOException e) { - TerminalDialogWidget.showInfoDialog(getOs(), "ERROR", "An error occurred while loading the file.").setClientSide().open(); + TerminalDialogWidget.showInfoDialog(getOs(), "terminal.component.error", "terminal.component.load_file.error").setClientSide().open(); } } }).setClientSide().open(); } else { - TerminalDialogWidget.showInfoDialog(getOs(), "NOTICE", "Page limit.").setClientSide().open(); + TerminalDialogWidget.showInfoDialog(getOs(), "terminal.component.warning", "terminal.recipe_chart.limit").setClientSide().open(); } }); - ClickComponent exportPage = new ClickComponent().setIcon(GuiTextures.ICON_SAVE).setHoverText("Save File").setClickConsumer(cd->{ + ClickComponent exportPage = new ClickComponent().setIcon(GuiTextures.ICON_SAVE).setHoverText("terminal.component.save_file").setClickConsumer(cd->{ if (tabGroup == null) return; if (tabGroup.getCurrentTag() != null) { File file = new File("terminal\\recipe_chart"); - TerminalDialogWidget.showFileDialog(getOs(), "Save File", file, false, result->{ + TerminalDialogWidget.showFileDialog(getOs(), "terminal.component.save_file", file, false, result->{ if (result != null) { try { CompressedStreamTools.safeWrite(tabGroup.getCurrentTag().saveAsNBT(), result); } catch (IOException e) { - TerminalDialogWidget.showInfoDialog(getOs(), "ERROR", "An error occurred while saving the file.").setClientSide().open(); + TerminalDialogWidget.showInfoDialog(getOs(), "terminal.component.error", "terminal.component.save_file.error").setClientSide().open(); } } }).setClientSide().open(); diff --git a/src/main/java/gregtech/common/terminal/app/recipechart/widget/RGLine.java b/src/main/java/gregtech/common/terminal/app/recipechart/widget/RGLine.java index 712c3748285..a345479fe2b 100644 --- a/src/main/java/gregtech/common/terminal/app/recipechart/widget/RGLine.java +++ b/src/main/java/gregtech/common/terminal/app/recipechart/widget/RGLine.java @@ -16,6 +16,7 @@ import gregtech.api.terminal.os.TerminalTheme; import gregtech.api.util.Position; import gregtech.api.util.Size; +import net.minecraft.client.resources.I18n; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.math.Vec2f; @@ -50,7 +51,7 @@ public RGLine(RGNode parent, RGNode child, RGContainer container) { infoGroup.addWidget(new SlotWidget(handler, 0, 0, 0, false, false).setBackgroundTexture(new ColorRectTexture(0))); MetaTileEntity mte = MachineItemBlock.getMetaTileEntity(catalyst); if (mte instanceof SimpleMachineMetaTileEntity) { - infoGroup.addWidget(new LabelWidget(9, -10, "Tier: " + GTValues.VN[((SimpleMachineMetaTileEntity) mte).getTier()], -1).setXCentered(true).setShadow(true)); + infoGroup.addWidget(new LabelWidget(9, -10, I18n.format("terminal.recipe_chart.tier") + GTValues.VN[((SimpleMachineMetaTileEntity) mte).getTier()], -1).setXCentered(true).setShadow(true)); } } @@ -62,7 +63,7 @@ public RGLine(RGNode parent, RGNode child, RGContainer container) { toolGroup.addWidget(new CircleButtonWidget(-8, 0, 8, 1, 12) .setColors(0, TerminalTheme.COLOR_7.getColor(), 0) .setIcon(GuiTextures.ICON_VISIBLE) - .setHoverText("Info Visible") + .setHoverText("terminal.recipe_chart.visible") .setClickListener(cd -> { infoGroup.setActive(!infoGroup.isActive()); infoGroup.setVisible(!infoGroup.isVisible()); @@ -70,8 +71,8 @@ public RGLine(RGNode parent, RGNode child, RGContainer container) { toolGroup.addWidget(new CircleButtonWidget(8, 0, 8, 1, 12) .setColors(0, TerminalTheme.COLOR_7.getColor(), 0) .setIcon(GuiTextures.ICON_CALCULATOR) - .setHoverText("Ratio") - .setClickListener(cd -> TerminalDialogWidget.showTextFieldDialog(container.os, "Ratio", s->{ + .setHoverText("terminal.recipe_chart.ratio") + .setClickListener(cd -> TerminalDialogWidget.showTextFieldDialog(container.os, "terminal.recipe_chart.ratio", s->{ try { return Integer.parseInt(s) > 0; } catch (Exception ignored){ diff --git a/src/main/java/gregtech/common/terminal/app/recipechart/widget/RGNode.java b/src/main/java/gregtech/common/terminal/app/recipechart/widget/RGNode.java index b924f4f8606..b9b45db6c2a 100644 --- a/src/main/java/gregtech/common/terminal/app/recipechart/widget/RGNode.java +++ b/src/main/java/gregtech/common/terminal/app/recipechart/widget/RGNode.java @@ -64,8 +64,8 @@ public RGNode(int x, int y, RGContainer container, Object head, boolean isPhanto toolGroup.addWidget(new CircleButtonWidget(-11, 49, 8, 1, 12) .setColors(0, TerminalTheme.COLOR_7.getColor(), 0) .setIcon(GuiTextures.ICON_CALCULATOR) - .setHoverText("Calculator") - .setClickListener(cd -> TerminalDialogWidget.showTextFieldDialog(container.os, "Demand", s->{ + .setHoverText("terminal.recipe_chart.calculator") + .setClickListener(cd -> TerminalDialogWidget.showTextFieldDialog(container.os, "terminal.recipe_chart.demand", s->{ try { return Integer.parseInt(s) > 0; } catch (Exception ignored){ @@ -96,7 +96,7 @@ private void init(RGContainer container) { } else if (head instanceof FluidStack) { return ((FluidStack) head).getLocalizedName(); } - return "Drag ingredients into slot."; + return "terminal.recipe_chart.drag"; }, true).setShadow(true); textWidget.setVisible(false); textWidget.setActive(false); @@ -108,12 +108,12 @@ private void init(RGContainer container) { toolGroup.addWidget(new CircleButtonWidget(-11, 9, 8, 1, 12) .setColors(0, TerminalTheme.COLOR_7.getColor(), TerminalTheme.COLOR_3.getColor()) .setIcon(GuiTextures.ICON_REMOVE) - .setHoverText("remove") + .setHoverText("terminal.guide_editor.remove") .setClickListener(cd -> remove())); toolGroup.addWidget(new CircleButtonWidget(-11, 29, 8, 1, 12) .setColors(0, TerminalTheme.COLOR_7.getColor(), 0) .setIcon(GuiTextures.ICON_VISIBLE) - .setHoverText("Text Visible") + .setHoverText("terminal.recipe_chart.visible") .setClickListener(cd -> { textWidget.setActive(!textWidget.isActive()); textWidget.setVisible(!textWidget.isVisible()); @@ -121,7 +121,7 @@ private void init(RGContainer container) { toolGroup.addWidget(new CircleButtonWidget(9, 29, 8, 1, 12) .setColors(0, TerminalTheme.COLOR_7.getColor(), 0) .setIcon(GuiTextures.ICON_LOCATION) - .setHoverText("JEI Focus") + .setHoverText("terminal.recipe_chart.jei") .setClickListener(cd -> { if (GTJeiPlugin.jeiRuntime != null && head != null) { GTJeiPlugin.jeiRuntime.getRecipesGui().show(new Focus<>(IFocus.Mode.OUTPUT, head)); diff --git a/src/main/java/gregtech/common/terminal/component/SearchComponent.java b/src/main/java/gregtech/common/terminal/component/SearchComponent.java index 2a8ae3bb673..3f61dfafcff 100644 --- a/src/main/java/gregtech/common/terminal/component/SearchComponent.java +++ b/src/main/java/gregtech/common/terminal/component/SearchComponent.java @@ -47,7 +47,7 @@ public IGuiTexture buttonIcon() { @Override public String hoverText() { - return "searching"; + return "terminal.component.searching"; } public void setUp(boolean up) { diff --git a/src/main/resources/assets/gregtech/lang/en_us.lang b/src/main/resources/assets/gregtech/lang/en_us.lang index c570b97d084..4fc5af8e57e 100644 --- a/src/main/resources/assets/gregtech/lang/en_us.lang +++ b/src/main/resources/assets/gregtech/lang/en_us.lang @@ -3636,4 +3636,52 @@ gregtech.terminal.app_name.theme_settings=Theme Settings gregtech.terminal.app_name.guide_editor=Guide Editor gregtech.terminal.app_name.recipe_chart=Recipe Chart -gregtech.terminal.guide.tutorials.guide_widget_api=Guide Widget Api +texture.modify_gui_texture.missing=Missing Texture +texture.url_texture.fail=Load Failed + +terminal.menu.close=Close +terminal.menu.minimize=Minimize +terminal.menu.maximize=Maximize + +terminal.component.new_page=New Page +terminal.component.page_name=Page Name +terminal.component.load_file=Load File +terminal.component.load_file.error=An error occurred while loading the file. +terminal.component.save_file=Save File +terminal.component.save_file.error=An error occurred while saving the file. +terminal.component.confirm=Are you sure? +terminal.component.error=ERROR +terminal.component.warning=WARNING +terminal.component.searching=searching + +terminal.dialog.error_path=error file path: +terminal.dialog.no_file_selected=No file selected. +terminal.dialog.folder=Open Folder + +terminal.guide_editor.up=Up +terminal.guide_editor.down=Down +terminal.guide_editor.remove=Remove +terminal.guide_editor.add_stream=Add to stream +terminal.guide_editor.add_fixed=Add to fixed +terminal.guide_editor.update=Update +terminal.guide_editor.add_slot=Add Slot +terminal.guide_editor.default=Default Value +terminal.guide_editor.page_config=Page Config +terminal.guide_editor.widgets_box=Widgets Box +terminal.guide_editor.widget_config=Widget Config + +terminal.theme_settings.color=Theme Color Settings +terminal.theme_settings.wallpaper=Wallpaper Settings +terminal.theme_settings.select=Select +terminal.theme_settings.image=Image File + +terminal.recipe_chart.limit=Page limit. +terminal.recipe_chart.delete=Delete Page +terminal.recipe_chart.add_slot=Add Root Slot +terminal.recipe_chart.demand=Demand +terminal.recipe_chart.calculator=Calculator +terminal.recipe_chart.drag=Drag ingredients here. +terminal.recipe_chart.visible=Visible +terminal.recipe_chart.jei=JEI Focus +terminal.recipe_chart.tier=Tier: +terminal.recipe_chart.ratio=Ratio diff --git a/src/main/resources/assets/gregtech/terminal/guide/machines/en_us/steam_boiler_coal_bronze.json b/src/main/resources/assets/gregtech/terminal/guide/machines/en_us/steam_boiler_coal_bronze.json new file mode 100644 index 00000000000..5a35a77e167 --- /dev/null +++ b/src/main/resources/assets/gregtech/terminal/guide/machines/en_us/steam_boiler_coal_bronze.json @@ -0,0 +1,33 @@ +{ + "machine": "steam_boiler_coal_bronze", + "section": "Machines/Steam", + "title": "Small Steam Coal Boiler", + "stream": [ + { + "type": "textbox", + "isCenter": false, + "content": [ + "Wrench this, wrench that" + ] + }, + { + "type": "textbox", + "isCenter": true, + "fontSize": 5, + "content": [ + "§nMinecraft Formatting", + "§r§00 §11 §22 §33", + "§44 §55 §66 §77", + "§88 §99 §aa §bb", + "§cc §dd §ee §ff", + "§r§0k §kMinecraft", + "§rl §lMinecraft", + "§rm §mMinecraft", + "§rn §nMinecraft", + "§ro §oMinecraft", + "§rr §rMinecraft" + ] + } + ], + "fixed": [] +} diff --git a/src/main/resources/assets/gregtech/terminal/guide/multiblocks/en_us/electric_blast_furnace.json b/src/main/resources/assets/gregtech/terminal/guide/multiblocks/en_us/electric_blast_furnace.json new file mode 100644 index 00000000000..3a3dff05723 --- /dev/null +++ b/src/main/resources/assets/gregtech/terminal/guide/multiblocks/en_us/electric_blast_furnace.json @@ -0,0 +1,33 @@ +{ + "multiblock": "electric_blast_furnace", + "section": "Multi-Block Machines/Electric", + "title": "Electric Blast Furnace", + "stream": [ + { + "type": "textbox", + "isCenter": false, + "content": [ + "Wrench this, wrench that" + ] + }, + { + "type": "textbox", + "isCenter": true, + "fontSize": 5, + "content": [ + "§nMinecraft Formatting", + "§r§00 §11 §22 §33", + "§44 §55 §66 §77", + "§88 §99 §aa §bb", + "§cc §dd §ee §ff", + "§r§0k §kMinecraft", + "§rl §lMinecraft", + "§rm §mMinecraft", + "§rn §nMinecraft", + "§ro §oMinecraft", + "§rr §rMinecraft" + ] + } + ], + "fixed": [] +} diff --git a/src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_0_guidepage.json b/src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_0_guidepage.json index d1152b62b5c..8fe3a94e403 100644 --- a/src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_0_guidepage.json +++ b/src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_0_guidepage.json @@ -1,5 +1,5 @@ { - "section": "guide_widget_api", + "section": "Guide Widget Api", "title": "Guide Page", "stream": [ { diff --git a/src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_1_widget.json b/src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_1_widget.json index f6e568a0ca5..7d8d23bea8c 100644 --- a/src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_1_widget.json +++ b/src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_1_widget.json @@ -1,5 +1,5 @@ { - "section": "guide_widget_api", + "section": "Guide Widget Api", "title": "Guide Widget", "stream": [ { diff --git a/src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_2_textbox.json b/src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_2_textbox.json index 15cf932947b..f67b885350a 100644 --- a/src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_2_textbox.json +++ b/src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_2_textbox.json @@ -1,5 +1,5 @@ { - "section": "guide_widget_api", + "section": "Guide Widget Api", "title": "1. TextBox Widget", "stream": [ { diff --git a/src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_3_image.json b/src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_3_image.json index a4038795115..93aba81b064 100644 --- a/src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_3_image.json +++ b/src/main/resources/assets/gregtech/terminal/guide/tutorials/en_us/api_3_image.json @@ -1,5 +1,5 @@ { - "section": "guide_widget_api", + "section": "Guide Widget Api", "title": "2. Image Widget", "stream": [ { From c65a89b529a582ce9c4ea334e66ca842facf312b Mon Sep 17 00:00:00 2001 From: Yefancy Date: Wed, 18 Aug 2021 14:23:57 +0800 Subject: [PATCH 58/58] lang file --- src/main/java/gregtech/api/terminal/os/TerminalOSWidget.java | 2 +- src/main/resources/assets/gregtech/lang/en_us.lang | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/gregtech/api/terminal/os/TerminalOSWidget.java b/src/main/java/gregtech/api/terminal/os/TerminalOSWidget.java index 5fb053879fb..445861ca7d2 100644 --- a/src/main/java/gregtech/api/terminal/os/TerminalOSWidget.java +++ b/src/main/java/gregtech/api/terminal/os/TerminalOSWidget.java @@ -230,7 +230,7 @@ public boolean keyTyped(char charTyped, int keyCode) { shutdown(); } else { waitShutdown = true; - TerminalDialogWidget.showConfirmDialog(this, "Notice", "Confirm the shutdown? (Click ESC again to see ok)", result->{ + TerminalDialogWidget.showConfirmDialog(this, "terminal.component.warning", "terminal.os.shutdown_confirm", result->{ if (result) { shutdown(); } else { diff --git a/src/main/resources/assets/gregtech/lang/en_us.lang b/src/main/resources/assets/gregtech/lang/en_us.lang index 4fc5af8e57e..935d378f658 100644 --- a/src/main/resources/assets/gregtech/lang/en_us.lang +++ b/src/main/resources/assets/gregtech/lang/en_us.lang @@ -3639,6 +3639,8 @@ gregtech.terminal.app_name.recipe_chart=Recipe Chart texture.modify_gui_texture.missing=Missing Texture texture.url_texture.fail=Load Failed +terminal.os.shutdown_confirm=Confirm the shutdown? (Press ESC again to see ok) + terminal.menu.close=Close terminal.menu.minimize=Minimize terminal.menu.maximize=Maximize
  • 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/listen_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/listen_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..44e895fb3af2b533c157716a00792b851bf4b550 GIT binary patch literal 935 zcmV;Y16cftP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-wAxT6*R7i=X)=OxeRS*a8-@QqiwlSt5=|ZipL@@Y5aalwV z)L?z!!n(3<+_;e{b>m({lx_;*MiE2>#YiFArQ%AoSg|d*5}_idT3-oCo7{16<}~NF z*LcN&!~MSdo%zqqe;(&_BEpce8#iJm-+#erEDfVPI>h&R+=rXe$asEROJm>S6D(r= zpMW}BMDz%r$F11FY64Y-PCBw3BRGMV@ZqqAx_A{&;XIbx{g>=*l_#(buj3$kTNxU~ z8+c5irI+B5znyeMM%hLe`E3U8;YkgZRjJC$*smnG^=JaS6pEG=8h2tkqo@XZsk=Y1 z21fJ{-o?2_aV(8|hPUt~e$U9S!o4_vYx4g#!f8B?h1SqEe5#ah&B=Jua}aN1FCM_P zO2wVP`)S~Cg8tSRn^4OCE}Rz;B4S@etVG0_Tt7v`Qbg>Hi0Ozpn%`F<;*W^xo}WZx+j zbWbW(W8*l938dg3|!+C(_$JlSZTCzUZZr?4S07i+k1Oc^P41g$E$x?X9%8HI+HmRh=d z@_mLwEN82v-_VZ5V%0`wBFn}*uSAm7(*7EpVn^bOTE!3%gzY19f*PtY-!OPvba zmHc#V(mR`23w86LgYQk{;5%!x+=r2Bcvd<14%p)0TgMa1jGIz;j%E!4uWKT8jwD9k zMP-=F$t_A`TU}1N_{M*{oU}5A`we&9`q&nI_iu(;`Ck{vzX3%>P6a5Q!{7h_002ov JPDHLkV1jV!w;uoi literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/listen_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/listen_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..d57503834e91af197989509a9c514166a8e73e8b GIT binary patch literal 1574 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 LNkvXXu0mjfAaa-X literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/macro_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/macro_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..51b4e5c0f289f87c97e63bd59a760c32a805476b GIT binary patch literal 1489 zcmV;?1upuDP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-yOG!jQR7i=XR!xW;)fPVI)V;T=ZuhI2>h5v%^eq%aByPiO zLTphP)XYyH7@uy8C?YN*F2p}X#6LvH%1uOZr}JcfI&WZ5Q6?Y^d5Z@c&}1Ws8_jh0 zbY;4_t8UdjE>bi0jFULxfr6?!_k7i$l=3>8{^~S2duRb000qnuUxru z>B5Bz>-(|C8xhUU&I)F}*BEn;G3H=V6m@2H0RRv&bsVQHrTkt>`6VKLv9Pd^|7D`t z+1Uq;F{hIxxpO!iT4T)6TAKsFmH`rxkWzY{=aJU>J1OOvg@uLx?u%%0a*|xvePb{f zJQl}sW{gQn4{$F4E&-&JItT*g`~F91n!dEMvSP1GboA&^5k=Aay2KxBP0QU*crOO|CTd7d*O5;McrT0{h921ML?w^B++N_l@A z$2DV2Ua!~3T-QBy?%cU$00062Xf~V5TKjAq$0;*|@B29byrZ>Vmr^=H2&=W0T5G3L zsR+;Ws8Xp&&+|wKVU<$C_x+!Q5bycEPs|J@*0arKQ*DQ?TCLulB*`IT%myL~MEsSR zy);c|A^w$R+5Zvo5db)qrs-8< zOy;^SZP^0=3Mj6y-Wc;JGv9JUEJW-gVhVeA03;&4yuAE&Q4}8l zz!_uALwTM*&&;Q@EPJNaYJE&Z;qHiR*_YT|>U27n9LMPrk=X4zGZ)NU0{~cBT6$4R z`Kb^>xvuLuj`MP>)%vX2Z2q$-iV9q7SEIH-M8a{LZnxXLL~Cnn>t(C=Ms~#j0M=T= z%r_r7a-;zO;5g1lzVBC<`IGti`8NRolv1}@Ysaj$77=+ALrUpMDZgJ^TU!_9S$yvM z{=d^S-QExpv6NC5MNw}w8t$-O+rC#m#``YuotR&eE zi|_kHM4tncondox^Q%gwaS(Rs9}b6gMASlv$C>#mGj~s(Jo&KJ zIzq%-5%CAD^|!9;{+y;MF>}bwxl&5|zJGCZbMq^Jk(4}k?AQZonts@Bw>MnZRbd!j z27m=?Efqz903hL7%`hUWYmv1n5fwzlWpjO~*X!MEj4}0kea!Q`Q>|8Oc?S^y!1VO= zTX7se(d+fDNGUxbgnylE+Dp(FljM1xhG94!1i{&*rKRm_Vn-cqY;3#|MNtC)j>mD_ zHpZmayIFS&GczJm7=|~6VL0FIc3&CQ)9AS~UNPX$46wpObJN-14>#9MdI?q^G{ zl+v|YEeL|(ED=4my1Ke!P`U1KGBY!CEYI`PNs=7e=WudS2ytd{aq-+000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-v)k#D_R7i=X*2{}sMGyw?-#v4aF^ndJak6mfLNGCA?aG}m z2#G7>LW~;`Tq)#%i0%Xt6d$7@APR!UMTnpncjBL5Fma(FAowB~hQ!S1j5AX%x|)0D z>9`5~wQlawE533g6;YoSD>6gV*siRMZ*`mZ_ zCI8h#TIy`L>h8qj_^fScE51?Ex5lIfyUFJQj^d&c{AnD)16WR-HG|m9DCvJcR_m@F zRI+Qa<&td)zLdK=iPJXAi`cCsO%HeE`+Dl_OYF}@got=ABCbco&pEC}#QPDkE9bXI zL_goVV|zsGh=|)F;)#g(JtBThoa>3LQ5e4me;NdN4R7Nrj_3C%GG5Ddf8ZlrNVoP9 za}Va4Jo;=Nx5lQv--?@S<1C&WVfb%@L|RYm-Tn0cw9N$TDH*n)5Et%JV)O}q z#0%Jgw>o<54BSZUoj0p>ZFvS?7>?;#x$!G=ewd#(fd-Q$+lhSj&k$vIO<=-#LXRQ$yTSIj8l#SE0hH zP6=uk)q_gvwu|bvG%{(wug!5}QLXX@o;A1!Oxla8RIoYBjRZceUa?&V?^RF%^ZP|i{O?KTn ls}$6sax+71`Ck{ve*oD`hf+%=Gspk{002ovPDHLkV1kd#l!E{O literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/photo_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/photo_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..d30d6f538084a479b9c33496171e1cc2ff427a45 GIT binary patch literal 1373 zcmV-j1)}000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-x*GWV{R7i=XR!wLdR}h{zyKi^(_oS6A<6{qPOha;Y3Oxje zRM@p0TRFr~=%Il^$R&YXT1r}IX?o}-Q0Nb76G}@Dwrg2-TufYI>|9KaZ6I|hX)Ymw z=+COXtJT|m(?eE{tk{l1zvJ6C^Uci8`(_vsK_}?%@9)lJGJQ%Z8vp`$t^E6E>anA2@&VOf&E#>oh|D}m?x!j19 z^1S0XhwJsal2X={Qa%7Q4HzQooO8>vER05@e{#+*=kxjN9T5!<4x(wApS!O6UaeMZ zNGY8#1Gbw33LS9Hqe2KH5{X>%Jny5$#YMFz(b1zvb=$VT-q_eUS*z8`0HF3F*n<#- z5b0zxIa4l|&#tbnZkJMTy_`%YKMP5Up?}uqh_#-Dfix3l0HA8MS`h$Frc$XA0DSmd zMkh|37_QgrS4*W*l`%%`B)YEiNF-u1#v0+V)@U@C=XqNIfNjaKuCA_>X_}|!=jRu; zi3SD+j94u8Td`O?AfEfFE?}mfOtH9%yFDUQp##r0*b|A5yLP_j4?;kw3J~O zKhDj~6!x~^*G zZCO@K2vHD1WS5qf-c(Axar5TQui6`6VPWB~jg5@~UDvZcJw3-0iNptqM1m0!0sy$K ztCUh%004I6$dPU##7~t`+!(UoJyLb9s5W3;^c<07gbeUQMM^KQ|hU zX(GCBn&yR5r%oj%CnvvaBWmwJ698--I)rJOrya*xotc@r1OPBJH1t3S@nvss@3qH| zA2(iPkBqSjW6Xn{4{-7ml>_x;O*L5#VPELNmUj;bl7U%r#+S*!C51DU7B9V7I&wF}<$Phvd77B$w#>U3B zEvKia{|11wdwCui8R;jY*NDg?B8WsHh=?};_K+Y%WQjz=&~^O|5&auJz@~Z zm6eqpi^`tM$@uvAsPFsd9mhG;;c{|E*Y(S@v$ONN`P+Bh8Xq6m0idIG3jmg8XJ=o2 f-D=1GT_FDhe}%uK=>guX00000NkvXXu0mjf7u;!f literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/radio_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/radio_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..15f71f790d7466f323667a48b5b7b52d8656fba7 GIT binary patch literal 918 zcmV;H18Mw;P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-w5J^NqR7i=X)=P+7MHB|$uRFJU61z2-#EC+{Cy0q+z;(c_ z21H$D1o5$vfS{-gv({AzL{MfUXtFbL6Cn`ILPQX^J}`;Ig^FT=iJABq$LXhwI@hkg z>1kR#(9pN4&i~gr=dV*$8xDtNv<2+Mw)p-P=WuBj=VFHWy?7A!2FYB^tp(ZF_znm$>=N6iH3ol_Xji|s8 z?32alD@sHSvig-xZ@m7cuuIe#8&BA}MbNZo~G7q7$j= z22o3r{{!fhL=Q`OT@I1~uHq+r9^`G@f?KgU)^sDHGA%b?OMDL_s(mvj{sx|q+J0SXQy&NE^+xTcv{j?7&+Us~uYMkwCJg?oP@A7|7I$H}^vd%R@O65_h5neX^ z;;Y(FO7D%5I-izZd{y1|B-t)W9lB+d^GT13e6AHfOMx-=P?_a%a-S60w8u$ZI&c5! sagtjD51H+`^?_?uI5Sah|LXzy59VF|(km8mqyPW_07*qoM6N<$g6MCjB>(^b literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/radio_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/radio_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..c6896aae47468d0326fc1d2befdf312319e46401 GIT binary patch literal 1585 zcmV-12G043P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-yt4TybR7i=XR$XWu*A@QGoqOkR*Rz_{%B6LQV@Pe;xD*T) zs$YylD;uY_B^wqO{L+MilTZkSK9n{OrIgaQJoE=@NJ?qJ*kDOk)rO?RmQAU!pJKZN zyXixINYYr^UG0wM&di;;w-25bD_b@SJuonE@BO}WzH`sHhm0}UjE#+rHAY58c4@6c z0AP%@@87?F_r{GIOPe`QPa>L{n&QToZ!4v~rIgxT6vePH#sL5#N-fJ;7DBuyg!nrV zy*)iWoqu7Xsi~>&D5YMB}axntY55kj;a$NAK8oX?{udaBduFaRfqhK7~_{P>ZGjvqh%T#_WOFE1~5h{*Iw z`rwQ)!8sQ~h|IR_&urWNPzdo~A}aDc|4N#sPsec_rfEvX7z_^&4>^wW{M_8!{2I}r zLx=22rSjLMrKO!pskoGjm&vwm+m3_~9}6Kq5<;}K){au@%UPB^m1Wt8Qi|nyo*83u zBFg(YYcv}7R##V#Ub%85;{Z^tR-cXIcyE?v9mW`Wo~K>cz0Vl?gfaH6@B6Ec<5Y?0 zt7)2!N-1kaQD^{NAwN}N^89}j$@}NiubkFiip4%gXej;5K9QviUJ zQoF7@0pLwOK0e+Ef?&5&Dk<|qTI*h=QhBB*ik})|R-}~ct||anmL)jn_monhl(JE+ zR;AYZ4Xt$sz#$?ir4pso?(y;Q2CvuayV5ib%VHcfS1ILXS++_<8V|0UD4j8Rp7SJ0 z2!Lgbv9;EQF(!(lSOd^n=S5M3VHob>#+a~dD{BQsL~ayCH$2b#l@P-9egA7(>r_g4 z&v6`PjNw_9aUzO{$R;9BDYY!6{LFD2@lZuL0K#>3G(couzkdCLiHV7&ZQHiJ$T|PF z*4izKqH^KFh2Pt@%?}?w{AVfU5P+PBxaWEAM^W@g^O&B-iKtCPDS*mARK?DnJMDe@ z_We*wd1-cb_Fn+dY&K6do6Q$SM@Rp}7;AIR6@Y?>IAd%D0DIJDN&&QatJS(21VNiI zwpDAb%6Rkb+qdu1T6g;-0C4f*#Y@d*^Jlkj-_CB`x^?zpuMZqJ@C`iZHUqak?aLsky=PzHrJim?z08X4Z@yl+v`~6<8 z*S0LHQtEBWZVqG2hHq1!t8^?1f}jxu!MWMl*|le4oyMI`=hZL_8vssryWQnd!Y6?b zngPIqAQ-9DYM0vW_N#-7>+b!+!a`0&XM-R(SFhItA%tH7n6lwM^7Yq+5PrR04}u^# z#~3@iu&}T$e~%qbCMPG4<$3-}9LIY%Ih@?#oWC|RGc&gl-V?{I$;n9$U{m83fVXF6 jX1@5i^|1ZF1LXezz@QZbTW55`00000NkvXXu0mjf?mz-~ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/sound2_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/sound2_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..6ed9dd281f2af29624557ffd9a4716597e304d1d GIT binary patch literal 966 zcmV;%13CPOP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-wKuJVFR7i=X)=h|(RTKyC-}{cE{>({Ny9d6T9lP7 z`n1tSpM`+{~s^dUkmB4QF9Wm3nPoMz^bRVllW&VI&c zIE2}yfI7?UXd9l#jhMsV3Dg*LGLXwKfFJM*KJ3>~7q8(d%;0>j-_os(hp-ZF;Tg;? z=V%4?;UR^VMtLPxr=x#zZ7>~8Wk5}k>+mj~R8iSJqgU}TPFC_O@H>v+JN%KdYj6{` z;98tZ;PJ#bg{OOak7&LJB4Ros{)~vRh&UY);}P* zDI1K4HzMLpMtLs3>D1dB5vx;oYw9(uOeOY3>h?s$WD3tl#KDT1y%8}V5yz`Q8ldA5 zF&7d0D*XeAF_xHnB0^WG_>GuO3I^~&{@;eja6-wzI=wr&b^;G(Qo#F((MimW80lhz zl9F?k@Ru~YHI3R%YG+BW)XsyNP`f z{IGJL3{}z0U{{`v%236By}nE7?2Y|UVjgDUH8GkIPv~XWkdjRwV-p_LD}wVjApHcXSP&lsLy0=+V0SLsPywV*`(}jxyMNtKf1)nNj(N} oxBi}6pX$9QF4<8%{?`NYU!O8PF#cEpIRF3v07*qoM6N<$g3vqG0ssI2 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/sound2_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/sound2_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..a3ffdca622604cdb2618821c729ed229665cff00 GIT binary patch literal 1622 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/touch_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/touch_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..c37f8ea0f2817246be953a2508109eff32c5109d GIT binary patch literal 961 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/viewer_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/viewer_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..f93b7aebf2794ec52e788c005c8aefc4eeea961e GIT binary patch literal 1535 zcmV000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-yc}YY;R7i=XmOX47MHI*1%+B22-rBRbYdZx6P!ZX23Md?l zCUO)kf1b{UB76u$C@8^B;Fwo4*3`4}{q?E^{l>JGP^dO=R06+){HBH;(od3!>Um}DomP)1gkwG&v zGgDH^)1K!Y4uU{QDFdZc3;>-M2&I&9&a>HUmgaJ~JDl?irBdnYzCdGRV^r7mk9^;M z-F4kaO6jE;kOu|8Gyvy3CxplthVfMxhG!QR7Sx`gqeqW2+qOS%G#az6>sA3k?FHBa zNQDrNWm$98YW3}#H*ap0l5O8?S=NUs$f#c z`wkI*4uaq>L~Iy_5!UN<)3U6`0boEWH5NtDvq2DKecx}URRQ1kRW_R)1%L%QJUrYh zrR7)a&*6wY9bN#l^+nmzI|58yg!L%d$kJQu!&0 zqVKO=yY`A{nxnRDf9p6-7h@~~03f9dq?G-`!^6GQah!umlGsYAm@%d~j^kUF^*!addR_dDAq%EEEctIp?BWF2B{?-TkKH zI5ox?Q%c22lGwIwAEbzABchIon8{?!OeS-2Zf@@D+1c6mJa} zgpfZerS}l=UaQs8H#av&8;wS}SS)@rH#c{cG4`>p>qdHrbO5lo?hzpb!Z2)mp7-MT z`1r9P2!@)?rk^B9l`&@9wtWHsKD%}6RssNT5JF&LVxs8#{vqG@t3eQGQp(rH$Hxbg zBr&5X^0%LRMhK}9LP7vAl~PHg(dZ?FJO%*G?(XgyAw)3>Rlm3jZ%655hWrfNs{=6VHl=q z-qtj2DT<=QN~wOO)C6N}5&$qs5)BboP1F2^F?J`8{wc%9fOJ zxAr9f5C8zCV$hKvKt$x6=M2MGZ?#%C08*`6US5s}A?JkOohH*&<(UaDBe`aDA1Q9_9(PJ3Kr7KsiR5}ZE`>uMue$KM2 zk`ST~5$P^f{!aoTQXxd2Wm%_%1TTKIVFU+=s1qxoaeUxBOU@k&Uwyp z93h0bNGUzFva+(nsO)J@ipAn|9LJ|U&l}vQIaz0nU6`MrFFz>WL+w_vSY!aOFS`W* li}UmIk8ZbikN;~R{{|mnHa{W{nR5UD002ovPDHLkV1f;$v$y~N literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/walkman_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/walkman_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..f6fd543ffe7029b8b40cc5758702baa41cdfe057 GIT binary patch literal 883 zcmV-(1C0EMP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-v?MXyIR7i=X)=O)hWe^AO-#N`ija5rpi)f>-ej7FRPggx9cF zre$#%@Rcaa$#J}aC$&=9?GrwTeX_t8VnoRM>gp-H+EXUEZx_q+h1_Zhkl6 zQ58o|f1eP;(WvH=_Q>NKO5g^)EnfnAtyQg@H+u6`qpcbCiViaJ9w{|E6Po-ZQ} zUZ=2j7WV&hv`4Q?M$6mTQrv*|u@w_?elEp+**Ne4uE*o}tL5loVIS+tiQkU1W#lJ( zg5iqf6+B#?|5-9;@o8T=e=DaN>Xh7eZ0VMl&03kkBX$0%h~F;WX?$0*zu;sG^lI5@ zqqwS^3_0lIm>81X(WL7S{94Li;#z#)0^E-;iNRnBqAmw z;^&AsS?9%w*cK5R>)a3#pGU;A5utT~vfvLDzoAK7 zSB{^-@u33#5w}!M&&lGxSweTomK~N0^CMZ;J1gRl^YS4+lg+TJ{vR#usb(|WCl}## z%d5*O$_7k*kI8PDwRC%rl+J?e*oAUvFOIEu1+7IZuAq5&X^rabs*5qwDXas9z2urW zio@94Qdo}>g>kqrvHZn%MCSFh^<8|MWxb!U%EfnH&dVV=BV&3Sd$|bPys^?bR2WMh zDuX;uZkCa)_BiRvJ$ONnlQs?GUV}Zi-jy@BEUjgzO&9fm{11idJ?)UZ$TR=|002ov JPDHLkV1i5eq^SS^ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/walkman_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/walkman_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..a0e6ebea25f47048a9990760a32f7ac88981603e GIT binary patch literal 1537 zcmV+c2LAbpP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-ydr3q=R7i=XmQ9Ep*Ad67UcdgHc|ASal}SVhImEI+J_rkW zF~(wzwG3LXc2)`43bBoSvVHQ$!5AZa5I&d~e;opeL4lBvoU*H#>`GZjTCKnY@4*5` zD9BeMf3Vv5=;@jMc-^mZaQ8A2UbDgv8k$$H{=cqQT}2@g!EV-(BS$7CCnxtSrF;MY z##ncAbMwZ=#>TDP_~Q?O78Vvb5gn6KJ|?9+kmvaxA~FF05HZm-ZA;hn|LMB^Z$$if zad9!bYtX{N!sAlPmqw$}{c#*CDP^pb$^f8rK*ku?b=|Toi#d+-UtQPVUtC=L=dM7F zMuVBA`BoG~&jvw|N-0N01o(XdR0!z0?g$|a+qVCdB*_~WE?iJMf{q?N%6;GeeZSv7 z83aKG0Mt%^9e_*-QTIIWADvF;#Vc2?Y+ofGKkRwlnF4aF(BBmVU^`+J1i>u;I9aRJ zwgBMu($3146DLm0#&P^y5CmJhgb)!y`M`I%Lqvoi2)5!ler|4VZuU0N^z^i$lzKS` zf~0h~LlN%CB_X0_+qS4wDpkjE1R}CAUkZXCA)=S3r>Bi=P^D6NG>W2wQpyn`j^~X4 z0Cin=HBGaMJdmbon(zBrtycSRVq)UAwOZ|Wp696o28f7K%257zqX0#Ylu|QM z6e$1z#+ZqSTAt@aL}Wq;W*EjLrPRc5IJ|E(8l|r5I+kU<)@rr>Qhd;*Mx(KhbABpK z(?R+FL{X$H%bEdz3v6m?YC=kRAWhTQvMjS+uYXai)jlyzQ#Vc1bsXmp=g*&inuwlq z9H)zjhNfvzzu*7Q_+4gM_B9b{$+iCmZxc&PDG@X z%JMw-ec#{DiO44+6A>9AZk{`L?rQ*m`T6RJ~kSS$CD&E)9?3PAq2Rt`&Z8S zpL@ODrsFuk7~5+Y#vi4W?RLBUK?yy6{P+O?Xb*?OpSiAkc4cMdh0-=ZKmR}&hJWkz zdgysxXqx6}hKOB6OaK4|g8>Z&gIDuBfBW*~%i+q(N=QUcbUK|!q?D)j?b|nA;J*yR zP$WsxOOoX3c)nV#)>X#Xw}_}0+FjP^bZ%&x)@6)wB7)&?xS1r$FJ@+DsznXm7e&!# znx=aX9Xj-IDTas-W?7agr6R*Hn$2c&?^r~$d7l5YD1~mf+r5EA1hccV?{>T0CzB)z z0011vFoSF6>KbAAN?YH=Jt6oz4@lp@= zhx`3LYMSQO>-E1cFE78si`rSWZTmM#k^mw?6h%pzriT$x%d#v40FYA3Ua#kJ&VNNj zD$BBA(IFs;q9{p{dpPG$ls2VQUaeLcV{CQ1V8bxHwwA<}v+qTaNA@+=Qvf^)x>E@32rTWot~>R5 zT?ipQVvIe%zP^6jpt9p|(rh;8vMhUPG#VY;<#2M1bN>F)(o*~T^nP&MYBrl30CqKQ n0l>#gOG|e@Zr!;U2Goi00000NkvXXu0mjfoR!lg literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/winamp_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/winamp_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..2beabeeba3788962c184d151a9e8c91fc28e9afd GIT binary patch literal 814 zcmV+}1JV46P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-vs7XXYR7i=X)=O(tSri4}uWn)`61#mX_z!%egG{9dJ`qF_ z)RBtdsIkFG>#&`OG>8*H0!{Z&M+O8R;6xN0iFD)RA2`uyK!T}gQa#xFnwzq!yy-r0 z236~+5$xyDflI#WU<1W7R0&4Wh z=rDf8cFbZrfy#hJZe$n(_#0PnyDm|It2m1pOjW<{__i86f+ogr9&`PO2Jt7330da4 zfcF~h+~jK9!f6#Li;jVqngnn+{A|rtV2=;FBK9`V_E*c5+^XO zvWq4z2q)DcY3FPv;4?fBrYP52!c5I7(O%)MshT7OR^g*K_&eC0*_4t`CFb5L(E%MU z=|KQL2uuHgQGCWFA>ZeYjm{;uLR9=_eCm-+DbrFR(-R!T&za4bIGawAMq+Np+Cgj* zmYnTD(h%L?l_D)9zqa1N7L(j|T_ zu~&Yt*GcdlqTfy7NCFJtmz*QQWj&2lh`MR{ws@I0z>55C4;~8>JiujfcC9}6Eqo}1 z_7mo7pmPk1!#*g^<2TW%NAb?Q3A$x7kl3#VMay`JouY}B0d1l0G>&G_Qz7GIC5v8i zl}>$$x20TnEtIaT`j5CMiteGf_$Gv#dSy`^MPh&Lbxq-{jpD$I%;dhX|7d1Wx6!tR zL0)4QX38vPM2!qpfM!HhZ^ipXl9aV~C247UktDZpN}r4G3r^xXmJ6NRmDvrvoFf@?JuwzMRO&oVwu#L8Jx&VzW08-O s>R5vP>OHsaiQ?@#zDHCY|LXzyFGH%;v?ilCumAu607*qoM6N<$f`^21Gynhq literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/winamp_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/winamp_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..6e3e6cf373cc00849794ce8c73a569c53e05a523 GIT binary patch literal 1324 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/zune2_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/zune2_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..d8e8883877619e7e1d0792fa883fe99200b5083e GIT binary patch literal 824 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/zune3_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/zune3_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..f36a6eb826b5be922729ab4e9322848a37e175a6 GIT binary patch literal 814 zcmV+}1JV46P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-vs7XXYR7i=v*4vAXQ5XjB-`@6~jd7ZolpM;T7&0Lx7vw?? zHdfxY4?+(`1do&p5g|sVQ@5{(ikV& ziDT%-FZ>9g+@KU2nTQE^j2>KWmZ*#qID$I97uOG4TQqJ*8&2aW8eoixgcs$z&;-a-&vTDX_W&`;U*dOCel~xtq8b-?dT5nwe_^ zwz8D*%Q1jAL2wy;xQ`D~o@7!~R%0x_YXO+&R8CMse_(f3&?SZBFFeOLDKJ*xJb!(GOv| zl!N`T=?8Jj8aj%1T?Mx=CnRm)9X8=D&R~B?+=q|S%~1{eJkq9Oew@5N2QN!`Qx6GV zg)CbzJNoUAvkNb!R9JwkSc~;xI}iIX1D_4u6hHB`lx0~bE`?9}@GN}w2nVn@Bx?&v z2IBPP7-s=imBPAOn42Kw(ymJQ;TcwiL)V1^H-`lEFsc`19$pSgg}H%(lv4t`H_xMM z!9Ex=ERuYcJ9fM`MLDql{}oi1idHR1#&hiyNlJm$6WD*1i7PmTSp|dfkO+)Zfr*g| z-#Mx9eKx+rH%lsf2aQqq2BnZbDP?+l0OWln@VvK&&B?&{D>9pToUD{iHrC^$j3-)r soD^FX+cfvwx^5_kS|%#Ce|kXv1~C@nc#FY+y8r+H07*qoM6N<$f?J1VH2?qr literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/zune3_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Media/zune3_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..4ca073c8fd28f777c44b9a10fb09ba03825f82eb GIT binary patch literal 1385 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/COMPAS2_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/COMPAS2_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..9e064785b510eed388234bcd37475666142b6891 GIT binary patch literal 1674 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 V8SWV8f>r(ry3% literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/EAAA_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/EAAA_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..1a46e448a8272f4022e0a45c413e7b6374c58365 GIT binary patch literal 1031 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/EU_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/EU_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..ba8ed727ef69999b2fb5fc8bd0440f616f8a9475 GIT binary patch literal 1770 zcmV000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-zWJyFpR7i=XmR)FFSry0E-uvu(&fe$ae&i<6i7ka2*t zXvkG~NqX|6V<4dQlP{BYGTNC;*PDwx}bVfxD zhK?_lNUbC{H|N}Q&)MhfbN2S3Nx4%pLyG^m4Qs96-fY%df26gB?P&l0{nhU7?g6D# z82|ud++0~%xqt88z18jHqfZ0X>vcnG{eqP8D^kiYo%5SRGYJxGAjYh){g5YJ#vL*%x2aQhz6^q3;ecyl4_x)7>AdchYl+tsY^WWOG z?EnB^j1|VX%sD@8nx>qYnfX5F{G{u;{{;Zk_x*f_JdZd^?FZF&-a#=mKG2~|3L^DT5B_o<3C9$?`K)| z*M0l;*-4VT0szkyi^YjzvG|VTIIi#eLMe5AXlSVL1mrl*kvNX`q-h!jT@iP0o3Nb6zz~vw|@$@7}$8T5EkI&+{lrlF8ZG**9$4UIYM$ zqG*rfI7gmia3rh_xAR-Ip-Iol;544 zoV>KQwl*n*_@NMDC`ppq%*@OKtuYQo{fM=)i#kRnPN&-E1}owAK;; zG$F(=45RG2?q4|PbBr+~%d(sha_8#RtM6~sC!HD`94uLub$fk%{j;S~X)y?bZ{SL$ zGLYwad7~Kt08o}?xs-B!qak^cBr9PUUfB)=0APN8ejOq75kiP$SynEW%L9hiy1X$~ zHak}X08&b+BuPHAzP|piTeogaYzNROgwP{|5CQ-b0Lpl)AjTNsoI7cn_8Erp?ZLr8 z>sdih%RmS<5kd(7*jj5%DP^{8zt1_Jl~O*BF@7{ZKQErTEesD2e=bc^b@%Swhffzh zdGe&Kwf?+PD%+^tG}hME?t7ls#2EJ|rBX_%MJfGgYHI2V09@Hj9vK;VzECKfC4`{U zr%(TJb#?V0eSLjD+p%NE=<@P%b2Dyqbd(Z8CgM2Wr?pNAAPt$ZPj$^@+SS!nvMlS|_3PJX06M1kjT<*+7-JVb z&#Q!CD8n%P&aPd%F4ybzFLi%Q+dOw;7HZRjiBjsVD2l!r1VJjLj47pzQfd-HGOcwA07`4E zk|fFVJO=;(N-1|;x4=2SL=pprnVz10cDwbo{$B(6KWWxtIuSJf6951J M07*qoM6N<$f+AQyE&u=k literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/NSA_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/NSA_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..2b3978e4ed51b8a86cad81c593ce47193662b845 GIT binary patch literal 975 zcmV;=12FuFP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-wNl8ROR7i=X)=g+#RS*a8-%FlJLs1M()P+J9g0>YDUAS-| zC|E6`1QlI~RFP0zT2Mhjx>QgRN)ZL^#)XQQjkOC!T!>w0MX*s`;cW4}0?e@AwAiccR?h!TurKj%(6Lf9@@&v9EC& zr?9dWP-`2HM(`xA#VY2G$Qs!#BfBkBjQ*@%%sk8Vy$D>$#6H0*qlX?9`xf&h5x_|-t3_K*Q8Hk9Kk0T zQ*HF&sdT-esG;(2oW&QI!d*#Eljewg zGGrDn;1B$$WYj7?#RGUuN#CWs$Sq2S4Ww>OdrP7H0EXMxpC0t#b-bnof3mvSUM0Av z)5Ej4Hw{Hn+fY`^YGUv2!C(T<;Z}U6w3U%c;RoD^SMV)9O8PFsau)+Nb^REu(|ZNi z<>mk$wYi-%#d$&r@TwA%t&D7v9;GH0m3mpq8_p_0ej?9Zi92x|k0>1Z=s;4fmP zjd7*jTw+lyWvB!IqDn6&sRd?o9C2sfOq1+$G(|9}2 z4klQ)5fG_!4(FRXI%T7#8fgmmFQp7_N~M!Z{O-ZKN`3X}EIqcj!jL zf)clPs`n?9E-}~P&2D7^-;AZkizQ`f^;e#B$_g&U;p*K{r3~ts)f8=iVlFkVH8Q5u z$xx+GOB1&Vr3jDXSYoVo=nN&+*t&9;!FN&_eA6}$K1y&uRL1tR9cP-UJEXLw!>Ym8 zZIt&a{cfvKzN#d^kP_PlV7HA?epF}bcTCuNjYPzmh**e-xty?*xuzpxDxY(C=1l5z x#oO*H2rj@KcJ{gTfznmF%6}QE<$rxZ{tI^?o$9)p=8FIT002ovPDHLkV1n$T%)bBt literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/NSA_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/NSA_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..cc66f9d3e73ea8ab0eda7a8bba349220fd822868 GIT binary patch literal 1630 zcmV-k2BG000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-y*hxe|R7i=XmQ9RXR~5(4{d!-v-}9Rfia=rkL=ja=gOCzd zM3W&UGp(I*qimp5B^3zqp|*=Ipy~puiUktw3KmF^szM3`#WQ1~L~T@$0unHrw(3YF z>H>sDRWg&Y{jTlzb?>`}MeN|XNtBASe0t~n?*E*7&p8AU;ePDUp+j@?^Yi+5q8jS`=#A8aSuPLRzP!z>1BH91|gpiCewkL#mUkGuT5b|cT z+0-8!)MzvwQ%XG>$MHjHni{24YK+kUFm@o6QqDPdT-T+Z=e;L{c(vJV{`tN@$B!SU zwr#(hB+0j>l(|wW9w{K>fAFRgA%qCV7)3-v2%$j`2-kIgmu1-tmo8m0cLg0ea)gIr z_^T+29+y&f0Kkj^>c ztJUfr0Q~qPpnARjXqu*{rIdS9SzMvIPZjE_>OJcyOh#prPR#g z;^NFCD9f@>E2Rvj6afIGlo=vEx3I8a-BMI8mygDAd?3&B9wCGvA~MFTa=E*BG-eP16UJQePKB5CHf!0Knqn;yyyiqSm??-y5Y=oFvJCa=CmI04`Ag0AtJ} zNs<(dF>c#-;JR*DtyZ16xw*d};@d)qYg+3aW6ZTEik=~ad?1AQJOIGSlP3>)p7*mX z%RYsO`J~DuNsKY(5dZ*k`0(L5-}hhd^?DDMN~MnDIA<7RT>#hyfZf4hP*6%U*L6=; ztJO#2I6jl-`45Vs_(xF`e-J{PiK58KvaCOqb|8d^FbuCsDZj;MW@h$hSr!sPEK2F? zmSw$WjImp-*7dQ&($dmrN~O~2;c$3a2=R8F=kIE*Pbj6nDy1}9YdLxbWKxkaMi)g9 zhGDp$B4UV$jxlDawLX%j>19OxTcgpajU6sty!fA;ot>kI_}i_mtq%ZTBhT}H4+evZ z)>=QW8;vnKj^i&5heIQTaA#*{p9Fx`*kfa3<3mEojaset%fVo9G)aw6wIZTCH9OfG;IU@<5*F*DT8_ zE2R=dEbg8)07@xmjCH%+?p3zEy&a!Dd-ltDo*&d&XA?y=S(d4yC>~DJbYC3D1IKax zRjE{7a~x-A+xF)WF(`^ckCfd;L`1YKt5hnLHrnlWla9!5xUNg@ARE&(?Mo@S*7_@q zv45_wumAqSg$qA)UH6IE+1d4KwYtL?V|N-iuIo}t=^Fr}7Bm$+Qm!Qic1pmw{R6GC3`ecy(O zjy*wxqA0YK@&RMaH^<-W_4<$EIDRb8^LVlm0|4=T-=>tl(r&kNfT?+O;>3xcODVrI zH73TV1kQQc_x(R{&VMR|_(>ec--x0pMnpY6AR>bA`*XhU|7LA%?bevMtuDP@@5LYp zn!fMPBO;wlBOwG3QERQMgpjBE{r*$kZg((-;7y~x@6QK8(CqbkFW#1w=^{274Q7ma zIgaC}`u+Y#M!9X<1*LQ+Ns?JawBUb((W_J{mgjkA7-KJ-KYzZsCunRdD=Rgv^|Nst zADCKB0B(+#f>O$a5RT(G)bqS8&iSjWtE;U$#k=RawX(9p0pPyYEdY3Pb#?XQuUpgh c|1OaK1%7x*(%IRS#{d8T07*qoM6N<$f*dUd#{d8T literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/Navteq1_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/Navteq1_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..cce839ada3af1869edc8b592cd43ea18e71c993f GIT binary patch literal 860 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 JPDHLkV1jpKp*8>j literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/POI2_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/POI2_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..b35d07baf130c0c31d652be10bc8b2cb766ac2a3 GIT binary patch literal 1422 zcmV;91#$X`P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-y2uVaiR7i=XR!?XgRT%%iH*a=!Ch=`{H?^0ZM5xhfi`5u} zQn#2;*re$xo6Lw{aWih003jG{rK_Y2kYzW z8@qXr&myW;tDJ~trIhbVDW{SoDH4$d0Dy?GVHi!*H1C_Hc?%J5)@n8NpNXo~>b#Wl zOb`UGMp2}tl#$k2QThN8kuk`y-UDGr#*J`zuT@f8Weww=Wdi~*uTneSsPt9iYl{k)r z)Icm2ixZY*eX_i~Tn7MP005;@DWkPM>v>)b00aOC0O&YQmUDh_kOUFgzJ2?w{&%fb z^N8px$8nMr4*`HY&x?uZY^hYrY!Qu*j~@%e@PL#uKtxOdIp_S3M~@!e=z}gSEW9v3 zKfiS7(4kx9a`~;kd}U>2-7t*1hGFzeAElH*7={PN$H$Lt5oxXG!Z6%cC5$l>5&vp5 z8t#DX!)~{G%yr$@IOm@YMe(6w80KJcg<+_*)^h*=d}d~5QV206rHuOC000n?27qk8 zC;$MIQoq=?{WlTWN~xa*SrE~t0hZLONJ=?1Gcz;E3WdV{BuVmG>up`FweD%HUn-Z& zulHs3di^$IY>sn2SFhK9?8|3oXZI4(v{EV@uobk{DoK)jKA+#uh$x?qmEjSggCH;& zV;AP<=eOFRUa$YYva)h_P|KDWJl}hD(-}leCuIs_SZSj=70MKTw zR_lRb7;VNF9|lSlsnhASgCO{PVPRpme^D-%r{XyN&UM{@h?1QQWsGsdFxu^Q`vGe- z8XM`T&(hAL9EnJGIvtrL$=T`YX#)VjFpSgPZudE*R1bHE84;0bnpx8{?>8Ea4VE(B zux8nUMqpLpZgwta7NbMy8V(dz1I4-qd3AuLE|)lQB{DI)+l z%sDUhdObPHAOJuigvA)Uw7R<5+adx0SYBSP+qQjG2vJO(+D3+mptbIWVfdo&`-hcM z(GIyGA_5^q(YEcYOG``j{>8RRb6xjBKA)cifRmo*H32{mf$1O!##67iRazQyCWI*F za=B~mcKgC0_O=38TU%3zcuELyrBEn{e$IySMv(q_`vm=*6bc0)gt)>OJGHj9wrxs` zTuv&L%7RkrOb`SI2A7k8kPa^=_c-U57Z(?ocfxz-x>c!EH~{Qw-2#A{i;Ii@ecc*9 c|964>2M;&T4asJ-a{vGU07*qoM6N<$f-QcN3jhEB literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/Sattelite_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/Sattelite_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..6b6296f5c2951ccdd9d6f997bf44f59298ae4894 GIT binary patch literal 910 zcmV;919AL`P)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-w2uVaiR7i=X*2{|>RS*X7U-$H6OvW*ZNqmF25)+MofS_cj z5m8qYK~Oh>h=?w95pXGppc`i+i0(8Xs3_wLUm&80Lc}DBe}Tj>gka|3eYmJ<@5xQy z>lF_)xBH$`Uwu`l>N}?z4u@tO`*0KXB#nTu}bJXB< zEQ_=ZI>0B5VUpZ~V|YZ7%6e?^i#Q@SxO6fsfOh0l7yrw(gS0)8Se+5wi?^`W!M4IK zoWoDa^p<3QHowOs-;D?GZs}+nz7pko9+xK5fvB=Iyn;{gLjoPZAv}reL=_V0KPQUh z7uTXD3+4(iDb6i5h=Wp1g;X*_bZ+keYcc$@3(t&*l17s_zYj;M|_YB z7dxC(_)GNAclbWvH^d$e5?hm=4`4mhHJ1@yCiZ1-zV|yE4Kqc{iBsbmY)>caiM_AE z{!CFn7xpuadvQI!!0ozKq)xEca8T^^w|FWE_Y!-5BdTMeNL`HwGrv1=L;iNj%OKf5 zmVgy*6y@JHDyH4zEZe-kml0iy&vDz7h&J%1sMvXYgC{bgf70EE(%lp#JxJq28PVlp z4|bTmM+-u9uT1czv}v(6vDV3}PO3&x~mdR4o6UW6y5u}a5haIzMX zaYE#}9sT0z74KaUwey2~%5~cl`*fT4RXmi77KCh63DkD_F8n^`XkHv6pJvph?rn+Q zTV*7wAB*#(ZOSIYp3Cp6@mxnl&xrPDTVpP5tHe5<*cXWEeWH5Sl3A(Tl_-`k@piJk zTQv5%i5h}4F8dsO2Mu_Ax{&4ZZ*A;0wSBw5T zhKEf#_000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-yrAb6VR7i=XmO*G7*%5~Sdi~yX&vd6pGa4s?TmmLi9K7Iw zv2{soFPn`w8`~O5VAxv>0h3Gi5CS2X974z~>?wyBHitlP5;PjitF_QBHnItk9Y_K( z*jmUTMC>7&(Tuu#db<1ddoKsIl#y0mwB$jby1Krq>Uw__8DnsqbMD-^#)%UrrnJ^I z0AP&uwzjr5o<4orInMX=X`p7a$&E4Jlv2JXr97pS8aKw+06;{kWm#Pz#B(9UheY(j z;^JcdnL*8F^E*({>) zMbQJ!`4_a-mQv~?%d&pj@An&V9G~_)?^OUR3;?v&uO~^OiHL*{YIAdQ4ZxoP{C#U2^r9{M%B+**y*8zY}Pfs^|-#;a# zOaK@nvL+`d-zb$z9ubYr&d!bl_}pMHP=`Ts&9$yv^MgLBTB&E`ZHh7J*FDPp`p4`lB&s2*A=>=SrzstyY`j#+X_mD+YiTLRiga^E&6;BO-rpZthEte& z9VIWCG3GRz%^RHay61UpZf@?&L{tW#cAL=H0BY=T*^M#k$&)AV_jC!!t^r2yQb=4^U;`s+dn4?t~x ze%>ac%5XS5>K}nIR=Rlc;%kht&ugvO{QSJv@Aqv0y6Be_K#y&2Z*N$Z)nklt>|Qz( zhT%V@l>f@}{Nur3@B%<4gm{_OsVIsz@;v`{mSvl99B%-~QHZW(S-oDbx53ue*E@yO zJH{Ajt&wG!%JW=FDV3B`8DmtZ)A>Y3X7}WIo~z=~X`1F*>ph`$gb>fy*Vj9|NPpFF zoVU_6RdF2Kwr&3|2m&g6@h}X-si~`B5r7|#g3g~m|AU>Kov9!QVj|jW zEW&R0mMfLYvnYxl03)J$<;s;e(=>gz+wJy=$Y4ad0g&(eZn<23%otk&kQrmXH5?A# z2!dc}jL|r#^fW#`KIS;ijisff5W+2$N&*1#JXcwkMSFpa z+WEfU@O}UG-Me@9$HalV(eL+f)oQf{fY~4jy7=GVBO-#7av-JLce?j(pRhal#;et8 ztJmw@8ufkP!mh2Yj2< z)($AiOP7RES_jXuSXc002ovPDHLkV1h4c5*Gjf literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/compas1_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/compas1_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..4ba5243306e499624d35753a98c3c2289aeeb072 GIT binary patch literal 1020 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 P00000NkvXXu0mjfRvCHZ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/gmaps_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/gmaps_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..f25c882e25c1715a1453a9bf53251fb29be005d1 GIT binary patch literal 885 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/navigation_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/navigation_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..099991664a9adf8573331dfa178462c922f88a7f GIT binary patch literal 1283 zcmV+e1^oJnP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-xeMv+?R7i=XR!wXhMHGH-c4ueT>x{ilf;hmHQmI_4+^SSi zRZ1KsMM$VOda5|J91sZggpd#i+7p+G!jV($<_GcvwGydPso;R9fR-adMM~|p*UpZ2 zXLp7J>&SMqRw~|Uv~S+`&3p6a+lN|fIF6k@eR^hgcJ_o)$^!r(g!udW`;Q(xc<}T% z@i>WSWo5=r! zW*Oj706GJplomMWmg6{IMN#z8=H{l#B|3BFjOlsa7oAS$LJ$Nk08n`ZIfR6BUMZDI zw_B~&yL)?khov-!Hlr^Ej2Kq?4=rvPxFTrM{O;KPBR3>HgE zOAGye|56YH%^VT{0OGptf$O?GL?lP}5fLE>f@Z(pzf`SO7e}C zq-lEFw(TS*Yd}PlQiei^Q^jKO>>-g->YNZl9Thal#xM+vG4{CI?f%^9bbhfc>krd3 zSx!~}03d`=N~v=I0Ay}%ZbnLZQcBsM)M1RVf?*h2_wL=3_wV0VhGBfm7<2OWXIb^7 zlqcur=4MExQaO>Psh2&*JR`Pk_tG?79ejx6c%3oU$!Q7z08mOLX_|VT=ba#0YcG?P zBTJyQ)|66*Qu@>8=H_pM@7vqke^N?+q?Ec7%BM4IFZVRVX4^JJ#MN;;!!YW$Z5ugZ zBSsL>N5lwnI*1TrGRB^SVYof+>-Bm+Fvk8OgwPy(%&>j4)oMNBocn~37qr%Lcvtpz zT+6cVY;A4rFD@>=Xqx6{h-f59@_wVy_`6!I?l8tK2_f3!%|r+>4a4w#-+zQ!YgkxV z_}usXx1%TuhBs@ip za?kU=+1S{4k7Uf-j^jLYUx;XGtsfT(g}1uh?$^y`b2bdab{K}8X0urig5XQW*hMMj zV?=zWe2(J~LdZ5iCaS$&@2=~*4-XCwUKvw|LxFlLI|O?9{FVq)H;r1p_DR) zV*mg-=Zp|?z0qjIheQAXYiny8j^o_ooKI(MtOs}#)O>_HO9nXS(~jfZT3ub;7&u4n zrQL2{E0sz$&iSm?noQEMant`9;hfKwN~K!6-M%*LA0gV^-AxejGUxnerBdOP(n1E1 zOE~aTN(+@rg>%kt5<)KT?(U9ATJCVNyu4gZlH^JlhNq4>oIEs5^G3a1UpoqK;<&ZE tyleu%vBoU`*s0g+&p&RB+y5OP{{_MYh)j=Kl#2iW002ovPDHLkV1n{LRgwSz literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/navteq_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/navteq_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..2bd2616ece7ccc644fc97c95cba65cd9445caf09 GIT binary patch literal 789 zcmV+w1M2*VP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-vk4Z#9R7i=v*1Ky|Q4j|3->#e8==vZeu@LNRd=M)iSf~gR zwGpvUE42}85&RoOunUNdDOD83A}ZL3ofe|_CS(fQg`mqtc@&6m%;!7vSl@9g~;Q+P-NiFu8LG}s{FoM=xK&5$3bOaZ$ z6~8bZK)FFF9O=d~yud}=>6EC9%Q%AxG>ZB&bc@DyRB;vO(4LQ|f@?S?g{3_U_*{~O zlfAfs(+Z(1&rrUE<5GebLLzkAVS7BVrZx*FI*jZ19^Ng4q$s&<4^H52k*JEtQu#KP zKvE>DOXa@@6M5(crRw?@Bm$!mn1f8^=#c4E(s38hVUz!E2eyjT@tZLg#8s(hs+bI& zU$IW2D?n;tQw_i-mdD;i=#B+;e+8SQl5EFuUtlMmVFNy44c=oQ_8WMEz4#EMyKoCX zu^(&0!Cq`COVyE&l?=nU7r^6E13n86ZwBxdjA9+0Vg(*bQ(~7i9m?T+4LvjaXdJsk z;jPrPtML)*@f_PDM5|)01W`9W;}KTQz*Uj@rWuCy@OB_V+Q8We2b`C3+QN?TdRt)Z z!xOxVQ{|JQiSMN>%ldI!>YHHoFs=k9X21A`rHk*Y#a(=T(#3bmJQrUJCov?AoxF7O zZ#MA!tB1`{U`%_cbn-YEkWMz=bqIxZ$w2|(gX509VOr* T000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-xj7da6R7i=XmQ83}RTRh1xgRs{%}nofrU{6+aucd?Rc(S$ zYl4T=CiU{n-jvqfhGCDds#>_1M0HsuSWo6~*!-o%7_p=}O z0?p0M84>xIh(02sqalPNB2onaK*U08y=JX_Vy*od5$|<69e-fZ+}zwJM06od(|7Vb zXClg(*#p2}11hDAwKj^PNY!e!N7mXaolfW0zCfo>pH|gs^}8&~K1-6MB%-u`0(?;b z=?AdZ)|_*dIF7FuMe)s@J9l_j(8-f0O{>-VzSrxWOOj+A0C+dREI4t;c>D$Pfkqk|aqXA{VEorYb{FqtTeo zvTU4)(*3^4o+LyhqBP60@kXODJp?iHsVvJF0AP?D+ml2@cFgbc$+mR@0FY%FGxI3` z05dr`IpUl4Uay}3fJ0jAPEiy!X8xdBt^O_|uT?6Q8})j9nuva3=16P(cABQQ z@;pCJM4>NPtzmli?>~>C=zSt$BKoUVt99czKBScTPbu|Anx=oGX?m>J>qXxCMo|=z zh-hZ6BVtu+y`q#_M8q0Am$?QJyNFmIVk3l5>-BnXdGE)KF=NJIxPgvqij1-GmKfG$o&v|yWMt!H`@z1@LOwZ?RMKa=dLQHzF1mX+R>=&+MLYJ&dzx6FQjQYzR%|5 zu`%Y#{QUgFi{kCsZq3fl8UWZ=y9EIE=I7@R-flf_ui8NV4|AmO3%QWrLI3~&07*qo IM6N<$f{3zbEdT%j literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/path_hover.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/path_hover.png new file mode 100644 index 0000000000000000000000000000000000000000..2a6491355e3eab6b04fab63f0b97e424c4c8ff09 GIT binary patch literal 870 zcmV-s1DX7ZP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-v;7LS5R7i=X*2|CNQxpgAPd&POXwp+@BN541S(x!i*ojB% z7({Fgt6^hfgN?1QAw4lG7B*}Iu`tQRU?cGlNJbbo;;|yFb%Y+>HPuxX=iIK_zp1LJ z;Utw`{eJhH?>YB-9{09Jqmen~5N^S0zHi_=tj}ZIon!qN9>lHbWGUBn(%Coo3}-Qz z2Gp9dqsQ?Q?!Yd#6Q~%pGLQr4;2d7Z$MZUB;|)BEKDKK8hHh=Vj77YS7crdWsEc=S zT+lL{06tAd8RRNH#4{=?+YRM4JSh^~bTSeY^>B5**HO08W<4?1rtRo4e1Od=y4q0( zf8agbg?k0HMRprbdw2?`Ye$RtQk3sj72SmdXyG8KzJc>yF*3fzouboA z9xmpu$YS+A%3T*nMVce)s>EI|v+k@*=iVe4HJ+D~c4F^=e=g3G<;#GSwZ5Qbnr^As zbBVoIL49#(y>Bwt@V7W=f5hEsyFEd#*e)ezpG(i9Q+Uq!9?;}`LG)EW9Z%9Brp=pp zp)5=~_}&$R@OS_1;JZ!?=%>v%_y#zU(X1Hfta-@Q;Pn()N!t?|7nOM~C%228&AObl w@wF?woYb;_hs<}~`qciuyCO%m{I3h-zpbtN`sC#jVE_OC07*qoM6N<$f+Q88sQ>@~ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/path_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/path_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..065107a11a0b8383923fda0e04fc3f10c846e105 GIT binary patch literal 1404 zcmV-?1%vvDP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-x_DMuRR7i=XR?UkPM-+drx~scuy0?0I92ax&6o^O+xykB9 zlxUXStnTh#kO)FPF6NjIPhupOCaLfA-J6+-t}A&^P*7FBU%l^#LnUcnv~KKLVPzE3_e?3UDeMeI(F=s83e&MTU%R;Q51y$pvMWS`{TSNA(K)z zeBZwjhT(_z?%mrqr8#`r_x+0{NxK9ZMx)YH6Gc%B@;r~L&kkviI_oIZVeHcivBQ50<=A`lT9UWjN(DYt?k_^Mv7|6*B|&{`YiIaVe_M2MnjGfmU8 zb8~aEBc?lk{J7=1?vL$u`!%IhY#0U#A+%|lF%fAZLe9AqLVUZjvhwB8qeu7qzJD`K z(*h9-0C2J_t0zekm!AaAd9B%O{@L&MXIiaRW&!|so_8XS<3mcRE&w3s+!aE6Z&}uF zd7i&QL>d5$!C(;1%*@Pso+pUty5l&=7()QqsMTsmEX!Jqq9{T{t(1zBBst`H-U$F$ zH30y$)~Avr8IBSpqHdODi*XzuA)*014Qmq-IRI!P$}01_t{WSM@wMx^j}624XlrXL zEs7#fl0-X>a|!@f&8exWrj+uaQYuBnDhde^jV#M_9LG5kRnb!bzyL;t(loVw-~Zfo z-Rq9yd_hF#y4|j)luDIS2dAc{nyk@i94Lw+D3ftpqtda2i14CS6h)q8naLPCQWV7> zjIja zdi%82N$CO`0D_S`8WKiC+BD6dgb;rdkpci9B94d#5dk8mhzN`^)3)u$L=*zR#V`zO zN~vVX4Nn0Pv4e;M7)s7O&ts+3v{LF#!!T^aFg)9~_j#W8>)pF|KiJsVxFm#-j4_Fb zc9vzYCrR>Y7=~6wQfXgecg!#hA4w@YjIl`~QkBi0JbAJo5nqL}x>%M~_kI5_0D#HK z$skFRxBLA*BBBNWDosVhC5tg;8ivv7bUKgN`ucjiEcFikt1A+b(pvYm)^WM|T5AOW zP!t7>oh8FTRGOJM=MLxm;rjY|o0ZJBgb>^1Xa}JRWEXcq2*DU*w*bmo*X#A}2q7MD z&TB6Ksp{DP5e*oNzAwUhmE}QLEL;5b=tX(uQY*Z|S#wp64fLXJ_AaUH9Xn zC=3A5|6zIh7NwLnW9&++)ye?I`q7y)XD&xkbZ&<>!8zxi);d#4^{ao3DFafrrlD@@rGD6zCFJ0-{^EY7lzMA0$^=z zEl0%nrIgnijfSjzHte^m>Qc8J^G4}r2+S000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-vWJyFpR7i=X*3EBCK^O+`-#x8XQ$f*Kuoor#7fMBZEPTWQ z3-)aI7o>@uL~PgyUFoV=5wWwXP>ICKvZV=%(%Wk>?`=<^Ou=vxf3w|I&vEL8zDY80KsbsR(!zXGT| zp%Dw&h#pMiCLVW7l;IYx;5QcX;|pW+lLyg+|5#|FZucW=&7BD;`=Av};WZgUPiPqq-4 zqj{n+g)FHc8;IXWT*fiH#Mby;RJR=1GU>$c!_Nveb@2*EB}=Czo7xzSz}$!73?ouX zHrGj#j}MqDS!gq`M|!1A?bq45vKYZtoRX~l9^c!9%Yi-Asn(UnB6bJCc_|sbN+qh& z`d;bWEMk++s(whGzrd~_n2)|Pk}R<2Gt5Zkrl$)vOV}y-{w3Ot8YMk}J(Ef2=aF@D%24OtbxFuZJ(nl|JJ=?EJ-%3Cuy?4UIBk5or6K;s+!n_J-W-#R$xsB_L`!4 z0uNOeRgz_GqAJ^Ji>ml=2RjPj?Py4z*QsgG*%4TiE0aquzWdU}H`ih1Wh7aUOyHuL zi*E@Ra2s2!?pf7km+u>lIky92%|oS|$H@UnS>59#!yD^-oaAEzj_B^W^~CC}yKbU< c{MQ5WFI;%VV%9v~(EtDd07*qoM6N<$g0*m0Bme*a literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/poi_normal.png b/src/main/resources/assets/gregtech/textures/gui/terminal/icon/Navigate/poi_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..28c2f358aa4f5dcc9eb2b49592c86aaea4362041 GIT binary patch literal 1203 zcmV;k1WfyhP)000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-xElET{R7i=XmQ83IR}jZ%-tNFm9D@nV0Tc$@{= z*w`?M=mVwH`%0RzZnN3koC|d6(j{hD);Chh&%-c0QcA^z0-Th9 ziUgcPEa0DuwOak%vaEU#1V02pU|W_|B_gD;Vk06drD7@Nxk{ySVFc1zUzAenlYkRu znx^Rxk+ZqE`PYL7559C=_mhQ%gu4d7k^e?=P7|JI6o_~0F*aLv908CWE7&8sS==FNNJ+`y6vtNvQ zn@;&TF~*RH^3wnSuZzPuw>jr8cXoF6S&`t0<2YF-T?snG+3d=bsT3milS#D(AL)05hC6ZLRe7Ds$mc! zLZ0V`Qp#1O)b~000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-w5J^NqR7i=X*3WBPRTKyC&wG;vF zoG~{;GEVitW!}7Z?)Q7{_ndp~t-9T=A#DQJV_W{8!x@|#X7b1o-=}aFZcLKV{I-;2 zpW_|8h2`~tssSsy4@Yq`E@Cl(dK0P)WFs2*6wl)IVTo!yk4MqQLh0Y8pmXey)oE~9ARlO&$RR=k%aRZ4t0 z&Wf`B7+2*O$8J29zEeG-3EYs8eTi4aCj1ExWz@IgiInby*ehrIa`Qu~F`X-G;*Z3h zsIg0w|J#(byOs{fnP)d_u>jX zojNb%YG?5y{=}WQIx!x`;~C&$l6Mk&yua6VQl3pXF7mW9-&ME<+wmsu$1!}9@-{`0 zT$W_3tQPxbDWB_H)grFMo|NNgO7;w1%DH>60oREfw(*rHrV@V%^EFP3cGD;vswCSY z%J>+*70DeJ4R<$wE26&%FW@O5b2BmLaC#({{RM8xsLC#|F{Rsw+eE>%@N!1m7S-Cx z=R+y?T*|m3vCs87!$DD9^H#T&F5bmG1!!fZua)hn7P+l(UR2z6Jb>9jEr`|qY`xxA zTIsV{q-8(az3$x>ht_C1mS;!R_dCeSxy{6Ev-+5r5f#hxJ`lhPj+fij@tzoYeTtC0000W>0fLJSS^xk59CSrkbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gHt4*vi~s-yu}MThR7i=XmQ83K*A>UlIdkuPXy)B{^PW}IMV*+28rLbM zkVqo5sIuZr`=5haYdDI{&dwg2o}NCblnMX< zh^V)>w|8@AXQy+N@9{yP)zwv|wLV*x<&$Muo{~~Fwbm8@03zmwVeE6xKjEDJ84*8P zTU)EXFlcpk^_j9PUrCbW8(EgAvMe*DR0ROz50Ho$=iIh!o2I6wu5->WuC1-TeW7`a&3nMOl`~r~>?~0D2UFb3P@6FdfJFO`hkkudlDG`+^o07FZAjzZ?t( z&xT>x1pswFzO)EX!VOwOUUf z0xd2sno6lx!!XQ80T2MlG)>EOUFQ2f3LzK~8Ju%vnr1ah!~g(;G3FtnIZjAxt-~

    x|B~a+0992@8Cq0O_~UnW zJ-Q6XhaL~hm*PEc=!(n~a6q?t*pLH}3fd(D+K$lB_$EG1%1>Hd>H3@|$?E4aQ;omk z^=%YL@mZ8SL{a4q-!beJ1-|PZ_n@Rpw9{VC@Co9mo_MIMro(7uiO&=1M-P6I+)p96 z%ObAeRo%F)Cp)K8+s@WWYHFc9py2N*-Rwx)`}aM1$$hIwfU7mk ztcydmt4NR_LMUOA6=E%4%NQuYOHNIWrNJ|_XR4f&DQ4xE+#qSs9}Hf#pfH&6u{t?0 z>A)Kj(nhy)1gB>PKR*injzYTFCFar@y~C;d&PzGruoeYngrH`L-#U?b67Zt6gwQ2R z5JpoJRPd|eU&6G;Tgy&&e7!J1uApn~`Buu45)sUIMc=Eg9}yP{-~7NnZLB4m8P1t< z1YKecFNIZA@TM{FWg9{N0$xT7UyuOB`4UJycK0|$J-YHQ**iL28}?wc%}d$1ul?TM z6Gq&IB`0TNAb`bfHCVnvXn3)V3v3`eyA#3eum%*k?ab~MxQ)OAq;KQ=q@sc0_)*&! z1}~z__t{e4;iA%?egeIEJ-xjmEUf6RB$>7P2Ro>;ftcExbvZxU?gtG{&_4X-GpM^E zAKi?okiq4^^Jg91PA892L>T(HH#Y>SAFan{MsBE5iojhQ{UC~_UywanHbO1iBN>T$tZ@JqQQZ4 z3&x8?^F2zB=%7YrVzX9=J>f@kVf$8cujmGR-Coh-8*)rJN7dk z%Rf-460pbvkWs(Xz1ML=Wi9ijS(H=zE1IJwCS+`Vac6)FVsJ)EB*IB2w6W+ z?8P{w_4M)a>|q%jX#VV z7=jVCB04+646cU*OCqgOPC8NLgqizNWg8Vmc9Bvqe#&^K@+WE1D>YShjxcQzL1(rAH&ebb&t zZp$Qp-#7GcZD{c)%}w@Bs2h9SqkV6_b!tJI6R%I`7P+x(Kk3)I7T}MCmCeKyW8BUO z1*Y1>$h2uF&Zd@|%YOJDMG*c=ZzdiN(7!Vs&GI@UXiBL=8D1VAnQ8Lj9lI&k;l_>p zQ*hTUG~GNSw^rnIkavu`!uy@~Rlu*fFG0;p<4P>xat6JQc>Z2EiWy!C>*Vb{3(RWN z(E~J}0#bCyci%#L=mC5Lq>ot_ppCIQNLmE?xG63O&Y6IHG_D%w#{r zV4=OR%}q~)Q0G+AzMr9IU3{Qlr~lrgITCi|v29xY)1I8| zdFzs_VSCJvO(v+Eb9HtO2CBMm*{V6(P2df)0`I8F2|K2UE-#u`8M(sruzqSlk9C9% z7;eN*9y6M9`a+cHLyE;b%{X`cyXzWWSCrJ}KHHY*Z5dibs$p1^z?ZMlz~A226=;pM z!b1V;WfMe>5QB`~Xg8zFj``QhDxgS`*brRopbvP}fy!$xrGj>=U{IOZk84t;RmLTC z?G{9e)DO0YseAe!J}h$okVh!3$=N6xX5ho}b}cK{K39H&p?z8&Iw3ENZ=OW1UU=U9 zts}eVPJQOyDskhc^@s7<3s+B>VLz;Vqc`|=Z*0cqhQsWnn{KZ&6zwKHzC3ud16?jC z30!_9a90o#naO?{pRr;HkweC|RXg6u!83eN?6z zv>C<3`rg5!^s9oYJ{RGnp0y`}y@9nGaOGvMt-_#zCg4=B9tko)W-lm1!Cx~`P=16( zY;6y{J!A*uXUq!L`504VbF{2|9(uBQ^N{B^A}y6z&~WQ{r2PcR3JU|K)F0H6Of&HJ^7!tQqG7W=?PyGf}Sc0ceYH(k^ukCy4PmNJq4JzHIQcG5t&fq^tRrl2gw|vi}0p@{4^jG z{Nz#dU;R75FK`fmrn{gK56yH}TrCBl`%9}BFlIqw4!lJ6xMENv@JPA(QwVfSa4r(D zSWi(>vS=5lTe5u*(ZR5F#U9erELQYZTAzosPdc`56qbCpBM$7r)t zW%wXly$=DB;#)KWV+C!gh}E0L{Ed%KC^gU2P^GL|mmhx516EGl`rs$NJG#Mh%dAN! z*-xLpBH0RfTNK`nGb@*uQ`mXeVBOmxqu#6gp9i*Ij!0nYU+!T*w}yT8P&3Bp1oxMj ztvrf`I^~NF*SC)L!R9d4oh+TL=E6H){ESM1&R26az;6OD*Q}C#wPzOK{@<+j-gM}5 zQ#)QLi_fvB`{lMks`2;^UCOz)ESW1@^o%pXqt> zWl%m=r=bMv2V;lQh7Y1#>t*!&PlU~Iy}P?|S|aAdnF^?FDXcm}Bebl>h1x~XN5SQWwzy&X}WUrVxN;ZJ!J`{M89> zeBaPaaMmMGP=@>ehLrJ>grB6j|A8(&n4xFE3xdwUdw97%cvz?t>G6YfMh&_qVi-UX zD{Q%+Rr7kuchz>D^J=VSh0~b;E;V5QiUjbvkxy>%l;(;Y%r+f|cFUWwQP#I?8@s)r z%D{~&m=rV;uoQ#}8E(GDVwC0~*beK|NG^=mXk!o8C&l#Wt8418d@O~XYImkP|8-m7* zJspe}d=5QpDg}{qtxHt`cUEpa6D}Gk*;PmK-6A4GZI9zj=M~gwl=_Ty- zisZR1Ir1!3*Y)J@R^IJ&!K(BNd#{OG@->1MMZk&3)7QVd0pdehu)O5eh#^tZUf!?k zRbMrc%&SKfkuWH_!!LJV8&}O`>%fZ_u^bz2!=IzOnX--i9;CVVC{QF@HrL!09VdnF z;P_47AX8VCqEW^O%LFafAF70H8ba@5`%hAzeXB?%Vw&M*%ofbked#DPAJ!rM2>;z8 z2fc!W63T5|Sq9e;jM2mGF)w@j1<_r_hy;V-l3k>%CQdVCqGhNX!cq8jR2d|*evdrW zcpVTeHP2MGPce^Y%eIMlp?D)qSVMtI9e&y5G7C*gf0#Oi*1O!=n5_Rqu_oqw^tT07 zorgu*P+?@TcUuIF>Z_%!M($(SNJKb^j{}yV#FKA`RVMRYvP=YY1nmGKx@e)3G83H6&2ywp8aj|GXEKE{?2^J;9nORk7rq}W>#}* ziG0ZlJhCt_WTPl00W2*N|)0HNEkxT)lE4g@6yoY{r8|rOMN(U;%KcP)-C#wI!Mds;O zrmCt#Gij*HuVo|;3O36&lzw>Wg8gPy(|Cu5G(1tQ5s484eqq`#dv@=%Bgy;BBYGRC zaegUTq_H@HzSAndm;Y+W5T;-$4!_l;O|v;|8N+i>P z)a?yvuF(UZm*gFk*Jx*SvKj!%AwWVE+zS}bZQOwNvRe>h_l^S=bD4|R`uNOLIc z&6ed)Fq77F8tbKtBJ7-z#qY)LZ|CSi@5HOio97DWsrR03AY?HKGdbiP=ZWk8&B516 z{0HGdZ~PFHwc!WnfiAKhHJp(UD9>=sB~$EgjU zqLWvA$>X8-1E1!8U9@*UGQYh+-ta_y?n&%d;L$M6i9OKfKNQfO?V}3TT~u##4Vfj4 z4x%I?y3F%qHZ1e}{>|5)FZl7d+W}gE(YgtKSHCmokMd0@#4n6x{zu_LCK=x@!ylSc zFEipBmB;0&w4-$0|0auN;L~%J=H5p;<4X?k$xBP}t)G&>6nw7Vf=@yE6nCMl=$zxe zBnWj_i+Mp{o)sbr6E1~!pdkzy^Vj=Rgo&Az*TZ9o9x_ORScZgC0=TN-6Yfi5(DD}j z)lr<2`B7N4e;~p}OXq$HmPHH^H&4Dl&^7Ccrm|v+%^!!cnOOM%vQK3x6E%f}vJvjp zh>H};3hCP1I^HLI4FrW@Mv_v*x9)#{0ao2etRN689<5Y%PzcUa!Ue-i!@>YXC_>Ly zt#~W`i7@&DJBf6mksg1A6c;#lIu`w4tPA7foAp$pK8vnuBYwdOcZFPD-c4+IQUg09 zrzR5;IBlF6GO7R4rx)6pbkmcoKbl?cxxe5{aES&nXpSBn!C9R#t=8MgU!;H%Tmwsr za;1WQ^EFx7xo?die(mJ}Uv(utjH+xzeM+KL=^D%*cgx%4kFq27KM_M^JC(tRvzDCW ziDoJ3ZtcaV=3%RM=5!^kZU|Q!PGg?zYF%L$BTlpYru1h!bXrP_>rlXD1w0Uhxs7N; zn7LnYn5{@u8AINoo5!S2Np8u`p<><4GA5X!7{I|#^UWpzeLq6|V;psbwr#WHXeeI6 zP|jxGvJ35r*DhiOL^nNaKOp2t{S!z$B)?$1x{=71XK}QJW?HL`9x7@%zq$o~^?q-2 ze>r*YGw-7VIP+|^d9T9??NLv4%5JPX@r#NbElGFX34@+v=c$*^6ckjGNK)KCsiDzP z%l(dVz`pEg^w-1oY)+Gh-+vMs@l#Hxj7iSG5jl1CPu=#Ss=%GA=Nw|{fO7e_k?Nd^ z>o8=aFF`Elt-i{)**^o<9p*87oN>Uk?7Vi>;ub%Z5RzH0A~F7Ey>t|2Ce9X+lT!1U>X`Zae+E^Lp504GL*$s)25m^dMfuJJ*Eix@pDBvlp5L8G=pPnOdLKfQXnNq)EEY-G452l*q znATWZ$vG8}gTI_Be8V~T_|f}i68yWhb=E`T3m+rMX>;XG51LsK79>-tU_bY*7qBr=%q)P4dYpXYvBusTj zr(>xe62Makyr9ey78MQDazEt%wx3~mZRTin`uAvQ>;NnkrB0t4?4{pFiHQ#@MvsMQ z8ac?Er`L2cSoy3!(|njWe7k@OZ0B>zBlMOLl|v%K+?XzZ%7s|mV~%TeZ|)pF5uTB| zL{7}zkH(TVHJ6`upQb3(m2S`~BFT7Kst=^YImZ2_ff?9qi0RS$U7TveVL5$=t*Y9F z|IO{5=Vbm*!&TQ_L%*w1?|l%6>-sOix~(CkDu)lmpKg`XMwa+yp17I@Ic_?TPcJ=J zqq{;g^o!1{4e}y1XS!AWRiMCFLpBSlo6I==(sh>i#7PGJXLT6S-~-tv*Q*|K8MwX0 zm59b4#`HQj0Pd1#64BQMom5}uibw_O%FMa`kEF8-h_Y+D@X#q8BOo0j-QC?1(%m5~ z-OWpPmq@2{cQ?{7(lG+k()B-l|0yRN%zk#Pd#!6dE1cr&yFEUWYH4k5O|bL~I`jZT z+MruugdCNWetcZ+1AFqQM2?b76haWN;{$8YwC_J`Umb*yPcKA->6^O`M~IKlfq9RqCpTN~v}((tB$?zcRiYlKNc3mNgSN=ES$Z>B z)y%gGj5wxT${(b0NXgf#u>wIzwv59L6wF(E2=n(3W{Ydq1ag${c*j&hh|f7uyj0hl z54^_=lJgyq6W}F?MCKpZa=JbQw01c)KukPbLs&7+sfiAF(LsY!%oaIRSw-kpA7BSK z62Dyi6%s8>6&4T~x%sPDfAbE`ormYoBPkp4HX7e>dGHTU!qJ&7PIrqO-Fpar@EQ@O z;Nt%Am${0x3;1d%n|)9D%xkB{rGyn~l&z8A^if)06n;EGrBg3h$J2{SKDOrM=PK62 zcbR$buQU90rk}@LU4&@h2I!j;;6bO3?w)JD@eU2DDuMkp%K1$9g2Dr>dw&}qe#jT& z1ZuohyUU^qT&?)`1v~p=y79ukfAE+M6T)OlNOY9a0P7Z}d-p zXjn_9f=<(4t`s?zcGt_lcloJ8$NfyJx~u;qL=qg14fvD+Te$e@i2PzB)?3?!wn zdhVwjot^8ZvKT>LDFkkk3?q)EG+P?}%!J#D-?FuX(`;P?;eh8FShz5 z-pa&1pZ;KXKi+hhm#CZ~4wa}J#K~aU<0n%8tv5zNfFqYiuLyI;_+0tlRcOhz^$(ym z0E^G!2zJNSCgaM}>AFLZp2qQwMXUaFk^d6e^VqRz=k4NU2`zAQ8UA)^ubEC0RQuF< zBh;WhkRvhowb?#mO4^@!8c6Cq5%DYwggOs;#@O7;RzOwXrKOkozChQhBaypdKJvTS zsVhZWZlDc1{fZ7Ua-_+lrA&}S{KzVex??yXDlw5szs#sI7_n`A9}~xzO$ui&r9)2_ zx#TUQ*d(AupgkTudo9HH2g2t}_i_MnJYVARfPrF3i0%qavoOyVdqyIYBFf2-(j*93 z)#Y^m5G3V>y1>Tyll(e+Y@D8H*5lmRJvu_=>G0>bL?tqV7gd&MF?FfbA?{K8Vek@{ zYFgOb|NQxoTdWu{ss#n?SpT_Mx)fOnM9_Cje>+Ytu?o&ckpFGD3l`fjo96_kM6KQJ z{r)Sv(_I38+NFPoQ5;9*EDPDM31ff1h@CbtCW!)<5>kg+2F0mm^G(lpj~@;*tq#Bg zZ5E4~^tw0TaT%OTT_$g8O5T`Duzi%5na*vgXC*7V`5gB@ZG?MQsrBlHgP6%zq62HuC zHtR=c`pzag=2sfch`brpgou(i_4b z#0z^9zB!Hq-!z_!8_4af8>woTiYh^tG>Hwmy`oB;Ad{a_yD38-slYDd5`8MnfY*po&$T6HrDW5kk$1T^}lE1%lR(imLjA$-Qt*#XrqQ z>feh|6JWso1K~UHp=x(7&{tI3RBrv3Ce)|Z^iqWigOhJk4>c~o+Cx5SrgKd+!*(q` zN$D+!sjl}jIX-zf4rJK zw6VTg8RM@|mKRXoGq@sOfd0VKu(mR;iIXy;CJuK~78N0UP@P`R? zD@jUA?Sp&_g2|55XTo-a$_tH-8y)Fxlu=6YvFYVnscSFq7a~v|T+`E4AtPCBc1boczJ z<4MaM5cxTu;@R99OQr+%-Zz5a`Sr5V?&izM=IpJ|%cb@S{slhJ_L2D>B*ZlhqyB>u&zV z%Gn?d@_zj`^zQ&4X-Z7Tf`f8=(o+Dg)N(Q48zEFPJ^Z0f#K_P2LrgpXVdZFZ+F5%k658X1p4|p(DG<#!-1UGtT8I$A1m!cm_OCU9Z%^>dLbEf+$*wYuKozz;V= zsEu(XB++5wkSQ#Gs-2E)_%teoG@s0JCQYUTh4zVf*cIKpe{7W&9Se*-WUR+5FO*RR zGfZve#Pndk?@V74G1cbxFeJh(F{(rezta559*p0h=I5mi{ldDZwPV&da?xcrlldvA zNnKxrv?1=|RKm-GwzjUAwm?jg;liDMq)41lnrfg|etHjMerwn2@rHT*F%hBc{ z5oS0K18|Ru3W7K5@nVn$a6#N(Ud+zb0XtB;W zg>wn2Lx!}v27ri_Ak5ca7NlH$S36X=dNmyBPqJ;maAAl#*_q$5&lKxH|CC*CdYHQ+ z$g$A?Pvo%MRT{iI54}Q(%7a@fkwz1=wqGt-ZCN?F z`4a(3sFINh?vD&w^7^I}U1Rf$Gj>o(J(L~v;fIaj*-l30n&Y+*U8OL@_1-ie=fwnd zD#I$Egrn6p1M9}nF9b+i$-oXaP{_V6<{xTkQlSNxI`6zg{??O;= z(#v1*PQ|2}A-~kO1_Ii`MBwd04V%cqG4HOScpU!kS)cg$GI!%9XX5hxf$s7^bwOTq zVu1;hvf20O1~VLufX@q009Y4g!zSr7Ew5(=AE~0XespA{zsOeKGs~|B0zyI$pn6U` zvfMDrda^{5Xr%2xJ7MIl`6kh5QyVUKeQv#t{><|mnci2tF535rm`Z%yaE zd%4elg#oG=u3iUK0xpG5f49MtU)v0h{?R0y`99Q&7`aqatu(=H=rz#jjL2=k06MBx z(BITI>*?w9|HBp|K_EWhi`|1>ky(Ju$jAF&O*zG$dc>dU7OvLY+J!dJo;xi2tbb|e zGSsLZt)Kg__Ru{yrp_ab%TblDd`19X9UqVtPeh?@>NW1M`~0OHK`!dj2CJ(vGawy3 z>tnuxicD0+#{8%$|y!_KEUMU z+HYqQZ2I4RsHx4{c`}X0l8I5(|CI~Ji|1O7x2J>4`jOQJLZGKq(+Igmeq^g{p$emh zrCGM1;Lu!-t_cD3c$=&t&r+8-7W$L4G{b6hJvgj+HvxOumh08uIlet0 zykqxyw*Wu&dzQE*JZlzQ84|UP>SQmQ9GCnsO`Nl`)m}_jb{+{4kgX}*nL2F+IKd-~q*aA4N1i8xMWnOz6`#WC!j%F^`6>c@zm$fIU^{*%e$d=QDJ5OfvqO#um;et=nNnW8p2`k~0$yUb> z2GA?bC^GSa@?ZYhKV6BuVguKwfI%5DKM)dmD2$&-felI4!K&JPI_%mU^dYCoPHAh> z>}w{_um^d^%sdUmyuyJoG+v$6D&@WS;uP-p?*!a-)uxAEJV+XL{z35mOXOVSmHQn- zt?%T-Y`bSMgsw!45{TE$s`sQmeOHz%@0T5g4TJoTZ1`4TVPFcw_+Xyl%x z&MvWFSNrgM<=M|ez?l^?DiP)Ewl_FuyNjN+U{0O%*WF+l_yqv>au>!7HAWG>epTk! zZ)S-3V}x2#qz%cXZ`Z;xwTKK~I2R}@wa^%YC<3$vAiQSPlZ1W{@J#~ByH-1rrC-mmU1`7z72vwE|F2=LDr6%Xapt~w$n`O<6)|J!p#$UR_?g*Jv@1q- z&Cu#9ffZEmYfHUJ$N2t4YVeJ!nR{gYcoBiDl|9X*?~x@P%&h*TK*8_E4_hEIl)m?Y z1^TXv)gRF7I$5I?jKEYYY%3q=S|J>H3$6sm4O9`x%4u{iS~B*)7VM@6Lz$l05~>=w20R|}MzH4Gl9ouEV9uF?flH!n zCZ)wenw;5znF!p*N3FAzqyE%kp9$Ww_9>bQghnofg=|?nzgqnF^KM?_-lg;Dr^L$K zBN8!3?Q~CtHbOUk@yFSuN-~~jbZ5JlrqR3@px}?@TdZ+#!*vn#k8`@=+KrvJEAAio zW62KKdZh~7FeEsemO1`)z$$ahQlXJfTODi3H>#c|HWguC`w&>n{jSgmxpZTgo3qkg zN5iO|x#Y|La`&9Lp|87VaydmGTXl+WM~cystH%{kKf%qR(s1NVf#EET6nI)LA}YDK zM?|$sGj6JTG;|E)&=$FX`%1oVl*rTPoqR(iY=?ZT{o7%Up8Eshr{#cW!WSSs35Q84 z*b8Vs!_Et9Qhd$*d=uy#_)dQtf=c%|PDt2!3w4!Z@6i*@#umpLzf2-ef@C;1%o+}{ z`Y{GP$N!9;Od5>)o0d zmP#a+N)K;WY1q>;amWW&IRU{817H=mcDnv|RjSpxcEXAQ7jB}+?8p+52ETcT0^(HP za_+Yt+cU0EsJ@mkh7JZx?9||-n3TN3Z(f~-G2Dw3#W6dvX8sI(+RB?hat)KKf2tKM z@8p-9xuMUaFukYqbAhREV~sPDpEGUJ!=f=;8O#lo^{te{BScq5p^3*2Hg8kpSWV4x zq=I3*agdwm!R3{NC+sEZYxj>VnhdP;6rD0U$wPvEaa&&_5~QAGf@z{*diuMTocfL> z-nP50xf!Tx%zlSx#KLq^V_%;wjR zp!e7erx7^;G&X@oX(=}@UFuObB9p-y^LIDj&bm|}C zM@d=FUml<*z-Ki#pt)V?0S_6NK`14{5t{5F3~CbO)LU3#YAy`zB?(Pb&Z zqNU{jOVX?u=D0+Zu?SEaO+xpuhZNc)(kpkg|NJ(Ys18{xu{nw2CLzCU?es-E>%PL^ z&Sn}mkwpGcB=3QtNKJGl(eV1d%>6&zC5+`wt02fmlMV&Qnc;6cq7{S*u!cIhH;MIZ zD(GIP_Kh3I+N*N2YKvy5UsqIj%^r3>^xp+vKt)7)Utcy~!`|N507_#QyzM6dG1lP| zQQrvEC#A&VJWhA%9p+28Laqv`!5i8n#<5B^+E)cj#+FdD?C#*~=V*yMVnCsKIr;W=kac5Z zphuW|%x_4zZ9*G-=sBRvxIx$<)_V3;DCBfYRZj(h7VWT`hMu*)F1#=dQp|{; zB)-V4?J8lw3s&a*0e2}iZ{j>$iU5iQ$IkVuzu#kO$iay zS}R=Dzi-T+6isxFcH8Dflr$sbqUqEv2*yLS@4$$Y9N2LGFr0X?*Wq}v_ei(ZyHlXZ z=of}86;yz>7}R^dcS!_Vny^4u(|WT6#2#y;?(=DRU@oUwlI%bN*~oP(*`q#tW*bCZxZ6A|3%2s9MW2Bv zfU;k+S{Vw3^7eH0UdLK)5POHJa`~j#(TvS^`dW7Gkv289QCsRfI7UrTqFlg}^CLxJ zPo^Bv(of2xVk)0?d}A;vy6Z@~pte-~x5`KXo9~>(A5pI56h z5H%NtMeS;+c7qn0?7{pT$rjAn#aqV$pPgU|!%;@K3}gN2;=gl%d4G;RsE9;iHv{^6 z`$%1+dqM>3P0@zTls{o&ImJxqGK`UBadN^387l;iA9c?2Yvd% zakJ~D@_4W9nQ5c1%P$9f2|9@UumxXhdEq1f)ec#8#4f?FH|>hdWy^523Wv$(rH|(_ zubVv|0Hnv13%ln@-?PQpu`T)$DQwEOih7|paJC^at}9iFYQ&P>c?*~m zRj|Z+-;{$H;YV~}fdC*9zfH1rfw|CgOf5fvt3%yIKjxOp%Wl}<(Qk=! z0*pc2$7je9WnJwZ|QH25PRp3 zKZJJ^_SM@IEEI5!~e<MvDaDt5fkVnH2Bm;k@>cTZ3lT-k-OD50 z-TjP+I9TTI;|E<9XUSz?n%36V#~T+la@m^Fls8MVme`*|m7xF>;?BIeOGGtKBse>!Gt*=hU zA@pjaWE^t3cEyAAsqibY-f*OdgrU={i zFMS0Z^plqFY50K z(%>olzVq)fclBsn)2Rz4!$4Aw^u+KK8KU=W#aZ7ukq*Ew@Scp!C{;i-D!*v#2W8&; zSomj=Hkp?=STFf*YvCFzoL(>krLR*(XF4@wJP_->pyVKH@In|Wwb%&?QXQ_z=7T0G zOU6tKj`p%SY#~fUi4ESzSP;0|*|^!X3*9rlN(^y^5)?&6Iq_R6v{jKHjpiW7L2s04 zQV%A9dq=KA@v|X&DdgZ$H7yo4A$@tl^Ps7exFogl%89cxl7uDgh0SoiTL!dEM*EGYqp+ju*R*fpr zoCP+qs%!Yih42unfBdUFAu3M0JX6 zg721b{tviP-Nw!EXy)=Fon!e)z;W~W6~;QAKYP$>nSg==OCsT`p_nQ5T1j6?a^tTE zjpE9+|KOlxmDPNbXz=xhyR?hnHWHQ8q$k_BY@ZzC${zRRB-@{HSUK)XkZu*o85=_9dLnDb(R49MJB1t z@RS1*R6B44uvbFti9%AgYrs2ev6MsMUy{4wS(0guV>jFIdvk=m@t|1L+QV~?NiYAiE5=C*>1pkOz5aP@w8;GTq-`cCfT ztGPo)gV`h?M(3I-(q;%E>@ivO$*lcYu!5_)w;)p)u|AjIp8mVXy2v1ElZ%Kj0@z~-19g< zHrvc}8gLH+l99|cHF=bw*bpT&nb2bZiG2NxKg`yv154u)NuEFl=;S3A)@z9N%d$f4 zSgaUA{k)N>yzsOCrP1NpIok{I(;X{~$44TJNA0ftZoFWC+N^PW-Dnpa9*!PO(;#}4 zPWoB}`aT#^ar>n9&$^U_2FH=%Dv$AJ&52;XL`TbuPQIv&II## z8|#=&l_mI(hNUNE?jR&j%2UKf(2{tBq4+)7LYK9@@REpyz%`W1>s7z+-shSe<~Ml93~^kzLh_Ph#s zyY;*uVasKxiBNb)F_t08XU)v6WhS(99hITl1A)Lk5sjX!w{Bs~E`yIh|uJib~ zu)EsyNkroQY3yN72nfc#CGp+e(~gA41ag;fyptPuZK$*;tnv=ylAUrGF(ngtVY9UJ z>Jdkk==9l-Kf7((kQw6X^rw)Nl@FQz2b!_o!rEq)u66bI3#HP;~mySXXvaTDkrDx=R;OF11=fjDGPSREsse>~qzh(YJ zi9hFt$XGx8`)2eX-v>Q{bIY?Mkcg1EO@)m;1_=QkrjhzfO)8AYoDs{S-LYHp)QpQ^ z*4$o-f0}%H8?5c8jy#-fuflzlkLt&;!&H=jQ0~xzWQGJ*a5hCGZOJSVPH z;sf1oFYy0?trHv$^X!kslZqVp5e2g3Uv8q;e)jJ}57=+%h*k#`g7Qu>^0f<sXatr4o4R{(6*?BlXe0@GF z1%M9z!OmdOBLi^^&xbvfJYm02Gctx=|J7(%((h~lWts1?q}i8)hH~9Wq@5x`Xtl~J z&U=QU6*(Nor*oY@+Z}<*N*iKM`)2;sT?1X&`5cB}W+omS#GD{pLV~JtD|wsM3a>DQ zee?r|kbN(UeBUP8Bg!6yv{G-w#TkQ*W%!`twzk3JvYkW)(Yn7gYwgvKNoQU}Ec}fG zgz-Ilo(Jlo9-r#DYw|d}2ugi6>t@gti|4I=NbI&Pr4Kzz6Y-VjHq9vb2^4u6y=MCG zERJ_q$!ar{2t9i-PbB{n=YA&|dR|K^Bz>Fz`ky}-29Yj z-th6g+m5({^gQdmt!N|P3n^6ZlgF1;)90)- z+2o~v^d7xn!Aph}ypJYmmy~m=jsrYg`HsZlqOJZQQo%bMsMTv+!xW-DWV`EjL#)OP zJNa||$S=t&M$SbugSdP9k>fKcbea$ewQq%gnKM?mU>X34hfEzvSG&Otk9%L#+sL6A z%sf+b(l)`Dry3z3Ly*DcqRg3FMN6ePvf?nBr;`3M(ukm5_3!($YYaX4BGIV-!fyi+ z;Ib}J+!UxSIg5fx3kopj=nx{|t=BnW2keq$4rOAn1;qhshas&XuLayhwl(R54YUH< z;6r#;f@fTHcfgA7`S6e4z2iep`lHMgXcRrcm5+uS@*8itlj2}ai+S;sQc@*rZX<)s z?uNCihpK@sShgNnm!SKPs`YBD;qGkNjz;8`A6ZsugdKAd;)(F7dyCcfNF* zPiJgy9i~{?yZ?}>ouxN!$mm%W$m^uN_H_~iKNh2;S)Z&E^%(7>-}orq8RC3P3wGy_hzH&h^cY610qJNQk zS>8l1-rw{_O@7k~MiJ#Don0-OT;x2>B4?~l+^GfsmXU!7qrNsoD3oyJ+lT3CZtE;* zQ#VB?pLZG<+Q>WOZtm{kMlYA?|1;O@jR7O~OZdqumQkSw(f+_e`XCTa->eTNlo$(n z7i>&WFiMGzu^Y(-&%}w$DiaFErlNwUewS$P0hCafD|3oLp0$Iv+kYzT;WeH<~D~_Z?2@9}wPShW! zB|s6#M#!ITa$T9x&|}IcAna)KjsEw!McigN*0nNja)sn(qu#ll7+IMw2s=@gg~E-x zY*NT`S%n~M!6H#7YFKTtl(=`YqIBAJ)0uX)?>h)dkH5?kfpitGDaA2Q1E8qb?8kLjFRcr5MQx;RFQKfaD<|h7FEg*0-Cma;+@CSXeD7eo zeV&;3m-}(IPjdxUFnRvm`Z@QM!!it(0o3KNANWo`EteTMdh+;Lh6+D*R%q6z!Y=4m z8F-x%^=A1yI*+j%H-5u7*eW`mUlTg&UN`}>Sdv@7>f1f0K(kvKzIu79_8wrZWN#i% z>CU_f45iZ(*H_Sy<&@jfSq=+`dg^%*RT69eK;no$&(;JI=62*PKR^lg3+(VXGbI^G z(cW=OqR?>FYHw}rJqvjC0ZLZ3UxCIzvbWV^0EuFl1 zJhF7++}6^c4%V&M(QX~X-s*z;SOc9=S^K!&_yK?Hrc~zz9?Oe08m(ZtwkNO8j*VW7GE;|AvRhWd@8b$EZAf1t&v4cS52Mu~ur0bS7c_C)CdxII_F5 zk(O_>8jCCHvTO$-h;<}buKdsdma>C*;s;sMAfSW#{eQ?VsJi{|4Y0d4EaZBj@-DO} z_>$y&Cn0LTl#ZJ=HUX=~Qh!2rSR0adcgVIp8Q+%7?(Y)AE4_d9#Ni;z79Xg8GtzU#EJmJ=am!pyZqOyfG7*wV$+LH z*kU^w(tf{^NYg;PBj5+p$Fftefk?KLCAi8lnB>?dIc)w9ZT&RmofejA`v-{jOWZ-< z$aV51Cu7-Y87Eb70(^l!^p&%l@^$clPe+N( ztUZ5DE=u6qna{uHKtIQ`p>mdI?6ZG-)=ED=^~_u)Y*D`>Sed3#i_Z49#5*uAHN~c| zpo1armD^b?;arcQE2#c6k+pC0-+znbjO2mE{0{Xgti)xMvQa*m3UGhv`@^?LlCz9*DMBN^&^x{dN>#9ZS_a+Z(TmR0cd!Hm5h!j$YZ1}=8Mq7-( z-~6tIpyaPF99ENfk>HHyz;OwY;_)xIO^OeCc8+Ss&F%3QTXW(Tw^hq*qK;JUn)$;^(UwEEx!H@<#YeT(0>YtqOQRd)kEdkhi zCAu+MaWYnPq2W3il91K~TJoe3>)3ItcoIT<%fL~vJ;Ze0-uzTGjwQ>oGn>F~x{F*w z!KG%%%+|;?U+I_jY4-6_^_bAd04vw+g4D<~CY5U;MLGF`G1s({r6}gBHSObpKK~DL z`&|Kzg3q!nQR7_}azUE;9g=L}V_B{C@k#a%H}|XBrE_6OEI3XHz7^33TO=lcy|d`Q zFVKevMBw!ZG#UfKB@Muh6>7B4u1Hfz&Jo87bxye;Zu#~7DlN~f{ipp8%QW7yH@?_r z0E<)rnXoVNCW#{ju9645s%%TMliLhzOt@IXK7y+RRg=SiS;ARbBosF5C#uxA-eaD! zer%V6E>%BdW_htsv}|S0iirZ|C_f|StSxPyt}6g!fC9)@H6h|mU#wU@yl;$ya|^Ho zS!v& z%)(GCb+nZ_pL(3Z-<4obwO2lyvNLmJn8w2#x8|e9bp36nQF-H~6Soq>{O%oW=DvcZ z{@UrHT{SW}4@Fo)cMAc^PUSedB<;^&YRYgkc@&+DA);jI6i^g=D{?e(#pc%>p}fGK z|NOP}<3Z796E#AVlTpT*rxirV3Pck8F{UQ!>GR+sCMB@R)@)z;{sOgtE<7(*a62Af zq)(w)V3+oHT}`yy=9_i^@`F@TnRSKWWDX_nX|qpe4EqI?;xHekJl5)djc!g`%YVw< z_{Ih;_-e4M3QzHKU=(|=i=h177}d3-|DztzOBn%-6nCCTgkiHw5N=^0r|8aL=hvBA zws2CVT~>^pG^iSXfS*=(->Q2w&`1PuX|UY?gbW`XNlR0YV{|07{qga}$n#a68AH}>uNx$(gFCa2o?>R@J97%30{)?=EK?|X zX4A9C=kW=N%wN=dSLe~gV-^uJN6{s zZAjK?`Ya))4ff8>j&;#KgKYgBl$%^ra@UB*|AgicQVv!D9T= zmtRFS3N&gA2*^L9VzP>jK;wy6*IsfQCsV%-SpD*KJT=M)4G>Jf zz399n@*7@Ya51)Bh*qK?kQ2uTyy76G*M**uZ8k($4F9YhVk=oX^ zIV5i&MjDHxv)9Xn&B}OE5;*BfZpGA-RP-i;T|qOxY_|H;YEnHzkXvKtXE2#mJvF>y z+VQc+C|f~!y|k0y{3|m3L1i;(+L?nKhwrCzZQO;Wn;0&JU+v+nC1>eXa~3`&&PH?8 zd6d4Sh4aIuKkry(b@P`VwCvJ$ZZag45;5j`2CL*$Bnx*#KK#9(uUmQKD8c34KZeim1InP?k_kB)EfLz*KldQ7oHw&YrMLWG5;Gia#`+^4F zFs*H3pi?>xm!zo0fyJ+iVOg0PBwSqyH8)zK0A(t0>Vz{lfY`A3{F=2Gqw)ktP6Wry}4MCy&EPKLw5+YJWE-;F2^-fMx8Duj}*CvTn<2`}!xdqet zK8-Pt_^bSat)qSpnT*4GVDw{rph4|E=4YHc-oc1@>hSmC&jr<2k@cb>Z|F1v{~|kV z&K%tcmRPq_s-Cv%{7hJ&5B1P!a${ogzD>_&NTk!*hEV7Ak{)mwk$ZF_UN5m>v*+|; zsgch@F2pmo4;h8+obD?GnVxiWckyUQGb7D{!2^x|n#H&_Oi13_AD_QGp6%TBJaYl* z1pny#*BwG$0RaU$uKJR$98WBhlu~B*2u8&wX)ig^tj5~lR(-ouwM)j~6pnMwnt?Sd zY^R}z#v%WJw7E3BzaP@K%1C-EsyR~_6iihG@wdH(Sx zGwW-{w)7{=ETa_I^Q-{Lx1-A1Sxz;=?>55X9#9N)rZrQ4e2uv1wkWLsCcaxhd;paK z7`Z)ki`e$%_u~?~y?>h*7pbMiTYYN1@ZD%7xo)0msTO+UW~A7`WE*$RJQh_tQDr1wZ$W7Abzs>*## zmu6!H3?h`#*nXS4zkbM&Qv%pMRm!1)rvzs=zu4pBW78V2aqNFRI8iH|tXn`*Cf1{M z)xZplXoH#dXLzGnZ;^`W;OG ze@lI7rKdM@nl=F=zRkqq$wY>qA8(ysU;N(EOEMIjx{&%Bv6-yGzmzs5!)0g7G(SyQ zW;xG_iBp?er0GMxd@`==&(f!NdHBdB;(ybCc>&;VVF1`EivQ({0IvXqc8l?uk%PK^ z>1SQqQDN-WnD*_wC@wb5w$(`+W%Th6osTDv?98Uk_c%0STDHP426SvHuz9+kXRL7( z1#XA$qa1%W{xq!O4k&+a;!v4yPBF6}8uca#+V}8e4CJ?9wB@PdB2Rw=r^nhCdw|O! zWVl#hN$fpp?qDzY!qyDYb-xTHDKV$Nbh>A8%3Kpx`(h65!V_Q~unQ1b#*QiyL zxGy9SG$mnkxU*e*VSto_^j_p~wq57dhCr*&Ewd>y@Y;hn-ivhpQ@44B-TyJu;5(bJ z@@~2@^YxCUh|A#AqPpP9SuY88KQgIIk?F>0RzyEC*Y0YIO~%BvsoikYeA;Gu$^rkS zH)Z|3pcjvzIZ+XZ8t~mOLymco-t!hJzqzrS%T(y4%*f4uNz=R*BL{7^{+E>hIktj6wMSF7j@gNNXQD$d0le5)DaLiF{w&1KR|P z?8#QNlsjY`dgvQSQnNYtG^{3oZbrfa=&2kz$4L)Ul+eK-+H8w&Fw4h;8sG&#ureh6xQQ+-Mpm(nZw}51!bY0WzYNQFaDh< zl39DDV#|$@aAxyO*4YFGke#m`L)Y`Afu9&Z!0hq{nk5KPNqgp2YW{?*RK{qC?h=K9 zS^pyb_e@p5mF|Ox6=dDtjsPZTY@|!s`^Z3=hKF&JEvp{4taI}*CJd>c;E?lp*_`F z^Dit6*Hli6m~|OE6?R(KLR(N1B4t1knazLb|Ek6?S#AtRM%hQ`Bh)J{*}D<2?4Pf2 zu)o{zqwgZKV)1Tu0KS{U(tJwF-sAzx`SPX-xQcaMQ;iu2rjIo=6ea@eExiU*#Q9z? zYTf;9n0W(8{C|M0%ArxA%uQ}yNBzDZC-9PT#hH_DaqdF7wleXaO+4YBm3Oy}(^}g3 zc7(_f+3R8a-Se4$bVCD20@Cm-99!=rEezHbacxuB9K@?I5;FXqG+tsvD$~Ip;!*T+ zH?f?h_v3nqFWQHHV09Ja(J#K)o(=t(F|N`#d|7%aw;fF(-q(}|QwWk|v6FFw;o)@H zIe(aPY*7wqX|}!ZjpuX~P=l%*Qaqffxzb4lJ8dBL#<|G!+$2GK2t^XmEPCpw4N80} zTD3Ngz_C7oeALM4M|+*HKz91*EoOYRzrU%!hcmVsn~ZDdHfMP-bsd{|u1*vcPuW+C z*mbscTG}wb?gtfTf#KtM5#i4UzX%?Ag2AxBgdFSr?g~{593z4kve}v|`T(@ud=+-* zUye?OOP$e}ko_;lo@mHM#D#MMf95{@Gb7%3Q%332%kpkQMMpKM2z*)`pJqS{e3s=* zom0*Gz%tv3kHe8zu;C`6o3~?^8gWgFW3~_i${oC4W-S>5! z$8m}~{?bO~-YS(NR?7Wq0>U73N^d;Rwgd1IlMaCaj}3ry&A$de+uglaA?SbFo5JRb zJ)6xOCfgD^k~jCB#^24beWScoSNo*6QFrU*h{3tihxKcjix6M7ttBs86I}J~(;n6b z&|6!142Fm);}~OBzj<3GPx~i&^nq&rANexaG8#0?mK?@tDeB%x+!Wh-H?=yVhANAd z!7bVjXFhodDh{f@E32|ZMK0~{o`#lUb#ST`p+4w>Ptfdfe_N!s9p`AVb(9Qs?+kP> z_%28-%UCq({{XOeAQSb2`+`COwfUp`cCvzwXB8pk^nJ*PR8%7&urHl{fW{g+-+k(@ z)jgrDFP%$0_0Pz^8YqI-hwnW@TOE!;Qi0)ui2aqQrtrBX5bJS8O14w{mtb@&oo9W>veT|K z`L?!8nn0cQ7CTI2OG``KXS5f;8tmU)!H0kzQ4L#863=#h0Y_d{xWPO1s<^am32!RM z4tk?Prb+}$a5=V+1d07WGJS{!@ zD!ai4rSe}f2>Q9+t|?;+_a(X?M;wgS|E-NabA0&%g5VM8*1`}5rC_tFi^}3m)^mQ6 zzxQ0(?`G$+F|Kp-tDLD4>WSg_Q}|ntsmbK3*{ikrzv`Ti@kkJ9I7tlg?JDP9^$Lnl zh%*39@51I1?%~c|gChorSfI7U*&$sZPWsIi`}N)JPc2V44w+6r?I1iZALUKzay3{b zzqX~y(`$50a&k5C%YU0}oLcWNo&JdTYLW$6pT0D8C-*qMRr-EqhjAHTmJ3{9Mg(rK zt!-nw@QB>NaS&qv-&z@ehZqsU6bE%Uu;eEun57Z2cSFO*mL?+c`zH|M2k+;}Hz}cc z+rkn-C4>fyB5~-rnSB+>(5%ll2QSzE25@tnNFs3mGT(EJI7$A=eetCZaPr5@yS4C*}lAShnjGI<^|y8-iaU74E?cGwHt7@!C6L zCre+ty@i%rO3;vWR@{NW0-y)nzD5&K@P_EzCVs{T2~2bfX;}H8fxQiQ)qA_E0!lI{ zT*htdm!zE}JOsv7#Z3~(mHB(KjWvu?TYs+--@-ZYXM?Ta0>S-Lgs6p>u(8WR(=wk` zoRa2W82S4bdlO((>gpjwB%Y2xvFT#;?t+6RG=)Lo30ItgvW?$?`{P5=JrP-=oxJ`F0la?5l)%A z0n5uLbt)zTI1djy%U$Xj8veVzJNsYM`f2mWkn~H^;c*{TJ)7NQG`=x9LC zjKzX+%Xx3iLDXYq@b0?%YYf47BE?BM*gs~u2RibQd;NP2x){TKgNBA&kFI0%Xo!E6 zvZ)0%+w9;xZPJ1e2u(SuS!{e=O?j4;8=-QqZsbI&S9PJ+3x%$g;mXfEuw}}fd`ckO z<{alJNG=%%NWh0=s&Q`Q{)*HXuq6RU>daV9Ih z?3zDZLi(k8(A9m3msTh|VWOuvT}EN7wYjVc(o!I8#!BItTWFC%6i;<>H9d$Y zy!#rsq{ROx;8y3|`L_JUu37(fjH6<-EPA0L0YfBRD@*Y0uPY!`>5YPt&0I>TUtLrD zLT+uEM8T>yg7Udlb|>TJEIZF?!Nj+Ds;&8*IS@E~`re)!?p=TU_t6Uw$RSe}s&;xN zE;yiqb+23pyEWcqj)W(F;REZ!pB%gF_H??j<9{kaJ-{+)XXIPxm5pVgz>AB%$Cac9*642L@wMfNKom2G9hExT$K zw4^2XZX_bgBZzA!OvOra^5JMujP~sVL&Xwg!itDTe)%Fhi#Z{Uwn$MaAGtNhH4x*t zGL#KHse(jPUsfFJ7k@*|r$PW%7K?AXc_^~y_L0~%ro>LUY#w>uxt$T<$9ijPzqMo2 z=T4%R`@QE!ezTYF3*4JsJ~-g*HXxox$M5GI3gCJ^%9WQM^(YP<*b$~IY-}@Wo>Vy= zq3X+Os2)W5cN_Z}a*R)oT z`zgBM21l|x_p7FEE&IQ{S4d0!Xom)fpFfJml9Lx(DYQC^P)R*HO06~k=Kh7@{oe2c z39w>(5bXHgF^D9*=q6Yr_M5$l)OPTX$v#0w(=`I zksJJf>GX|hVZ{%lC2`7w4glG5D|^AQu-rmoseE?+hU~)}*I|$A8701R^V*(8#{e_p zUOg@Y$9d2rhoAv2d%F81ubhi3M|e7=DDkn2bF2(Uc;j(&e9#kOCLL^j(xtLuPVvWH zS!(Wf+zLX3%NAk#zRJtt6Zt{{JX+-$KBv5bfy?1xHX|MHH|qT&dUGZav4j(05gZK< z+B~uL3;9z>5~As>nU|OmX<3H`h%A@iQEc{U#>`YP$zSHfGYBhDuq;RX(6lPv?B4rg zE{QqYi3Dq8VrH#hqcO8u+q+ckX}$g<+}a*1rM7siIi=}J7K9| z$Hd0Ty8k*2!|DHH>k4+qAA=|m0)fiQ z??4RF8Ijjv!O~oHQO(CDMi@@XDcLkw_Or%D^9e8QGAkB8W`O$N_7t&^alFH)5%d+= zli0#E_NyYc=Tu7vnJ{%*SDTxIu1~6yf_v?KqdV?ZNFe3{&S~s?Fi{-21940Yu)p4W zf2*0b(ghqWh37g>s8uobz?a(6|Jma?hwwFpc z4Ltk>BPF&@-CHKBU|iTddNmT8pry5bH#|g*M*L6Q5L=)2#1a?FMF_AIbP?xRA#Lnu zcVZd~Tn{2&imX|y^dTeFk&7kNLh?sd+gW7 zEpz5Hby?+p8(U}5T(BmfzQiO|&Z&p|I^3!`P*TeCwb>%!v{4YuY|YyU3P?7lm6S$w(Vkp*Td~ zvb#IYdpni5>T#nwr=9kA-@MmTCyI4f{KlULTv8WDajjRlj*t+~l-n&cjB{*%_>wA< z$suf}O$6}iI9t!ghNaKm#e!Xt8Zs#E25eaALLw7n)+27P?MRS{kc3O}in9Ked7p+oY>DD&u;rIB*c3_rio23Y#+Iwahs0Lo3CZR|DgFbM&q$|c2HD+ny}7^ z)ZPrdy8oARoT=fH zeNo4=WHmU|hjJ?MR0>Qgfw4x?BkldH6^nYFLLuCOWAjI15II*Zf+CSyd;_UWr=IB@ ziypZj|61?Xf*K~!Yx89N*}Dy;9zkn)`IN0uv*pPo1i8qI%JoOolQ}-N21QE!4QlPq zj!}T?FQ3{!la{9tDd{Zog8N+7UuLs~7CW7eC=Io(WGWVlKEZdQWq)_-cI(mv3)oIX z<}(F;KJBw&&8Zp-3zQ0-S(ul;0DAb}o4tpocckO8th%UMg;{LK^p zq7_j!P`2&^!=Cw?Nvy&9MiY^9WYxi9k6kDK9A*vO;s zP@$Ah%!Hh7y?^+QR$n^K>$-SCkpa3#O85`yY4VeXkRlCx&*+=E!jZ6rhT%QB(sD0C zwiZ?{NnGpNmQl}6U(`Zrdbef%z%u*(N;B0LkEM#B;dMnXh4+{xk7cXV7d+we^~w#y z^K1J{#Xx0rk7LFa+urS;;bg#A1yE+K0?{@<-~vkYvPHCyyPHk!M_oO6(UZ_4V~~cy zB2AhD?J%PEQr~?gx%>A>Y05G62nFZkU1~<5V%Iv7CJYr70cmu;ZA1mWmtLKc4Omh5 z2RbJ|Q_3&wZFhD2`xpE7s19jZE7FDZMOAVx4h_Nh-(~F-i8vej-{W@Z=WRmfaxJW9 zPa3Y_TG8xc{+9Tl#AFmSTamT7#3hrmH3%i{XCi|NFRYYn@;dp%F%fSHz^ekVu7gic z*je_`fK>Jqfbb`{0y^-*Lg%Y58SB~48J5iEe(Av(^IL2II8>89@Pt*`S<8JYUh>P8 zYd(is!BxMFwxp*Jtl}(w`-#vwFvKaYG*Q&*SzI{Y ziMT9ACGQ=dzLNtJgh3qaw~VcuXK7#MYw#-#Dc6B-=h-T7n>8}k&(tEJv`DV?@=4)T zT8C@z2cnf8CY>xXr&h6fDaR2_Vj5V&LOnm&_T&XRX!VCwgE@9dsqV-*)MUGiUFk>WkWW}F zFX$~Y$}5c)v}{@KMW`Y)72DuHorsf~ziw>MVvScRH!`r^=$cj^x!#)W+HfJ+HIf2m z*it&bn?J!csy+~~&A3nOAlusZxcYU2(!dQwbGIDg{ke>KfRTxCXqL)`xsXfF*m@Sl z1Rf=wc0F=~%Aw`sImV#kRYO2zTSUYpA|-Vbx|B~yw+6aUiZmCeiXzw0wH6nCWP zh8xa=e@^C1fz%e?_id4uH30Ku9nqHe`Ce;}kqG3#Z~lyY-3QWmnq2=zX0gk{=D0hOD^fx$RDo zWm~LG#o*_x7p?hY++=j5=zX{-$kblQ;fx`yG_Me{vC(C)kMb-}&6PIV4DXaLsyRKyZ!E5a@;-7gtLT;e-2(vD$H`A-&@>qwP(NP#D0r1e6viZ zkR#DR_ce#>4bcGi?$Hr!#~Y9yGdLuWScox-J88@<^3;Enrb%xCvuKx+OOyIHa(1n` z#T>$qM#YcSkv-ggrCInkq1vTYsu5yIaH2w{X5$>=>~&nXbNT0SZlyKg1A=o)0wK$x z`793!q}|ZG7^;$F-gCX(6&)}1j*IeDU>I0WHvm4uGPj6CN;sJ_FKnDm?j zK{FY8RiScy#ZdP`atrtijxX*zlD-dXd2`K30A~>ia9ltfr#QG_L4;e}G}U={5uYRH z>q5`5MiEDJ47}<+Y}Y|^+Q;yL9u(?*SC{LUdCj@b-#1`C14uDr4br{zWdvO+<31_5 z-awo6(f9-0}BOvG9&Sm8i1c&xp*-zt4Z?Fl^YV>^o|%%Vq@O ztjJfB1d zQ?b5@Vr`~)I^c|ubWBF8SM|k2fyi`+%;u;O?d1(gr1m+SUlnty*CBIK6EgBWIszdn(E z>(@i}j)d|Bc&JU7h-|;?bwN@r2DW}pTHhz+>}rad^WopDx;!yXQ9sJee}6q?*MU*A z4gR5>7eTG<5OWr)Wuq$d-}*XDMo<%tGY!LY_Xtj2z)yN8$DTW6z}YPUeT4lKt1x6mZ%Jqug)@H84H57e0>E>M_m>`_p`jt3<_)CvX7ODjmce9`r`hz9 z@730uRM^PV_$@BZE{V5yf7+F43Yf$FbxfqWn-&LUTH0eYNGo>OmSl1#P zooh6BGw6OS4;!DZO@MFt-8PPtS`2M}US{_$yf4b63AqU_v0Tg5RSM((^uQgK_ij(z66LteR>w6hou3b@n@bY9MDBOzmv0EKXyPR-J%h`=NJf5?0tn6HpV7X1c=3Kp3gp zq~CM&KxwbYU}?Uw*PUuBD*e@DU30=`<3-!OhHg9lt;-BAG0%&k{64re4_!1nT=&sS9}1`_>mi@IF0dEQDtD`5(@EXF-C$gw^_#@NKYXX(0B z1dDCJ3x(7O$jA7tXh;)1sir`xI|0&b!lUOWsI9&!Zk0x+ozDrf3t3W!dSwts zNR$>URd%jx#EfOFU8eazCmY37G=xK3{|neYOW={-XGj~y{L@&8n4Uz@q75nb!~^7P zd=c#kyLMu}K7D22_N*LBvsHH)cRzh>*M!~yC1>|AvccRinTVzB&S zjw30cosePfpQQ26H*@K|WHN^5hDgNxX7dU4S#THNIR^5scO;co+QIAK*=8hqw1EO? zHq)a?;1fPVmFEjo*4qL=uJ7Fx7slOv(GJyTG*$WU=wcYm!NW_qH!(w6nVb?$b85lV z8-$BfmM~&f_tMi?NXm%yKMerz2vA>+4xcC%TCPiX zEqF-8kYZ$XbZ$75WWcjA-;`~W<&JWaL}IdH2l;tg(wuLQF(-HU99vbhrYA^gkz#nl z#aQK&0~QWwHC85?1Qi%zirXbDloZY&s7`=R2QDVzXUbvAdI6?aN);M79GV{nD>nDlu=0{j5;Dr1%AzV zcz%+#=w#&e*rEL}pvq96hCt%uPV9;U)CAHZXz&l*n2Vd&N6(oxP7GFRV*C@bdNxst! zyoe4_xO)f#Bg80 z@3G-8Dps$6Q(`?uMT0t7ur6}wVr3soTqE%*32K}956p=jxRDd zgpFW@3*C^E6Gd8+*EC;hIIh3&I1%>kUW{voAOMVfvpt&W;)S12qy3$T%>1iVO_~a| z2wJX4+~R<3_3Hc2xYDFP)tu!GY?Bz4VnQK{zLfm2_b}Fe+!4%4o;V0i%@t3eH3Dc! zX|IM7_B^j@+3jk(nlkjB`h9uL0u30!0XO%je`ON?T($oJD))vv^aft#1UfvI7_qaU2;lodAu zSFxk_`SSiK3BoR$e)+k*2}bWn#r(&1NVpz}U#30NkB0h(WJIY2_OtetqM5`~C%GA8 zuw|0AA#5=?r!OgVTJ9*wpK{t%y?ufR9d~RtDKmM#wb-4Sfbl2XvN^>q2ZSTMQk8Pm zr024S0XLeO^REDntnqcvb$rV4ydd53jft^cb{zP!?6zzeVbxB!TQ2fq!=V^2jMZi@ z=BYq$t4?DCg2|Pu^TH;)>9wb z{`UHG!?wad_Ar1-IxJ{{D-irBYD0!wxAxMYWvn(;P$Csk^ zD=3|m%5;Jw4(wDLDuLT!Cx-0q@s47;+5vvZ%_k(e;lAp|u^ao_-CJj9I6M^&#sFMg#U~Se2{hI*hqC#wDk6_yWQjR{2odCpWk0vxi>(B2pE!W zEb|9iVLq~frP%$Rw_7x7Hf)!!V;2*|N1N~Sn~OgwK-tkqP{{|%pYolN^^eiQuua)| z`NommCW)&`i%Nc^9Ba=$YnI{>XPo_*P^2f8RE#P*tyqvgw2-C#h#f;<%|n`mE;*&9 zaP)D%lMZebv|^5R{!fOMr(KI`~jNWOQQfvuvWQJZO5$+#<(gZJvC_%nIKkCedfoK^4ya;Xpk$O_d{|^yFO{UO_(VxSanhk5l3&qn}HpOIRW@a_T!O7LqPR^QrIppSRSPdLQ>`n2dz4ZI& z=&xOI(kukJB^pgm!4;=1!%WA!CJfk>uN}!O*;#b_C=ltdJQL)fuoRNPI_gZtmIZrt z7lfi-cVmtaAT3o~lc~0Ct8g)t)u0N3BSB5q;VV0DH^&cgA zYz{azvkSIeaW#3@%UW0Hk-fzK2uWguHz2P&eIfzYhhZ_tj0+LWxhB;BE*>-&sKQosIF(dQ<`*x#g_>%D_Q;vwt5(u7P06k85-F)!6bEz{E1oipI zyo6g{PrNJ+S<0W#o2R?jk3T7lFb4CNp{wM{+mfM|{Wpzm;$73PJF2ar<8IAvP&1&q z)8m2Ec-%4@Y^QtzgkXF+uWZ&VN5c9K#nGm51Cu11! zTpO+7!~^%~1%GQr)U^Q@X`RhD{!*r-WMwqUdeo`9L5#%U*3AxT(KHTCzwfdo`(u9a z=P14>nPib5{j{eq`1wQ}JefgM`=|CB!KTpR5q&%mN;EIEE0eVg&eRO0O%#7mj&-;V zll|nYWYhgAt$dl3+R1td-=`;1tjoX8CktD;Y_Csr!}w+Ltm5jzXUAPXzc#okAe;#L zBfi!IjNrmP9;I>bIIssnQ>9AA$V?Bg)c4NJ( zoR@vMiV5iJY&jjQ{s{7^_Jzpf*&y)?K(nK`Pn$(ZA(4#z+nE2YQ%^@qK?kz#&|;7t zn{%GMnuWRZ({{iIk^kMs&hARjI~H*BvIpihU%V8W&7dZ(t^1u2?#am5ii;}^?vIOM zG^a~loEfc$R-RLujGo%@cB6`6kw{SqT*J%?Z1AP^86(N0IAdX|cI%SUXIRpxV&nBk zO$6vE#UZcNgsr#apm*EcYQpf8S0Hy;3Q?!Y%GmWG)S*OB`((WPlpY`HMQ_$eIVBo+ zS;R(Tq($jXVa(;o-7q63dtQ4Ht>`K_!=%?7za-L) zj6cHC7T+`W#vdEEBXqZ)I@8siw-PLM)Djwqr2XmVU@$(9OlNXFBs0OPfd=X1L&;v3 z)O_v~`F`&ASTmR+>wY-fUzAV&0PL*5%mO2Ihx_Z9|I!PBzoGmLw>)U@;#x#n$DmHiTM&q9z4}H^^K`yF2)OBUVKmF$nBkY>7Gw7hgroeqY}wiS7XW+MaKwRupQFyG zCFd*|OcxNlo;iCEPNZGdcF+P%^SM2@U4N=Yc))N#pMe4&K=n{W^%p$d^1r%@%O@_Y&HY<&p98YA!N+XS|X;^9}>Eop+< zb_t1v&_GSD!EC=W8ZkIW z&h01)`se2h;D|8y4JZ_rJ^uRXb%Mw8kd!=Cd-Nr{yt5ilOV{F-?JH5X=|LuiY~+$5 z?Mrq~)(3r)x~>U!4Ii`9A@^#-s=Gz#c{{LM)j&8f8RU)_`PO}HysHNADOMX2=9r9) z@3N+D&-i?A_!&X4^Hb$2bat{Cit&?IX(L+)A_~1e@>fqJN@aQx%2Cv^eP$4fKsy&a z|Gi&cZz2RGlyWl>k{H7w%kPx|LoyDa;ec=i{ue#l%u*w#8pQyEEqrGLv1kMBYV_tc z*b^{?3%=NWo`Iy^_J7II-tA<;Tgblx`}~V6{pYr`6 z%vBi$y%CMu2+!5}q!}HHdMJ?9DG{f}@Wo1XUNFBIZfz}|J!cMiJnjk`FOg`Ik^y$RJjrKN z5Hd)wnw7Qy;YU-ey)nPCl3GkvBxmw{rWkfjG6TJe(5Nxt&|xwv#6$Thlnc^tI1RAw zH#JIbG>yq$Gvc;cFJm#h@cxCx#2_c=>cmMiO&P{GCeWK13F8W2jl@_?O@=IHezD;! zYTGNozO@i@m7P8ZNrj&*#qUr2QehS#;x^Z5w~+Rk99Oz!k!2kOWz#;h3N@wA;M-;C z>Uh<-_^)p3&}wcp>!VH=1(1Zn8<|W~D3^e29BAmSwf&pF`W#VQKJ!=Pj$xdq7CnDS zev#hVDeg)r=R9wo;9-EQmMmqVOO;2m@j3;%5PSwff0~s((kN)bJJ0^+U&QL{IK+b? zQV%ez(T+agJuMYi?Jpep_ok2@dsEE zj=M&#j$jQ1UJ-Dz7yvqP&K(eO8v>mgpw#}%f9~Zewuj1IlDHs9kzwD(&2(thYk!?2>AC zu_ljtvw9Gr=>pIH6O@K~nmzB({|HJa|2p+56;LB@E8K94ZE1-{kvY;c;Ot;9HSl_$ zuWP@2?Yx7@W;Y*FgwLkjrKz`|rc?Djmj89mi5nJy3!W*0u7yUrXZfWyw#p(Pxtxi| zm^kNwo+kXHKf!je*Fr2Mm$^Mrk_?sjVQtnxH0J6f37MI#RS=~e0lke>%VxUwHJ5d$ z%J$R%=SOT*I3fW{blF&v>VT@8gSU!UJ8G{LZ@{4dstbL17ABftm`tB_dt8amv?ccY z8rJm>hm=+nYmKz!>%<#yNtY`~=mb&4JRnc~kJfYzg^u_2jvNP&A{wpGA{h&InOLXw;n-jXN)>M;9F7<}nwEX7l+4V}u(XA^(1+EiqQ?{%h zP2Zf(#-Zc6A=2zJHI$%&Y0H{j-44pCL&w;k5^DfB0y>sj?X0l{@sD53+wvHz&YSH4 zQY^Lp)?-5+vZIYiQ)MYfY^I+J5%=#KkVy8~+`Is|q|jG?Jr&#|EpE(w&FP9DUbM1$ zwuA>>Z7np$CKS=5S! za~&jFr`0JYoh#;}!=bh%+fQA&y8DGn0)pe}jeKi>nDt+#ci+O^PoGNt2Vtfe`bU1e zUw;h$Qy~9yV;*apQ1Yhw1DfPU4z}O8V___2;1ShDh_9D_9$HEp1z#VU+>i zmm*N--GAEx-V9JY9~XBgAIsHXL=)X@+Nc|v9&fanzfl?KTz3B<5(Q2X3!X-|7m~`( z&#w#$xtuw6X`UjG2aFs>#LOi;OVDsDdkTMIm6;M&Mh?YbdFH3Jy8!d%Z8*L{D2pl1UfvPwS$o` zqJmg+z?k{zz1j#1766bcA$b^ag+`XnVxhSHen_oTO~Ww-V(6{Q&r{7AHodlIot zz4%9b!ynne{5|TT~q_HpjHmkRG)FNpQ9i8 z5gnJ?oG?p19K78TZTNPU_IO|89~8RvEe5wo`OEo`#e1<6@|Ai}MVqk(~zLT=tWq}(1}G`^Di$yG+5yoLT5DpT*5bPE_Nnl8&wM}GN+}hQnVmS1xt?E zv(nI+$l?7(1{=TQjdoUVt|G@u>r+|q)^ObWKX+iRE^kjXte}^1{m0RM*@+|YNd{u> zy}N7mPs3JeNwHs%AQ%($#D9LuY3wI2U2OUJYb;t_Eu$FgQt%ZXR*xm-OTf^_giq#q z4!jTL*Yt-DdtKBH>94Yajw=eGyRR+ENX;ce4j!GaJ_gxbz&x3^$KgEryXDJCXZ(V@ z!OVX3#^}ZkpPPQPbIj_cL+zR!z$tii_(3X}vYDuTYp1_6?!P9FZ36$>JpjoRP6A~) z$3<4td(@$JzOB2o=PraWjakV|+3YQj99LX0Bpl!rbZ~HR0>Vqcvr)To?=2{X*?<@+ zJ&;~z_Z>bx&8WA2dg*%d05Ka5)sS&{+_nf9E7#R0By$+potLrarh{XHXkCxlZq#%O zWrW{5qk_I7Z~)dTX?2SOEml8Sgvo{9ddbm{$C1gnNvtR5=LCb{@w@szCZc88<^TC? zxFL7^UZCTNg!)(Fzy6P>0gQe@gr&j8_ad2&g3!#x!Y@*2xjBPjQtG&%yT-6gDGa0N z8c;;2vU?VC44@__jyco8#BLOR=)iSK=}~5b(Vm2y6)|$lf)#o>5q-T)>*<{ldPWuc z7@Bb^>$R3A&}wdKtYd@+xm?}CS~r>*mvar?KRA}YZo53MQPiplMdwh7@@y4R$}N3v zh#)aJ2($`rDaeCLww<@xM2`j~O4j(}4wL6f^}!d<2sg)YLvWtfKpz@s@UJPmpioeH zqORic&&I|M;hP4^B9KZ9;*x(uc-d@mD@}}JT7NC42?5nQAUf?*N3sP!-$^s@^m;*x zhe28I)|wMfIaC>qhE3iw<_t3|8^NYKHs6CMWFpLUGDi+2wCGeyu8)~p1kLccLy?C( z86diD!F9wJ@+HOKdI`sJqi;4UiHKR{y`-PSB#g9$Saj;$a;NBz&BTj1l$!M+ViIL! zBWTdGU5)Oem<8=1tFat%8V6>R|2t=qau+Y_B5aTnj_)LG@#L0Ni zHo5K?qUhBVX6N^1Ueo4zK@ef88L}A(lUuH^Wzg*;C^u;U|2a%z&PZc55 znEw{R?!MGO^B=OGiGtyb{h!b+KH!Pvf1FR(_wC`sLzsxk5su#vj@r9zmspCSZ8XH? zeLr)0iUjm{caFw%2wJwzoeXiRV_^$R?$t_&b+|s?Wl{Qk3k}_a(}9s|F%bWpcYi%f z@j!PJ`GuOp3^sKTYiV<4{0UwP-w!YP^vf8uE3E@}0hg`lSaMQC2x>7l;1{T?{~5J3 z3~@6TWFFb?QmOrg_V_VOmO-6 zoqt3&*5%FDcE;<_xBq7Fc1vRTE$gUUpGwhd`H2AIjKM%UId2<`9zwo9=QBhpy_YN3Y1 zWrR7Mf|e_HP>kdEUtn(Zk2PPEbd3k%0{@;9U57Kq$O;ncypl+gRFxDqS%yy#N)y3b{HF1bYVk0lOg)D9iawe=8X%Z_9$}2n z$y@OVbe1Fs$!RH;w%&Jg8U;4{3zzT;Dr3l$^ zgrsl>5HZlV2=TjG@(59od?)t}~#yzt=p0taM@U z>&>a-V2ySUhOP~Y{6^26vls8pGgB5;)M7#euY8gkjildKYGmyWKQ1-s6}rBvgtc!u zP{H>n%H8Gp5M6VO|>TyvXIg%bsTjV3o9X?Sp4LZq7AC}hp zhMU0xfNYd+8=WF|SYro1u0Vc>ifv}zpIy&GUF~Y@j(pcvklx0#qZVkivA@r13Y<9R5_x=P{>lfk}Si@gWm52Lu`G! zbY@qDZ6D>A=5h^eI$w>2OM5vHPR31YJ>sTx?+A{WErgNI1Ge4lx_jEx?DBJazXcZl zSa4^Uvm8U4=U~kXrd5g%&PCG>gw=&D4G9iS<$NvX@Tl~tHuxcn5SaZb^(9(+V8Pc!r>+ekZG6r0w+mAsPKCdD!_KK$U;?}J^AkgT!OC9e`IxW)X7N1~ zNLfV2!GZi+$j~2LBVw1E?S4g&bVko|wIA&hITcP5@PYtRd(cgLQV&P%icD!#IqZsX zyS;Gx5&t+OpriyiUfujXRRz9KMdYX;N?*^*ZjbHx?@cQG^vVHMYhZlh&vBfyKz|8P zBPhMVwnmJN&(k=1E+68BKilDE|K4F{v|s}^f^8TXg+N9-_>vB{Bk+W**!@97Nan%C zH;BqQ8!1d%En4npR3|J|80xF(yg~-;6h{>)MdUk)@2`NyXd#^mC~UA4)J2gn44^&gud zLhLImSzw>SUkAxpkGs=fIEaaVXvK2HfWkigpdo?{i2maDB;p){7Gt81e(HLLPn9;@ zSEd4m2#p*Mp)G(-3 z!fE81OjWz|jg`^G#Ti!Q_Ju;;PT3(2LX0I={8{r!gxA8g1)DeU;Mux#(a~+{Hu1&D z^V(C{jo!*H_u>47P=z!F^3mSjBC|8(cJf#1ygf08i^eV7r^csZ4cPiqDG(vPBr6jc zX#UZd(g{(TM789l=Gyzbp~hFAcBUwY$7;-!OFonIxV~CNdxS>-V~7z$2-x>MHp7T+!_~Pu zhk!yQemfN-g2T#2n-#VE%hg#Xk;?ZWGWub_Zr9`HW{0b*Ydn2=g<k-@EdY) z-pxWb^421W)|fT>r9LY;0=$!wHULbqA#G)4yx@aFg1`@lmO1T|5_l>>js=L7=?>Gz zP;3xO{*<#DE@B9nnc2zZ;CPA=jv}0DIgC%(B9VQA0j&mOlaq5^GGC*RcTJ--v&2<^$l_uw^HTY4#jRl3Rc^_8w0=y)_bGUyg|_5<#gMf^%t*;P02Kz9 z6lh7}08bu-h!{s$Y*Pp$#&O8jEGPREd99I1*P^xUChg~hCT960o3NCHB|ByiAg3)S1z<9B#e0=8ViYju6iiTn zi_2vR7OgM`#$k<4wN4m#BIn?kw7xF`A;6K>#1LX-0~k(|a7dAG()X+JU(ARhf*jzZ z`2DkY2^ZQJi${~wF=T*+4}l1dJkml#e$_FC%-WKyK|plbMN(0YT^V!EM)?#Wre_l0 z|3HKQATY2W0vg|lz?(c7S#M;=A-sqjCjoU1{;)V6 z01EIn{amNt_FiJ3hG9f#99&BZo;e)EwzGcBV zQZAPP<#)h*?booNCX*d(EXEL|NIjG6?<{+?xE}5k@Jyv~nnuREw2T!uGwI9bWa<|w zuyPLjal~#Muw_PIplw8kmrCYu%JaHxh+Qvpi=)IYkHdi7 z%?)Q0AsJ$H9T%JSo^^u?B`N`@x&T6d|dli#{r<$x2=jZ2e&f)6n3j6&Y zwdJWapP#zP)mDdNub%=dRyQ_zfsTz40?zvkV4^K_U_8;>%q*Z~BETmBLIh+f7|4}{ zp=1`qFrzLY7Rep})IXUuX32pfrQ(Fy)7-`>Usul)=Opf_?<0os8lQgtIl4`UP1E4) ze1r4zb40Zz$b`@JycQ((8E~q>Q>Nua3v1`kub<9^`X_^@xr^NlNL5dw+X*5^aGb_i zfq@VMVzB;)TmJ2Qf|D|0-exI$)`EXhQY-+FwSloVGH9dvl!Lr|_T6MWZg=lo zQb^V3+I%SiATy_;xxV!XqX1w@C=f7?T@mxtp=nxNZqKmUbl7Y<@wzymAb(jTiX6%O zI*sKSF^)k2vPTFE?=`_gj9_Skc)?R(DL$ti1 zuuf>z&_xrrb;_;H)f31B_6Pz86|Ts%{&L($NIytbcQ9sXnng2b+eRW_3C_Vc9lFke zW5hr}2$Ti=$$z1gbY_A`w62j@V4ggAf-k>(fO~f?u|4nb!3Q5m%Iz2gTslg^O$HQV zlR8RM$vnCK81QrmB-Qav`TX*D-A?g2a&|MD_IhI4pY-3{{Y-nN;K}Z9#p75cLYT8f z>2EI9ss$}n!YR4Wr_AwVXh{e;*oL0YNvov_0Z^VmW|hq9GBZ*kySz-B6ve?je#M@7 zsZXzr;gW(GVo>w~2=oC-7mWSpWNag`sHNewpQC}VD>5Yn|qUe-*lAup}zKrOhg&;3^+jIG_{P1x|4`u19Z(*il?;22(n3 z%%XhieWNNg%r$V|_t^A3eB;pgI?2t8dERFwQ`%YWtKDvoo81kbUR~k)r{ClH>Ke>Y z*G+==4H_TBb#wF>8jr>cc(U>w&f6{~%~tDuwd%t9*GsG5$u#Rk zgza{l(jX3+wT>tYk@*`4^h4X-Gp))Fxw z1x~IIMZqR`itu0sG#L_)#ZiQez~Tpu7y&05aPNUJm_Kv|Pf`C%ThQW$YZ~8ttly9L z`s;7-+2^0bw}j1RgSX#)TeV0T!~umSC1y{)8uTnBZ-}OuFOoMH)%61EYp3nRmGff) zPca&9j~eGh6Q-$NBa=;9erL;3J$ItIVwg6koQq|@h$OqyFisO&l$F+}v065D@=ICU zsORtUcHmmJQ-3~a?Xfq`BADyjN7NWVat@_is{ufQSX)J4Vz~5`x}sEC+uGW;W^sEK zYxODQoXhJMBrY<^?Z#X#p%z(^BA~>AS=fPG)V1RC__5AWmN+R>mdH5B_$1z=LYp&Q zq2EDODT#-Wfhl=IW+98|aSd=mU3YUL5TrH4HQh*%ZsBDxR=`abg$PW z5FR@ACX%_{HBF1A>5{8m2-zwh)%p&7_oRZTDZdB+7cP3GMWjr=FmaVDT#W0irxuHy zYw^ro-9$k+&Azr&G&i-4QXxRI^W<|*kzQu@tHF)kzwC3}*7RIbK9e(hmgm%;m%!B0 zc}sKOej5m0Ixod_Ej-t&pxGW=C_fD})v`nVQ+Ac7jW6EQET@vq(V_2$n3$A0K>v)keN<{DSm*Xa8J&UXiaAxOei0i$ zZGBkN8r1g^Ye1pJwRj%Yf{k3d8mZ8M(>7=(3&4h|k(~&U5FtxLxkb<-U6(3MMo18+ zFakAuI|zW%%_YW&I7kwS7&T9SAcSOfDnO3OX*G7F>2DjR7=b5GuJC#M98F8Oyu3sR z0r&3R#o5_*qP1hwWUq|Sq0K+vZ$2NEv`F>eOBSdpaHHzD`R3;Y5@He%0ay}klrDN& z_%()Ef(Oph>7@T9m?|?h3KK$7D%iQT|GxEq4Jf=Q(6FSHJ*3QFib>EGYYJ5OR;0w5 z`X6RxDJ-ANAViVMy|myWPm~dBmZ#TEGA4kzlL=B(i-|tIBp7p|s8ByR)7lxyx`p_{ zMTsx6p-wKEiRTzYko6xKYJD`)uzDseaYrogD<@djYrF$B z4cfB}yk?Lb#sRw!FfxEqT?)xI!3ZFNLV%+viEVU)lp0uog*G^ik58Md36a`c;geG4 z!OlzLXsRG)<;$et@x^Yt_53UUepBXVP4yaj-4tVlQ!7Q=TJdPztA+t#l-N(_2#tYN zKr>LV@{qYQZf*Rj*w9J=-hhtrWsAiY4R}+vQIFrW9X&EVrvN+aL%$AG7SBErcucxO zQ_It#`<3^p$F>G|nq$`U*qQb8vT9%0cd=qOOSOrN_fH;B8C{y zh9+kf_7UC(IPcJSOKKy^zsBp_!c?iuoY&e9MH%!WX%#$~cEu)8(=<3gKL=D3zuWC5 z+Pzb$WDKU=uLbNweUlH0D3Sm#pXDW6?H2tZB<<)a#6*+8F=7cS4=mC{(r$C9lC{FB zy5M1xPTcaw7!YDa3{f(nAR+{odQ1^0%5Nskay=|*2o}JU@wpIy@1N}O%{O1;%P+sw zH0CWfn+_<1;@r?wW3}`%{XV~savmIa?bPyAp93rbvU&gV0FVm)mK1^!0%II|_1Uju z^QQMQ7d<1}pwrxptUkU|L7>!zPO?a*-j?rXeg4(sbnJD{a-Q7J@&%bNu1W}s;-;g* zxXAP@0&@98Z2#PT&(|fW%CnX8QjQy@5kW5iEZOt8wD6V!i?ghJK+c#)uneHmPIezo z);jP?*Cq=Xka5H$cC`Y~X; zX@EvzoyZZw01%wSS0ZOwL<;#8#gJo&-#crNGK&Szvsv;qF$5J;La#69#u{I@BnVu- zpchCl3P9Cu*s+%-G`!3;Q}bE*oE3GMw-UVbXuA%Z%?93k3<_GpI3lWI$&?1FlbDN@ zNpM@619JsX`mY8(l$B{>eF|urxyMSzV21(EZPuo2VG0M|$Lu}}_q~k{oqCGZw0@3y zo|XWsw(8k=O=YQjt;ziwm1ybh}J!8)-NwF)A?n5$Qr_5)11_s zm`(n=enHuG%>V!Zq0kf1^mUnIsTKmNr;5rQ}5LwC4Z- zXMjoGIf0n>f?Y39G>m~5Cb}xe?W(kUs zCzc~=pD>1)3dHUAJ$AcmEfDPB8&aR{20#F@2SGMQa|0>+U=}7KX_wI=C z3`e5ru_{7H&tkvJ4PYtOYiYwTsoory=I;C=PQQte#!g~f3~@7{^~TB?z1}-h0cfY? zGi%&Wag){Cp8^VBlt9V|;F#kL<-sXg%h*!>tMDEIz>W-~2&7;s*eRPW1MJ{k132ra zrOVH2k2U!Qpb8wy>G3VG1b_sf09COtl7>)D%OH-R>5^@H?6~n!5?816F3E#6$a(Ao zMn3`sw3{v3p~ukg70{90JrzqPC;gWc#?mQA0LaVzwDz4>0XIa+T!ti++2hCAlvomk z(=#0@T%ST~+W&HnosxyG?#o1QxMjUAU3YBzHBWffp!J$J+Z^U7^B|(+#}VGO>ay1) zL5X7&@ML={TuL+pR-Qnr%whmBds@_cc>P|8v=Ap#QXbSYgSq!xd`jDT#8}o|%F4XD zC~o52r3!+kZgwSq&uvcQkCv=46RS?uUdgM=^YV8<3E-C6HLAUHtWA5~@_2pC67Zj_ z5mgj9%-_qa08d1el2@cL!*s6L{_iv{)vjTNT8YNAFA>oMJeARzHF#>A)B0HAhT3?K z^X)kRQOvXBG^bzYP}p1rrYuqTJP^i^WSqX=i}k4=u-o?-V}$QKh#K@EYUqf??%H#c z?*Ae?JI4qv!i50KM(jMnIVreo84sg^%4W6r@#rpuf(oLq0M6CD#l?GRbq_tU2%zWVAb z+`W4@6__)#v~4u@u!n%qTzfSg!`prU%z#q;-b*l*H?b@*Naj2R$1FfL1l2l)fZcwO z0)YJ|B^@ z#}MUI$tVN>$rPxdI|&?;U!RBo=MiJTFa$K7&^nK<-JtgY92i8oUXCTqU^X6>5ws^! zqREg-nm&#qBr*UWNmBYl?oR-Q7-2zD7F=wpHH@OBf2DM^Iypx9pcrzmg#u!HQqg25bt(yt|5-t$|t&?NVXZMr- zNz2DZA+WrbYg})>w{2QA&?-MKuSEmPGB>2pOXtWh z2ThQY4(Itd>xT+X_V=nXq5#XUmgUZQ1(E6@6L>L>p}~xyO|Kgx!Z5&b zgSKt3={gMEh!_Zf2Uy*Ri#S2KiC2reFr{F?jisohi!w(9z7aeFAl6!FBs{ECjx0Qr z9b+5wmozJm-J5P(OSO_`>AIImC6BE8_CkmX{^uRqwn3})T!uI*-!<^G{I+DTv@tQE ze7eWid(L$H=CVQkUQFhY*ry&bwmKF%ldAV2dtrT?6>J&kw|gxQOnrQ*Z~5pBSO3PXc`Z%nL@MYiFt~sLTnhIp2YHP`6xw! z*b+Q3iA8lBN3^Zg#u~8O?a}uGnzlh(0EO2HpvG~;&CLyNZf>x@*-2sC>uc=$K^2Cy zu-hRW5jXMtZB*HkRjwLF$x7?J!zh9)+QwnuwP>3Loo_^5@(rk|=J8(pzrPiZd zxTdA+x(?gzHkru2qrpDl^*Lw)rHD8#Ed~ z5QE$&l4k1CoO{d&ECT&Fh%g>FTWHh+Cd&^bX~l_1T%fd=uiQ6l$f+#qqEB|r;$;Rl zn+6|#^gcfRHjanf@Rr&r&tJ;?6V8(Dem|%dWRQyEy=0pih5`GYF$^lyPzG2riW#05*zI<3PTlvYfh!9A)th;_={P|{ zU}P{gop;kY15m2SUHhxo7TtR8FSU7So}MO5mCV21xNVINP=r6^Btru6BLW!<_NJw z5tD4(iC+b^&g*)wsWpm`{&^nLv?G{my zSBM@%7=eLP>|Yu?GJZ)2YAFgfWrFkzc;C-MndihA zKbZ8l08J*uzsmlt{e5a%^^bv_G>0L3eAjhw-izz`IAE|i&|B`2cp#a(SRT8YKa`5p z9Ak<_L9FDv2A;fksxa#`o%%d}sbmEvFk9dBfvbMkz$be`)O*9yaVqase4h70~&kftcSl+C<^-2UR|R?E|DvFKv<-s9}-Y*JM8 zS*cu!Cf-|x0Kc@^E`3*9lV)Ix%M`X#fKXIaz>O6OcLUh-|(w~6#Ixu?z2$+49_*mun9mZz7qLEA!R03J|HvVf(S z&M>FhoXTAMzmtHk`vNP-NzbYlpX8QCq{djtPvs@n( zkz6OWx55+T9LISRG!ST6%pFNUa10SlBb=ASF(IgHFayo#&=6tJwKwN4&@7;$;9(|s zRh)?HUWC)nkpsMoU=EAIW;q9R0zMZQIF=3p`tqEm^VWpP*Fmr1zT`!4wK_lJ5L8%| z?0V(mEk`DK$B}_C=p=MG!|cQbYZ{}I!019vL;GBUr?QCoFbtYK%+Kar(gjos6-!uB z0;a|BSo!XlYnEi0^0+C157C-J>ezlAQm{<`6U{A8uX3K(Jfdw|G`_*G+oS8GXzzBr zMc3^yjsfGa%WRW5#Va9Z)p@j}TQU)oq98q$GbL7p?e^YzQLt)~ou+Bh9xmhYYLq4= znUW(>IkyQaT-x|W$UXk#i~<_$?U-{>9`CsorDXn=vCih7 z#iYcTQM4oy$Z6LT*d!CE1@INR%qg!+{VKpy@&zsD3BV|QpiQtTv;!qE3An zGSAgEd&*}1(p7l0{FmOFAZv?2X`T~1gED%Nt-B1497*y9b_Tj8=`=)1pnoT~Akw5R zI^LcgqVl3~ELKeJq&Wlv5a43MC^NLy7Nrsl$-R(t7ITE7C~kG+<^E)D(V}_eSjOr} z(Zf~)Dg(!)$u(XaI0Dg5xkSi_TD>qk}NivuVg^TL@*;e zCFYsOV4FDW2%b6rC#TPOKV4YiGmNO^H{4T<$~EoZ-A)BW#4k7Yg&~F)`iqFQ*IXRFsjeC zeu~#n9=B&AeMn|b?U!v)diFdXhv%9p&}{!H-beMj>ct|J>r9ewax-g%uHFF@I2+VdG` z)_$!tZ*qle99;ANviE0QlH*94DEJA$Mb*sQBQi6xyQ`{icXj3T{Qti*XXa_ny>n~J z%y4%zT}T2l4*~&%AgHG1ODvgzI3A`-l}R7q3>i|R2iiuF~qr6WK>~2 z1zeHJHe@+{+Itb;0K^b6xfz#JhoO&{C&sc!CS#S=)@0GHzHR#@DWSf!-2_ifX2Hd@ z?wm`O49dwP=6TMr8Or_Bx75G>iJz{R4KL z6*3dTvPky3G!Rm5NNV&f91(~SDG7f#fZ*VJCmKk#Br;`+kcC=S z0K8q(w=6!Hd8kGYg~H z48)X0GbVQkp+T}R*tz6`FA5Zp13QU_qxt%*C#qOYw!O!~vxkOU<}jX!;83v00}{ z2(tZH1ENaq%0jcbSN?dPWhK+9+5@uUiMPO0%X>&$OoB(>_t{;~`%<4s=0oB}m4=GK z)Cfhq9<fH>~?WegBnkh+30Uc3-i0 z6k&wAq}g&34;4d7t9|zhKvlVr)dJ1F|cG3TP3Zq6UODk zicmBJ5zCx()?02t7Fev-xCcBud@OsZ>$~*cF`LV|5o>YF9phUOuD4j1?|tsiqv0|t;F{CBBSN8-YLo%9ccAktbbH+;Un!t88)ak$Vn`r%owjy00(zZUw-)#+kY*N;<+u~ea(2sAd`=Scr14#l^tv%F zm>r?_4&DKscj&x>^BqKBHW@ArE&r{3eyf2~t-#1U05CL#bF2rawaB5kfo>s13-2ov%EVelUV=R@L~nMNPxKWl2GUI_<-Z_s2AmHbRGXxjjHE6l8o0O$uQSx z!u+tH_Xk|A7mWQG=j#QR%N3NY#7hb*5n~i30Pa>(W>b&LXH^~$a%QnCY*VHiD@8EM z{`&Pnp|`g;gC|Q|EP&D$lGVVbf4%3P+G@h8zgxnrO+%>3Ab6)lIwbG}%1oM^6RjE6 zgj=mzZykr!wn>o zKl~AoPY+obD?-(pfo8x9aZ_w1jHqLD#QMQI-vvMkcvXO>@k~p0^PDD0e<^=wNwN_F z=6S+A2VAZf%*za|E?xqB4Qnz?$-YYqNN7Jp2yo1p!jc6B)mCb@$6D)a$6k-O&QZld zi>cbCYtDkGd@ccC8vwfnDMeVQ1$S=l(XZKRg~pcvs9#JYb){6%Q0F2gjbH+k=JF=v zabecH!Lu?ZX+GpEM3!R1q@@j1`^_a7UH^$dU}H&(q5~)z(3mp-YF5haJP3$VkZy!& zn;2rJt@Z-S9%Ap|Q;dLWEJG}c6#}IMILT*OX+U61aY9Ex>^zvo(k053zkzl13u=27 zr>)Y0GsunU_ZR}g5Q^`$5fL+&sDqHszqqdfw>5b%+uDeOd)?J~WKDl%G zZNi2O;I^52ok?a=|I3f6=qCZ2_iSBLEIP=aSIXE1xVg3F_xiPW?yc|lx7Y?wKT}i4 zIF2KZ$3wO{b(%t-HAXly=Usrq+@g7fE)u2qonmy&$wP^EXxc{?u8f;%=?yiE9EpoOx^~*+gcT& zGGv5`-c+sgzlZi_@YE{ssQ}6fuh;7}3!;0iMHFhmH&zV3o+JfMig?wW&Q$z`$rme? zYVYg1JGThj?fw(g@}wFM@x^xVoPrghAg8+Tn>Qon*e7{*0WQut{O)((<4=G36aMt4 zKjDWz{vN|&SZVfb5m)=(`d#ZIyat}~aS$|oN3Biy-b|8`J&HDcnkMm`PiZzU*Q->< zK3_4-vs9~(w3;6VXHcVnN#?(dB@rd}5Y4z#`h1I-)bC?mQSI;RwYPq5y-sWJ!i3d# zU~6frGx6nXtMRvURjj5HP=KTbFH`IzP%Jah zHNct(FMW5JHWYy>#Rw+XPn(@c$Ic3X-g|`LQSVOxSe9VU6XCH-e^oe8g+j3ao7dDn z#ad`h|3unt?4Oe93{DCsI{=)lwoA(V6k`MeV~J6BEehHUKx72yI(F!MK<7OAZe4hK z6^GIUh4)SC-(#z3hW%{m$m$ph$mbBSOjFiGXKTI%;D*N5fTdRSwC2h_+tSDkzH53# zrKm4agmdDeHwRA*JRvDr9EXOt57_a)>>i@mq$$~VI1vslXV5n3E$ z=3@D|>Qw|rOyG%niB;`;kACRU4<3E;;?j(&Rwg2~I{gBc&bMxF22V~|vZ*&l{s zCHUE*qpkbAwy`bI*S007<)bGD=hXaqNW`{e(n4g+$qJ)pUMsAwi1#afE594d6ASZE z;YR>OM4(u0*e`2Va8Gg$e)!>g{L8=m3;y({|AilZ_&we|J;8aBAYbiX^^V(r0)m*a z^SPW;o~`p;0I3CA;(~X<`FzGS&$wJBoK7c9(<~YEu5&6%MZBAcIrQCk#>mcdPFbJ& zc9Fk(E6=zN#u&%Dk}Cf~pH z*4c$-wKRJh@g|UgWZ-*vct8jN=kqyd;oE4Ib{24bT+gj70a??70$6ksog;Le)>?6h z91xcvKt`<^jSaT{-n{v2&M4?x-BijivcV&RW60XKH35FR^-24oses?Vf5LzN@BbbD z{LlXjfB3^6&=39Q9crO^FO@i%V>;$m2rqL;@Sbw|SslL+QazAa>M&g{Qp`;%Vqb7N zU$KNmb^8#-xPvCIU=Tpgj7wa-gFaiCF~=0+6au0d-}?P6gUj=rY9=gceW{hJUSo1h z$89T+==pYBmt}$LLWjA!}$ zC5(IT`Fr=Q=i#;E?fZ&rnQn2B4+%gJ(8Pc^sWB)*l14D6ngB?Fx0IP2Bh6j^&hwsWS&4D{NGIDv!}MLMa*Lc5JdPXr;U=F00ib z=XY>KfRoh1Aw==m;~-XLMov>oK7hcok4YjvBCj>|+LO1_$KRT^T5#94J*L|Dl$aoj z%V|`lmRuwWlmHZ0qV@h#rJ)5*D&Q{5wBq4=z(ej#d0nmF2N3IL+bvs_O%@Qn)><)7 zueFvUtkv22J?&@rM&Y~Fzt(3<^X{d8U*2q5>~`D8TG;lp^m7J;r{*G#jL>F^&VymkTb}0n_DzX_Df<%MzqkX-IsGl+LRWfYA3I<3T`cKR9%~7x3!t z*av^Zt+Vkkx*)|A=$nI5YnQAbsKjv?20T4I<>R#rpWeT3F&aG%0})@xJd7W(k7T3)0!*hG#Ok z)fx}`nL#K;2N{6F)6)a~=l}d4_@{sRC;ah`f5f|YPf19L2w~m-8Z=puBtWF(o(wT$ zcQ`xtrJn$^+a!9pUazugQw8kv`HbsTGQi9sh1?TCHSrRRsOh1L&?LjeC_JVFAIrO> zH0bK8r*O>7V?BSHIZce%f<(KX*Vod9XLG^}Mk zS!Sqxm-D?>iy*I_&n%gVYS3gA5Oxgo`t`HY7;`&XZy%f%x0hDCM|lEZ)lb{@?%Sdx z%{4&f*<78gg1P`6P6c80{1jQq0JIWFbO{)x(gz^PxCaG2X)MSA$-RN0**dGal}^|f zN~>A4>-x{-cM|6aRknMlHApy>4-mrV$mM=)X{rPb=kZtx8!4k-UUTdI=57L;`S$7k zI!_3c_Jf|y$gX};%StSLbCBN#?~^Ntx`CEGygRGQeNvt zu>^n#POYkx3NuquvQ_+3d9u1wDZNpedbz}vw?`|6S^FgWv!+!^!I6)Z{%0C$EV4>- zRbkjttdLpXTLspB-&Xx>$U^$v2Gd)>RRq-6=gZ0@wQ~DDV7!0-uh;hPZP$n$)7XeT zvb?C(y3Qvz%|Qy;4g-$IWAZl9L{dmDXCW(*Y#)TT*ga5an99I_D5&)KvIO*f%4(W2 zCVop`x>0SIy-!JYgjpAT*MUfszoF|f^%MH8&lw7@^Mu1;z;GHcoX?ns9@8`?*=$N- z6%ywp?y_QS>iZr~Pfs{L9B~*29FGGubv!xoknndZDgG8)H%(I}ehP5jnmhqm69+30 zDj~gIuX(a>xkj~wQwwhNyAr<;m$dL5dh$7|9xsf@OUYif1aa}gT8OL#$1iS429`yh zKmv)GRsF{iOB!~4>Yf0&dVc_5LP!?0uJ?HN?j8Q?fBkRx$AA1synFwMVeFxa8NiA0 zVXckX|CdB65+N{h5#$L-X^M;Q`xF8$(5h-b%D*(4*nN*&i4;f}zuOB2g3!O&Y^K#DXZ!AD%eKIT9 zF+$qbUV)?pDd4p9&7mKA_`XMsJ;E}B!vc;A#CwlYEga;5W3<;|?%!|iO>GZw?VgWB zi=qH^&w!V_TnLy zNsBhSQcrJB5o*V0?|1tS+LxQkxZEdNt=C)htOh}!L;G&M-RorZz_NKe+@y53{ zPPC}+dmIi2JU%|+>FF#PdsD{U5G+578-A{af_l7FP6d!%0&PvkuhIXvwwOsO!`U%s z-pmRSVd#BwpCq+v9*>x&E3VfI#<9cse8u%TrF8wk>;jw< zBg#0Ac=zrd9*!d(9}gG~9r`}SJCTg>-z#tefbQkx1>Q?FW%XNEq3bQp5=s@^#&OJo zof6J_S_?n{RV|xLSVd^`&ck(*t3OC_63k1=;I=G?ApneA$g$o)-(qu!#x5;r?^Dt# z75>-pJobIoq@Lv*hJ} z%YxH&!t&AYIiP#5 zW*Q2p>^^T<7QSWMBfLKknA2i{z*ay=bHe5`WNS%cnp9_zif&vpL<(?n(Bie!h!ttQ zZvfy?)} z_KegW6W6U|Z8gum$5n5uu-YbwD8IMwbqlNjD2j;cyq0xp?;d-7xdo2C1`zvYH{qX> zb?=DB$478Pa^o8?O-lya)}y435w&}wmRrYhNV1ycjb?)giTb8Zr46eZyYr!#Y1@j^x$#X=AlKqK86gL0@n73B7uPLmlwMqI3P!s^=Qvpr{CoXY0F@oD{=33K{ z8443p9+o`TpFVxUzx~_4rEDl3zyJO3WsFGzx&yBXh7yrF=1IYm)MJTxlQ1(bmkX9< z!R2zvZh4o>1?S5Zr}Guh&o7u$Vv5?IxXzj-#{p%$tO8Ri_$$CtK!Lg+f=fZ*4S1@S zQ*Eu&&rQo7)(l3$s6D@EN!x2j&#|#|0CN0`09soj3!EO1D>9q z(02ol#|In^M_evb;==)#%enC426$@qhlud-aFq3wGWuC?O+<;7zx^HFPJ6h3DB5}= z0F|ha5R1}&0h&_F$sQjc>-E|sFmH9;t2LBL5Uh`Cj1lT4c+b7`vlRw4hG-l|@%01{ z;*5EgjRTgX2f4CxWWaF|fCNE(I}J^eZ8L$?@$?QI9LPmrv6|xcyO+P~--t9Fv0VS@ z(d3nL*a!JV^PLeTil8h~~PQ?hR<({|4EUEh2zD~iK#sS#l+UI$m^IA~LTZtq4cI}rZ z0t{!jrlO1x8J{WKe| zX|{r;@-rn;`AT*wuHqMr29&{~@Jai|cOC$PLpCyrD;SsWc3f;w`D#>%@UtzEUs-D@ z;kGBOzYyXdJ8!Ee7Q#V za`R2zbf>RH%jG^2h}rkO)HhlJ9C-}Gh;cmNdX*$q%mJ6n2|3d;6@|1~=gT~6tvxyK za2RnoNIj`>91}qBC^aU30@D*@=t#t|GAoG&ME3|MA~^I2KIh;qyVGjcS* z-m~A_YGJ6}Txkr7>#B-Gc2HJAUFwenkqa1bBy@QpMOLQ5uNYw z{{4FlooE_BjE%7*3G_j=ye_#qE(@;HjIabaIGoNWeE9GIFQ=0LsFe6YQjE)3CmR^Z zl~|sb(u|WPMDU66vAQ9x1vb*81k7MwROK!IA`sz{WTh^fmEdH7+8c$cT9Yk=)Fnbm z#SO~nnxX;6Ovx=S1}q$f;APN+5);ER-b)DRB)woF$c5+?F*&8+g)@S%1^VT$b8d&h z>ClvzHK~!&BNJMV@LqypWxq&(tsdhTvBZ#)$+1eq8*8189U5~29lfuqoVd|8``8M9 zrbC5s>UldMZxH}uxhBe%hKKB}RIM0D&b+yQc9aqw*tB0UbH9f_)mFlLuP=%yRS2X^r)jPu zGa>^arX(szDh4i^00lT|6=$RvBuHR6NHSE4n~#H9@GYRoF?PxOrB8}D5niopUBr0k zaX5@{1Po(`zIW(*2O+(}D+C-Vedm0w044EKX^lk>syEpkfGL&?pKJe(ikJBPj-Mege-F>>^y@cy)}HJ3owIY~g# z4d{G_u2)c*BUY0LOIhaGyujZ`%dD1xPBoXRftIwQ%O)#W_D$X)#CzHiy@xHLtIumS zYhu;7sc{@LXwv-t@_hi78GYw4_B}r0BhKe@x{pU#b(Qm?xM#Cw!f383#4-`aY)jP~ z_vv?KDj<*(0n4TARjQ2*ETMowV|kE@XzKQ$l!1-~FvK+OUMNVCyCT35A3vNBL&P|Y zc=z;#<9NUiKm34k9C5y$vcSm98Qg$?C4t%Nbj9g(!sR^SdY*B)TyeRI#p&hc1=s6U zfbSA=Mi%dV%KjzwwK8lZ4>Eu)s`X1jhsuatiq6Sii>91M%CyA-5M_K#mPb2L)l}YM zAhkuzIhQSSA^_B8=<)#VS~PtK$&wmVhC&O5^0UqUxlWVJVb{a?E)ilOaDWIb63%2a znk1uW1%Uhx+xn-g_p1kpsJP>*yO+4?I#c_sL*EB1A;2#Y%MuYG3`3P6+VVKF0cwR~ z=}8-!LG|@F`~P}tF-2z1V_y!g&tEA}HvQxLh0GktrzGf+SiWPjlBlgj_IP@4ms~#6 zF~uyDA0$eZG5`}n?7o!A(oO)ycBU|ShgE0ObE~w=N=qrMG^fg9*XfeiVh*hyB1c+j z8>n8=31APX}Ug{xTLwxL_j{f z6`kG(QnzTP_Wd=lnp@VZqWo??X1B#%C0^bC{HfWmU8TBD8D*1&ory6Vd-(nd^E_jk zuAq)FT_apzjN?PIFYS!EC3U=7U4~)6Fo@e)*L5bLi6}KohU7c=m63byY4z>YYp1+L zqp8wrb&i60WKSLP-}N|*bEy{@v!)B4#NyQXK4sHX%d(wCtF&6X zHtwy*U#higZzw$8pRrmy3vghQ`8bZj``3R><8%Z^;17TN1AN~J=&53I=6S(~4n}Sht#CycTSnfs+arDK)#g zxxL1u)P-f5CO9W91><pK|NKEJ=#TFv&;YF5?qT*oSCtu8C5 z#Ym?3b?yF|3Kmw+`Kj8sepY7gz-ri4Rgzg8#WHW~vcQ%VBc^>-29iPS7D(&~;`g>K zm9jsUduJ`LJ}V+s$3n>^%!(T+gH2T+5WB?i1q$ZT(lyU}S-{@#E)50CFS%KvUccAB zwa&jq1J~AA``N5gLayUypI_6?)xIPBT~dms-VKGbJUR^*kXkI*g-$ zC+9URpig|b%&olNTG3zMo2zOb=-3Y=7S4Izm9 z^9}0)zt(EX_1dhj)_AH*s9pqW*wC1$44y1sPyciu{+ia=w``sDSyb?$!R_zfy~_ip z+LKy~{94n+2&^>=AqkR7tP~vSf>p$?=wBDK^{1Za8NAG37VvdA9I`-bYf1pvFo4f* z!W6dQ)4&DHYtD?Q%tHtVr%LYXZk815ZXH+)tb>x* zMTxNvN^gKCdz=YbgYh}S&K_v8{~WCu`K|RqM5|gNZGgT7hqmduFU9^$`tp==m&o=r zjX`FR_MUCGz1KA9H8a;l7IhKjuIn)jA*UBs`e4sl&*3`z+pWI*np+WK#RB4>XLP^jw?6rjCPd9b(M>$r^11rN8bsRerm5Cg!J_6Q@5g$19o zyVsFpgtF@s@U(qUtMpsf)o1XopR3(e;#7i--EVddZ0$OGUOo5iIZbY=tkqPOQu6n95*8Ar_l>t?L zRE2w3LaC`)J)`M4QQcpyPgbF?{gU;+rr+P9?agv)yNV+J_5PH1Ok-h`GTGwWO8&r{ zV<11LjM3j}%YHn%Xp~qyKR@TiG7Q67>-xrKCrCjK08G=A7r(mX^?fPsRi`}#>U8A+ z4l2O=oYhaWim8UY*2eDjvE6J6V*pl|FHZV;6A`G?pwCe(NKv(3njtIIx_~mG+zZq? zUdxO!N6Y7?9y<9p&5XbP^&>j}ugULMe1ZYafa$}B4>+Apcz%Ayr%#`90*`5$Fi(;o z**OvHEvRULVEw!ioQ$@z{7bGj)wL~cP??kDB89gz4g2gCL(A{h08cH=E(0szWHprb z-1<8GYzs%0dMCn+JMZB;hZvn<#6|dUZXN%mav&jDdhTqkF|>2wR={wVG0ezq_Zu(*0Y)Px_YKaEMZ>@}y9R+5uvyODbtjb1E?oN>lA$ zu(Ia1fVbCLps3yhtM~Yd{C^|l0D#xHK>!hOwiXq&EJzBR2*taJiaRec)Ws}SY<*K7 zzt(#E9N>9xv$VAS*Xo1*W@*=3gv9*W{!Rdr_k#c_SBtb;zQmq*+zu|lWYlIYs(j`DuXtyeU)qAF<(UvZ$aFlh3_l7^I1)|VDq=V@w%;WS$)J)ysmCpipybB4I(9>z{(ER$ zt+CR9ndcdwK7B%r5%1o;!!VAkirM$JdPA?=?vj~M0h$6POOR{fysitO+AC&Ba-rG? z-2}zO=u4QVbs$kjqRfP{_Ma2D$pUsz5P?i|`C)&IB?Q0V!$B z(|2o$s5hBJlb6^nd!N;tRE%r8#qVblwqNx|w+yGYI<@bgn5fAZ`PzD_Q}N0@C8@>| zCM=;xA3H=ic|&jR10%)pDi_1)c0RA_bGVN{VT#t zgmc@>g1O$K@UuWE0JIrycwTXWX}S}icJz867K z^Q85Wt=TGQ5*VRaM&(KXTd+|+uP33n%ok;Y0xY2`Vqqd8IPc)8OWC~SyC_KI8a=n` z`egm0>{)R>pK-ZdR)A71O|>Mx@tgN;^zCm|Sbgi7)@Efv zl^4iSD($>&*^8>We@!=a?3KUW!|#8It))28&n>#p918$0joYtv9KJ={E$BoRRD;E0C*TT%OyiMpvu-1M1j>sNC_!Ga3n4*)3o5nzkUSK z|Aqb_E)dFGPN&nRXsdI;FgSQG!GNR>Otm~DnAkkq3|YjwUQ`*Q?fk!0e#rvmy^N-J3EBe8M%khF zXJqAzsd3tLcVT9LCEKWr06Qf2UbR3m7%s;}r3Y{CBR6Z06=7}U|IAju@8{m*E!XZn zvtGA*LS}tUO|xX)to5k?9RW;Sq0ged)R)ng&nrbuG*0Hx*p596Tbw3ps7>1@B zj|(yB9){%8C6n!kB1L|fM-eQ!&P?KoI^S?^)_yRV_IEzX&y@jA(nfFua8j1t$W zu2zDagjRJ@*)ai7my|*PV;y6-QBqXL*JIKitGBlLx^3Lweb?=^wsLUI^IGp``%?2? zJ2y>bPh^ly!JHINa()nn50$m!oXo3B{72pK*ID-frETJN2NYpdfKum$-w6Ma?4!;( z0aiwdq^ZiC^Y9+|bAAV2X9ZTpt11aK)9)s8aAQncph{(kd0w*Ha*W08u=8HPWdyu) znP=MT_mpjW&)r)ax6Zru4%+I^`_KDQHN)+8iwCrn0Qc;z6$p5vshPRW2U_!I=i!^Q z9VN(Kqx`>D&eQea2w=_Tyq4j2*T>F$e69lNZ=vm4o-DDsUavWULudS(ZM(e@+eE50 zS@v)JxxSa~@A_UugyZp;zrVb^3x)m z$mi8~L4#$>x-5dfo}}(P?J+HV1c2h2AVMu;2?0zo0SHY4JFXIMC;-**v_!;?i`BYi zfWf>GSnd@>zofM`EK$<*XF<<`rnOduNK>u5?4qIoTN$gasg=d#6;RSrCdhXw4yxcz zKZ}4O712d@)cacngcW#w27PkY+rZOX30+I+K@@X>30rs<0Gx{%RIS!YI#)AcTC4EA zegEY)vp-0c87TXn6T+h8QetVIuFLk_HuLow)2@Hhz1!;MW zv&WI?%wl5cGEI(>4xNeMnBk%-Xt1(6Wt%^h{p7OHDz3q0ERvG#EAjXifYIZ7!fgwT zzIC0~*R~QMX&;&Zsc~$3Jgn$BsoNeCD7mF7&2-MeCqCkRm#xx1(^!3XU55m9y;OkZ zeJXX~HBki0zuZG-_}9M7V4DJRBFb5V_W)XTjn_QSxL(hg=YV-$5JHlL^7RZ& zJ6--2&6`#1)Bp;4_G(ez=Kkws2g1CZ>p(ssq68?UVzkMsA}^gi0$T#suF!-wL*6}> z-|Wj;&4~1QAx1Mw^3Ke~ZNvttGe>ZwtbI`d-v*4@_h4qMREj(OTF+S#rcqs*1qjU| z<&!2i0cw{uy;=)JU15xHcB4S<*J#eGqC{QLqNFYkL98w@{exuOCf%L)#=Ll7x)mL<5nghgB&JB&+hh!ZQJ@7{Qj%ZqL1^@2zLI1n{@E zjc}UwivpVRvy^Mlq$w73FgXM<$tJL*@pMT|;IuZ?+AR!NCj-a;3Rr)B<2&60REx4o zi%rLs3vA8jzGSUiWyBsBs?TjJ!m95H-0KLvwht^Y(0{dJigfLhf+NXEspr<$ukMu@ zqJk<)^{2#Z!1kr?n<{9|=X1`OX6Z}~ZtvQMq=|kCcP_Ii`vSkVQ z^z5)K3#Ms7Ng-VrP|h?3eU56J)#{{~)6_Mi;gUfjv{L@BJj0%+;}WB|cZoKTvBWtG z;@*k1#gWNGllysFJH6MK_O*K7sSP>aO={dFOXWny!WC2fViS+tXBOFb+bhI)-2G5z^nld5fEa; zcsSzSy9XSOBZi^NLDI5hWNqYqm6DJ!r}v`*qIi{VtURifp|JUGbo(>&+WiJVic8oE zYK}ZaJ}EA)8vmqCuTi%@O?fUQ3nqjh=W0!~pITOUljUiBC3Mipd=((2*)-E$X9oDj zyJc&D(1HB50m@f>#6EZmAtYR$_KcTIinMYuUjKc|K3)s*hEy?9YW8$bT|?f(v4>-= zy;Cey66cg8XC^805F?@sa52T71OZe%l|4}e;`KP`yYMQL-+k>CFS<1rHLu!Jq!Zjn$P6#?lw^R4LIG`@;JRw zc>kQe{w>>EvxBx0@$BE+tbJ5;QP|U(R2rq_Xf-S&V)-~hxBFolqX(^7re5(8@@ zZ^vY4+XF=QxvM@HMkIeJ@#gKd%m4?8L+JVu$Hyl`P|h|75-piaLaWp^>QVtdi3{?M zq(Gl{tAJJja2)aO={=Z%We&JrX9NyKjx}Raz)=#69h)9Egmx}gCVkJkJnriBM5LXQ z;8m9aATano7q>00eMP|Gq>+_5yASl1zIreRfYlw2R7OmuWGYmkA-vq&jIvuB%%%hc z`%Y4-D?sj2-4E|Q`k}|+aL9Anr?q-{IH2>uhYy77<$@5RNzGfvyI6hF^Yyn3Q0nfQ z^EO(Y#JGttj7PkCe8j`U1BRhT*ZTyqBrsluW?ch};;JO~vzF4eP_rJq#?f8%+8)?~ z84Eo#Ws?J?D&<8uCZo|3R~?TSODO?PR)?;0h>_8CE(LWXS##%@a~@Gm-`= zP|KpN=Ov`;Q|k2Kz|JA^8gQr}D{hv0EWMq1~!9}LuGi|Z>LIe6#Lbp)Scl%#aR zdM^o0BY+)J1^7$%%&qB!0+IN{qvt_zanUfaPbFuK`k!epw>MkrM5Z z%znicdQDr)8^b)K&{$FKh~jt&3+50ohX@xXF%f$*2F_wBYgq}mqt986d5wP6fV}nl zeT~bXjkLbQL-wC~=QDq*wm;6>gHmeZp7Y-XQhuS0m=ROfUt!MBy4L_w#!~=*iMdza zo?k!7NvOu;XB?i-SAKq8y9u6ZqOKt7dcB$qI|L%1+{Fk$%m7LlQrEm^EsVFcboF&@ z>y;}yGA@LUnIV~)B(QZDfe?Yngwy#1UR<_Jc;_$-V+Ms1)8*kE(5*e(GSQ6@@V>|6 z!xN@=v$*czl;WSF(Rgx|eTeht^}EoDc#2k7GkA%R8VP{$r7o7il8)7aJPov!^DToh z#r^=)?mMmd+Wj4VtGUqYRHn>Gt!7hXj<27Swa_a~E}(w%UDsh4djQDpnU9Z0^t~{~ z&UYBbA;+qzcDnC8ILuh)31OLY3UUQGF<2MN+6BdcUfLd4a8*EW5p)0HOp0ts4_#L6od{DZ`{vw1^=0?!531PMHaH?ZCR80U(D6 zq2~%#nOrJROd`C35$6bUDfM;oCg2#e5Uaq8Q$L_|kCNNvW_`6LUVmG!y?YqOx8XXo{|E{JCCvV=sSn5b0sc`IDsXh63!K%L@Cw0 zcwfjml8k*0ofFWTy-1uSV?dPszzLD4wcW-OsSB`{1K~WaggGfSk4KHO3#nMI(pcfG zd(FxuB~zb5Z2|MsvVb~=LpK7cOo4MA6ibO0JMS&aS9-h6bNA-!HOpr!8}hc5g4Mc@ z?-4Thd@p#XuF_jAH(zS$$=6f6KW$m(MqGD&{3pVQZw_aE!>}=1xAN`f`q?G~)9Y6E z$n=3X=ez~5w0QbnzombS)(ijCma)4mPqq;xHTda#%A53XIH2#n5jv%<&Hs9A`_g+B zDEobvIbl1gzW$F*rXR$E}W{I27%cC)G(_~$J8Z`Eoy3;+p`%lBa%@Nhh0 zJd7DMj$@C<#|I39RI<<6pQ_+(u_E?39uER?PZwM+=OoO#lukOOmEVAh`!#~9ahJY} zX0q#h^uvI@@6h!foYvF=0E$?-X_|X}tvPv{Yr=ihxW*{;KHh#V*9~I_j-t`^UJ7Mu zrbvw~h!HutfLa{uL=!*Xnx*RRy0ymD$q!%z5W5V=Sv7xLSc9vremagjz0uG`3uv=d z5ORN)EIaB_$Oati{gn+=QII*r6vIUMp8B4GV{+tI`oCmmBZx9cuc3S%z*_i+ zLk988oGUWOJlEv}G-uym5#h!i-H)TFDeK>I-C>#wUl1!2oF z(c*=lBUtWTw`aZ5F>W>Gjgo24qwkB0yDC%d{@>EE253;N3JUGeOnEguwHadT-)e9v zePAq$)PB-_7I*J0U2XNdF`_AL`7AWO>rzd}kSyq0!*W}A-NsvQ#-O61_qO}bZOkcI zZDzej_U`-h%Ll);pQimb)3@83!4r^VN@iTI*Cd=qIQIZRYv71~vbg4Kg@~Hy?E$9x znp;|!)-#9*wZHQ?ju{+vIo0aA`gpnDHa4Ml!w~lik9Y6hWx{X&-s=0kO|KOX3lXWEv@7)wUru6;MlthXWhp7mvK9967dOm|VWO^crQ_^qAT9cdeQv8<)6jBW)H9ewaTxAXK zGJRjofLR9$y|fNgS_w&Uu@+$K`e3?O83LZbQUOZcB?Evi1bFA*k%~`yNq?UEMhVmz zA$(1*zdXr9-RzpM&#e;}S=wdKdCg)~Kj$^j^xF4&57{{2n*Ug(qitoZ0d?bF*Nk%c zySnSf7%@$=QM6EwlhjPV%Cl`>t(8v4OA`dC2SWY6mhW4uO>5lrzA-Kk_wgCSFxtCq z)>acN-ueBl^y~HYVG&wU(dh0oKfdX?zqQ}m-(!0-c(SR7V~Dt1E{HL}d$E4V1}+)G zYE4TEIPEc&`nk2%Q17>AL9tpWZO%Cy4u?#TE#b8HmA_ldnSF+8!a|AzdwP1p<#Ne2 zgUa)b@N-XV5O@HR#R~u>EuXENUXOwNQ7I_2He#RUxnIIy^o;;OXfJ6gb(kgPg&xcI{ve zfGJw7>8HuL0LUAVrMM&}P1fIyH?=JmZ;^4BIXjX7rtANsP z^8yaJ){Uj_Eu~Nvka;WQ$H)j2#bu8?JQ$9mr0KCV-dMWS%iwj(!5SYHp6%aJC2Yk#k8cWr(nS@-RhCsN^Cf-z$f&_8}8JUkra zrd_wu-0fM0-eP$IDr*(*GXZ-pP|WGA>f+X%zhW*8<3p=&mXJR@JmC5H*_h~+Xni?D z7CDRHJC|GpRE}b(l|#?e)aiTc=I7MP*DXfQ7Ne4cL^P3y!+_(%5q&?PA38i7k7<1= zvjPCgghXJ})i5c^cx4?B$a#<(5cvR*#7V>t3oe&g_)K$bHhT2C8j&QkczSxo)6-)X z0E$fkrC(HzeG33}8{{>wxOu-@ijdacuCL94PPTrO43pj$O?8YN`d*4rD==D?C2ON? z22Bg9e$LjmJQ0dT#}$1qOFWds4HX4|y1FS9AxOqL1>aEbZvwy$l+q^yX)FO~ab6}3 zN%zR^)KP={4d?~uLcV40#JVG??)AwDFtKC^WnxG{U~$!BTJIN5;Lon{?Vw?^9q@bK`ETt<_| zHi19wi}$Vqz^{+_-dyeV?^eB;+hD^A685PpYuXCo#nSE(Sd<-7Yfjw63CS`cn^oS!Np?qo#r;reasp4@i(8`Z z$6Nbk&+2n;tCb7({qDWCbmNydR`UL29V<&!;1HD=Ck^@B(id=_f=4)7AzgF`rlr1j(MK*n8mnYJd7X*oK7b^ zJRCOwQ4?jL7yamUkO-?Nmy`H6Jns!OjqXug^1Q(MSH}4 zEyS${-wIo{e|yZl1-i5y4hQ`H_rHg84j(>zz~yquZbnwyX2(SZB$tYqk|T6}NU75Y z^!vd^C;W!R>|NcFG_q*TWa5%ts9?r{sl+miIUJcM~+XK4yoPTd?35@M=EE-Hbtf{H( zURlo@t;~%Dj;3mhc%IewLlS3uIZ+lYdbFXyWNYo!S>r)YYqg2 zPujUn`3i+z{1u+_frDfiy8K6cl|&i6fqSG_lD!QY;D zOL=CG+4x!A8?{SXao<}5rxs9Hg9ZYa;K)l_^30dTdYN5ur;rjbL})!k3xKpQHa1N6 zeh4AOvmP?v)$>CLIGs-U8U;`_Ski0i<0=!0+#&Ib%VEgRv^)%uRpwp;O!l{oTkccT zw7?Ru2E6G^S+6^pRso2@WkvpFpWIs3o9F++fY~rn&-E+uIuph z^pt(W|N7Uz;^pNfKf_w7lrU?NROiHt(mRiFIO1?T;Njr`$KwMIhXddpPUkbazQd5mtF0e|t{dQ8kNFtz_;ALj@REzPG84S-0gz~}vrxOWM%ewMSsWi9 zAMpPDdmIi26J#w}zvTM0Rr0kBeh+YZ?YCCj+v{0Du@bawAIh;cNLp*xRd}-J%kNf6 zqly3p14w_%Io5it|N6eqK*?s~Q-SJwy-Go3v-ecc(sOm))${t*2`5Nxj1CT-JlI8vH3_V*F4j2B z2jAQlvhJd(PbeUKo!Qh{GVD74TyXt0+uoXOeOBJS28v~D)xr;yI44UVgie<_Nv-x8 zkh02Bu^2{7(-re9S?mNPZRr>hpUKh$2=aj^}7D2 z=an&_TwY{HPDX#TDJ z*8YB4_YeQ@4>+IC`1tYTDn)3!?H?xs5P@Y{aK<^`L$lji0tXbKWv!iBg9=LktQp^C z{1LffZKZlkv)9&fPj79OxvTr$^?J<&-?|nQ;N;W$NO9g_7;qR5I36D}xafPyD#wn{ zrR;K=%2~%n1XHZW@TVkbHTcyg0HwX3AVaE4PcSr%)C z)>x_CiWETESSS6fE}&KjsOgc_EZ1wd1(d%|v-?v%JITe6pkquf(y53uL5dqD0f&{ z>o5bgNcVl8d8776W2zJ&x5lI;d+1-A;g3w_!8NT;*ARVE?%M*Et?w!aa1e!uy3^|T zTji^CTjoehn`p9)B4C{}Z&1Y6DMHam?rJx8^}D)gvEO4F5!Mdk=kMPqyq=&7~i`q^IpxmGAE zR086{_uY5j!8wN?fBbP3SEkQVE5+e(#PRrur+1HdI6T1n-Vp0T@PGAOi%Pa*IFXxM-$tKa;iQ>N8ycWD`hRe(th7k`BM>t;ubp^VL5ldo^ zk}RRsUme@l=e@bOx7}m$vU{usakTfI01+HxRp5}4!a%d-S+`Qp zl59e1I;p9N^4hlruJ^(3y357#ls~1tDkrElNN83{!~nB)A|WgWfG0tjv!!Q$?XDDE zij1J|l=|uj8t~33jd_86T;H&)-OY1NY!udt1bO6^SM2S(Zw;*O1xxmGp+%+d%Bx$n za-9*itt_kWU3dY5s8}lWTq#_u)~3b8Gturcu!@gb*=rRdTEfD{D(PPfp7s>Db+cpR zeJM)seTlEieOF~zbV zPN!3LgH+)3@bHkmN1XRS+-AD{t^L;imRtA!{d+j)M3b`woG%xwYJ4=C3g+cJ)%XYj zV@%Tw=NwL_QwBU%&;kljlD`2V6aiBO9j%u{L@QxOwLaZ=D2($n+Md?zbDF-J#$F7= zu=15Al2{D2wh)oAP#oZWigD_C0Dd)2P{ENU_T%B<0bvnWrSs|hQ{trDCp(`O1lc+u zT7Y;QhYYZNR~U57Pzy750D?$|xve$R%)u~m*JLO+8%eB)%#Fvx!xLg4ssA(u#5hCZ zo&vyxfCZ6@<+K(SR9SGnUeR?P*Xsq-JfKI(?xdRAvh3>hM;nHC3j{V_>y7Jok3mbF zEgQ3_zgWQu`SVt>qShr^ozDp%P_}${tQWAgLNHRmPfDs$gnvC(tOV*(Bt>^?;i#-f z56SN6k_9(pA*_z|)OY$^+VWZ>`&VPh*vdkrBSxqYAv(_Q3Qp zTSatii1Ju%K~g$KTgz5?=k~kTmL=s!wYBDRdB)djZ?Qa;^UI#rBn!a0EC^7>-Nrpx zx?t~ZL0PRhSu4oYU2n=>8F_B;x*@|VUW=lz&|!7mv;5b_M7FGMwpq}_%xmhDz_!qp zG$u(QR^Izt(fOg${anFUm)aUvs{IQi)%`V47x}US9D0@{E_4 z6XscDy2Igs_wV25=Z)hC(9csA;?*MmX1jlZJuRZ$5GJm;ex!i+=&Ygvud6eEc1*Iqts8R zEKhRJLh!8bvilBMSTDj(5ldDyhJfhS45pUNbM_~Wnd#>rZ!RXiZmnhV-ltU6PdVLc zNd(bj7!MeRLveosV~LE;CuOcvZBdHXNCLtz4mdm>F<#GDmIYH-()cHVh>(hKa#9ng zzH^y3q46;ZF~%jwfHv({ota6~z3Tg@MoQmTYbmV*kV|EEWi+a}R<{8i%OYeGR{u{j zx+JEf(q9%gA#ytYg~2PJFKeN=S1@aW2)WP0!vijt3(n^YLQrN*2usAm0a}}BPlKy5 zgk9I+)2B}$2RuAHpzr#WDbS^a8KR|+T3;sZCr1THs8Eo{o>II@{!N0HS8JX$n7?jo ztK90BUB0aVmx?P5tPs`$c?3xcVjosqFZHhqZ`$`-NX=I!mmEnzAsOHl2#8K$9g86A z%E38C*GVQz%|6-p9wBteVk;mjgay;&a<)TjiHfl$kZuR79#&@uv@B%6&P;xPdvyVY zj1nKEZjEZJ%KI~ofqo-I*#kl|JjURMo-hbty8K zBBD!c(U4A#EcKVPE>z|tQqVTjUpq3Cl0qQ8Qv!@mlU1P52V!}@NK(2Wregvmqdhsl zlPsiiqs&K4kbP~r(LMQ7)Dp9Rv7VE?xbi|#1*vrj)90lpo4?Ai5}ip!njQH(M>1s$@A}L~kH-ge-5@f?G-06tjmggM z52dllv_lNNWqgG8lz2YpJUZv$;NVEC!H5hO8J-vp42NVTb_IOZlp}xVeZ9e+BHLQv zx0XTyKc~|Pr_%{9FE3dZv3xqa&-VlR-bv=(bh%J4iyOcNnU0c^e( z>wKuC49UtVKk6Ep=YSD0**w;W*J9KRp7GF%fizEICywp`XO#79$i<2#AR8~_cNAd z&Q_?BaZ9Y>0)Wu2vP2cB144t!qYW% zxF&h2$A;O014+RTm=xgYS(!FM+)%wINnFK@q4#hUfOx@zP*fL*4Ou0p>}{Xd9mgQg zNCG61fa#KZDS0QLJh1TCAT+P@a=ioP(ixPLe#B*+X+O%`?9t%n;pVzi6zF|BczUZK{jJY`OH&&6t(pVD!IV=;$K~_dtybedWqQ=zI$0}Y$a1&t_l{ER zYGin|E~c?^&aEGa^0~?Kt5(yuR@+zV-9KO7YHqvBH6! zjM3URyUp14<~5(6fRf18rfB63<4oW3``h#N9Ccd+tgD(sh(-7<0BsuwrZ=}tyz6@$ z4@XJUE8GAv1O&dv|G2@_bxJGkqXyt=->r2?0hG?4UTa-9vh{~K8^E0VI>clpgeHNf zSU}5I*>z*xLy$5@iGO&&bS>#{#rJ#877BI|xiF_`^_mMI;Bq;`Ic$JrUI#12X@Cmr z%0mW(b$WCl33B_PGJ{+1yk|+Mzkd}0fY-le z#X=>Jzj~kQ9n7uw&ugC3ejXzt2B}{KRU&BKbuhf?YXQt_K~#UuX)JU>mW~649<}=M zx$V|E|D1chW(mBn;BffaGw!GS24-FE3}DP7=GjEFl9ZmlAlu@FexzS(XJHBVMkjTt~0O zdih));(R`*^_2L3q%41lf>12}Uvppl)^4{Z{I=uoCz7=bBH07{D08f4YitZe1_3>d-CoJ&Pf zoP{T?#k9F^x}VMBQzsRu{i|cj7yrj}E!Y;VV^UI%uazDaoFm|ZjLd+aeR2iII~ zw(#U@ZEruyvt{krtd+OkY410i!OwoS<1Bk?KVGW{&XiqZd=iL+49K&+CxC=*_3&8w zfG)Wa&$CO(CL)~Eno+v` z5hIu;fF0mP%S|jUpdzO_cxQxQV#TLmx)NJWvdxfY6*{_)EN!yDsRmD$4(!DZ)k$(xn6`-wEO;ty&HvvrM)jVm zm9PZ}7T~7}IJrz#SPsYJ0>_#p>$*;No%OoRkJp_rl^)QTUlQ>*}Woc%Gl1<+?fI@$m`o-aTb6pc2yx?5R?I zYu~P^`al)y$a0v2^BzlxSkgRZ_t_wpdhb2PVZ<;BHt;4<%Wq9uhZw-(V}ri)_}%yK z;lMbbPqa`rwN0KmLdrgR(Wh5oIErF*jD6x9f zf{5++>RmvIm~AJftywIn9{@NB;(gy^?0ZaopMA@7qK%!2w_|KSd!udCbfmRQhq@iw z;>tB6uNkTetm-;fiY%7+qt9v9%0)@TD1tK~h7@}d*Py2`7$qDtrfI=EPqW)~`0o#9h##+d1jZI5P|0lFt*jtO+_k5Nl7cnhfg+Tg0G{KHz|b?aE&N?DAx zyY=UQC)>w8dS&VEG%=P%UHU?^uj}_MuB5dbu-B}@Mfa$6!(H{CV3>chR68JYve4-I zOENzbV;lyILyuw547mq%z0W{QtTbs4IiZKGKGx&)x$CA*S^`K4_w)Ijtw#Ene1{ay zl>}+|9GE3jUR;kK$F;|e-e27;b&OA^lcboRfn|yLowYlvgeUHQ8kc)#pK0aa?MqDn}Jn-`z za6X?UtvR+rqP7+TDaVRc=X$;7#UWO%22olSl1={cy2zj!rljdi2?jI;uq;3aBCUr2 zNS&d5?O*F1)*AJ<5l!ia5I)r)c>w4-bbXJZAE4=9DG|t<_aim+YZ_S(?@AF{tyiSN ze(RlXy=&bvn4@|g-`-kGSD2lRjVnRRk_@24*_}=&gveOt1=DrHvIIzQt~X3S#c~iq zVvAe`Pb~no6||&Z*%uroP`Wi^*EB?RN{T>UYsKZ2QonFZD4ySDg>&x_}r0=4DBWq?iRVRR$@b(r46wt_COeb3LAW z{j}|^pz7zkj|p+C&fi`yfT+~8Vo)a693uh&SWFsu=LMWa&a|-Twi#YDUSPx&o5g4m z#A2Ojyh}q7@YeRV_MDA#s_9LO_tZ)UOY3bxa{Ij&=4~ca`?>C$1z1*DXxFj`-6i%= zudU;(O5cG@d+%tL9%xg`|0w8O*X~oHv0Vm35dq`a<2a7!h8~CG0ms7;$HM`` z&?nGflw8Pq*Kg8l#SBsm+B7XVpD#F_E;ygBIG?Tn0ln+M!2m89G`Tb-m9adlwp?nn zw2fK#X$%n`<3}Uch%3Bg*tI6S3cUW-zDdhsB@x)A*c_d8JYD}E$L}>vP3MMTVy0`u zba!|6#?{RgccvMeZeu3K)mL9JJ*Hh<)2^6_YYe~h{r&Hc`*=8?bKal#E1v6(d=HdI z)w{R3`!}`AD8_ahhJMX)Rj2lKT!bc{blqqjlO^MI_VN?&eX#wd?$}}tMYH<9!om+E zC2Jeoz;xXZ%k*_<0O7Nz(xF(Ob5`nyYk%{iuRTS9bp6!>;!W`F#2fyZ3kE!?evLS` zO~4ib`u)dytWPuUMeR%F6M-xVXFDg8?0droBMK;UEVdSSHU}sE^SeO-Di_V?mhb44 zhlS;^mGf?M#2hsmFl$F;f2+fz=v>&_zq`7=WI;!?P*En-uE%=PDi52`Vnv6MK5|_Y z_A5NMdMsf!FrvQx##lJ*WoboNO(=Y$U?8Ib3VMTcYF5sMetI!-j6~U%@Lm?LN z#ld@K*Cn*p(bT&~+OhnMo;0K0Ujc98R~CeMoK2Ip7miK0#E0;uEGjYCt75X|W_2LpJt|jZSm_T{lms(Xng0r&Du2EGw3i~0-GCJZ7 zR9SI&lym4Fsjdst8sx>zZsX&_`SFb7!&8;^-Gd9`Gu7=+7iRU}>++WtE!%J{E()wM zw!_fA2)Yls2uxZS_=RorGS-ne{02_&0?{_(8%JrNuPgO+@;wH=r7YtRV|zGBB6+O~ z*S`JXQg(9GcOnT#A|56ly}8wb!u#JqJikG5>F@|QgIj-vwAmEM|55m~t}|HLSvn@< z6|b8j`MqPu*dMu&lepc|EAgM|@nxdBe8J}_P!AK0yJkdii;@D2CA#8lL3+N*#Ke&> z?3_}%xgfy5({pwv_MZKx!*QfwDvY%JxwR2FSx&Vg0~V2$qH)7T-hInxkk%Uw^T#$Nv5e`yIu{=^52NhJUIG)}KR+S>y?%8_*f zY%pw6XNJ#=YoQnh-U?h*z{yqo+?^vQ}AwgZCW zcIuU|itEnGu698_mSkS4T|>w;GT~O_oj5vD$Y*wq5)Y1pi}I<%eZaFJv!fOpsNt8* z$`%MH(fxlz1n<^-T9sML2ee`WkgGph_9gmR15H52H%CiEN|s+MOf$aXyB=C2%R<*K z=JCA}ncaoUGdA4*{R%KBg8CT0Zi3p~8BvC#qaU|mN7~JeDWv%&Ro%cn^TSG#X8sshnzU?H7FSBqHN<1+e=6;PC zfUxz8(!eVS&esoJG)=$sd{(iEU!WMel=)N4x=1t>@;Xy6xe1fs=9)Rbbn&_|P2}>7 z$2g<8>I`*76OjA8(&bLCM(7qYuJ7rw0!L$$&n@lq{l;UV z_qE<{s!yyjgHt-~HI$+i=$x;nFTuFaN~UljBb|Q&2zm2UQ^+?(*ZGrZNdN-|qo*h% z(FwN^a0V8-nk_6bWlO#7beRdUJ(d;?}>t#W#J$ zZMCX{f7NpoyrWzs(S<0LNoEWHoV(PX7=h>6}sJc0#lxX;CVAMnocE)a!#*89xVp13#Nul8L{K(C!o<*_25x7=#qFj+MQNi^@_RDW; zdpS&JOeltG8dMS;?}!$_rzaLoeAZDBh2Dy6pAv|f%%AKaVbKi89$&6Vl_C8tA;$-; zE9hzSC*T{rZ$WuBKS;8DR68C_`I)NVmLzFyS}9J#<(S=F5R;R2_9}UAWtHVlbPM(q$2WiyDcDS0tdyPx-XXG9n-i$Ay1hhnB8dWAZgaO5&vg`K=G?hdJaf$pMAg*A8O2?pf*PNdw)}?gCaqaY$K4q;T5irp6{KJ zJ_aqqTTe+w{xLp9>?QZYcVF>*&sM9`Ki&f|+I(34sS@PR`qb3wGg*}T9DC08v6INW zvPr++{F8_X%vi`se^C7Q4*%i$u5O_DqF@J=(z-D~nSrg{-vPFEMs<_lqVzsF zE^Ou3+KmhleX)5bdvz~yKrSZ6`dmuKjC0&9bkgxXYm}8U@EaV|U$gkm6bp&(a!XoE zvqPtjw{Y>nUagRDlJ)(&>L-E(0j8<5bfktY_dGvM{}$b95%|9}>&L#Llu|4KIWtiS z`0VBNo_d17v~9eD5oEea%9WPGYHN||Cg5|CcLzSS|ESaO1E&I31qmE>-b&Xr{yU2} za~u$ksS;^0&EE<`%Ow{FtDiWQAW^R~TRNIPS47HZH^KtMN^fLu8aeuo@C9U4$wdr8{aIWuEM#ZqL4L`rJsKl5XC`n zou?9-FG)v(i|{?FoQfZ^rH#k2a(>zHwhkyfYRM(}&*w4V75OtdGfMDmIj6~F zy8_3p4I}a{J;2JvxERJ^=)WJ>$gS;3))^2;OG3UDD#}XJh1I0y)Rt1$bje;Zc#e=P zNXId>D-!vzn|A(IDVCX|IZoFhpOyu*rL@L%}3--1?YtwRsr5v>k31XT_S&Op9 z?gx{f3h=Q^BcT{PP$~7U#}VYElM<0`mF(C90lNZri9)O2r`tHpoS(*bg@A%^U@fz& z&Zz-V9HiDNBY9#q?&~F<;p+PH!`N`?MSsaWB)Zjs>sGwJXeP;r@kT4=4^FYuOy&VG z0&@Jokl^kOQI>&N-gnG@Y4rKS$eesKUg^z!V{29RS{zk7w9~Sc()3{`W*)?%5{Gd5p}+5%V{Rb3E0LYsXOcF>CP8 zIUa2@4I`d$#U&F|>Pn`^&qe*3!Qc*~?=|~AJhXE+^@oU$vgMRFGjEvtCs}JZ^6Sb2 zJheJiTxC^`k?LCe9z1#kB`zSu@u0Rtke;~RmK;mLk&(D|sftiH;2z47xl#(Au zEOgq@*QXo9#d!jHNAFXLt1@I8Ki^DGza9qdN?2%nT3LvQxVN9Q(HG8OYlq1Kj<&%E z(YAdP0l&w-2(7DLejZ0XBca!JzJnXx0j{oCFH z!j=uMi19=jm3{L^*qrL=y#vNkCtoC7vS~UbfRs8DeidMw^pv2VykNjuby>WIABo^h zFvmB~Tm<)*B|kmgnC6fuw5}cX)@VR$`e1)C`5@{XZ@`Q7ktb&~QEaq(o9OnLb`|;OQWR>qVRHbTOpfSZ?H3h^!^x#t_wp1`Tp>3O$K0`TTNBx~{EFlY@ z=N8i)+)gk__m_^H!H48N0^q(J6Z25R_%s24gN6hRpHTJnYjP7415XjcwvV z(q|$cQ)&x7V~q-yw&kh!?p2xI8q;IF>&<;vO?TT~eZe7U8FZWU_G7R9 z2}l*_3y9m?l%qzW|t$TO~Ygr?^Iqr_j2uKXFUqVGDX7AoVfM(% zN9j3rD4lgWEUzwJzSROAPUu_hPdcxlR)iraP)~$ss1Y^l31(J`^J?;hnOn@?K=vb6 zE(!`sEaEv=Wg_Z@0oBYvw|t~m8cX#UMO%`LL6u(U8lhWqVztovFbBrGfS)lqu@_X5 z*c-am`#RZbcv-#?<^K=Z5hcS*z781tJy1D=*7 zYp**bq&GvPHvj&m3;+B3nHE60nt5#v2om*qtd5ML{a@oOp6EwA;n-Eh+m(B<{yO(2 zZwRv(I;HpUw_fo60ce?1jp!*uPF`44m5%J9=FSrYi>@uMwy$f}W{56f13> zaQ4@|Dzm~qKMitwoyBk!HG*%#xlP|+`(XEo@Mzy`rlCf0htMZ!U4y_*iRq%AUG;{M zdH~=FNKOQi48j7i11sRH?qPr=w_APq?vH7=qi*$lX9cdNUR>s_k=C@=uY@T$l^E&$<^BqapKoy zam;fGO6N+e2IE$J`ldY+3;~y4^VR03USm)m&D|qEri{Q}sA1(dy3^UgM~z7cGxdqN zFcX+fgEfjb67j^1un)pQ9T!f#5U-p39`SuEYp%ORi}SrpV)i{lGT>4m7Nv(Kz8_yW z@3YhtKJ1<7g>nX>^-><3a;u)B#9(c%ZdhBZNX(uEN8``0u0mET87NeHPSdPU&7iqa z2l8f1;AK246?iHJ{?XcPnq@tc@!fbIfNIkQ8f72vy^9jv^4`F4;MTbI}X@~Twt`jEjUneF! zscv`v>_65;LUdJpHWQ;$b*OV!!hN3tZHzf%NP5TEdzON2=b)1p<(J5Fq z4t2q#u6p3oMpu)Au1Nm(77ur)t`r}w^AQ!l9X@(ogiY&8l&E;u_IWnNZdw@K=YwU? z@5tZtr9(iD+(hV^BkwxR&;o7)e@f%7xm~}>k{tqX#2;LJ^DWVkP7VCl|8&eJ&bB^E zW%gI`F>SDg`|+6tm&8on5=6Y32(}`=X_6E14;pF#qhfof6{{?lQz=H7olI&s8G$0| zqV_ikByH8_{%px1qd`f`+)on7=|2RTI!J?-^V>|X$EV26jW24RUKlkkU+4HqSb4W+ zQ(M&N{R}I}^mW44POJrl{zBn4vd|g~#zef363NEILZBabX``v^z?=nC2dfHB)JukiUWl*@aqH z(gM9a3pphcGMj!k3No=nea1KzZ@{{7ED2H0I$Y#m(6ph-w9&+&9CW=iM@f1i-vUyi z#>lp})W^hpwPa<3wK?XnqKqG-R&0c z@Kfu8(~aJTp4f~9i~>my!3_zNJpNnT*WC6wZ&J76ISLvRzIfoW5h@}%758hiObc&j zQi;~8+Gf9-tw$*I3y^B`3SA8Kn%#Dfv^lCQrp9uP2kDL40Mz#$3 z7cvYvtGSTy{P=dF#_9NmEMum|cjVliOl@}kI=8R!`e(<8nooZB z*X;2@+sc&A?Bmnxf=eiMu!EO^h@S)E6+P=`x}T>80z zL3qPhYz5NAv^8JZ3Nk+v5pI*)gla`>!iM>qvXC3S3Wz^qwe> z>k{_8@Ufnyq~CLLGQrZXdc{0yLyY%nJ=L6&>>Ve2Q98lKuuLy0-j`Ec@*+E!J}$Yp zmawR>OanGmLJC6Mxsb9Yw$)PmxxN0t57Z|ZUCd(>1Z@s)VCJU!xsO*imqwD=i+@W$ z$t>7J7w`6iYrhv83C_7{EWYuZtF2@5ONlCcB%Ey|)P~x16(J;~6mIU`evC&hM{09I zFKExFhHt1c18e8^K0&@EHTA6-n_YDMDc0oPOz~>(aT7)j3ar_DhCUn9)jPucr7JikKVZeIs*`EIyy*gn z#!UV17eDV_qI_38mJYmv)FJSP5GoxVv%&2JfjV?GjzX6bRLDlahtL)6zH&2azP@!= zUF8gWSqZAcG&CyaZnye}ZEfc8E``3GV-TuAy{#y><|Ca9O{-|eO>$HC1u@HMey{D*wXPYYv|0XI47O9x^z@nz7}7L z6(6ui|6V`pEJ3JZ95xyM;RcQ{XOvb6%9vKQ13uS<|3&IUu1_ggU@`W|L00Rx*eC72 zD~qWWogOO&?hO#BNSu*hzyJKhkB5H&)k=7H&D)?Mo@r zo>R41A6F#hjeP4z{MkP*c5`Mzga(05-> zYWdgHM&-5W#WpM6gqV}(knjrzbGdXsw|cBMNb0nTWvs|%?48GXv*Q&wr6{C3{DRtPbwyiim0aXcSfZ>#GbWYS#W!D{ig*I$%cK#M2?6~C z%YF<=gZ~jjh-2PUHftJHN;&p$3(t70Iw~$vm1H$FH=TgB{2-GVD1;l1>c;%SwxmL2 z?d5T-6H%Os+$8g#1&MJ$rFSL2n#K#_=y4eFw5hdUO2~%6;SCDKxGEO{IN~C;Qz%?LMSWyh6t^7G_0WsH zXS7nB6RsrFYdB6W{%D3~PE3R+;W7%0%1T+>Bd@$!u*ZsKZP&miCH)oY{9!19gerpt6h8ecgR-RJ$0$y(lO)P+gTIlp5O3L zSi1dbH!nlrBl@+2`{uXM#bsnC0@W<}Ci%@s-EG(mmJ3hg98-BxzYCZhnq+x$5MA@H z5-qXwH%CaT^Z2;Qh-LrG@Dw+#&4XD*lgf|GTR}AOKdI%EpV3ny5nqNufcOFNAai^3 zY)0pzqsjO?)txD`5lnUeT<6keb6{I2ud0q}@k4=DeVS|*&tavkW2dW>iBD)hwLwV* zo&y0vM+lC=aMc1+qJ74{R1H#rcs7OiYQ9oi$A!qbHs99F;t4|pO6?%Z*dqp`)=X~gw}e3FbvyR4NxP1ZOd0lr1s z{ZG!2_7=6ZCTZPfXB9Jc6JBH+x*>+MaIcplHZzLKgWt(Js?qCD>X@3d_#4cAP*R)f zWbeqnqo>8T{xX!Sxzo~-`{)?4uDX(xLEBw{%H-j7S=;A%+}_-DWOC}Fi5T!>`wZaM zE*PDiiNI*N2C8%OW3f?{jFRhr@Z3a%6nw?m=34*4x$OBF+zUk%>r!Fxp*UjAk&_MQ zfanwSd&TOr0g!iIgDX{YCo@EHE_B(LU}o)TwQ>n=Qcf+i1}zM}Lthw%*QC>4n?mXq z)*O;J+o__M76uJ^%OdPUKYSgA%3T$F#yrldwQnd(tiZX>u(Pc}R96gsn;nN1^n47Q zL|t{EYM@K2Eyz;cW=J{iD}=JjZP3#!DsXG!bX!dZ@vN^S3BQ{RPScGl6=*b%DqKbZ zkC*F#!CRwMn;Xs(2J#iJ%3Txm#=&j2Vs!v_o#rN!NH(!#bmu=bbTWD=F$F5|R)klT zc4d?1;_t=s!3lJ(xf<#BlrF}N*;A%_t7Q14TpxW&^jC*w)$vcSW&4EGsLOH6rs+oL zS<#<;@QUUbS;uLx#E@E>?c0Tv&pX$*eZTK-)9og-r1<3z2CN|mr>80Y!!%t;itq9d z>V?Vg&QBrCI}jpDO-Dz2HHf*jDFxvbDGdD2hxqzyF>ZA=&9H%y5ke~~trQLz9eFrO zUkj|`Vd^MJmkL(d<|(te1!ST9_zBr?*oK=*vRNj;62AMB*@Z`Xe+T_{+?IL23*EU12Hcw*0`SEyCSowxf4VH@Vg^v+_9 zU4ZHen_i)4E2LH1p}Td_Okp2M1KpkVVR`7ugxzeDo$wk~P*z7YZGf$Xqb>5gc9YJ2 z^q6E!?0oFqH#5z4qBIR@w0^m(5_SL7w5sS$0nBcX}4b7kbnz7HIapCIaDY^EsxpUHGI3+sIa}6cf>I&CSAk`o7HJ7Lc8)QPY;6nH#+MTRVl!gFv4~U@Of+V zHxX#~prrZSM7Vr8&xprH-YrAC2Z%yJiT25LC;Y?@qOI;KZlJdXFO5bRD+_h+SH8GG zK^3bM9t+Pd{Jh@DKKk~I`(L|D-o}UAuoUUFB5G7a(y?+g~3@ULZ z`Ei~oBZdcbav%Gc6jE~X6#fQCFuub4Gk>euj5NPDFb_}A-9Fnk zuXnE+7ost=CQbaX2U}EaO*m8f&H$kp^3)ZK6mCf& zD9X6BWHcgpMS{;piI+OY;TL-`cc7L&m{R?#V%5zTEcDr#P!`<@<5Tdppilr$qKmF& zevO2|?DAq@7143TXc4H_&lAeofyHiV z)7+uo7&4UpV0U%IbJaUsCLW13G>f!@u_E^Xl(8(z`ddfoMOeX=)gJ*g{-GK zK61tUTNOPs@|6b*)-IsX}0FkPOu8V99NK-O_kA!tlu8tnfcV*&Xs`p0><2V{mPPLx!=wa#5 z69&GJbN*YE!7)OVwqKcTjWDg$uzDhUNwtnW)WFoO{wqJ_8Q<{k5D|QVHLOFma#JOi zxWZ`kJU7q8GX)=7@J4=%lQ8`ZU=;CWaD1$&jBz=?{%^O5$5zdZ z)4TO^c0OkDk%wtxH^0$(1;YLCP{);@tdnzrpEhP z$4>YYg~(oKQ#?o}y=*De0ON&|M=IdU7*hun?mYk|pVO-=7?3RzWt_mgH$mzVY@2{b zP@=9$&tyLiyq>#t21_hm%Ji&CnqxkR4s9*Srue?#*i*SEV+C%|>Wh9(&e_!Rv!^O3 zQ{M0(d~9)#*)+ z^L)_U;Q&YwhV?_rdc={8{IdQl7-VFneOJkr&K>Q~c2om_aSD`0SK zeLjS(niQZgh>NG^QYfsiizqMpGi-r|D_f-}tf3qYPO%A(6Gm(j$+n*9X->`<3uv=V zvVjTMa6`iPEBv2-Hg2q>XKb^*I*hZ`V$K3G5c_l=3U zuT&e0*jwE4q+KI2k~IC$R{@4$;~j9(?lQ7ZGNG;ui%;kl0dsr>7v5`B=<8yC7q84a z4l<PEiVx*!;afigr)nR6tW%f4P-2eR>eAlC6eaGJLc5~GoUYCKD7*4cH=G6hWmZ8_fr8DoleiDZ+m>0JW8!X*^?L+XIL+eNIi z1gL6sbyQ8JGf7cCJF>)mmK9&#jy?^Z@U3-Uyio6s`gdQfm|^Q%W$7C0X4)V1*cQCS z8&hc|0;P2&c*!>w2amO*W*yR5hH2jZ{Af$duSr21LpF+VO!~R&hFf>xvpP}faz6`c zT+PgDNz3CJyv&mPTKCPl>Vv!~S9)UytWBii$^Lb4=u5VdFA>g&WiC%WV|8`wx$ztE zoE~%G{ax4QoyOVK`tg7@zg=pxuKF*Z-6a8R;j5A z`W>)?`n{Pf9nZ#L>Mmz-r`~VDy3h43y32g==VQ-2qiapac8n9YkgVN@7=Df80!rO1_-~McVs{k5| zJ=>4eek$$gxC6{nzWEL6RRsweXw+$-xON+62Fp)^(U|v7w$ao}Y72)4r%InpD(N;w z0k||i32-|dwAUj3KB{SonOhb2vYZAx@pEJfUUGI@$9g4Vvqtc3L&{S|L}F_}ymnx= zKbdC^1GHqqMIcD9W{S@+SYXHep*^P!s1wakPu$9`(?sIf^Mal5UH=al`6Gcp94aOI zG^SIY;%agYJ~pDF-k#WzwM^cmzxxu0!0I-m0!-Xw>alpbM34FsNmDMP@yM`Qv{opZ zxhxYWD6zBuriH!mnZ?*)?T~sEI9;J5-D%g`h?5danOFMQLv74MIkR;oTfgECS-%lAlw7+~;5_)A*lkqb9cQE&nIPpnA6XZW z&zDg))xmDun_Qzh?A21K-{*r&4#$-Ij;yqV?C3Cs=Y{y89Q{pg%~(t=HD|T=dMuQ^7YyO_kyg<+kx+!jAxQ zZI0r+<+RiZ1yJ6cj~%}_MRk&FG*4hZ+j^fqXU*DcHAm$G$U@V*n zcsM#8$)?m{VWr3IU}hdyWB5_$N+7a}8D1D<_WR#{nuHA=GjH5WYyHIL=aXvE+g9S* zt58qYJgc#+9j;O|RgxPwd*3z@Q88f_{#e{p5WOP1uNF}9MC0+*_lwx(Hk0q7+v5IJDVzVGBR)lI~aoF z`mm;Af{OV`Da{v+U}+*77Vc?me<@QLN+R&5;-D`gF!C?Sf?Us$pqS@U#aiXY)IxCr zd~<1Z8r>*z;H;6+nXo+T`*U27O2zZxg+Rh@v;=L6*Vrfh^Jv5CJ>;Vb1zJ+KBBx~^ z#+XykuBE>{*+hx!JLZdW*Ssv!Ag2LgJ~}Erhcqh;+?9Ud#nIC4OM(qj%G3JfQJD}iZ4V;f)EyZLc+(Ny(3*3SzM8xFJ^F_u-TAvKvv1}w;oe;nM~P5$Z= zs=71LLf_?^^GTK!mrlnuN}|ka5hBwPmOT4<8$EaY<05#u!Fyp%QAg*uf%yW2RMFI= zg6GkT`NYkvO_Z;eVM4iC7}DwXn412W@VAGf0m?KEd6MG7s;T6~lYs4VFaMUvOQNq6Q2&$t*F^8fPpSmcA8%Ir z>P0Lka21Y>Qyu-?2<-0NeD+_z-_=zt;1H`wm{;BK^yUqEOj$`$$EunVU?6S;GQdsy z;{+0lc!A`euw4l!DA@L}vCPj)7b*ECDv(@$A12{k|1TJUiyOO{-7DJD#v@t zHNI8`mVVPdn~7XYbApfAMh7q^$2_Yh`JS5`L#BPg*yGt^#kN!c@-fY;chs-vGQ^V2 zFd^a`jldhB_j>o-1^9KAYhSml>Z3DB1prz?MVtB9S%jliJp!|G0}z>4pg?!#Z!O7c zi;V3x0`Vp2))K6!xkGl>A}hLq|(@A}z}hm{47_6nM$YVFz&tXbIR6v(TE7eVDp)!`Cx1 z&t6NgM*(o5Wr#R#PQS{Dz2#LE*E?$5rnv)=3|*=Z=Ml8ExU>fEO1Qc28n-H}2#qG@ zI)nMJB?f*OwUkX}Aa=U;U$X8h&{te0wygWniJJbN@gsNO>I(SHz^tU&#l_1vl(RJE zSNV6LrGd8RBxAxb8Se7V+6ov7HJoqP{FC8PlPDjErj*dLNH%AF#i1W^-0|k!!j=?S z^!1ms)j!?dpt`FsIz12{8~1V%Qr~d>BynBvb=ZvtHW)t^89luXsPyQx23ELZZwUHh{om@{6=jVDofC7 zV--$mhi$*2s~UCC$cxZI%2yO}S!DJxq|`#YDOtY)=}!T*rZwXuDnpOUglCfVZHAkjo^k=Z|lG=N1?{n1b8rr>>RLdQ2KOsgUW+w57LO!*xePx$uL88O}#Wgzo-j zO79kz!$#Is$9>+*&w;)6$XFgw_NZnzaPuf?te~L7$2fF@A|I%<(?0fmaN8ZBlfJvM zugCVMjp?K_eh5GxGmHU-{ThVld3FOiU#F4WjQy3%mz%x5@s%{{=sMh%9upyW`_9LccrR*j1();iswec40$e;nXAnxZUI*(`l7#JBDfx~Q) zMzd*~ifdVLJMwfFx`ZpCxRb_E!|GkjN5bSRZ+@x^;cpa+W;tXh(8so+dU*`ecDcrM zzDH}M5R~sXGwn>J!M-edI_n;gX(fID^T%1AQugtT<1oW?1uq@C_8UK?ce_005vqt2 z`b4@kRX7**0x2~R3q(6#rMfJ-25UQNF>5Tumw@wMa91eGMyO{}Ztb5D8nh| zntvhN$VuDo-MjPv=kG!dKc%JlnFNP162SekIhos$4PQ~tU@4|vE)}6x*RCTx>d#w3L62sCQ%7v^Hoowx3Cibx)cK*p9 zer9{_q&*hGDSI*CEj;E^a>4@c50$C&qh~3ypZ;))NxfHTI0+Jc#S+OoDOdC%$3*5T z6D3OIxw^Rlv}*=v2L=WX-4A$KAR8E_N71QIvi>ExwkrGg`Y=8Gs7>Aa;#sXWHGDPM z)V8wPfjs%qWaDck)`uh{I^M5X)ckYiqHYBI^BMR-ll0B-WWwzyQQ&>CB~=|9Le{V zDAy-tFQL5j_yYRRdvPv>Cr$ejNMLr}5HoX|L_{JZYaM=9pzMMIub=c&M9)5UanOEU z^Y}r!e%4^@wz%W(k{=@Q*Ut$O?TyR;x9jfDF!l3w^B?ij%I(fUDVhz8He9Y5_RS(5 zA{%^e?Vm5l;nf-xSiJ8di5xG#;kd7?@rwz{a1>UbJn+Q+#bQq?Kk3_7W*To(j5X|5hD4>=#Tm_-*S^&@?Bmr%(C~Kd)4qsXI^%b zd)`8DzK}*{&-<9c6JK>!;Aed((2c^U(wnWH!AQL?vn5>%U5itXHY4@%DuY5gF1xlKe!LN%FCa7MsYGpUDE%uMaV{eP`Sn!5{vL&X^1xK z@{*VL7>9!)rQ-p@?N)ghx>`_ol@DIrGc9^NorKg&`Tgg8n(EH*k!*SzuaSzan8&p= zkn}_Sui?f2_CD7ot5M`X^HRR#<;ooJ8X9(pv`e6$!bq+np)r_~0?!bMt#cH$=r%b? zb<+>(YnwUU61yW)yKe7vKk0M%ORdw+_rN4pG!EhD%L18VnS0@i{g_Z#p6I8Ly=A~- zJ9gu#bak$%#^(%R@nYxW;{X?Ig4l6C%QS;{Tl3k0$Qbv7zB@KYlZ@KWpz@1`Lkm=# zaHDmblCxs_=8Nof2762Wi<?HJ*rkA`EM$Z5%v_5GY5k*~VCzjF6?)pP4l?isb1R|l)#^WaM@VYb6LKopr@_39W zhT{G_Y?C^#BMLe0g-h=jagi;bx^}B@|8U8$%Tt3g-kP~G2%ooZTMG5qjO}%?{cc*d zL3s{WuuK?)9l3~nVcH14#nb< z%zIsw0hkQhx0t;v&Vf@ncnYhga9ZWCtwM)PkwSfueOR6^>bbks?)*b1=lw1DI!C;C zKqft{VKqpkA!LH^%uFx3S79IQeu21!&FOLO~ z$)PB7ymRxh8n6qHj>VWB9l0#Ke5`=9n*erY3RwDYE6ikA^}ARGW2Z5M9mop&oMG1y z-&6Hb00jiK`9+fM>__}aM@ur$sfV^}j^PgPm&2EJKFGPi?I!~5#F z>AIV1nj39zI-3^@WEShQR(zyEDU#ZdlAuCtjtG-w&cPL!MBW*mE;$3IH7luvv!y&I z5SNiGC|Hdfc@<;W!}H$pmX_LSE_ zCYdYsQdmQ(f&_M_Gy6Bp!;?Z;I2!s!k26mfxZc}g)Dm`w#GgaqitqD$7W#F}cQmU) z;>j{%@r6V)9A1y=%_B}yMTFnv=$Rhx>K?AT-^A~|0>^iFSp2DC0y2E;IB&?`Q!oXG zg^e|up~OHObvl2Brpl16HDZdNUvese#i8%~; z%(kIEFJx9h_)VF=6G&b{c_Fj9boK2gc&y0YYqVpZn{fRxX!KwmQXE$Y3US(y~v92PLauEkZon!QnNj6rUVx8-rA z7Rs!JE5;HORb@ZDHI-Bt(@l`|9zWylr>%+tnI@TU%wK-R5p@3$H9K?Ah83Tic~QhG zx7jwE6U25!OZTBFv}qf)7|eiomI|5ammhcn3aJN)Ml#*Ejb$Ec3?IPPGh>Yeyr4h>eI0#! zCTQunMP#Q^(foYX|IzF=y%|=1=QKZ&n0YRO9~pix#UV5QJ|2RJP zNNR~AI9deBNv$YIeQ>z?gFB+bXW^&D1R1mV=O?)5!;gKDT3MwDeHG`Dc#+J`*(8Gx zq?k)x1I<^fLd^zM)iib&`#n_qec0Zc$1+@3$DBxbYq9OF=l9B_1PMoqfx`=hS0B<7 ze{sP4Kvly1yw#uld`SIQX3y`Tf21S6=uaW30GRkwA-v*+rEV%dHn`_Z@r&ZnT!b!?;a+fvV7QC(P4?7y>jMdV4&I6v=A zyWjr~@7}-1_uqeyuJ1810C#{(Fi8?jIP}ir92lN}At_rOlH9X1_e8QbRpBJrPtTaA zfEd;m-@PrTfJT674^fzeq{xht5a=?)(n>3Ax5lkS(~9B^E2T(w8-_fBtLtiDYoDWk zr|Seq4*q;b-+OeOOEnJbYug?ue+z9x=hN4I5cgF;V-zL+P3K5LH?+h^l2~tykMfPo zi(;XXx9AinxwG>Q&U-9jfk&}Y>Aio=fXTKFsK8JKOIJc706XfnV4&Gx_L?I?Oj2uG z8$_!hc+32(8F{5WWzHJ3lG0S-k3gk3Tz-x#+H!H1ZA>JmbjhHU!7U{hm>rg+`C@YU z-V8=^cwY5!Z;@neJBy7=lK`}ch#dz75w*LFj)&FYs_(1woa$$-HLc&W-P#H zs`piJV1?~l)&~0yHb7O6>GSLyt>&2Yf9>^ftL+I0_1dk0VM{@>zTdX5YQiE8yt;%6ckmSnH~&(5rEz>b?megMPIJstd7=+p^>E8pymQ^zPBby|!BO zjXA03R{@+BrEaaK)*P(noRQMwxB8P#u-6;KN4<6|__+0c^)dbH$iaJp?-G#eIuJ)( z=LIn?VDI3ZX#OKJ=4D3Lc|5**kMF+w4*%`H{WtvK``^KPkLhy7rEe0fIX6CS1o5A%YF3D*dmrUi%h z-{Ft%zsJ+#0}i7Hm=TyUO;U$xiV<<1(Njcpz~~4)IXK#P_b1W}b0H;plF||4I_nY; zO&#Az#7TKX3{r~?2z?JQAButw4l!t^yRCbb-2?WwdT+@dmTa=6?$%K1eI-}XuIoUs zw4d^OZuhmG6LWS@a>b4Bcs!u*JAfF=B0NeJLw_%gh%g>{fF41_Nx3O0_zs6)FY6?NmcmJNKNU)2WPoFG;jr&S` zfIj_f!C{CIt`au)gxa_CWknoTOmr(WubD(5JZ=qQEI`nC^WJ0VdpIZQ#D{UnS@qW7 zseJc7`OYIkToXz$$=z`!*)8`9oqOQPf^(u$%Vr$Ml-a3NizlM&B03B`;9WM`uh;f^ zEVXt^DYU!a?>&NED_rVl+`BIJp4$R{d+%hyW_@n!dH~t-3KYhpz_2BlsLS-1tb2Vg zwQkw__r1?rN}}4ON}s9gTjNF7V{cuBHAA0GE|K@M0lxJZ)v-_av|9|>&W&9&E&il` z)puVl81-}Zl0+1+F1${^Zr{^>X36Rn*Wh2TtF6~9+SU4O$FlEx_})wGQ|CdE(Dl7! zT#LXQCxj^RBmeNnf5Z>}?=`%DsNK@DUn!Dy57V2BlFyM*Ndk^B6eOT<$AruADG+ib8?>wh^ zNjKKxs)?H*SS?T|K@L3=r09Vqey@ z&vRMP1X5*sDK@RjyjoH7rR{47{(@7!p~5-|*26I1@#zsD%6wKlr;-bv#uuZ=<#PFY z+^l>VnL*6SHL@uF>+#OATZouLfOqTlQzsz#TWHzxlsAFqhOS!KB*;vnUifNxYHbRj zSe{x8lw7j*r2E>*0otjmiGYqMYZ*#vb+I_b=&^*hh7NcQCy2mYG`8Zt;-iO#!m;+l z^hd|8CG^yckkg{q#bwVWqLnsU$5qEzwZYnA1hg2g3h+b>a-Eo66O)h=Zoc>zw|X-w zsEnBzZsR`mJPQ&T>!b_yGwSx5KvjQt#^us#NNQn3J}04vwv5?YhnOW0|8P8{s_QZE#TC=ZfC{ULWlRFIedJ4Oje?RX)60~S!Mu2 z9EV=+X+fU7pAzl!`J7!zU(-hEZ#F~W@p#O_t<8j13&U$hEN^{ptA&J?(6HCn*13C% z8Vj20RNAd|y7$|*|NHNyF=K$b{YG@%5kx+@^OR?;V{iau3trIvjIG@j${_tP^3;fvO)AJ|%fB(<_6CZ#4Q8KwQ zz%e4sGvbmGAaIIVAx7r~2j%G#oL{GhSX!xLz)J`S>H2^9#bV0C7R*9LRTYaRzuB!>LVygBC)S z0`_lF9&rYtNbl<$Np>_Ac;!5By-H~o9S^%_YfJy??)lk!$*6Q)imXDW&sMRqzo(_& z%#3-Oae6rw1=JF7IF4{0t9$+3G%Dk(wGhF@dqrf$kdlpDz%fGN8J<;{7 zl_YxaI;J$n2xzGvTCbIR`01~yZPnVa!cU7~w1HE7t$tPlsn=F#=kt|E#}GH0lmP)( zFyI0JIKWXXe$&v}FCL&CA*9gE7!%XdI0%hxswc7#ckOUQfJ@caodcW)I(AreApx3R z0_y75YMOn-ym>wjK$6A;s~MA+A4!^!GyoN`EMs1ey~)b5a~;vQ)dIADZzMnib9Fql zP;tG^9Bs8)dyM6^wkxDK5io?2Y_*hDu#*-*u7D?9zbbGEV@Tj>JYXCS=={2llO%{x z%Tmn37O-|r)xBdi-nK8gXEdA5J!7z=7g=eEwI6-o z>JO6ZVOdvJkk(iytChZ`iPG^`Aa{ItKtBxV`VyC7#|01pfLLipY|xw6$4K6#1}mzm zYq+f#K`bj$s{83V+SCf9?u#(jU?niG1-{R1*W@Z`i)(ki&*MXm;K@UU6X`cseX?U= zwDhdBhDsLD7!a0#d07yaMV^115W=$Zr6(~#K$T~-^Ny>-mOQHk6ZP+H!C6~mDYCBF zpnS5-E-B6j>bEAVnL^2PNF&>V1djCC! z!x0ZpPdFYPu*8Ue{lEVefBpCueERq!F6Rs2Jo>H!rz~5Mg>ZBvRw3^k2oj{9U*9Uq zDuvh@ycCx!U~PE<7sY~0aZb!8^*$n)3G*z;EP(eZ9uEL9Bu%$Vg8nvzz5PooH`M~3 zh#Z*2^C8BFn7m64#|L=V!_QN)>h%aLvDMEnC;Y$u-~S){>%ad8e*cF*;D;Z6z(4%M zf5X$$d%S!19fn~l!#U+wD-ByGzp%c5mkCRfRcmGavMl0y7eY!R zA_b)#k<@{slAheUICHdsImtJu=9al3bN_lTxPa<-)C0=%WsX#L*GhNhOLh?F29 zp)XB}EgCXH)b!zfw-GinqtN5|uMi+d4qz2(CD>lXN+Aqk2@)X7nntr|pYk&r%axtN zqU5p{0rE~v{j(5z0Z(dCk^ZPAjSM*C$VKy?9;HxC$15f0MpHp zMienHh@_SSlcbh*tD=B}y@(mLUhM&ntu}PK88kjZH>ZRyF_>g5)f}7yUX_5R>s|JL zUT2BX=W8)SVC_Dqno2#c*X06;)%(aMFD`N`M(YZA@-De;@*+%H&-Y$F`vk($Jv3|A zVI1>4OJ*^#GKuoC6e<;02AM}kno&rq#!KcYT4{2KIAw@j&%ytny+7%(B-zpgvG0h8 z4tFp!caQ14d_z`db5$s?|3MWs>pcpBEsEmx|0qf!o`szBC1#Q+P&`P5$^Hg0Pc3}nyRR%3`frR9Rdb`CTeis zaLo^tgz%5Tco)XNXoE#nV_#Ni_WPKF#)S@f9a!(s!NOUtg;Ep+lvEZE@y}h`g1mDsV>Q~}N%#sU z5c}T3bv>JdT<2@J_*d0tv_SVIURnYv)zu%bGMS z2wD-m(I|~UYq;2H-}mT<3p#RY+dUKCEOIRB9+=R6qc90GBkZQNz~8l(Ip^JpJ`lX*u92?jB0 zm33i12jCw?AkSx|JkzBECq6@K4Xq56<~);nQR3?QhWRQf^wy%;?eX~Vh{w$aZPTD> z53qd~g&tUku4(xc4bXRr0>HFVaIOcuhej5 zR%j19XxF2J!>e_TO6w?8@}75mPKLeY0C+|4ialMs=76T};Jk&S0-d#JTN^-yL{5rt z!|xbm1tm%%Td`A|(VxgV* zr&1<@cAb+Clk@Eu?hPNjZyhU6ny^?fh!6!&=!Xswdmm%gsG-cc5R7v&XPONaEPE!1 ze(znBR-;_0Rg!5vq0k1`>ouR}o}Cipna={icHc$>NKFd8Tx z;`LQpaoH73@Z{iqNR=VJ$05~{lfI7+U++1BW=_YLqPaEmY;$rZnPfSV9t^rOAuOLy zE(jqqh(bhi1S6JDQeiLVc}w~AUapredSfzA7j>grGplMi)UXQxq|tjFDoX z2u==T6%IQ;vbuW4>lp~L;eaI-tSmkkkkSvz6iR`4^r@A+#kg5=N*2g?^2oW$_hi;9 z{!Ydq4Ah{pVUqWprBnVc(=b+|$1ePMT^w7=YG`Fco>|`HdwGwc_0=I)dd8Mo0HIpF zj*N5)TtI{uQF{0v1!ZX%zt0Lr4Ii6jRg+2 zZ{ckZ7c5srQNa5YDkfnRM(boiAu&rJv?am}qViVPHP-7juCK1KTCGsm6(}aiLiAL*pibj`5ax?eQ=x6#&QL*!$l?#mkTI79Ho}9I#^_X}ZMYT-Y%?t>0%AfF@ zz^`oIqstUE$ys56hg;O760hP`*Z@InGV+0Ua&0_=wBmgHEJCyQ5)v5d`app+doc>F zP!7XT3qVYnDhQ*ImzfEZw4zc z9DXcHc^VT>2%g9Ac8WbsKz<&lb4&O&z($3(>GAlugHi0yV^o}EP z$OBGghF%}`gb!X=R?K_VbEJeW;IxAa%G}^=a4vczBr4|ETPslq4%PTAXGnSY9?8ouGW?Xxl7IhWD?slel~7jDF;#swJa|dCnO%G zL6U6tz0NFj#~};(yXVT{Wei2`brjX)lh+;@Dm;ri5+WzaNs_lR?yGYi*7qO_^u3Lt zXnC$4aLhEd=H89hOj$BQ(`vQCdcDSKy+T!$*;vt8;}gAYnK1G$%z4(*^~627*EH^d zEC)yc937LU-`6qq$mibRRC-m76l!?>yUq+GAcb6B_ThA zUpog0o%9}AXdVE{J=;mp;;=?S(;TqbZ1CIP{vN;j^{)XUeEaPmacEl}3)jJe4SiA` zBHv#$vkqgFN%&oP<{7#uI5$d)DaYXvJ}TaILLRm(&*Lj6zRSj1a)6{5Xun>;UpXkP zL*56&S&I@Rz$bD}K}{8b^!1uP*aL%YPNKa9va*X6Y@qP!0?8&yPvclEXRg^o}v#FqTfz4)% z-EN1zPiImpZJ}c*wjf@L@>CQB%F0Ak-m(-~hay1G)D&E#aDD>x!IdWh;$c07B9#9F zB>%!k7j!hD1Vu%1mg44eE|{@WMPua@ymGO~qqsU*A)`UxApLvd{L4KRP#l^fVLpE1 zuo)uZ4ZS#tFUZ12c=vS3PcqV=7&`A_ytG`V6xYX~U@vCtst<~Ufl?thID|9~Usx0= zihoOrS$c1en2@;Q1OVRe8b6v6n8jc{J^3g&@Q$ z*nE@vCIY7XH)=m$yW`)r;yN)B<2){mI=)Z#Y_2fL!JEIUysxY;SvSnA6&8yctJMPQ z^$N>n9mWzt&>F6(asLPJ7T!GZkkhg7bK^V<8LeiXn<@MGyGoR*C^s^Wxp#A#Pn<`& zaF`bsmIE;tZ20fo2UD1%b_5!le-}?RAOdDQxZ`tk9v$9O`s2m384MVjV5~vkb?C+N ziRrl^qM7keLj9bAGags@m)9Q>0U(wN$lfU#+=hx$K9=d)3&{_ygM;%U&ZDd)4pWWi zl^P1aq}WOvYsP5<4?^E}aHOzUEK%1U%jE*j*#I^Wl&iqwoX?{kC_Zd_Hp;w<1v{Uc zVNPc96i7q`kpM#Y3I3UeBPnb{ouyfgf@&U$R$*A17b3$CD};BXw7wW6v5eG08yNpV4aO<#YDv6hezJLp^`IJ1oPt1 za*Y@|gpcHNK3AVjj3kG{A(p&|4148Gfx;9ach8_O231|6t}B#f0b`1Y zR;q)SSNbvj_j95j$McjOGE)L)PEsX%d@!Z&vcHS&K_1>K_yF_ly$=F*f@$>Lg+gKD z=bb;H$Ne9FH*9N8_{qN?Ti8S}nY%Y`MCD_sBhhiPz6e0@iNR@otk6tbX;?{}D@>c1 zr=R?Lde0Ga_Tu0QLX;v9>GK zilHz{fk>Fk@IW88lPgL2eB_7kvFA;!u+vKOQ$*PZIY7M^?*TXKXu9obrH0p)(kX{a zycko$tQ5f%<$A0*2u*#KF{$f{!66nLt{^|f`jsWMoH;(p5HQu3bLq5lcHTYwjzI2t zOsJVIqP?9p*E82Rmn%lYkjb1kh)^R1n?ZRJf8arwQb_pkJikei&HJR{{w9!7@%?h1 zZpc9EplmlyRMO@nTPEJu5C1;p37Yfpru9~b8Z8UyyE@k=}+ zIm3JqHj`qKEAGPAgy(T?fr100vT;FahlhuIJUl+)@o^L2@g3kpm>`nzYPij^(6)T< zB7}8@vq}tqT^9^1K8v~-3Fv$d<>Pof4u}d=`hKiLfVC;hIshKNWHKX|Bkd5LP@Dp#T7$JobkJ_J@YY$ayrKlz3o; zT|&co968)|Vxh!w7a*VLC8dA>taR`oj!@=g&yh#I+@=&KF(#yt@)TLI-|wT>=@c@k zd?$NJYE$j^``C6>RZvuf`hZXKI)0Wz*Y#*y2Fu`oJ4S?52#RtzE40BBirjP4MT&rr z{~iA+7_+$eaY9mr*66zAwd=Z$-*Hg|4-kjOYOMiM9FsglvgX$7HJo=)MFFMFpcu7> zgDHlQGE#?9>jGs_p)4z|RT=85EtiXkP+C=0KoQn4cXTXg{oLroD^Em63IZ_nP7DR# zq4Jc|vBloOSwLL#L}KM8IG2=(RA(f`B+tb=Pm)heR&p(p<_~zEhr^vdOrup+EVXjb zlQ^M4ZL(saw*plbHkB7|hKLuo#K%p2`b7WLVp<083cxF8v3Fz`qzUR{RAxs4^0dz`X z8u!Nstz4LBUDwfynAh)_Q-;Q#wdr@rm0gXxuCZJ$v0ksST-I1Dm{}*@Fm2&HP06Y} zHD>3~x#K@~yvtb2GKJPSJQTDmvbSoKsN6d13FmoJ%;` zE8{WA>yoDy1ZkQOHF9o4&DN$3>kBtG9<2aR>>OTcNe!> zHa|QtgSi}xUbdc{bLcw{AJ(-9`+eV`ZLdR7T`qtOACxG;rx*>r_b%44YTK5_u`1EJ zp+YYFZ+xEQRM$03QK9QN-_R*wQ5N{sufD=pFJHj!ws6)#OGhU7M*dA6S`JV|C6qBx zq>j&)EQ~L`F(h!cTA?U3QrPeGIhXgx zIgiK3yI7F>aM*=8Zn>^jS)#5ND2kfpi4)4o$3}Vh>29|}+qLMeg;p$|^}WYtv%_w; zh1Le^^%_@KE7XfRd76vUUN%{$Wm)3-`WmDSK$;B+O2z%rG|hmgNeK$c-xdQOe`bSf z5$c(hr9lx8Tyq2R*ogddA~P0l^39NMxZK*D3(;e1-e3bDc!z)^29r-x{u5c;aU!uG zC(9c@MlnK^=R&i2?n<;8WfSQfD^T9|@OG%6NllFS?h-N(O!s5!wYZa+dg(fBEbiwq zX3S~)q%Fkr!UIq$w`S&VpR9s>9c7C%Ssf`0f6GJ908XIg14WAErNdt!E;-pyP>Ry{ zj0NQ+P}mR(!M#*r;^g|66GQ~13LqFsr2obgSsz1KolaqL@=t_aockR5uI}xdQTZFh)WJps7jPok>I0! zzW>ithK9=f@VS@Jtdex$^(;Il%k$xIh~axu0bV?9@_;F!ar~KuCmWTewrwLExcogA z>|`&u0m8hhDmW*ht;cQW`zIQF2+8mhKu^e14F7_c&>sx=d43LXE~bLDj1YQ?j@G6J z{KP%uwJnMe3skZW9Ezd}VJBr6o6)(2{X6HdUSHwv;T~$w2%Zj%{#aKPKpwsA2LgLM2j%_A zM@5K;f@dkzcnjh5&I4`V!Feubs|yX%L*A|xpQ*f_^4z}6Fc;R>JU>o-Wrf0M^Z_ng!q6m# zFjrV)ZTGh4M0*OU2Hry}k6(TDEByZVe~vG1*4Vy%gWK=F=kXY=k@&7*eaSQPI(JGb zILk_2p*aUi>12>%AP64UInbNjn32nL@=l^i0f=Y%*zi5IPlV+9wr#Q7?Sgkmp;Qc> zByxzXTd7MV9(4Zfu-_lB+ilS_4fD3i6H&mFQc+3H?@Q-@9dn+_l8vcypVpGk%|>jaIm~a$@bq&cGxqWvTf-55&#xIX z{4qlliPqi~ebAnCkXF`|runf@P@(r5~wmjED4s!1ulp|PJz}jKv4<$>Mmt#Yl zxVc$S9N2;eo16`3Q_N)e46XC9yabM+RD#vc8B-K|l!^#Nd2(EU;?Ay$|WVcdPHlOto2`V{6>QOvuQKIF=`^iON{I6(&`BtX5&!NcC4u$~5Ca)4AU z=Yzu>y=OwYOAyL3h7uc`rh}rQCUY?!FZn)Sci~eIRE9=^^xi;jP4muS2sScJ$q)gI z#qp;sHUrc(pZ&=1d!mgg;Y5hX-VF{#1ee+TH5+O*|U#xvJ5}?QYb?P1R{G}X>K`7?~>3&23 zn0bJ#Y2H%^A*5-)^PZAxT!1r`zw_IPRm%g!%5-ih8lD-#^MYXv4vb0oew6QNQ7rgS zmwnF&a2#e*ae-Bp^1E0oOK6_b=Ge=cKX2-@(DYt74kOIxU4#_23RfYARY#;%7ecfK zA(=XbS$XeKR|Rffy+9X~fihT^fAeR5hTr~HPp>d3p z;J4_yE{50@A&-gA_h~Z5;Bm9X>o>3Q`t@ti z4S3+yXRq+v-~I-#)+@B@H4d9cxULOIioX`g74aygxTO=~2{#7+#vDiFtb> zuNtl4ZQzRo*_^{-z29*NV^d7v$*{dV++vPtjXw_$1-5SGlyAH# zniD+6VISUmc4Igj(R{pPL^MfUSD7F#8nU%LtW)S!58ta8Go2Ut^4>GFC;@OD)+Im$ zPOMAGyw*B&E&r|+p)7_1vAm8_xz+W!iv5uJCNCO$QB*j%C}Qr5B}(owrpUrijLA3~u$58GJ?knBK^A6OuGa}YvJqwq|vDS$7i6j~P;tq6y?=Z`&W4$3GL zrWhz!`Joe&P=kb(|4rH-eg}*}Bjzag?uG2w&*-}`d{LxwXA=Q{$`p+#$WFc6G3E1-D?7%RQ0=}Mpt)Jg9?m=$VJyt%{6un2 zR;v|Os}+{Z1s02%b5OL5U1nh?eycgp*;N1YYu-ia%G(*!r7h*-DPGikt%-o)eMmA_ zX7Kksr$NRxQW6)c!J6041I+P`FeGd-JPC_Xw&K^zMvVvDuAR=_OXEvudrM$ zQIrDaF`x4BW73gKJfTRig5O7v(*S*xh`s7rVRFQD0Tsr`q3u zjn7K!Tug~rs0u})QP(Bb>lJo84u_N+D_)O0t^$IU*LsS^CsNRcLN24`5MED{v9D6A`JV~z@E5-1k1m31_A5S;Tl3VY$u zeoA?ggGc6P{M^CX4KelS2vqOt5h3r7L=aDi#ZrB^W=_a^TA4`m0i;|VK}`}1?BQ?- z;S`A8j~pamY$%ZRP}eo;MIGQ+tC)PMw9K&x`7+iX`__@HyvQm(c7p=Dwb} zUJg<5KFPR>M-M>EM`BS5;b&32cQ__V5fk316u`ML=Z|H4Eavx9zW#ErKvgjmeo+)5e^lNr!GY(H z{8P_3tA7*MrFo&FIn4#XeC{G24PJO{G}mCs?%|q>slBf2ad&qIN65lJ75?t;{tkcn zmw$=>=D+^0(KZeK`~UvG!_})-sHy@UO8`JsmaGsdg?4{H*EF$SSl@-Hg0e*62}NO0 z)pht=%LP@vM`0)#P;~NK41q2ZGNTwu;&8glc%jk^j>L+c)aCQo?;9wkW4N&tANQVl ziy{|u$(-}(UE*EVT7VeARym8%}HNJ`7B2k{A2Zjm&$(SnZa83@B_Yi>8FaV|@Kk zmZ8BOl=k*Ji^sq-#JegyZNJ}Rx7%T}*O`<&ulFsub$S1|19i zOlW(vy!?#s<7YqgPKv=xloc^PCYf6P9koRLyZzIFB)^gD>?_oWKFbR)XL(B(3S_FPgFhv2Q6j$MvukEEVU4Sb*ewE|0eCP?QDQwhjrF?5$$vD1E?@GL(C{c=PCBjR-Z7 zw1UxDKLJ*(1pI-xKq{1j0B+>ycf$~r;F%+WG6tmdVBW{;XI{~n^B&0s?CBZ)X<7gq z+?2IH?#tYIJ%@NrU1%|*DO)`TM%^i)?_6bq*RUC^VVSFZeaISV8k-3zGzdjV?dhyO zM8!pTYhI64RiY?Tz7M~g%ao{KUCv(mY0uL!+TNx7=hXO2(X3ZJJ5X|uUcRn{#~zvn z-XkigdEfJ#0I8+Y_gz>+i64&zmto(Jq51PXO2k~!X+?Y7@8hw-Kp7egW_=~^zb6j0trSS@ell^v&{cel>evj>DgTtP~sGRp$U)`YVTD*Dl26a_I5m1%| zs;WjAJjYd4K^N(4h;t2@?%d#)-d{XNb8~+Dy^8DA1tVu~SwIzUjTG-@#RD;|AYZ6r z6cg~8ZDX<7Zt%xH{xNvRm$8px;m`M3OtLQw99k$9>Kl2$I)~RkyvD!v7HAK6xm=*@ zTGVA36``Xwmc1|UO{q)BxoKVuXdWEG*QZh-2qBoB*!zUc^CV+A_SBp*qUU+U$BE!oudr&gZrC#-~*47e894-18BxzHB7FN=b~J;7}NNC ziDyuj?jcIzNpaqLDAG{~DasOs zF;JjvfteU~mqP4RwD2-xK)5bh`1u_7Y++QHr%EaIK0&OJninc4S{V5L5VN1vEpg7F zt2@+ng|6?>cRjAJudv@A(6$Y_u8-p*N?Y=J8EB(Iyt;fgp=Od!;Wpu5REm`;6{?~W z2u3S-vhcn;+F1F4A=RiADNc6I)?Qp!vq}<1*Ev~igFog8;iPyS3AjmGamSz8Dt!#f zF&Q^b(xE9PLSYTXVMA`YKbOd}#d)lA%^5>1f3r-m%NWi}V{ z?|O2a=MKs>wd)6})Q3pe)J|+QNJdu$iWn!h9deb47p|-y!{x`Hj3oYG(lv z*)ty>$s+`UVN#{=9~lcD&O#!B&%E(sgjz0ZP!qy90d#$XuYUb2{I~z@e}{ke&;A+y z5C7Z$J^uN>_!sy$|K{J|)vH%{_1Q~YU0tIr3OLK*JrB2cczk$7+qO9D_SkN>T$t8- zY<34+U0>m!{?mVo{cewc`1`*{-?ga95_MUEh(iFYvdYdsIqh>rDdoWNcM1;4=yDGE zOh||KTo`!!h{wlATwhyp`5k zn1EciTrA>q7mEd|nnOZ$p`jWsl50a`i-W`8{oUW;5C4gV4Z|YrdDwlnkRVYN@hU%Dx1!kRa$O!CEWCtM4e~HpGuR8_2}wXT z!sjq}7Apr7JS`S|--Wy<4rAl6UjQ z%1|;Ai;^Q}B##+_M>H-(3~B~QAzTtU1i@np09>R8A%8Uw<=*f2SS)HR7Rw0mKp>FT z;rygfD7=V|ilM>Ig$S$Q?F0o`Rt@A$1X-SqLfo@UPS{UX%`!fQ!HhNLbWu{E5QX2d z0LGh)FkWj?Pa%FE1~?u-;K56WOVGFzj}4<6L|(o)+~?uZ!zl}qeZA7~#zTswv1ZQJ zC~Fj~Q}De(uMG^C33P3XjSIybgW>=UfD}A2GI#R$fH;gS^v!Dz zHy7^=o8H5F6<#l0EMXk-ds^$sGngN` zD(|7s-esnUY7!pgU4$v7cR7a$B()V|4|uB_w=u=k=YCJ`D}7Ud@}S&$9uHH3Ql8hi z>Ctx%g;DWe(>B=eLk^+m`fH_8D2>K)Sz)zWpsq`3o$-{6CkdRn91?M(^M$9!CkJ=Q z*61v=K4DFqqNhS$#-A1W80Kpfk3m@|I7{d|7OuS05v9w)qw71M5wxuWI#}5IzD3g> z&~_aJMRcefOIQ&jfC}ut^A1J_^u$$#vMNxP8pcTYS_0-Fub>qhs>D0P{7Jxf@^z9k zY(d`}jx7PPaBetEK%V!l13;SM9&ka)WDCEEXkod4>|KsFN!c7bc!j7y=~APzCAzLd zRT*AuaB#lQl$bD=(V)Rz&bZ%+*yz?Vzm&eXkmJ|e9(_Pn^U}XCUd}ttMHIGxX zV;t_~0Y%WB5%x$EuMyAKI~-b_pT*%H96*4f0tInSFqe67xW2kV+cfyAzxr2rb$tzQ zJG8qU-hBT9e*e4Q;pNp$JfE880Cn>MSF0;@eTT3A)7SX+kKeLqv}>_#w)mg_7ymQ- z^MC#?@PGXu{s;W~zxj7iM7X=VgV6>z*H`c!c>DGi&9cF2wG6p@8qV9Gq-cNw9J}Xp z#(M{aa7GSUE9O9WthXRygQoW$P1oV=-94POSgzKn7t2tjT7euv6I-3cpxF@%^xH#^ z&H+`qz{~4vXl<}>dw5dln-=Z9_axq;W=2PaIyhmNuSXBH^04s*Z>ddeVFJco! zQktTC?G3%w5{cu2fkz@!2t^?tC<)I4td(3#DXME>t%p(x)QWTG0tz58g52TI;&A9P zSuIC(7Nfos`5a2ASeq?D`7@A$HU@AGWVEOgNdc8c2U{hQLrM-1=lWn=VrA_Rau}cG!BhHRR)AB z&rG>q)S(z|g}N?+!cN(^hfWQWPDLR&->MjgH6QQOgD~CB%sf98x-k|?0MALaAQUAh z>b6bE`yLL~hIb5-6G6j!mmwf=?nBpgXxau{*G8U4q1`-EAb)ODL_)QBuA?P+YhuvJ z!cpX4B?Se}1tN0U-bvo3aeh#^bCBPX4Nhtv`5tuunWU@)1i;XHh_}vK7tRYBK%?j3 zLHS`E!`ie$sS1D`+U@}7`

    x|B~a+0992@8Cq0O_~UnW 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